【问题标题】:Cropping CIImage裁剪 CIImage
【发布时间】:2017-04-09 02:41:34
【问题描述】:

我有一个接受UIImage 的类,用它初始化CIImage,如下所示:

workingImage = CIImage.init(image: baseImage!)

然后使用图像以 3x3 的模式从其中切出 9 个相邻的正方形 - 在一个循环中:

for x in 0..<3
    {
        for y in 0..<3
        {

            croppingRect = CGRect(x: CGFloat(Double(x) * sideLength + startPointX),
                                  y: CGFloat(Double(y) * sideLength + startPointY),
                                  width: CGFloat(sideLength),
                                  height: CGFloat(sideLength))
            let tmpImg = (workingImage?.cropping(to: croppingRect))!
        }
    }

那些 tmpImgs 被插入到一个表中并在以后使用,但除此之外。

此代码适用于 IOS 9IOS 10 模拟器,但不适用于实际的 IOS 10 设备。生成的图像要么全是空的,要么其中一个就像它应该是的一半,而其余的又是空的。

这不是IOS 10中应该做的吗?

【问题讨论】:

  • 显然一切都取决于sideLengthstartPointXstartPointY 的正确且有意义的值。但是你没有给出关于如何得出这些关键数字的任何线索。 (我还应该提到,像“在模拟器上工作但在设备上不工作”这样的现象通常是由线程问题引起的。)
  • 对不起 - 还有一件事。你为什么要通过 CIImage 呢?我有点担心这是因为你认为这是裁剪 UIImage 的方法——但事实并非如此。如果您对 CIImage 没有特别的用途,即如果您不打算应用 CIFilter,则根本不要使用它!
  • 此代码不会裁剪 workingImage。裁剪后的图像分配给tmpImg,但由于从未使用过该变量而立即释放。所以workingImage 不变。这是真正的代码吗?
  • @matt,实际上,这确实是我认为裁剪图像的方式。我不知道任何其他方法,因为我在互联网上找到的大多数与裁剪相关的东西要么根本不起作用,要么使用 CIImage。如果你指出我正确的方式,我真的很感激。
  • @Codo, tmpImg 被添加到循环中的图像数组中,我忽略了它,因为我认为在这种情况下它并不重要。就像我说的,这种方法在IOS9 设备上确实可以正常工作,这让我更加困惑。

标签: ios swift ios10 ciimage


【解决方案1】:

问题的核心是通过 CIImage 不是裁剪 UIImage 的方法。一方面,从 CIImage 回到 UIImage 是一件复杂的事情。另一方面,整个往返都是不必要的。

如何裁剪

要裁剪图像,请创建所需裁剪大小的图像图形上下文,并在 UIImage 上调用 draw(at:) 以在相对于图形上下文的所需点处绘制它,以便图像的所需部分落入语境。现在提取生成的新图像并关闭上下文。

为了演示,我将裁剪到您尝试裁剪到的三分之一的,即右下三分之一:

let sz = baseImage.size
UIGraphicsBeginImageContextWithOptions(
    CGSize(width:sz.width/3.0, height:sz.height/3.0), 
    false, 0)
baseImage.draw(at:CGPoint(x: -sz.width/3.0*2.0, y: -sz.height/3.0*2.0))
let tmpImg = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

原图(baseImage):

裁剪图像 (tmpImg):

其他部分完全平行。

【讨论】:

    【解决方案2】:

    Core Image 的坐标系与 UIKit 不匹配,因此需要对 rect 进行镜像。

    所以在你的具体情况下,你想要:

    var ciRect = croppingRect
    ciRect.origin.y = workingImage!.extent.height - ciRect.origin.y - ciRect.height
    let tmpImg = workingImage!.cropped(to: ciRect)
    

    这绝对适用于 iOS 10+。

    在更一般的情况下,我们会创建一个涵盖两种可能坐标系的 UIImage 扩展,这比 draw(at:) 快得多:

    extension UIImage {
        /// Return a new image cropped to a rectangle.
        /// - parameter rect:
        /// The rectangle to crop.
        open func cropped(to rect: CGRect) -> UIImage {
            // a UIImage is either initialized using a CGImage, a CIImage, or nothing
            if let cgImage = self.cgImage {
                // CGImage.cropping(to:) is magnitudes faster than UIImage.draw(at:)
                if let cgCroppedImage = cgImage.cropping(to: rect) {
                    return UIImage(cgImage: cgCroppedImage)
                } else {
                    return UIImage()
                }
            }
            if let ciImage = self.ciImage {
                // Core Image's coordinate system mismatch with UIKit, so rect needs to be mirrored.
                var ciRect = rect
                ciRect.origin.y = ciImage.extent.height - ciRect.origin.y - ciRect.height
                let ciCroppedImage = ciImage.cropped(to: ciRect)
                return UIImage(ciImage: ciCroppedImage)
            }
            return self
        }
    }
    

    我已经为它制作了一个pod,所以源代码在https://github.com/Coeur/ImageEffects/blob/master/SwiftImageEffects/ImageEffects%2Bextensions.swift

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-24
      • 2013-10-24
      • 2013-10-21
      • 1970-01-01
      • 1970-01-01
      • 2019-05-10
      • 1970-01-01
      • 2022-01-23
      相关资源
      最近更新 更多