如何更改图像中的特定颜色?
image-processing
objective-c
4
0

我的问题是,如果我有狮子图像,只想改变狮子的颜色而不是背景颜色。为此,我提到了这个问题,但它使整个图像变成彩色。此外,图像看起来不佳。我需要像photoshop一样的颜色更改。是否可以在核心图形中执行此操作,或者我必须使用任何其他库。

编辑:我需要更改颜色像iQuikColor应用程序

在此处输入图片说明

参考资料:
Stack Overflow
收藏
评论
共 3 个回答
高赞 时间 活跃

这花了很长时间才弄清楚,主要是因为我想使用Core Image和CIColorCube在Swift中启动并运行它。

@Miguel的解释是关于需要用另一个“色相角范围”替换“色相角范围”的方式的。您可以在上方阅读他的文章,详细了解“色相角度范围”。

我制作了一个快速应用程序,用您在“色相”滑块上选择的任何内容替换了下面的默认蓝色卡车。

在此处输入图片说明

您可以滑动滑块以告知应用您要用哪种颜色替换蓝色。

我将色相范围硬编码为60度,通常似乎涵盖了大多数特定颜色,但是您可以根据需要进行编辑。

在此处输入图片说明

在此处输入图片说明

请注意,它不会为轮胎或尾灯着色,因为它不在卡车默认蓝色色调的60度范围内,但可以正确处理阴影。

首先,您需要将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))
}

然后,您需要将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)
}

现在,您只需遍历完整的RGBA颜色立方体,即可将“默认蓝色”色调范围内的任何颜色与您新希望的色相“调整”在一起。然后,使用Core Image和CIColorCube过滤器将调整后的颜色立方体应用于图像。

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)
    }
}

您可以在此处下载示例项目

收藏
评论

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

  • 加载图像
  • 获取加载图像的给定像素的RGB值
  • 设置给定像素的RGB值
  • 显示已加载的图像,和/或将其保存回磁盘。

首先,让我们考虑如何描述源颜色和目标颜色。显然,您不能将它们指定为确切的RGB值,因为照片的颜色会略有变化。例如,您发布的卡车图片中的绿色像素并非都完全相同。 RGB颜色模型不能很好地表达基本的颜色特征,因此,如果将像素转换为HSL,将会获得更好的结果。 是将RGB转换为HSL并返回的C函数。

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

  1. 色相-主要可感知的颜色-即红色,绿色,橙色等。
  2. 饱和度-颜色的“全色”程度-即从全色到完全没有颜色
  3. 亮度-颜色有多亮

因此,例如,如果要查找图片中的所有绿色像素,则将每个像素从RGB转换为HSL,然后查找与绿色相对应的H值,并对“近绿色”颜色具有一定的容差。以下是来自维基百科的色调图表:

因此,在您的情况下,您将要查看色相为120度+/-某种程度的像素。范围越大,将选择更多的颜色。如果您将范围设置得太宽,就会开始看到黄色和青色像素被选中,因此您必须找到正确的范围,甚至可能希望让应用程序控件的用户选择该范围。

除了按色相选择之外,您可能还希望允许“饱和度”和“亮度”范围,以便可以有选择地对要选择用于着色的像素设置更多限制。

最后,您可能希望为用户提供绘制“套索选择”的功能,以便可以将图片的特定部分排除在着色之外。这样您可以告诉应用程序您想要绿色卡车的车身,而不是绿色轮子。

知道要修改的像素后,就可以更改其颜色了。

使像素着色的最简单方法是仅更改色相,而保留原始像素的饱和度和亮度。因此,例如,如果您想使绿色像素变为洋红色,则将向所选像素的所有Hue值添加180度(确保使用模360数学)。

如果您想变得更复杂,还可以对“饱和度”应用更改,这将为您提供更广泛的色调。我认为单独使用“亮度”效果更好,您可以进行一些微调,并且图像仍然看起来不错,但是如果您与原始图像距离太远,您可能会开始看到硬像素,即过程像素与背景像素接壤。

拥有彩色的HSL像素后,只需将其转换回RGB并将其写回到图像即可。

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

收藏
评论

请参阅下面的答案。我的没有提供完整的解决方案。


这是使用OpenCV的可能解决方案的草图:

  • 使用cvCvtColor (我们只想更改色相)将图像从RGB转换为HSV。
  • 使用指定特定容差的cvThreshold隔离颜色(您需要一定范围的颜色,而不是一种纯色)。
  • 使用斑点检测库(如cvBlobsLib)丢弃最小尺寸以下的颜色区域。这将消除场景中相似颜色的点。
  • 使用cvInRangeS遮罩颜色,并使用生成的遮罩应用新的色相。
  • cvMerge将新图像与新色相合并,并使其包含由您在第一步中保存的饱和度和亮度通道组成的图像。

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

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号