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, но не в ядре.
Есть идеи, что происходит?