在 Swift 中,过滤器 CIAreaMinMax 提供不正确的输出

问题描述

我使用过滤器 CIAreaMinMax 从图像中获取最亮和最暗的颜色信息。

通常,过滤器应输出具有两个像素(最亮和最暗)的图像。但是,当我将此过滤器应用于包含两种相似颜色的图像时,结果将不正确。结果不正确的症状是,两个像素的红色通道已经切换,但GB值没有问题。

我使用的测试图片here一个png图片只包含两种颜色:

RGB(37,62,88)GRB(10,132,255)

经过代码处理后,会输出一个包含两个像素的png图片

RGB(10,88)GRB(37,255)

下面是 swift playground 的测试代码

import Cocoa
import CoreImage
import CoreGraphics

func saveImage(_ image: NSImage,atUrl url: URL) {
  let cgImage = image.cgImage(forProposedRect: nil,context: nil,hints: nil)!
  let newRep = NSBitmapImageRep(cgImage: cgImage)
  newRep.size = image.size
  let pngData = newRep.representation(using: .png,properties: [:])!
  try! pngData.write(to: url)
}

var sourceImage = CIImage.init(contentsOf: URL.init(fileURLWithPath: "/Users/ABC/Downloads/test.png"))!

let filter = CIFilter(name: "CIAreaMinMax")!
filter.setValue(sourceImage,forKey: kCIInputimageKey)
let civ = CIVector.init(x: sourceImage.extent.minX,y: sourceImage.extent.minY,z: sourceImage.extent.width,w: sourceImage.extent.height)
filter.setValue(civ,forKey: kCIInputExtentKey)

var filteredImage = filter.outputimage!
let context = CIContext(options: [.workingColorSpace: kcfNull!])

let filteredCGImageRef = context.createCGImage(
filteredImage,from: filteredImage.extent)
let output = NSImage(cgImage: filteredCGImageRef!,size: NSSize.init(width: filteredImage.extent.width,height: filteredImage.extent.height))
saveImage(output,atUrl: URL.init(fileURLWithPath: "/Users/ABC/Downloads/output.png"))

解决方法

来自文档(强调我的):

计算图像中指定区域的每个组件最小值和最大值。

这意味着最小像素的红色值将包含该区域所有像素中最小的红色值。其他频道也一样。所以不会保留红色值最小的像素的实际颜色。

,

这可以通过一些技巧来完成。

  1. 首先,拍摄您的图像并应用一个自定义 CIColorKernel,该 CIColorKernel 将 luma 在像这样的 alpha 通道中:
kernel vec4 prepImage (__sample s,vec3 lumaWeights)
{
    return vec4(s.rgb,dot(s.rgb,lumaWeights));
}
  1. 对上图应用 CIAreaMinimumAlpha 过滤器。
  2. 将生成的 1x1 像素图像渲染到未预乘的 CIRenderDestination。