feat: eye tracking dots properly working
This commit is contained in:
@@ -824,7 +824,7 @@ extension EyeTrackingService: AVCaptureVideoDataOutputSampleBufferDelegate {
|
|||||||
|
|
||||||
let imageRequestHandler = VNImageRequestHandler(
|
let imageRequestHandler = VNImageRequestHandler(
|
||||||
cvPixelBuffer: pixelBuffer,
|
cvPixelBuffer: pixelBuffer,
|
||||||
orientation: .leftMirrored,
|
orientation: .upMirrored,
|
||||||
options: [:]
|
options: [:]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -59,8 +59,26 @@ private struct EyeOverlayShape: View {
|
|||||||
let label: String
|
let label: String
|
||||||
|
|
||||||
private var transformedCoordinates: (eyeRect: CGRect, pupilPoint: CGPoint) {
|
private var transformedCoordinates: (eyeRect: CGRect, pupilPoint: CGPoint) {
|
||||||
// Calculate the aspect-fit scaling
|
// Standard macOS Camera Coordinate System (Landscape):
|
||||||
let imageAspect = imageSize.width / imageSize.height
|
// Raw Buffer:
|
||||||
|
// - Origin (0,0) is Top-Left
|
||||||
|
// - X increases Right
|
||||||
|
// - Y increases Down
|
||||||
|
//
|
||||||
|
// Preview Layer (Mirrored):
|
||||||
|
// - Appears like a mirror
|
||||||
|
// - Screen X increases Right
|
||||||
|
// - Screen Y increases Down
|
||||||
|
// - BUT the image content is flipped horizontally
|
||||||
|
// (Raw Left is Screen Right, Raw Right is Screen Left)
|
||||||
|
|
||||||
|
// Use dimensions directly (no rotation swap)
|
||||||
|
let rawImageWidth = imageSize.width
|
||||||
|
let rawImageHeight = imageSize.height
|
||||||
|
|
||||||
|
// Calculate aspect-fill scaling
|
||||||
|
// We compare the raw aspect ratio to the view aspect ratio
|
||||||
|
let imageAspect = rawImageWidth / rawImageHeight
|
||||||
let viewAspect = viewSize.width / viewSize.height
|
let viewAspect = viewSize.width / viewSize.height
|
||||||
|
|
||||||
let scale: CGFloat
|
let scale: CGFloat
|
||||||
@@ -68,36 +86,47 @@ private struct EyeOverlayShape: View {
|
|||||||
let offsetY: CGFloat
|
let offsetY: CGFloat
|
||||||
|
|
||||||
if imageAspect > viewAspect {
|
if imageAspect > viewAspect {
|
||||||
// Image is wider - letterbox top/bottom
|
// Image is wider than view - crop sides (pillarbox behavior in aspect fill)
|
||||||
scale = viewSize.width / imageSize.width
|
// Wait, aspect fill means we fill the view, so we crop the excess.
|
||||||
offsetX = 0
|
// If image is wider, we scale by height to fill height, and crop width.
|
||||||
offsetY = (viewSize.height - imageSize.height * scale) / 2
|
scale = viewSize.height / rawImageHeight
|
||||||
} else {
|
offsetX = (viewSize.width - rawImageWidth * scale) / 2
|
||||||
// Image is taller - pillarbox left/right
|
|
||||||
scale = viewSize.height / imageSize.height
|
|
||||||
offsetX = (viewSize.width - imageSize.width * scale) / 2
|
|
||||||
offsetY = 0
|
offsetY = 0
|
||||||
|
} else {
|
||||||
|
// Image is taller than view (or view is wider) - scale by width, crop height
|
||||||
|
scale = viewSize.width / rawImageWidth
|
||||||
|
offsetX = 0
|
||||||
|
offsetY = (viewSize.height - rawImageHeight * scale) / 2
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert eye region frame from image coordinates to view coordinates
|
// Transform Eye Region
|
||||||
// Note: The image is mirrored horizontally in the preview
|
// Mirroring X: The 'left' of the raw image becomes the 'right' of the screen
|
||||||
let mirroredX = imageSize.width - eyeRegion.frame.origin.x - eyeRegion.frame.width
|
// Raw Rect: x, y, w, h
|
||||||
|
// Mirrored X = ImageWidth - (x + w)
|
||||||
|
let eyeRawX = eyeRegion.frame.origin.x
|
||||||
|
let eyeRawY = eyeRegion.frame.origin.y
|
||||||
|
let eyeRawW = eyeRegion.frame.width
|
||||||
|
let eyeRawH = eyeRegion.frame.height
|
||||||
|
|
||||||
let eyeViewX = mirroredX * scale + offsetX
|
// Calculate Screen Coordinates
|
||||||
let eyeViewY = eyeRegion.frame.origin.y * scale + offsetY
|
let eyeScreenX = (rawImageWidth - (eyeRawX + eyeRawW)) * scale + offsetX
|
||||||
let eyeViewWidth = eyeRegion.frame.width * scale
|
let eyeScreenY = eyeRawY * scale + offsetY
|
||||||
let eyeViewHeight = eyeRegion.frame.height * scale
|
let eyeScreenW = eyeRawW * scale
|
||||||
|
let eyeScreenH = eyeRawH * scale
|
||||||
|
|
||||||
// Calculate pupil position in view coordinates
|
// Transform Pupil Position
|
||||||
// pupilPosition is in local eye region coordinates (0 to eyeWidth, 0 to eyeHeight)
|
// Global Raw Pupil X = eyeRawX + pupilPosition.x
|
||||||
// Need to mirror the X coordinate within the eye region
|
// Global Raw Pupil Y = eyeRawY + pupilPosition.y
|
||||||
let mirroredPupilX = eyeRegion.frame.width - pupilPosition.x
|
let pupilGlobalRawX = eyeRawX + pupilPosition.x
|
||||||
let pupilViewX = eyeViewX + mirroredPupilX * scale
|
let pupilGlobalRawY = eyeRawY + pupilPosition.y
|
||||||
let pupilViewY = eyeViewY + pupilPosition.y * scale
|
|
||||||
|
// Mirror X for Pupil
|
||||||
|
let pupilScreenX = (rawImageWidth - pupilGlobalRawX) * scale + offsetX
|
||||||
|
let pupilScreenY = pupilGlobalRawY * scale + offsetY
|
||||||
|
|
||||||
return (
|
return (
|
||||||
eyeRect: CGRect(x: eyeViewX, y: eyeViewY, width: eyeViewWidth, height: eyeViewHeight),
|
eyeRect: CGRect(x: eyeScreenX, y: eyeScreenY, width: eyeScreenW, height: eyeScreenH),
|
||||||
pupilPoint: CGPoint(x: pupilViewX, y: pupilViewY)
|
pupilPoint: CGPoint(x: pupilScreenX, y: pupilScreenY)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,6 +162,13 @@ private struct EyeOverlayShape: View {
|
|||||||
.font(.system(size: 10, weight: .bold))
|
.font(.system(size: 10, weight: .bold))
|
||||||
.foregroundColor(color)
|
.foregroundColor(color)
|
||||||
.position(x: eyeRect.minX + 8, y: eyeRect.minY - 8)
|
.position(x: eyeRect.minX + 8, y: eyeRect.minY - 8)
|
||||||
|
|
||||||
|
// Debug: Show raw coordinates
|
||||||
|
Text("\(label): (\(Int(pupilPosition.x)), \(Int(pupilPosition.y)))")
|
||||||
|
.font(.system(size: 8, design: .monospaced))
|
||||||
|
.foregroundColor(.white)
|
||||||
|
.background(Color.black.opacity(0.7))
|
||||||
|
.position(x: eyeRect.midX, y: eyeRect.maxY + 10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user