Пороговое изображение работает в Swift и Matlab, но не в ядре Core Image.

tl; dr: Когда я устанавливаю порог изображения с определенным порогом в Swift, я получаю чистую сегментацию (и двойная проверка в Matlab идеально совпадает), но когда я делаю это в ядре Core Image, он не сегментирует чисто. Есть ли у меня ошибка в ядре?

Я пытаюсь установить порог с помощью ядра 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 и получить чистую сегментацию:  введите описание изображения здесь

Чтобы дважды проверить, я "переделал" ядро ​​в outputImage на чистом Swift, просто напечатав в консоли:

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, но не в ядре.

Есть идеи, что происходит?


person Cannoliopsida    schedule 01.01.2018    source источник


Ответы (1)


Решил это.

Базовое изображение «услужливо» переводит все в светлое линейное цветовое пространство, потому что это помогает определенным фильтрам, и вы должны явно отключить это, если хотите истинные цвета. 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, а не где-либо еще в приложении или во всех других типах обработки изображений; это кажется очень непоследовательной и скрытой «особенностью».

person Cannoliopsida    schedule 01.01.2018