为什么我的图像 CIPerspectiveCorrection 在每个设备上都不同?
Why is my Image CIPerspectiveCorrection different on each device?
我想对取自 AVCaptureSession 的图像使用 CIPerspectiveCorrection。但是得到的校正图像在不同的设备上是不同的,但它使用的是相同的代码。这是我获得积分的代码:
targetRectLayer
是我在其中绘制矩形的图层,以突出显示聚焦的矩形。
scannerView
是我在
中显示视频会话的视图
let request = VNDetectRectanglesRequest { req, error in
DispatchQueue.main.async {
if let observation = req.results?.first as? VNRectangleObservation {
let points = self.targetRectLayer.drawTargetRect(observation: observation, previewLayer: self.previewLayer, animated: false)
let size = self.scannerView.frame.size
self.trackedTopLeftPoint = CGPoint(x: points.topLeft.x / size.width, y: points.topLeft.y / size.height )
self.trackedTopRightPoint = CGPoint(x: points.topRight.x / size.width, y: points.topRight.y / size.height )
self.trackedBottomLeftPoint = CGPoint(x: points.bottomLeft.x / size.width, y: points.bottomLeft.y / size.height )
self.trackedBottomRightPoint = CGPoint(x: points.bottomRight.x / size.width, y: points.bottomRight.y / size.height )
} else {
_ = self.targetRectLayer.drawTargetRect(observation: nil, previewLayer: self.previewLayer, animated: false)
}
}
}
和
func drawTargetRect(observation: VNRectangleObservation?, previewLayer: AVCaptureVideoPreviewLayer?, animated: Bool) -> (topLeft: CGPoint, topRight: CGPoint, bottomLeft: CGPoint, bottomRight: CGPoint) {
guard let observation = observation, let previewLayer = previewLayer else {
draw(path: nil, animated: false)
return (topLeft: CGPoint.zero, topRight: CGPoint.zero, bottomLeft: CGPoint.zero, bottomRight: CGPoint.zero)
}
let convertedTopLeft: CGPoint = previewLayer.layerPointConverted(fromCaptureDevicePoint: CGPoint(x: observation.topLeft.x, y: 1 - observation.topLeft.y))
let convertedTopRight: CGPoint = previewLayer.layerPointConverted(fromCaptureDevicePoint: CGPoint(x: observation.topRight.x, y: 1 - observation.topRight.y))
let convertedBottomLeft: CGPoint = previewLayer.layerPointConverted(fromCaptureDevicePoint: CGPoint(x: observation.bottomLeft.x, y: 1 - observation.bottomLeft.y))
let convertedBottomRight: CGPoint = previewLayer.layerPointConverted(fromCaptureDevicePoint: CGPoint(x: observation.bottomRight.x, y: 1 - observation.bottomRight.y))
let rectanglePath = UIBezierPath()
rectanglePath.move(to: convertedTopLeft)
rectanglePath.addLine(to: convertedTopRight)
rectanglePath.addLine(to: convertedBottomRight)
rectanglePath.addLine(to: convertedBottomLeft)
rectanglePath.close()
draw(path: rectanglePath, animated: animated)
return (topLeft: convertedTopLeft, topRight: convertedTopRight, bottomLeft: convertedBottomLeft, bottomRight: convertedBottomRight)
}
这是我将点放在新位置以继续进行 CIPerspectiveCorrection 的地方:
let imageTopLeft: CGPoint = CGPoint(x: image.size.width * trackedBottomLeftPoint.x, y: trackedBottomLeftPoint.y * image.size.height)
let imageTopRight: CGPoint = CGPoint(x: image.size.width * trackedTopLeftPoint.x, y: trackedTopLeftPoint.y * image.size.height)
let imageBottomLeft: CGPoint = CGPoint(x: image.size.width * trackedBottomRightPoint.x, y: trackedBottomRightPoint.y * image.size.height)
let imageBottomRight: CGPoint = CGPoint(x: image.size.width * trackedTopRightPoint.x, y: trackedTopRightPoint.y * image.size.height)
应用 CIPerspectiveCorrection 时,笛卡尔坐标系的处理方式为:
extension UIImage {
func cartesianForPoint(point:CGPoint,extent:CGRect) -> CGPoint {
return CGPoint(x: point.x,y: extent.height - point.y)
}
}
其他数学都是基于我在这里设置的那4个self.trackedPoints。
这里有一些我的意思不同的图片,看看没有被切断的区域。突出显示的 targetRect 完美绘制在文档的边缘。此结果在这些设备上是持久的。所有图片拍摄于portrait
,运行iOS12.1.3.
为什么这些图像不同?
计算使用比例值,没有硬编码值,并且它们与大小比率无关。
iPhoneX,见space左右
iPad空气2,见space上下
iPhone 5s,这就是我对他们所有人的期望
我发现 videoGravity
属性 配置失败。它被设置为 .resizeAspectFill
,因此将视频的一侧推过视图边界以填充另一侧的任何左侧 space。由于所有设备都提供不同的 spaces,因此要补偿的空白 space 是不同的,并导致在以全分辨率(而不仅仅是可见分辨率)拍摄视频流照片时出现所描述的行为。我太专注于数学部分而错过了这种可能性。
iphone5s 的完美匹配完全是随机的。
这是更正后的代码:
// setup view preview layer
let previewLayer = AVCaptureVideoPreviewLayer(session: newCaptureSession)
self.previewLayer = previewLayer
previewLayer.videoGravity = .resize
self.scannerView.layer.addSublayer(previewLayer)
self.scannerView.layer.addSublayer(targetRectLayer)
我想对取自 AVCaptureSession 的图像使用 CIPerspectiveCorrection。但是得到的校正图像在不同的设备上是不同的,但它使用的是相同的代码。这是我获得积分的代码:
targetRectLayer
是我在其中绘制矩形的图层,以突出显示聚焦的矩形。
scannerView
是我在
let request = VNDetectRectanglesRequest { req, error in
DispatchQueue.main.async {
if let observation = req.results?.first as? VNRectangleObservation {
let points = self.targetRectLayer.drawTargetRect(observation: observation, previewLayer: self.previewLayer, animated: false)
let size = self.scannerView.frame.size
self.trackedTopLeftPoint = CGPoint(x: points.topLeft.x / size.width, y: points.topLeft.y / size.height )
self.trackedTopRightPoint = CGPoint(x: points.topRight.x / size.width, y: points.topRight.y / size.height )
self.trackedBottomLeftPoint = CGPoint(x: points.bottomLeft.x / size.width, y: points.bottomLeft.y / size.height )
self.trackedBottomRightPoint = CGPoint(x: points.bottomRight.x / size.width, y: points.bottomRight.y / size.height )
} else {
_ = self.targetRectLayer.drawTargetRect(observation: nil, previewLayer: self.previewLayer, animated: false)
}
}
}
和
func drawTargetRect(observation: VNRectangleObservation?, previewLayer: AVCaptureVideoPreviewLayer?, animated: Bool) -> (topLeft: CGPoint, topRight: CGPoint, bottomLeft: CGPoint, bottomRight: CGPoint) {
guard let observation = observation, let previewLayer = previewLayer else {
draw(path: nil, animated: false)
return (topLeft: CGPoint.zero, topRight: CGPoint.zero, bottomLeft: CGPoint.zero, bottomRight: CGPoint.zero)
}
let convertedTopLeft: CGPoint = previewLayer.layerPointConverted(fromCaptureDevicePoint: CGPoint(x: observation.topLeft.x, y: 1 - observation.topLeft.y))
let convertedTopRight: CGPoint = previewLayer.layerPointConverted(fromCaptureDevicePoint: CGPoint(x: observation.topRight.x, y: 1 - observation.topRight.y))
let convertedBottomLeft: CGPoint = previewLayer.layerPointConverted(fromCaptureDevicePoint: CGPoint(x: observation.bottomLeft.x, y: 1 - observation.bottomLeft.y))
let convertedBottomRight: CGPoint = previewLayer.layerPointConverted(fromCaptureDevicePoint: CGPoint(x: observation.bottomRight.x, y: 1 - observation.bottomRight.y))
let rectanglePath = UIBezierPath()
rectanglePath.move(to: convertedTopLeft)
rectanglePath.addLine(to: convertedTopRight)
rectanglePath.addLine(to: convertedBottomRight)
rectanglePath.addLine(to: convertedBottomLeft)
rectanglePath.close()
draw(path: rectanglePath, animated: animated)
return (topLeft: convertedTopLeft, topRight: convertedTopRight, bottomLeft: convertedBottomLeft, bottomRight: convertedBottomRight)
}
这是我将点放在新位置以继续进行 CIPerspectiveCorrection 的地方:
let imageTopLeft: CGPoint = CGPoint(x: image.size.width * trackedBottomLeftPoint.x, y: trackedBottomLeftPoint.y * image.size.height)
let imageTopRight: CGPoint = CGPoint(x: image.size.width * trackedTopLeftPoint.x, y: trackedTopLeftPoint.y * image.size.height)
let imageBottomLeft: CGPoint = CGPoint(x: image.size.width * trackedBottomRightPoint.x, y: trackedBottomRightPoint.y * image.size.height)
let imageBottomRight: CGPoint = CGPoint(x: image.size.width * trackedTopRightPoint.x, y: trackedTopRightPoint.y * image.size.height)
应用 CIPerspectiveCorrection 时,笛卡尔坐标系的处理方式为:
extension UIImage {
func cartesianForPoint(point:CGPoint,extent:CGRect) -> CGPoint {
return CGPoint(x: point.x,y: extent.height - point.y)
}
}
其他数学都是基于我在这里设置的那4个self.trackedPoints。
这里有一些我的意思不同的图片,看看没有被切断的区域。突出显示的 targetRect 完美绘制在文档的边缘。此结果在这些设备上是持久的。所有图片拍摄于portrait
,运行iOS12.1.3.
为什么这些图像不同? 计算使用比例值,没有硬编码值,并且它们与大小比率无关。
iPhoneX,见space左右
iPad空气2,见space上下
iPhone 5s,这就是我对他们所有人的期望
我发现 videoGravity
属性 配置失败。它被设置为 .resizeAspectFill
,因此将视频的一侧推过视图边界以填充另一侧的任何左侧 space。由于所有设备都提供不同的 spaces,因此要补偿的空白 space 是不同的,并导致在以全分辨率(而不仅仅是可见分辨率)拍摄视频流照片时出现所描述的行为。我太专注于数学部分而错过了这种可能性。
iphone5s 的完美匹配完全是随机的。
这是更正后的代码:
// setup view preview layer
let previewLayer = AVCaptureVideoPreviewLayer(session: newCaptureSession)
self.previewLayer = previewLayer
previewLayer.videoGravity = .resize
self.scannerView.layer.addSublayer(previewLayer)
self.scannerView.layer.addSublayer(targetRectLayer)