为什么我的Image CIPerspectiveCorrection在每台设备上都不同?

时间:2019-02-05 12:12:11

标签: swift core-image

我想在从AVCaptureSession拍摄的图像上使用CIPerspectiveCorrection。但是,在不同的设备上生成的校正后的Image不同,但是使用的是相同的代码。这是我的要点:

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完美地绘制在文档的边缘上。该结果在那些设备上是持久的。所有图片均在运行iOS 12.1.3的portrait中拍摄。

这些图像为什么不同? 计算使用比例值,没有硬编码值,并且它们与大小比率无关。

iPhone X,看到左右空间

iphonex

iPad Air 2,查看顶部和底部空间

ipadair2

iPhone 5s,这就是我期望所有这些的方式 iphone5s

1 个答案:

答案 0 :(得分:0)

我发现videoGravity属性的配置失败。它设置为.resizeAspectFill,因此将视频边之一推到视图边框上方,以填充另一边的任何左侧空间。并且由于所有设备都提供不同的空间,因此要补偿的空白空间不同,并且在以全分辨率拍摄视频流的图像而不仅仅是可见图像时,会导致上述行为。我过多地关注数学部分,却错过了这种可能性。

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)