在Swift中从相机裁剪图像,而不移动到另一个ViewController

我有一个图像覆盖在CameraViewController里面:

描述 我想从这个红色的方块里面得到图像。 我不想移动到另一个视图控制器来设置一个CropViewController,裁剪应该在这个控制器内完成。

后面的代码几乎可以工作,问题是从相机产生的图像是1080×1920和self.cropView.bounds是(0,0,185,120),当然它不代表相同的规模用于拍摄图像

extension UIImage { func crop(rect: CGRect) -> UIImage { var rect = rect rect.origin.x*=self.scale rect.origin.y*=self.scale rect.size.width*=self.scale rect.size.height*=self.scale let imageRef = self.cgImage!.cropping(to: rect) let image = UIImage(cgImage: imageRef!, scale: self.scale, orientation: self.imageOrientation) return image } } 

您总是可以使用核心图像filter调用CIPerspectiveCorrection在四边形(四边形形状 – 不一定是矩形)中直观地裁剪任何图像。

比方说,你有一个imageView框架,414宽716高,1600宽900高的大小的图像。 (你正在使用.aspectFit的内容模式,对不对?)假设你想裁剪一个四边形的形状,它们是(50,50),(75,75) ,(100,300)和(25,200)。 请注意,我列出了左上方的点(TL,右上方(TR),右下方(BR),左下方(BL)顺序),还要注意这不是直接的矩形。

你需要做的是这个。 (1)将UIImage转换为其中“extent”是UIImage大小的CIImage,(2)将这些UIImageView坐标转换为CIImage坐标,(3)将它们和CIImage传递到CIPerspectiveCorrectionfilter以进行裁剪,以及(4)渲染将CIImage输出到UIImageView中。

下面是我扔在一起的一些代码。 有用。 这也是一个有点粗糙的边缘,但希望你能得到的概念。

 class ViewController: UIViewController { let uiTL = CGPoint(x: 50, y: 50) let uiTR = CGPoint(x: 75, y: 75) let uiBL = CGPoint(x: 100, y: 300) let uiBR = CGPoint(x: 25, y: 200) var ciImage:CIImage! var ctx:CIContext! @IBOutlet weak var imageView: UIImageView! override func viewDidLoad() { super.viewDidLoad() ctx = CIContext(options: nil) ciImage = CIImage(image: imageView.image!) } override func viewWillLayoutSubviews() { let ciTL = createVector(createScaledPoint(uiTL)) let ciTR = createVector(createScaledPoint(uiTR)) let ciBR = createVector(createScaledPoint(uiBR)) let ciBL = createVector(createScaledPoint(uiBL)) imageView.image = doPerspectiveCorrection(CIImage(image: imageView.image!)!, context: ctx, topLeft: ciTL, topRight: ciTR, bottomRight: ciBR, bottomLeft: ciBL) } func doPerspectiveCorrection( _ image:CIImage, context:CIContext, topLeft:AnyObject, topRight:AnyObject, bottomRight:AnyObject, bottomLeft:AnyObject) -> UIImage { let filter = CIFilter(name: "CIPerspectiveCorrection") filter?.setValue(topLeft, forKey: "inputTopLeft") filter?.setValue(topRight, forKey: "inputTopRight") filter?.setValue(bottomRight, forKey: "inputBottomRight") filter?.setValue(bottomLeft, forKey: "inputBottomLeft") filter!.setValue(image, forKey: kCIInputImageKey) let cgImage = context.createCGImage((filter?.outputImage)!, from: (filter?.outputImage!.extent)!) return UIImage(cgImage: cgImage!) } func createScaledPoint(_ pt:CGPoint) -> CGPoint { let x = (pt.x / imageView.frame.width) * ciImage.extent.width let y = (pt.y / imageView.frame.height) * ciImage.extent.height return CGPoint(x: x, y: y) } func createVector(_ point:CGPoint) -> CIVector { return CIVector(x: point.x, y: ciImage.extent.height - point.y) } func createPoint(_ vector:CGPoint) -> CGPoint { return CGPoint(x: vector.x, y: ciImage.extent.height - vector.y) } 

}

编辑:我把这里解释的东西。 希望这不会违反网站规则。 我们两个人交换了项目,并且在提问者的代码中发生了一个零回返的问题。 首先,这里是更正的代码,它应该在cropImage()函数中:

 let ciTL = createVector(createScaledPoint(topLeft, overlay: cameraView, image: image), image: image) let ciTR = createVector(createScaledPoint(topRight, overlay: cameraView, image: image), image: image) let ciBR = createVector(createScaledPoint(bottomRight, overlay: cameraView, image: image), image: image) let ciBL = createVector(createScaledPoint(bottomLeft, overlay: cameraView, image: image), image: image) 

问题在于最后两行,它们是通过传递bottomLeft转移到本应该是bottomRight的,反之亦然。 (容易犯的错误,我也做了!)

一些解释来帮助那些使用CIPerspectiveCorrection的人(以及其他使用CIVectors的filter)。

  • (1)一个CIVector可以有任何地方 – 我认为2,几乎是无限的组件。 这取决于filter。 在这种情况下,有两个组件(X,Y)。 很简单,但是其中的4个CIVectors在CIImage范围内描述了4个点,其中原点是左下angular,而不是左上angular。

  • (2)注意我没有说4面的形状。 你实际上可以有一个“数字8”,就像“左下angular”左下angular的“右下angular”一样! 这将导致两侧彼此交叉的形状。

  • (3)重要的是,所有4点都与CIImage范围有关。 如果他们不这样做,filter返回零为它的输出图像。

对于那些以前没有使用CIImagefilter的人来说,最后一个注意事项是,filter将不会执行,直到您询问outputImage。 你可以实例化一个,填入参数,链接它们,不pipe。 您甚至可以在filter名称(或其任何键)中input错字。 直到你的代码要求filter.outputImage,没有任何反应。