【问题标题】:Thresholding image works in Swift and Matlab but not Core Image kernel阈值图像适用于 Swift 和 Matlab,但不适用于 Core Image 内核
【发布时间】:2018-01-02 05:58:56
【问题描述】:

tl;dr:当我在 Swift 中对具有特定阈值的图像进行阈值处理时,我得到了清晰的分割(并在 Matlab 中仔细检查它完全匹配),但是当我在 Core Image 内核中执行此操作时,它不会't分段干净。我的内核中有错误吗?

我正在尝试使用 Core Image 内核设置阈值。我的代码看起来很简单:

class ThresholdFilter: CIFilter
{
    var inputImage : CIImage?
    var threshold: Float = 0.554688 // This is set to a good value via Otsu's method

    var thresholdKernel =  CIColorKernel(source:
        "kernel vec4 thresholdKernel(sampler image, float threshold) {" +
        "  vec4 pixel = sample(image, samplerCoord(image));" +
        "  const vec3 rgbToIntensity = vec3(0.114, 0.587, 0.299);" +
        "  float intensity = dot(pixel.rgb, rgbToIntensity);" +
        "  return intensity < threshold ? vec4(0, 0, 0, 1) : vec4(1, 1, 1, 1);" +
        "}")

    override var outputImage: CIImage! {
        guard let inputImage = inputImage,
            let thresholdKernel = thresholdKernel else {
                return nil
        }

        let extent = inputImage.extent
        let arguments : [Any] = [inputImage, threshold]
        return thresholdKernel.apply(extent: extent, arguments: arguments)
    }
}

还有像这个简单的叶子这样的图像: 得到适当的阈值:

但有些图片,像这样(背景比较模糊): 变成垃圾:

我认为这不仅仅是选择一个糟糕的阈值的问题,因为我可以在 Matlab 中使用这个完全相同的阈值并获得清晰的分割:

为了仔细检查,我在纯 Swift 中“重做”outputImage 中的内核,只是打印到控制台:

let img: CGImage = inputImage.cgImage!
let imgProvider: CGDataProvider = img.dataProvider!
let imgBitmapData: CFData = imgProvider.data!
var imgBuffer = vImage_Buffer(data: UnsafeMutableRawPointer(mutating: CFDataGetBytePtr(imgBitmapData)), height: vImagePixelCount(img.height), width: vImagePixelCount(img.width), rowBytes: img.bytesPerRow)

for i in 0...img.height {
    for j in 0...img.width {
        let test = imgBuffer.data.load(fromByteOffset: (i * img.width + j) * 4, as: UInt32.self)

        let r = Float((test >> 16) & 255) / 256
        let g = Float((test >> 8) & 255) / 256
        let b = Float(test & 255) / 256
        let intensity = 0.114 * r + 0.587 * g + 0.299 * b

        print(intensity > threshold ? "1" : "0", terminator: "")
    }
    print("")
}

这会在 0 和 1 中打印出清晰分割的图像。我无法将其缩小到足以一次将其全部显示在屏幕上,但是您可以看到叶子上的孔被清楚地分割:

我担心 Matlab 和内核之间的像素强度可能不同(因为 RGB 到强度可以以不同的方式完成),所以我使用这种控制台打印方法来检查不同像素的确切强度,它们都匹配我在 Matlab 中看到的相同图像的强度。由于我在 Swift 和内核之间使用相同的点积,我不知道为什么这个阈值在 Swift 和 Matlab 中有效,但在内核中无效。

有什么想法吗?

【问题讨论】:

    标签: ios swift image-processing core-image cikernel


    【解决方案1】:

    解决了。

    Core Image “有用地”将所有内容转换为光线性色彩空间,因为某些过滤器由此得到帮助,如果您想要真实的颜色,您必须明确禁用它。 https://developer.apple.com/library/content/documentation/GraphicsImaging/Conceptual/CoreImaging/ci_performance/ci_performance.html#//apple_ref/doc/uid/TP30001185-CH10-SW7

    您可以在初始化传递给过滤器的 CIImage 时这样做:

    filter.inputImage = CIImage(image: image!, options: [kCIImageColorSpace: NSNull()])
    

    我不知道为什么这只在 CIFilters 内完成,而不是在应用程序的其他任何地方或所有其他类型的图像处理中完成;这似乎是一个非常不一致和隐藏的“功能”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-30
      • 2012-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-01
      • 2012-02-07
      相关资源
      最近更新 更多