自定义图片过滤器

时间:2018-03-17 15:30:59

标签: ios swift image algorithm image-processing

1的简介

  

所以我想为uiimages开发一种特殊的滤镜方法 - 我的想法是将所有颜色从一张图片改为黑色,除了某种颜色,这应该保持它们的外观。

图像总是很好看,所以请看这张图片以获得我想要达到的效果:

img

2的说明:

我想应用能够在图像中找到特定颜色的滤镜(算法)。该算法必须能够替换所有与参考颜色不匹配的颜色,例如" black"。

我开发了一个简单的代码,可以替换任何图像中的特定颜色(颜色范围和阈值)。 但是这个解决方案似乎不是一个快速的&有效的方式!

func colorFilter(image: UIImage, findcolor: String, threshold: Int) -> UIImage {
    let img: CGImage = image.cgImage!
    let context = CGContext(data: nil, width: img.width, height: img.height, bitsPerComponent: 8, bytesPerRow: 4 * img.width, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!
    context.draw(img, in: CGRect(x: 0, y: 0, width: img.width, height: img.height))
    let binaryData = context.data!.assumingMemoryBound(to: UInt8.self),
        referenceColor = HEXtoHSL(findcolor) // [h, s, l] integer array
    for i in 0..<img.height {
        for j in 0..<img.width {
            let pixel = 4 * (i * img.width + j)
            let pixelColor = RGBtoHSL([Int(binaryData[pixel]), Int(binaryData[pixel+1]), Int(binaryData[pixel+2])])  // [h, s, l] integer array
            let distance = calculateHSLDistance(pixelColor, referenceColor) // value between 0 and 100
            if (distance > threshold) {
                let setValue: UInt8 = 255
                binaryData[pixel] = setValue; binaryData[pixel+1] = setValue; binaryData[pixel+2] = setValue; binaryData[pixel+3] = 255
            }
        }
    }
    let outputImg = context.makeImage()!
    return UIImage(cgImage: outputImg, scale: image.scale, orientation: image.imageOrientation)
}


3. 代码信息上面的代码工作得很好,但绝对无效。由于所有的计算(特别是颜色转换等),这段代码花费的时间很长(太长),所以请看一下这个截图:

img


  1. 我的问题我非常确定有一种更简单的过滤特定颜色(具有给定阈值#c6456f is similar to #C6476f, ...)的解决方案,而不是通过每个单独循环像素来比较它的颜色。

    • 所以我在考虑的是像过滤器(CIFilter-method)这样的替代方法。
  2. 一些笔记

    • 因此,我不会要求您发布任何包含使用 openCV libary 建议的回复。我想开发这个&#34;算法&#34;专门用Swift。

    • 随时间截取屏幕截图的图像大小分辨率为500 * 800px

  3. 多数

  4. 你真的读到这么远吗? - 祝贺,但是 - 任何帮助如何加快我的代码将非常感激(也许是获得像素颜色而不是通过每个像素循环的更好方法)提前感谢一百万:)

2 个答案:

答案 0 :(得分:2)

首先要做的事 - 配置文件(测量功能不同部分的时间消耗)。它经常显示时间花在某个意想不到的地方,并始终建议在哪里指导您的优化工作。这并不意味着你必须专注于那个最耗时的东西,但它会告诉你花费的时间。不幸的是我不熟悉Swift所以不能推荐任何特定的工具。

关于迭代所有像素 - 取决于图像结构和您对输入数据的假设。我看到两种情况可以避免这种情况:

  1. 当您的图像上建立了一些优化的数据结构时(例如,其区域中的某些统计信息)。当您使用具有不同参数的相同(或类似)算法处理相同图像时,这通常是有意义的。如果您只处理一次图像,可能对您没有帮助。

  2. 当您知道绿色像素始终存在于一个组中时,就不会有孤立的单个像素。在这种情况下,您可以跳过一个或多个像素,当您找到绿色像素时,请分析其邻域。

答案 1 :(得分:0)

我不在您的平台上编码,但是......

嗯,我认为你的蒙面区域(具有特定的颜色)是连续的,足够大......这意味着你有一组像素和足够大的区域(不只是几个像素厚的东西)。通过此假设,您可以为颜色创建密度贴图。我的意思是,如果你的特定颜色的最小细节大小是10像素,那么你可以检查每个轴的每8个像素加速初始扫描~64次。然后仅对包含颜色的区域使用完整扫描。这是你要做的:

  1. 确定属性

    您需要为每个轴设置步数(您可以跳过多少像素而不会错过彩色区域)。我们打电话给这个dx,dy。

  2. 创建密度图

    如果区域的中心像素设置为您的特定颜色,则只需创建将保存信息的2D数组。因此,如果您的图片的分辨率低于您的地图{/ 1}}:

    xs,ys
  3. 放大地图设置区域

    现在您应该将int mx=xs/dx; int my=ys/dy; int map[mx][my],x,y,xx,yy; for (yy=0,y=dy>>1;y<ys;y+=dy,yy++) for (xx=0,x=dx>>1;x<xs;x+=dx,xx++) map[xx][yy]=compare(pixel(x,y) , specific_color)<threshold; 中的设置区域放大到相邻的单元格,因为#2 可能会错过您的颜色区域的边缘。

  4. 处理所有设置区域

    map[][]
  5. 如果你想要加速这个速度比你需要检测边缘上的集合for (yy=0;yy<my;yy++) for (xx=0;xx<mx;xx++) if (map[xx][yy]) for (y=yy*dy,y<(yy+1)*dy;y++) for (x=xx*dx,x<(xx+1)*dx;x++) if (compare(pixel(x,y) , specific_color)>=threshold) pixel(x,y)=0x00000000; 单元格(至少有一个零邻居)那么你可以区分像:

    map[][]

    只需在0 - no specific color is present 1 - inside of color area 2 - edge of color area 中即可完成。之后,您需要仅检查边缘区域的颜色:

    O(mx*my)

    这应该更快。如果您的图像分辨率for (yy=0;yy<my;yy++) for (xx=0;xx<mx;xx++) if (map[xx][yy]==2) { for (y=yy*dy,y<(yy+1)*dy;y++) for (x=xx*dx,x<(xx+1)*dx;x++) if (compare(pixel(x,y) , specific_color)>=threshold) pixel(x,y)=0x00000000; } else if (map[xx][yy]==0) { for (y=yy*dy,y<(yy+1)*dy;y++) for (x=xx*dx,x<(xx+1)*dx;x++) pixel(x,y)=0x00000000; } 不是区域大小xs,ys的倍数,您应该通过零填充或图像缺失部分的特殊循环来处理图像的外边缘...

    btw读取和设置整个图像需要多长时间?

    mx,my

    如果仅此一点慢,则表示您的像素访问速度太慢,您应该使用不同的api。这是Windows GDI 平台上非常常见的错误,因为人们通常使用for (y=0;y<ys;y++) for (x=0;x<xs;x++) pixel(x,y)=pixel(x,y)^0x00FFFFFF; ,这比抓蜗牛慢。还有其他方法,如bitlocking / blitting,ScanLine等,所以在这种情况下,你需要在你的平台上快速寻找一些东西。如果你甚至无法加速这些东西,那么你就无法做任何其他事情......顺便说一下,这是什么硬件?