【问题标题】:How to merge several CGImage into a bigger CGImage?如何将几个 CGImage 合并成一个更大的 CGImage?
【发布时间】:2020-07-03 22:26:05
【问题描述】:

我创建了一个应用程序,它将神经网络 (convnet) 应用于输入图像,然后进行后处理。这个卷积网络基本上是一个输入图像(加一个参数)并输出相似大小图像的过滤器。由于内存问题,卷积网络无法一次性处理大图像,因此必须将图像分割成小块,然后在应用模型后将这些小块粘贴(或统一)在一起。我的问题是关于图像处理。详细介绍完之后你会更清楚:

  • 输入图像是 UIImage
  • 将输入图像拆分为 UIImage 列表,称为listInput
  • 创建一个空的listOutput
  • 对于listInput 中的每个图块:
    • 将 UIImage 转换为 CGImage
    • 将 CGImage 转换为 CVPixelBuffer
    • 将 CoreML 模型应用于返回相同大小的 CVPixelBuffer 的 CVPixelBuffer
    • 将 CVPixelBuffer 转换为 CIImage
    • 将 CIImage 转换为 CGImage
    • 将 CGImage 转换为 UIImage
    • 将 UIImage 附加到 listOutput
  • listOutput中的所有图块统一到一个输出UIImage中
  • 融合输入输出UIImage(后处理):
    • 将输入的 UIImage 转换为 CGImage,然后转换为 CIImage
    • 将输出 UIImage 转换为 CGImage 再转换为 CIImage
    • 使用 CIFilter 融合 2 CIImage
    • 将生成的 CIImage 转换为 CGImage
    • 将 CGImage 转换为 UIImage

如果需要,我可以发布与上面列出的任何部分相对应的代码。

我遇到的一般问题是 UIImage 到 CGImage 到 CIImage 之间的所有转换,反之亦然。我正在尝试完全摆脱 UIImage (加载图像除外)。我确实想从头到尾操纵 CGImage 。这已经可以简化代码了。

我修改了我的代码来操作 CGImage 列表而不是 UIImage 列表。 CGImage 的裁剪部分实际上比 UIImage 更简单。但我无法找出相反的方法:将 CGImage 统一成一个更大的图像。这是我的具体问题。 Bellow 是我为统一 UIImage 而创建的函数。

func unifyTiles(listTiles: [UIImage], listRect: [CGRect]) -> UIImage? {

    guard let input = input else {
        return nil
    }


    let outputSize = CGSize(width : Int(input.size.width), height: Int(input.size.height))

    UIGraphicsBeginImageContextWithOptions(outputSize, true, 1.0)

    for i in 0..<listTiles.count {
        listTiles[i].draw(at: listRect[i].origin)
    }

    guard let output = UIGraphicsGetImageFromCurrentImageContext() else {
        return nil
    }
    UIGraphicsEndImageContext()

    return output
}

所以我的问题是:

  • 是否可以仅操作 CGImage 来做同样的事情?
  • 这是个好主意吗?

一些注意事项:

  • 后处理必须与前一部分分开,因为用户想要修改后处理参数而不重新应用卷积网络。卷积网络的应用确实很长,在大图像上计算可能需要一分钟,而后处理接近实时。

  • 在后处理部分,有人建议我直接转换 UIImage CIImage 而不经过 CGImage。出于某种我不知道的原因,据我所知,这不起作用。

  • 我知道使用 Vision 我可以直接将 CGImage 输入网络而不是 CVPixelBuffer,但我不知道 Vision 是否也可以输出 CGImage。希望很快会对此进行调查。

感谢您提供的任何信息。

【问题讨论】:

    标签: swift uiimage cgimage


    【解决方案1】:

    UIImage 转 CIImage

    这一步:

    UIImage 转换成 CGImage 然后转换成 CIImage

    被夸大了,因为 CIImage 有一个 init(image:) 初始化器,它直接从 UIImage 到 CIImage。

    裁剪

    您似乎认为裁剪 CGImage 比裁剪 UIImage 更容易,但事实并非如此。要裁剪 UIImage,只需将其绘制到较小的图形上下文中,偏移以便将所需的点放置在裁剪的左上角。

    图形上下文

    您只能在图形上下文中绘制,无论您喜欢与否,这将是一个图像上下文。如果这就是您的想法,则没有绘制到“CGImage 上下文”之类的东西。您可以将 CGImage 直接绘制到图像上下文中,但结果通常是灾难性的(我将在下一段中解释)。

    最后的想法

    总的来说,我想让您对 UIImage 放心。 UIImage 是一个的东西。它(通常)是一个非常轻量级的 CGImage 包装器。 CGImage是位图数据;包装器添加了比例和方向等信息。丢失这些信息可能会导致您的绘图非常糟糕;尝试绘制 CGImage 可能会导致绘图被翻转和错误缩放。不要这样做!使用 UIImage 并快乐。

    【讨论】:

    • 谢谢马特。我确实找到了一种使用 CGContext 将我的图块重新组合在一起的方法,但是正如您所预料的那样,我的图像是颠倒的,需要更多的代码来纠正它。正如你所建议的,我将坚持使用 UIImage。我认为通过减少代码中使用的图像类型的数量,整个事情会更简单。
    • 这就是为什么我试图让你以不同的方式“看到”一个 UIImage,即作为一个 更好 CGImage,而不是作为一个不同的类型。 :)
    • 哦,您将 CIImage 转换为 CGImage 再转换为 UIImage 的两步过程也被夸大了。再次,有一个直接的方法。但这种方式不是 UIImage init(ciImage:) 单独的;如果你想要一个基于 CGImage 的 UIImage,你必须绘制生成的 UIImage 才能渲染它。
    • 我意识到我已经将 UIImage 直接转换为 CIImage,正如您提到的那样。很抱歉帖子中的错误。现在,关于从 CIImage 到 UIImage 的转换,我使用 CIContext 将图像渲染为 CGImage,然后将其输入 UIImage。
    • 您可以这样做,但这不是必需的。只需调用 UIImage init(ciImage:scale:orientation:) 并将 UIImage 绘制到图形上下文中以强制它呈现,如果这是您的意图。您可以从整个故事中消除 CGImage;它在您的 UIImage 中,但无需查看。
    猜你喜欢
    • 2023-03-23
    • 1970-01-01
    • 2016-01-06
    • 2011-04-14
    • 1970-01-01
    • 2020-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多