如何在图像中改变特定的颜色?

时间:2022-11-21 15:09:40

My question is if I have a Lion image just I want to change the color of the lion alone not the background color. For that I referred this SO question but it turns the color of whole image. Moreover the image is not looking great. I need the color change like photoshop. whether it is possible to do this in coregraphics or I have to use any other library.

我的问题是,如果我有一个狮子的图像,我只想改变狮子的颜色,而不是背景颜色。因为我提到了这个问题,但它改变了整个图像的颜色。此外,这张照片看起来并不好看。我需要像photoshop一样改变颜色。是否可以在coregraphics中这样做,或者我必须使用任何其他的库。

EDIT : I need the color change to be like iQuikColor app

编辑:我需要改变颜色像iQuikColor应用

如何在图像中改变特定的颜色?

5 个解决方案

#1


21  

See answers below instead. Mine doesn't provide a complete solution.

请参见下面的答案。我的并不提供完整的解决方案。


Here is the sketch of a possible solution using OpenCV:

下面是OpenCV可能的解决方案的草图:

  • Convert the image from RGB to HSV using cvCvtColor (we only want to change the hue).
  • 使用cvcvcvtcolor将图像从RGB转换为HSV(我们只想更改色调)。
  • Isolate a color with cvThreshold specifying a certain tolerance (you want a range of colors, not one flat color).
  • 用cvThreshold指定一定的容错(您需要一个颜色范围,而不是一个平面颜色)隔离一个颜色。
  • Discard areas of color below a minimum size using a blob detection library like cvBlobsLib. This will get rid of dots of the similar color in the scene.
  • 使用cvBlobsLib之类的blob检测库丢弃最小大小以下的颜色区域。这样可以去掉场景中相似颜色的点。
  • Mask the color with cvInRangeS and use the resulting mask to apply the new hue.
  • 用cvInRangeS掩码颜色,并使用生成的掩码应用新的色调。
  • cvMerge the new image with the new hue with an image composed by the saturation and brightness channels that you saved in step one.
  • cvMerge新图像与新色调与由您在第一步中保存的饱和度和亮度通道组成的图像。

There are several OpenCV iOS ports in the net, eg: http://www.eosgarden.com/en/opensource/opencv-ios/overview/ I haven't tried this myself, but seems a good research direction.

网上有几个OpenCV iOS端口,例如:http://www.eosgardenen.com/opensource/opencv -ios/overview/我自己还没有尝试过,但似乎是一个很好的研究方向。

#2


29  

This took quite a while to figure out, mainly because I wanted to get it up and running in Swift using Core Image and CIColorCube.

这花了很长时间才弄明白,主要是因为我想用Core Image和CIColorCube快速创建并运行它。

@Miguel's explanation is spot on about the way you need to replace a "Hue angle range" with another "Hue angle range". You can read his post above for details on what a Hue Angle Range is.

@Miguel的解释是关于你需要用另一个“色调角度范围”来代替“色调角度范围”的方法。你可以阅读他的文章,以了解什么是色调的角度范围。

I made a quick app that replaces a default blue truck below, with whatever you choose on Hue slider.

我做了一个快速的应用程序,用你在顺化滑条上选择的任何东西替换下面默认的蓝色卡车。

如何在图像中改变特定的颜色?

You can slide the slider to tell the app what color Hue you want to replace the blue with.

你可以滑动滑块来告诉应用你想用什么颜色的颜色来替换蓝色。

I'm hardcoding the Hue range to be 60 degrees, which typically seems to encompass most of a particular color but you can edit that if you need to.

我将色调范围硬编码为60度,这通常似乎包含了大多数特定的颜色,但如果需要的话,你可以编辑它。

如何在图像中改变特定的颜色?

如何在图像中改变特定的颜色?

Notice that it does not color the tires or the tail lights because that's outside of the 60 degree range of the truck's default blue hue, but it does handle shading appropriately.

注意,它不会给轮胎或尾灯上色,因为这超出了卡车默认蓝色调的60度范围,但它确实能适当地处理阴影。

First you need code to convert RGB to HSV (Hue value):

首先需要代码将RGB转换为HSV(色相值):

func RGBtoHSV(r : Float, g : Float, b : Float) -> (h : Float, s : Float, v : Float) {
    var h : CGFloat = 0
    var s : CGFloat = 0
    var v : CGFloat = 0
    let col = UIColor(red: CGFloat(r), green: CGFloat(g), blue: CGFloat(b), alpha: 1.0)
    col.getHue(&h, saturation: &s, brightness: &v, alpha: nil)
    return (Float(h), Float(s), Float(v))
}

