Swift 在iOS上使用核心图像对图片进行二值化

Swift 在iOS上使用核心图像对图片进行二值化,swift,core-image,Swift,Core Image,我想知道是否可以用核心图像对图像进行二值化(仅转换为黑白图像) 我用OpenCV和GPUImage制作了它,但如果可能的话,我更喜欢使用Apple Core图像。您至少有两个选项,CIPhotoEffectMono或小型定制CIColorKernel CIPhotoEffectMono: func createMonoImage(image:UIImage) -> UIImage { let filter = CIFilter(name: "CIPhotoEffectMono")

我想知道是否可以用核心图像对图像进行二值化(仅转换为黑白图像)


我用OpenCV和GPUImage制作了它,但如果可能的话,我更喜欢使用Apple Core图像。您至少有两个选项,CIPhotoEffectMono或小型定制CIColorKernel

CIPhotoEffectMono:

func createMonoImage(image:UIImage) -> UIImage {
    let filter = CIFilter(name: "CIPhotoEffectMono")
    filter!.setValue(CIImage(image: image), forKey: "inputImage")
    let outputImage = filter!.outputImage
    let cgimg = ciCtx.createCGImage(outputImage!, from: (outputImage?.extent)!)
    return UIImage(cgImage: cgimg!)
}
注意,我写得很快,你可能需要为零回报收紧措施

CIColorKernel:

func createMonoImage(image:UIImage) -> UIImage {
    let filter = CIFilter(name: "CIPhotoEffectMono")
    filter!.setValue(CIImage(image: image), forKey: "inputImage")
    let outputImage = filter!.outputImage
    let cgimg = ciCtx.createCGImage(outputImage!, from: (outputImage?.extent)!)
    return UIImage(cgImage: cgimg!)
}
FadeToBW GLSL(0.0因子全色,1.0因子无颜色):

下面的代码将其作为名为FadeToBW.cikernel的文件打开。您还可以将其作为字符串直接发布到
openKernelFile
调用中

Swift代码:

func createMonoImage(image:UIImage, inputColorFade:NSNumber) -> UIImage {
    let ciKernel = CIColorKernel(string: openKernelFile("FadeToBW"))
    let extent = image.extent
    let arguments = [image, inputColorFade]        
    let outputImage = ciKernel.applyWithExtent(extent, arguments: arguments)
    let cgimg = ciCtx.createCGImage(outputImage!, from: (outputImage?.extent)!)
    return UIImage(cgImage: cgimg!)
}

同样,添加一些防护装置等。

您可以使用MetalPerformanceShader。以及CIImageProcessingKernel。

下面是所需类的代码

 class ThresholdImageProcessorKernel: CIImageProcessorKernel {
    static let device = MTLCreateSystemDefaultDevice()
    override class func process(with inputs: [CIImageProcessorInput]?, arguments: [String : Any]?, output: CIImageProcessorOutput) throws {
        guard
            let device = device,
            let commandBuffer = output.metalCommandBuffer,
            let input = inputs?.first,
            let sourceTexture = input.metalTexture,
            let destinationTexture = output.metalTexture,
            let thresholdValue = arguments?["thresholdValue"] as? Float else  {
                return
        }

        let threshold = MPSImageThresholdBinary(
            device: device,
            thresholdValue: thresholdValue,
            maximumValue: 1.0,
            linearGrayColorTransform: nil)

        threshold.encode(
            commandBuffer: commandBuffer,
            sourceTexture: sourceTexture,
            destinationTexture: destinationTexture)
    }
}
这就是你如何使用它:

    let context = CIContext(options: nil)

            if let binaryCIImage = try? ThresholdImageProcessorKernel.apply(
                withExtent: croppedCIImage.extent,
                inputs: [croppedCIImage],
                arguments: ["thresholdValue": Float(0.2)]) {
                if let cgImage = context.createCGImage(binaryCIImage, from: binary.extent) {
                    DispatchQueue.main.async {
                        let resultingImage = UIImage(cgImage: cgImage)
                        if resultingImage.size.width > 100 {
                            print("Received an image \(resultingImage.size)")
                        }
                    }
                }
            }

我成功地使用CIPhotoEffectMono或等效工具将其转换为灰度,然后使用具有高得离谱的输入对比度(我使用了10000)的CiColorControl。这有效地使它成为黑白的,因此进行了二值化。对于那些不想弄乱自定义内核的人来说很有用

此外,您可以使用苹果的“色度键”过滤器之类的示例,该过滤器使用色调进行过滤,但您不需要查看色调,只需给出数据二值化的规则(即:何时将RGB all设置为1.0,何时设置为0.0)


(请原谅,我将此评论作为回答发布。哎呀。)是的。检查是否存在CIPhotoEffectMono()。我还编写了一个定制的CIColorKernel(GLSL代码),可以“淡出”到黑白。我将在几分钟内把这两个问题都作为答案发布。嗨,dfd,非常感谢你的快速回复!在尝试自定义内核解决方案时,在应用内核后,我得到了“致命错误:在展开可选值时意外地发现了nil”-您知道为什么吗?我使用了以下代码:
let ciKernel=CIColorKernel(字符串:“…”)!让image=CIImage.init(image:inputImage)!let extent=image.extent let arguments=[inputImage,inputColorFade]let outputImage=ciKernel.apply(withExtent:extent,arguments:arguments)!让context=CIContext(选项:nil)让cgimg=context.createCGImage(outputImage,from:(outputImage.extent))返回UIImage(cgImage:cgimg!)
Ah。是我的错。从工作应用程序复制的未测试代码。这不是输入图像,而是图像。我正在编辑我的答案。出于测试目的,在apply(withExtent:arguments)上设置一个断点,并检查其他值是否为零。虽然我需要将binary.extent更改为binaryCIImage.extent,但效果很好-希望这是正确的?此外,似乎很疯狂,苹果没有一个开发人员想到包括这样一个阈值过滤器,尽管实际上有数百个过滤器可以满足您可能需要的所有其他功能,但这对我来说非常有用。非常感谢。