【问题标题】:Cropping AVCapturePhoto to overlay rectangle displayed on screen裁剪 AVCapturePhoto 以覆盖屏幕上显示的矩形
【发布时间】:2021-06-04 11:36:14
【问题描述】:

我正在尝试拍摄一块薄金属的照片,裁剪成屏幕上显示的轮廓。我在这里看到了几乎所有其他帖子,但还没有任何东西适合我。然后,该图像将被图书馆用于分析。我可以进行一些裁剪,但永远不会对显示的矩形进行裁剪。我尝试在裁剪之前旋转图像,并根据屏幕上的矩形计算矩形。

这是我的捕获代码。 PreviewView 是容器,videoLayer 是 AVCapture 视频。

    // Photo capture delegate
    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
        guard let imgData = photo.fileDataRepresentation(), let uiImg = UIImage(data: imgData), let cgImg = uiImg.cgImage else {
            return
        }
        print("Original image size: ", uiImg.size, "\nCGHeight: ", cgImg.height, " width: ", cgImg.width)
        print("Orientation: ", uiImg.imageOrientation.rawValue)
        
        guard let img = cropImage(image: uiImg) else {
            return
        }
        
        showImage(image: img)
    }

    
    func cropImage(image: UIImage) -> UIImage? {
        print("Image size before crop: ", image.size)
        //Get the croppedRect from function below
        let croppedRect = calculateRect(image: image)
        guard let imgRet = image.cgImage?.cropping(to: croppedRect) else {
            return nil
        }
        return UIImage(cgImage: imgRet)
    }
    
    func calculateRect(image: UIImage) -> CGRect {
        let originalSize: CGSize
        let visibleLayerFrame = self.rectangleView.bounds

        // Calculate the rect from the rectangleview to translate to the image
        let metaRect = (self.videoLayer.metadataOutputRectConverted(fromLayerRect: visibleLayerFrame))
        print("MetaRect: ", metaRect)
        // check orientation
        if (image.imageOrientation == UIImage.Orientation.left || image.imageOrientation == UIImage.Orientation.right) {
            originalSize = CGSize(width: image.size.height, height: image.size.width)
        } else {
            originalSize = image.size
        }

        let cropRect: CGRect = CGRect(x: metaRect.origin.x * originalSize.width, y: metaRect.origin.y * originalSize.height, width: metaRect.size.width * originalSize.width, height: metaRect.size.height * originalSize.height).integral
        print("Calculated Rect: ", cropRect)
        return cropRect
    }

func showImage(image: UIImage) {
    if takenImage != nil {
        takenImage = nil
    }
    takenImage = UIImageView(image: image)
    takenImage.frame = CGRect(x: 10, y: 50, width: 400, height: 1080)
    takenImage.contentMode = .scaleAspectFit
    print("Cropped Image Size: ", image.size)
    self.previewView.addSubview(takenImage)
}

这就是我不断得到的结果。

我搞砸了什么?

【问题讨论】:

标签: ios swift camera avcapturesession avcapturephotooutput


【解决方案1】:

UIKit 世界的左上角为 0,0。

AVFoundation 世界中的 0,0 点是左下角。

所以你必须通过旋转 90 度来平移。

这就是为什么你的形象很疯狂。

还请记住,由于原始翻译,以下规则适用:

  • X 实际上是上下
  • Y其实是左右
  • 宽高互换

另外请注意,UIImageView 内容模式设置会影响图像的缩放方式。如果您真的想查看图像在 UIView 中的外观,您可能需要使用 .scaleAspectFill 而不是 AspectFit。

我用这段代码 sn-p 来看看幕后是什么:

// figure out how to cut/crop this
let realImageRect = AVMakeRect(aspectRatio: image.size, insideRect: (self.cameraPreview?.frame)!)
NSLog("real image rectangle = \(realImageRect.debugDescription)")

上面的“cameraPreview”参考是您用于 AV Capture Session 的控件。

祝你好运!

【讨论】:

    【解决方案2】:

    我设法为我的用例解决了这个问题。

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-05
      • 2014-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多