【问题标题】:Cropping CGRect from AVCapturePhotoOutput (resizeAspectFill)从 AVCapturePhotoOutput 裁剪 CGRect (resizeAspectFill)
【发布时间】:2021-11-18 12:41:13
【问题描述】:

我发现了以下问题,不幸的是,其他帖子没有帮助我找到可行的解决方案。

我有一个简单的应用程序,它显示相机预览 (AVCaptureVideoPreviewLayer),其中视频重力已设置为 resizeAspectFill (videoGravity = .resizeAspectFill)。

据我了解,这只会拉伸图像的宽度以填充屏幕。

在我的预览层上,我还应用了一个 CGRect 作为具有固定 x、y、宽度和高度的蒙版。

现在,一旦我拍了一张照片,我就会尝试从图像中裁剪出那个确切的矩形。据我了解,我应该使用某种数学方法将 CGRect 转换为与我从 AVCapturePhotoOutput 方法获得的图像相同的纵横比,但它似乎从未正确裁剪宽度。

    private func cropImage(image: UIImage) {
        let rect = CGRect(x: 25, y: 150, width: 325, height: 230)
        
        
        let scale = CGAffineTransform(scaleX: 1/self.view.frame.width, y: 1/self.view.frame.height)
        let flip = CGAffineTransform(scaleX: 1, y: -1).translatedBy(x: 0, y: -1)
        
        let bounds = rect.applying(scale).applying(flip)
        
        
        let topLeft = bounds.topLeft.scaled(to: image.size)
        let topRight = bounds.topRight.scaled(to: image.size)
        let bottomLeft = bounds.bottomLeft.scaled(to: image.size)
        let bottomRight = bounds.bottomRight.scaled(to: image.size)
        
        var ciImage = CIImage(image: image.forceSameOrientation())!
        
        ciImage = ciImage.applyingFilter("CIPerspectiveCorrection", parameters: [
            "inputTopLeft": CIVector(cgPoint: bottomLeft),
            "inputTopRight": CIVector(cgPoint: bottomRight),
            "inputBottomLeft": CIVector(cgPoint: topLeft),
            "inputBottomRight": CIVector(cgPoint: topRight)
        ])
        
        let context = CIContext()
        let cgImage = context.createCGImage(ciImage, from: ciImage.extent)
        let output = UIImage(cgImage: cgImage!)
        
        
        let vc = PreviewViewController()
        vc.imageView.image = output
        self.present(vc, animated: true, completion: nil)
    }

再说一次,基本上它确实在正确的高度进行裁剪,但它只是宽度似乎不太好。

我想要捕捉的图像示例。

https://imgur.com/a/8GryEgX

如您所见,左上角的边界框停在“Q”按钮之后。

结果:

https://imgur.com/FwKRWxK

正如您在这张图片中看到的,它确实在高度上正确裁剪,但是如果我们看一下左上角,它还包括“Q”左侧的一半按钮(Tab 按钮)

对解决方案的任何帮助将不胜感激!

【问题讨论】:

    标签: swift crop cgrect avcapturephotooutput


    【解决方案1】:

    我设法用这段代码解决了这个问题。

    private func cropToPreviewLayer(from originalImage: UIImage, toSizeOf rect: CGRect) -> UIImage? {
        guard let cgImage = originalImage.cgImage else { return nil }
    
        // This previewLayer is the AVCaptureVideoPreviewLayer which the resizeAspectFill and videoOrientation portrait has been set.
        let outputRect = previewLayer.metadataOutputRectConverted(fromLayerRect: rect)
    
        let width = CGFloat(cgImage.width)
        let height = CGFloat(cgImage.height)
    
        let cropRect = CGRect(x: (outputRect.origin.x * width), y: (outputRect.origin.y * height), width: (outputRect.size.width * width), height: (outputRect.size.height * height))
    
        if let croppedCGImage = cgImage.cropping(to: cropRect) {
            return UIImage(cgImage: croppedCGImage, scale: 1.0, orientation: originalImage.imageOrientation)
        }
    
        return nil
    }
    

    这段代码在我的案例中的用法:

    let rect = CGRect(x: 25, y: 150, width: 325, height: 230)
    let croppedImage = self.cropToPreviewLayer(from: image, toSizeOf: rect)
    self.imageView.image = croppedImage
    
    

    【讨论】:

      猜你喜欢
      • 2015-10-28
      • 2020-12-25
      • 2013-08-21
      • 2020-11-19
      • 1970-01-01
      • 1970-01-01
      • 2019-05-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多