Then you need to convert HSV to RGB. You want to use this when you discover a hue that in your desired hue range (aka, a color that's the same blue hue of the default truck) to save off any adjustments you make.

然后需要将HSV转换为RGB。当您发现您想要的色调范围(也就是与默认卡车相同的蓝色色调)中的色调时,您需要使用这个颜色来保存您所做的任何调整。

func HSVtoRGB(h : Float, s : Float, v : Float) -> (r : Float, g : Float, b : Float) {
    var r : Float = 0
    var g : Float = 0
    var b : Float = 0
    let C = s * v
    let HS = h * 6.0
    let X = C * (1.0 - fabsf(fmodf(HS, 2.0) - 1.0))
    if (HS >= 0 && HS < 1) {
        r = C
        g = X
        b = 0
    } else if (HS >= 1 && HS < 2) {
        r = X
        g = C
        b = 0
    } else if (HS >= 2 && HS < 3) {
        r = 0
        g = C
        b = X
    } else if (HS >= 3 && HS < 4) {
        r = 0
        g = X
        b = C
    } else if (HS >= 4 && HS < 5) {
        r = X
        g = 0
        b = C
    } else if (HS >= 5 && HS < 6) {
        r = C
        g = 0
        b = X
    }
    let m = v - C
    r += m
    g += m
    b += m
    return (r, g, b)
}

Now you simply loop through a full RGBA color cube and "adjust" any colors in the "default blue" hue range with those from your newly desired hue. Then use Core Image and the CIColorCube filter to apply your adjusted color cube to the image.

现在,您只需循环使用一个完整的RGBA颜色立方体,并“调整”任何颜色在“默认蓝”色调范围与那些从您的新期望的色调。然后使用Core Image和CIColorCube filter将调整后的颜色cube应用到图像上。

func render() {
    let centerHueAngle: Float = 214.0/360.0 //default color of truck body blue
    let destCenterHueAngle: Float = slider.value
    let minHueAngle: Float = (214.0 - 60.0/2.0) / 360 //60 degree range = +30 -30
    let maxHueAngle: Float = (214.0 + 60.0/2.0) / 360
    var hueAdjustment = centerHueAngle - destCenterHueAngle
    let size = 64
    var cubeData = [Float](count: size * size * size * 4, repeatedValue: 0)
    var rgb: [Float] = [0, 0, 0]
    var hsv: (h : Float, s : Float, v : Float)
    var newRGB: (r : Float, g : Float, b : Float)
    var offset = 0
    for var z = 0; z < size; z++ {
        rgb[2] = Float(z) / Float(size) // blue value
        for var y = 0; y < size; y++ {
            rgb[1] = Float(y) / Float(size) // green value
            for var x = 0; x < size; x++ {
                rgb[0] = Float(x) / Float(size) // red value
                hsv = RGBtoHSV(rgb[0], g: rgb[1], b: rgb[2])
                if hsv.h < minHueAngle || hsv.h > maxHueAngle {
                    newRGB.r = rgb[0]
                    newRGB.g = rgb[1]
                    newRGB.b = rgb[2]
                } else {
                    hsv.h = destCenterHueAngle == 1 ? 0 : hsv.h - hueAdjustment //force red if slider angle is 360
                    newRGB = HSVtoRGB(hsv.h, s:hsv.s, v:hsv.v)
                }
                cubeData[offset]   = newRGB.r
                cubeData[offset+1] = newRGB.g
                cubeData[offset+2] = newRGB.b
                cubeData[offset+3] = 1.0
                offset += 4
            }
        }
    }
    let data = NSData(bytes: cubeData, length: cubeData.count * sizeof(Float))
    let colorCube = CIFilter(name: "CIColorCube")!
    colorCube.setValue(size, forKey: "inputCubeDimension")
    colorCube.setValue(data, forKey: "inputCubeData")
    colorCube.setValue(ciImage, forKey: kCIInputImageKey)
    if let outImage = colorCube.outputImage {
        let context = CIContext(options: nil)
        let outputImageRef = context.createCGImage(outImage, fromRect: outImage.extent)
        imageView.image = UIImage(CGImage: outputImageRef)
    }
}

You can download the sample project here. It's using Xcode 7 and Swift 2.0.

您可以在这里下载示例项目。它使用Xcode 7和Swift 2.0。

#3


13  

I'm going to make the assumption that you know how to perform these basic operations, so these won't be included in my solution:

我假设你知道如何执行这些基本操作,所以这些不会包含在我的解决方案中:

  • load an image
  • 加载一个图像
  • get the RGB value of a given pixel of the loaded image
  • 获取所加载图像的给定像素的RGB值
  • set the RGB value of a given pixel
  • 设置给定像素的RGB值
  • display a loaded image, and/or save it back to disk.
  • 显示已加载的映像,并/或将其保存回磁盘。

First of all, let's consider how you can describe the source and destination colors. Clearly you can't specify these as exact RGB values, since a photo will have slight variations in color. For example, the green pixels in the truck picture you posted are not all exactly the same shade of green. The RGB color model isn't very good at expressing basic color characteristics, so you will get much better results if you convert the pixels to HSL. Here are C functions to convert RGB to HSL and back.

首先,让我们考虑如何描述源和目标颜色。很明显,您不能指定这些为精确的RGB值,因为照片的颜色会有细微的变化。例如,你发布的卡车图片中的绿色像素并不是完全相同的绿色。RGB颜色模型不太擅长表达基本的颜色特征,所以如果您将像素转换为HSL,您将得到更好的结果。这里有一些C函数可以将RGB转换为HSL并返回。

The HSL color model describes three aspects of a color:

HSL颜色模型描述了颜色的三个方面:

  1. Hue - the main perceived color - i.e. red, green, orange, etc.
  2. 色调——主要感知的颜色——即红、绿、橙等。
  3. Saturation - how "full" the color is - i.e. from full color to no color at all
  4. 饱和度——颜色的“满”程度——即从全色到全无色
  5. Lightness - how bright the color is
  6. 明度——颜色有多亮

So for example, if you wanted to find all the green pixels in a picture, you will convert each pixel from RGB to HSL, then look for H values that correspond to green, with some tolerance for "near green" colors. Below is a Hue chart, from Wikipedia:

例如,如果你想在一张图片中找到所有的绿色像素,你将把每个像素从RGB转换为HSL,然后寻找对应绿色的H值,对“接近绿色”的颜色有一定的容忍度。下面是来自*的色相图:

如何在图像中改变特定的颜色?

So in your case you will be looking at pixels that have a Hue of 120 degrees +/- some amount. The bigger the range the more colors will get selected. If you make your range too wide you will start seeing yellow and cyan pixels getting selected, so you'll have to find the right range, and you may even want to offer the user of your app controls to select this range.

所以在你的例子中你会看到像素的色度是120度+/-多少。范围越大,选择的颜色就越多。如果你的范围太宽,你会看到黄色和青色的像素被选中,所以你必须找到正确的范围,你甚至可能想让你的应用控件的用户选择这个范围。

In addition to selecting by Hue, you may want to allow ranges for Saturation and Lightness, so that you can optionally put more limits to the pixels that you want to select for colorization.

除了根据色相进行选择外,您可能还希望允许饱和度和亮度的范围,以便您可以选择性地对要选择的像素进行更多的限制,以便进行着色。

Finally, you may want to offer the user the ability to draw a "lasso selection" so that specific parts of the picture can be left out of the colorization. This is how you could tell the app that you want the body of the green truck, but not the green wheel.

最后,您可能希望向用户提供绘制“套索选择”的能力,以便在着色过程中可以忽略图片的特定部分。这就是你如何告诉应用你想要绿色卡车的车身,而不是绿色车轮。

Once you know which pixels you want to modify it's time to alter their color.

一旦你知道你想要修改哪个像素,就该修改它们的颜色了。

The easiest way to colorize the pixels is to just change the Hue, leaving the Saturation and Lightness from the original pixel. So for example, if you want to make green pixels magenta you will be adding 180 degrees to all the Hue values of the selected pixels (making sure you use modulo 360 math).

对像素进行着色最简单的方法就是改变色相,将饱和度和亮度从原来的像素中去掉。举个例子,如果你想让绿色像素为洋红色,你将会给所选像素的所有色调值增加180度(确保你使用的是modulo 360)。

If you wanted to get more sophisticated, you can also apply changes to Saturation and that will give you a wider range of tones you can go to. I think the Lightness is better left alone, you may be able to make small adjustments and the image will still look good, but if you go too far away from the original you may start seeing hard edges where the process pixels border with background pixels.

如果你想要变得更复杂,你也可以对饱和度进行修改,这样你可以得到更大的音域。我认为最好不要考虑亮度,你可以做一些小的调整,图像看起来还是不错的,但是如果你离原来的地方太远,你可能会看到硬边,处理像素与背景像素的边界。

Once you have the colorized HSL pixel you just convert it back to RGB and write it back to the image.

一旦你有了色化的HSL像素你只需要把它转换回RGB并把它写回图像。

I hope this helps. A final comment I should make is that Hue values in code are typically recorded in the 0-255 range, but many applications show them as a color wheel with a range of 0 to 360 degrees. Keep that in mind!

我希望这可以帮助。我要做的最后一个评论是,代码中的色相值通常记录在0-255范围内,但许多应用程序将它们显示为一个0到360度范围的色轮。记住这一点!

#4


1  

Can I suggest you look into using OpenCV? It's an open source image manipulation library, and it's got an iOS port too. There are plenty of blog posts about how to use it and set it up.

我可以建议你考虑使用OpenCV吗?它是一个开源的图像处理库,它也有一个iOS端口。有很多关于如何使用和设置它的博客文章。

It has a whole heap of functions that will help you do a good job of what you're attempting. You could do it just using CoreGraphics, but the end result isn't going to look nearly as good as OpenCV would.

它有一大堆函数可以帮助你很好地完成你的尝试。你可以用CoreGraphics做,但是最终的结果不会像OpenCV那样好。

It was developed by some folks at MIT, so as you might expect it does a pretty good job at things like edge detection and object tracking. I remember reading a blog about how to separate a certain color from a picture with OpenCV - the examples showed a pretty good result. See here for an example. From there I can't imagine it would be a massive job to actually change the separated color to something else.

它是由麻省理工学院的一些人开发的,所以你可能会认为它在边缘检测和对象跟踪方面做得很好。我记得我读过一篇关于如何用OpenCV从一幅图片中分离某种颜色的博客——这些例子显示了一个相当不错的结果。请看这里的一个例子。从那里,我无法想象将分离的颜色改变成其他颜色将是一项艰巨的任务。

#5


0  

I don't know of a CoreGraphics operation for this, and I don't see a suitable CoreImage filter for this. If that's correct, then here's a push in the right direction:

我不知道有什么CoreGraphics操作,也没有合适的CoreImage过滤器。如果这是正确的,那么这是朝着正确方向的推动:

Assuming you have a CGImage (or a uiImage.CGImage):

假设您有一个CGImage(或一个uiImage.CGImage):

  • Begin by creating a new CGBitmapContext
  • 首先创建一个新的CGBitmapContext
  • Draw the source image to the bitmap context
  • 将源图像绘制到位图上下文
  • Get a handle to the bitmap's pixel data
  • 获取位图的像素数据的句柄

Learn how the buffer is structured so you could properly populate a 2D array of pixel values which have the form:

了解缓冲区的结构,以便正确填充具有以下形式的二维像素值数组:

typedef struct t_pixel {
  uint8_t r, g, b, a;
} t_pixel;

Then create the color to locate:

然后创建颜色来定位:

const t_pixel ColorToLocate = { 0,0,0,255 }; // << black, opaque

And its substitution value:

和它的替换值:

const t_pixel SubstitutionColor = { 255,255,255,255 }; // << white, opaque
  • Iterate over the bitmap context's pixel buffer, creating t_pixels.
  • 迭代位图上下文的像素缓冲区,创建t_pixels。
  • When you find a pixel which matches ColorToLocate, replace the source values with the values in SubstitutionColor.

    当您找到匹配ColorToLocate的像素时,将源值替换为替换颜色中的值。

  • Create a new CGImage from the CGBitmapContext.

    从CGBitmapContext中创建一个新的CGImage。

That's the easy part! All that does is takes a CGImage, replace exact color matches, and produces a new CGImage.

这是很简单的部分!所做的就是获取一个CGImage,替换精确的颜色匹配,并生成一个新的CGImage。

What you want is more sophisticated. For this task, you will want a good edge detection algorithm.

你想要的是更复杂的。对于这个任务,您将需要一个好的边缘检测算法。

I've not used this app you have linked. If it's limited to a few colors, then they may simply be swapping channel values, paired with edge detection (keep in mind that buffers may also be represented in multiple color models - not just RGBA).

我还没用过你链接的这个应用。如果它被限制在几个颜色,那么它们可能只是交换通道值,并与边缘检测配对(请记住,缓冲区也可以在多个颜色模型中表示——而不仅仅是RGBA)。

If (in the app you linked) the user can choose an arbitrary colors, values, and edge thresholds, then you will have to use real blending and edge detection. If you need to see how this is accomplished, you may want to check out a package such as Gimp (it's an open image editor) - they have the algos to detect edges and choose by color.

如果(在你链接的应用程序中)用户可以选择任意颜色、值和边缘阈值,那么你将不得不使用真正的混合和边缘检测。如果您需要了解这是如何实现的,您可能想要检查一个包,例如Gimp(它是一个开放的图像编辑器)——它们有algos来检测边缘并根据颜色进行选择。

#1


21  

See answers below instead. Mine doesn't provide a complete solution.

请参见下面的答案。我的并不提供完整的解决方案。


Here is the sketch of a possible solution using OpenCV:

下面是OpenCV可能的解决方案的草图:

  • Convert the image from RGB to HSV using cvCvtColor (we only want to change the hue).
  • 使用cvcvcvtcolor将图像从RGB转换为HSV(我们只想更改色调)。
  • Isolate a color with cvThreshold specifying a certain tolerance (you want a range of colors, not one flat color).
  • 用cvThreshold指定一定的容错(您需要一个颜色范围,而不是一个平面颜色)隔离一个颜色。
  • Discard areas of color below a minimum size using a blob detection library like cvBlobsLib. This will get rid of dots of the similar color in the scene.
  • 使用cvBlobsLib之类的blob检测库丢弃最小大小以下的颜色区域。这样可以去掉场景中相似颜色的点。
  • Mask the color with cvInRangeS and use the resulting mask to apply the new hue.
  • 用cvInRangeS掩码颜色,并使用生成的掩码应用新的色调。
  • cvMerge the new image with the new hue with an image composed by the saturation and brightness channels that you saved in step one.
  • cvMerge新图像与新色调与由您在第一步中保存的饱和度和亮度通道组成的图像。

There are several OpenCV iOS ports in the net, eg: http://www.eosgarden.com/en/opensource/opencv-ios/overview/ I haven't tried this myself, but seems a good research direction.

网上有几个OpenCV iOS端口,例如:http://www.eosgardenen.com/opensource/opencv -ios/overview/我自己还没有尝试过,但似乎是一个很好的研究方向。

#2


29  

This took quite a while to figure out, mainly because I wanted to get it up and running in Swift using Core Image and CIColorCube.

这花了很长时间才弄明白,主要是因为我想用Core Image和CIColorCube快速创建并运行它。

@Miguel's explanation is spot on about the way you need to replace a "Hue angle range" with another "Hue angle range". You can read his post above for details on what a Hue Angle Range is.

@Miguel的解释是关于你需要用另一个“色调角度范围”来代替“色调角度范围”的方法。你可以阅读他的文章,以了解什么是色调的角度范围。

I made a quick app that replaces a default blue truck below, with whatever you choose on Hue slider.

我做了一个快速的应用程序,用你在顺化滑条上选择的任何东西替换下面默认的蓝色卡车。

如何在图像中改变特定的颜色?

You can slide the slider to tell the app what color Hue you want to replace the blue with.

你可以滑动滑块来告诉应用你想用什么颜色的颜色来替换蓝色。

I'm hardcoding the Hue range to be 60 degrees, which typically seems to encompass most of a particular color but you can edit that if you need to.

我将色调范围硬编码为60度,这通常似乎包含了大多数特定的颜色,但如果需要的话,你可以编辑它。

如何在图像中改变特定的颜色?

如何在图像中改变特定的颜色?

Notice that it does not color the tires or the tail lights because that's outside of the 60 degree range of the truck's default blue hue, but it does handle shading appropriately.

注意,它不会给轮胎或尾灯上色,因为这超出了卡车默认蓝色调的60度范围,但它确实能适当地处理阴影。

First you need code to convert RGB to HSV (Hue value):

首先需要代码将RGB转换为HSV(色相值):

func RGBtoHSV(r : Float, g : Float, b : Float) -> (h : Float, s : Float, v : Float) {
    var h : CGFloat = 0
    var s : CGFloat = 0
    var v : CGFloat = 0
    let col = UIColor(red: CGFloat(r), green: CGFloat(g), blue: CGFloat(b), alpha: 1.0)
    col.getHue(&h, saturation: &s, brightness: &v, alpha: nil)
    return (Float(h), Float(s), Float(v))
}

Then you need to convert HSV to RGB. You want to use this when you discover a hue that in your desired hue range (aka, a color that's the same blue hue of the default truck) to save off any adjustments you make.

然后需要将HSV转换为RGB。当您发现您想要的色调范围(也就是与默认卡车相同的蓝色色调)中的色调时,您需要使用这个颜色来保存您所做的任何调整。

func HSVtoRGB(h : Float, s : Float, v : Float) -> (r : Float, g : Float, b : Float) {
    var r : Float = 0
    var g : Float = 0
    var b : Float = 0
    let C = s * v
    let HS = h * 6.0
    let X = C * (1.0 - fabsf(fmodf(HS, 2.0) - 1.0))
    if (HS >= 0 && HS < 1) {
        r = C
        g = X
        b = 0
    } else if (HS >= 1 && HS < 2) {
        r = X
        g = C
        b = 0
    } else if (HS >= 2 && HS < 3) {
        r = 0
        g = C
        b = X
    } else if (HS >= 3 && HS < 4) {
        r = 0
        g = X
        b = C
    } else if (HS >= 4 && HS < 5) {
        r = X
        g = 0
        b = C
    } else if (HS >= 5 && HS < 6) {
        r = C
        g = 0
        b = X
    }
    let m = v - C
    r += m
    g += m
    b += m
    return (r, g, b)
}

Now you simply loop through a full RGBA color cube and "adjust" any colors in the "default blue" hue range with those from your newly desired hue. Then use Core Image and the CIColorCube filter to apply your adjusted color cube to the image.

现在,您只需循环使用一个完整的RGBA颜色立方体,并“调整”任何颜色在“默认蓝”色调范围与那些从您的新期望的色调。然后使用Core Image和CIColorCube filter将调整后的颜色cube应用到图像上。

func render() {
    let centerHueAngle: Float = 214.0/360.0 //default color of truck body blue
    let destCenterHueAngle: Float = slider.value
    let minHueAngle: Float = (214.0 - 60.0/2.0) / 360 //60 degree range = +30 -30
    let maxHueAngle: Float = (214.0 + 60.0/2.0) / 360
    var hueAdjustment = centerHueAngle - destCenterHueAngle
    let size = 64
    var cubeData = [Float](count: size * size * size * 4, repeatedValue: 0)
    var rgb: [Float] = [0, 0, 0]
    var hsv: (h : Float, s : Float, v : Float)
    var newRGB: (r : Float, g : Float, b : Float)
    var offset = 0
    for var z = 0; z < size; z++ {
        rgb[2] = Float(z) / Float(size) // blue value
        for var y = 0; y < size; y++ {
            rgb[1] = Float(y) / Float(size) // green value
            for var x = 0; x < size; x++ {
                rgb[0] = Float(x) / Float(size) // red value
                hsv = RGBtoHSV(rgb[0], g: rgb[1], b: rgb[2])
                if hsv.h < minHueAngle || hsv.h > maxHueAngle {
                    newRGB.r = rgb[0]
                    newRGB.g = rgb[1]
                    newRGB.b = rgb[2]
                } else {
                    hsv.h = destCenterHueAngle == 1 ? 0 : hsv.h - hueAdjustment //force red if slider angle is 360
                    newRGB = HSVtoRGB(hsv.h, s:hsv.s, v:hsv.v)
                }
                cubeData[offset]   = newRGB.r
                cubeData[offset+1] = newRGB.g
                cubeData[offset+2] = newRGB.b
                cubeData[offset+3] = 1.0
                offset += 4
            }
        }
    }
    let data = NSData(bytes: cubeData, length: cubeData.count * sizeof(Float))
    let colorCube = CIFilter(name: "CIColorCube")!
    colorCube.setValue(size, forKey: "inputCubeDimension")
    colorCube.setValue(data, forKey: "inputCubeData")
    colorCube.setValue(ciImage, forKey: kCIInputImageKey)
    if let outImage = colorCube.outputImage {
        let context = CIContext(options: nil)
        let outputImageRef = context.createCGImage(outImage, fromRect: outImage.extent)
        imageView.image = UIImage(CGImage: outputImageRef)
    }
}

You can download the sample project here. It's using Xcode 7 and Swift 2.0.

您可以在这里下载示例项目。它使用Xcode 7和Swift 2.0。

#3


13  

I'm going to make the assumption that you know how to perform these basic operations, so these won't be included in my solution:

我假设你知道如何执行这些基本操作,所以这些不会包含在我的解决方案中:

  • load an image
  • 加载一个图像
  • get the RGB value of a given pixel of the loaded image
  • 获取所加载图像的给定像素的RGB值
  • set the RGB value of a given pixel
  • 设置给定像素的RGB值
  • display a loaded image, and/or save it back to disk.
  • 显示已加载的映像,并/或将其保存回磁盘。

First of all, let's consider how you can describe the source and destination colors. Clearly you can't specify these as exact RGB values, since a photo will have slight variations in color. For example, the green pixels in the truck picture you posted are not all exactly the same shade of green. The RGB color model isn't very good at expressing basic color characteristics, so you will get much better results if you convert the pixels to HSL. Here are C functions to convert RGB to HSL and back.

首先,让我们考虑如何描述源和目标颜色。很明显,您不能指定这些为精确的RGB值,因为照片的颜色会有细微的变化。例如,你发布的卡车图片中的绿色像素并不是完全相同的绿色。RGB颜色模型不太擅长表达基本的颜色特征,所以如果您将像素转换为HSL,您将得到更好的结果。这里有一些C函数可以将RGB转换为HSL并返回。

The HSL color model describes three aspects of a color:

HSL颜色模型描述了颜色的三个方面:

  1. Hue - the main perceived color - i.e. red, green, orange, etc.
  2. 色调——主要感知的颜色——即红、绿、橙等。
  3. Saturation - how "full" the color is - i.e. from full color to no color at all
  4. 饱和度——颜色的“满”程度——即从全色到全无色
  5. Lightness - how bright the color is
  6. 明度——颜色有多亮

So for example, if you wanted to find all the green pixels in a picture, you will convert each pixel from RGB to HSL, then look for H values that correspond to green, with some tolerance for "near green" colors. Below is a Hue chart, from Wikipedia:

例如,如果你想在一张图片中找到所有的绿色像素,你将把每个像素从RGB转换为HSL,然后寻找对应绿色的H值,对“接近绿色”的颜色有一定的容忍度。下面是来自*的色相图:

如何在图像中改变特定的颜色?

So in your case you will be looking at pixels that have a Hue of 120 degrees +/- some amount. The bigger the range the more colors will get selected. If you make your range too wide you will start seeing yellow and cyan pixels getting selected, so you'll have to find the right range, and you may even want to offer the user of your app controls to select this range.

所以在你的例子中你会看到像素的色度是120度+/-多少。范围越大,选择的颜色就越多。如果你的范围太宽,你会看到黄色和青色的像素被选中,所以你必须找到正确的范围,你甚至可能想让你的应用控件的用户选择这个范围。

In addition to selecting by Hue, you may want to allow ranges for Saturation and Lightness, so that you can optionally put more limits to the pixels that you want to select for colorization.

除了根据色相进行选择外,您可能还希望允许饱和度和亮度的范围,以便您可以选择性地对要选择的像素进行更多的限制,以便进行着色。

Finally, you may want to offer the user the ability to draw a "lasso selection" so that specific parts of the picture can be left out of the colorization. This is how you could tell the app that you want the body of the green truck, but not the green wheel.

最后,您可能希望向用户提供绘制“套索选择”的能力,以便在着色过程中可以忽略图片的特定部分。这就是你如何告诉应用你想要绿色卡车的车身,而不是绿色车轮。

Once you know which pixels you want to modify it's time to alter their color.

一旦你知道你想要修改哪个像素,就该修改它们的颜色了。

The easiest way to colorize the pixels is to just change the Hue, leaving the Saturation and Lightness from the original pixel. So for example, if you want to make green pixels magenta you will be adding 180 degrees to all the Hue values of the selected pixels (making sure you use modulo 360 math).

对像素进行着色最简单的方法就是改变色相,将饱和度和亮度从原来的像素中去掉。举个例子,如果你想让绿色像素为洋红色,你将会给所选像素的所有色调值增加180度(确保你使用的是modulo 360)。

If you wanted to get more sophisticated, you can also apply changes to Saturation and that will give you a wider range of tones you can go to. I think the Lightness is better left alone, you may be able to make small adjustments and the image will still look good, but if you go too far away from the original you may start seeing hard edges where the process pixels border with background pixels.

如果你想要变得更复杂,你也可以对饱和度进行修改,这样你可以得到更大的音域。我认为最好不要考虑亮度,你可以做一些小的调整,图像看起来还是不错的,但是如果你离原来的地方太远,你可能会看到硬边,处理像素与背景像素的边界。

Once you have the colorized HSL pixel you just convert it back to RGB and write it back to the image.

一旦你有了色化的HSL像素你只需要把它转换回RGB并把它写回图像。

I hope this helps. A final comment I should make is that Hue values in code are typically recorded in the 0-255 range, but many applications show them as a color wheel with a range of 0 to 360 degrees. Keep that in mind!

我希望这可以帮助。我要做的最后一个评论是,代码中的色相值通常记录在0-255范围内,但许多应用程序将它们显示为一个0到360度范围的色轮。记住这一点!

#4


1  

Can I suggest you look into using OpenCV? It's an open source image manipulation library, and it's got an iOS port too. There are plenty of blog posts about how to use it and set it up.

我可以建议你考虑使用OpenCV吗?它是一个开源的图像处理库,它也有一个iOS端口。有很多关于如何使用和设置它的博客文章。

It has a whole heap of functions that will help you do a good job of what you're attempting. You could do it just using CoreGraphics, but the end result isn't going to look nearly as good as OpenCV would.

它有一大堆函数可以帮助你很好地完成你的尝试。你可以用CoreGraphics做,但是最终的结果不会像OpenCV那样好。

It was developed by some folks at MIT, so as you might expect it does a pretty good job at things like edge detection and object tracking. I remember reading a blog about how to separate a certain color from a picture with OpenCV - the examples showed a pretty good result. See here for an example. From there I can't imagine it would be a massive job to actually change the separated color to something else.

它是由麻省理工学院的一些人开发的,所以你可能会认为它在边缘检测和对象跟踪方面做得很好。我记得我读过一篇关于如何用OpenCV从一幅图片中分离某种颜色的博客——这些例子显示了一个相当不错的结果。请看这里的一个例子。从那里,我无法想象将分离的颜色改变成其他颜色将是一项艰巨的任务。

#5


0  

I don't know of a CoreGraphics operation for this, and I don't see a suitable CoreImage filter for this. If that's correct, then here's a push in the right direction:

我不知道有什么CoreGraphics操作,也没有合适的CoreImage过滤器。如果这是正确的,那么这是朝着正确方向的推动:

Assuming you have a CGImage (or a uiImage.CGImage):

假设您有一个CGImage(或一个uiImage.CGImage):

  • Begin by creating a new CGBitmapContext
  • 首先创建一个新的CGBitmapContext
  • Draw the source image to the bitmap context
  • 将源图像绘制到位图上下文
  • Get a handle to the bitmap's pixel data
  • 获取位图的像素数据的句柄

Learn how the buffer is structured so you could properly populate a 2D array of pixel values which have the form:

了解缓冲区的结构,以便正确填充具有以下形式的二维像素值数组:

typedef struct t_pixel {
  uint8_t r, g, b, a;
} t_pixel;

Then create the color to locate:

然后创建颜色来定位:

const t_pixel ColorToLocate = { 0,0,0,255 }; // << black, opaque

And its substitution value:

和它的替换值:

const t_pixel SubstitutionColor = { 255,255,255,255 }; // << white, opaque
  • Iterate over the bitmap context's pixel buffer, creating t_pixels.
  • 迭代位图上下文的像素缓冲区,创建t_pixels。
  • When you find a pixel which matches ColorToLocate, replace the source values with the values in SubstitutionColor.

    当您找到匹配ColorToLocate的像素时,将源值替换为替换颜色中的值。

  • Create a new CGImage from the CGBitmapContext.

    从CGBitmapContext中创建一个新的CGImage。

That's the easy part! All that does is takes a CGImage, replace exact color matches, and produces a new CGImage.

这是很简单的部分!所做的就是获取一个CGImage,替换精确的颜色匹配,并生成一个新的CGImage。

What you want is more sophisticated. For this task, you will want a good edge detection algorithm.

你想要的是更复杂的。对于这个任务,您将需要一个好的边缘检测算法。

I've not used this app you have linked. If it's limited to a few colors, then they may simply be swapping channel values, paired with edge detection (keep in mind that buffers may also be represented in multiple color models - not just RGBA).

我还没用过你链接的这个应用。如果它被限制在几个颜色,那么它们可能只是交换通道值,并与边缘检测配对(请记住,缓冲区也可以在多个颜色模型中表示——而不仅仅是RGBA)。

If (in the app you linked) the user can choose an arbitrary colors, values, and edge thresholds, then you will have to use real blending and edge detection. If you need to see how this is accomplished, you may want to check out a package such as Gimp (it's an open image editor) - they have the algos to detect edges and choose by color.

如果(在你链接的应用程序中)用户可以选择任意颜色、值和边缘阈值,那么你将不得不使用真正的混合和边缘检测。如果您需要了解这是如何实现的,您可能想要检查一个包,例如Gimp(它是一个开放的图像编辑器)——它们有algos来检测边缘并根据颜色进行选择。