带有卷积的垂直边缘检测,使用 Swift 给出透明图像

Posted

技术标签:

【中文标题】带有卷积的垂直边缘检测,使用 Swift 给出透明图像【英文标题】:Vertical edge detection with convolution giving transparent image as result with Swift 【发布时间】:2021-11-24 16:30:48 【问题描述】:

我目前正在尝试编写一个函数来获取图像并应用 3x3 矩阵来过滤垂直边缘。为此,我使用 CoreImage 的 CIConvolution3X3 并传递用于在 Sobels 边缘检测中检测垂直边缘的矩阵。

代码如下:

func verticalEdgeFilter() -> UIImage 
    let inputUIImage = UIImage(named: imageName)!
    let inputCIImage = CIImage(image: inputUIImage)
    let context = CIContext()
    let weights: [CGFloat] = [1.0, 0.0, -1.0, 
                              2.0, 0.0, -2.0, 
                              1.0, 0.0, -1.0]
        
    let verticalFilter = CIFilter.convolution3X3()
    verticalFilter.inputImage = inputCIImage  
    verticalFilter.weights = CIVector(values: weights, count: 9)
        
    if let output = verticalFilter.outputImage
        if let cgimg = context.createCGImage(output, from: output.extent) 
            let processedImage = UIImage(cgImage: cgimg)
            return processedImage
        
    
        
    print("returning original")
    return inputUIImage

现在我总是得到一个几乎完全透明的图像,它有一个像这样的 2 像素边框:

Original

Screenshot of the result (border on the left side)

我是否遗漏了一些明显的东西,因为只有当矩阵的中心值为 0 时图像才透明。但如果我在某些 webpage 上尝试相同的内核,它至少会产生可用的结果。设置偏见也只会使我不理解的整个事情崩溃。

我还检查了 Apples 文档以及 CIFilter 网页,但我没有得到任何结果,所以如果有人可以帮助我或告诉我在 Swift 中执行此操作的另一种方法,我将不胜感激:)

【问题讨论】:

专业调试提示:到处添加打印语句。您应该打印输入图像值和输出值,并检查这些值是否为预期值。 【参考方案1】:

将此卷积矩阵应用于完全不透明的图像将不可避免地产生完全透明的输出。这是因为内核值的总和为 0,因此在将 9 个相邻像素相乘并将它们相加后,您将在结果的 alpha 分量中得到 0。有两种处理方式:

    使用settingAlphaOne(in:) CIImage 辅助方法使输出不透明。 使用CIConvolutionRGB3X3 过滤器,该过滤器将单独保留 Alpha 分量并将内核仅应用于 RGB 分量。

至于 2 像素边界,这也是预期的,因为当内核应用于边界处的像素时,它仍然会采样所有 9 个像素,并且其中一些恰好落在图像边界之外(距图像边界正好 2 个像素)每边的边框)。这些不存在的像素作为透明黑色像素 0x000000 贡献。

去除边框:

    将图像钳制到一定范围以生成无限图像,其中边界像素重复到远离边界的无限远。您可以使用 CIClamp 过滤器或 CIImage 辅助函数 clampedToExtent() 应用卷积过滤器 将结果图像裁剪到输入图像范围。您可以使用cropped(to:) CIImage 辅助函数。

通过这些更改,您的代码将变成这样。

func verticalEdgeFilter() -> UIImage 
    let inputUIImage = UIImage(named: imageName)!
    let inputCIImage = CIImage(image: inputUIImage)!
    let context = CIContext()
    let weights: [CGFloat] = [1.0, 0.0, -1.0,
                              2.0, 0.0, -2.0,
                              1.0, 0.0, -1.0]

    let verticalFilter = CIFilter.convolution3X3()
    verticalFilter.inputImage = inputCIImage.clampedToExtent()
    verticalFilter.weights = CIVector(values: weights, count: 9)

    if var output = verticalFilter.outputImage
        output = output
            .cropped(to: inputCIImage.extent)
            .settingAlphaOne(in: inputCIImage.extent)

        if let cgimg = context.createCGImage(output, from: output.extent) 
            let processedImage = UIImage(cgImage: cgimg)
            return processedImage
        
    

    print("returning original")
    return inputUIImage

如果您使用convolutionRGB3X3 而不是convolution3X3,则无需使用settingAlphaOne

顺便说一句,如果您想使用卷积过滤器以及 230 个中的任何其他 CIFilter,请查看我刚刚发布的这个应用程序:https://apps.apple.com/us/app/filter-magic/id1594986951

【讨论】:

以上是关于带有卷积的垂直边缘检测,使用 Swift 给出透明图像的主要内容,如果未能解决你的问题,请参考以下文章

边缘检测Paddingstride三维卷积多个过滤器

边缘检测Paddingstride三维卷积多个过滤器

卷积神经网络

5.2 基本边缘检测算子—Sobel

OpenCV-Python-图像梯度与边缘检测

DeepLearning.ai学习笔记卷积神经网络 -- week1 卷积神经网络基础知识介绍