Iphone 如何更改图像中的特定颜色?
我的问题是,如果我有一个狮子图像,我只想改变狮子的颜色,而不是背景色。为此,我引用了这个,但它改变了整个图像的颜色。而且形象也不太好。我需要像photoshop那样改变颜色。是否可以在coregraphics中实现这一点,或者我必须使用任何其他库 编辑:我需要像应用程序一样更改颜色Iphone 如何更改图像中的特定颜色?,iphone,objective-c,image-processing,core-graphics,pixel,Iphone,Objective C,Image Processing,Core Graphics,Pixel,我的问题是,如果我有一个狮子图像,我只想改变狮子的颜色,而不是背景色。为此,我引用了这个,但它改变了整个图像的颜色。而且形象也不太好。我需要像photoshop那样改变颜色。是否可以在coregraphics中实现这一点,或者我必须使用任何其他库 编辑:我需要像应用程序一样更改颜色 我不知道是否有适用于此的CoreGraphics操作,我也没有看到适用于此的CoreImage过滤器。如果这是正确的,那么这里有一个正确方向的推力: 假设您有一个CGImage(或uiImage.CGImage):
我不知道是否有适用于此的CoreGraphics操作,我也没有看到适用于此的CoreImage过滤器。如果这是正确的,那么这里有一个正确方向的推力: 假设您有一个
CGImage
(或uiImage.CGImage
):
- 首先创建一个新的
CGBitmapContext
- 将源图像绘制到位图上下文
- 获取位图像素数据的句柄
typedef struct t_pixel {
uint8_t r, g, b, a;
} t_pixel;
然后创建要定位的颜色:
const t_pixel ColorToLocate = { 0,0,0,255 }; // << black, opaque
const t_pixel ColorToLocate={0,0,0255};// 我可以建议你考虑使用吗?这是一个开源的图像处理库,它还有一个iOS端口。有很多关于如何使用和设置它的博客文章
它有一整堆函数,可以帮助您很好地完成所尝试的工作。您可以使用CoreGraphics来实现这一点,但最终结果看起来并不像OpenCV那样好
它是由麻省理工学院的一些人开发的,所以正如你所料,它在边缘检测和目标跟踪方面做得相当好。我记得读过一篇关于如何使用OpenCV从图片中分离出某种颜色的博客——示例显示了一个非常好的结果。有关示例,请参见。从那以后,我无法想象将分离的颜色改成其他颜色将是一项艰巨的工作。请参见下面的答案。我的解决方案不完整。
以下是使用OpenCV的可能解决方案的示意图:
- 使用
cvtcolor
将图像从RGB转换为HSV(我们只想更改色调)
- 使用指定特定公差的
cvThreshold
隔离颜色(您需要的是一系列颜色,而不是一种单色)
- 使用blob检测库丢弃低于最小大小的颜色区域,如。这将去除场景中颜色相似的点
- 使用
cvInRangeS
遮罩颜色,并使用生成的遮罩应用新色调
cvMerge
具有新色调的新图像,该图像由步骤1中保存的饱和度和亮度通道组成
网络中有几个OpenCV iOS端口,例如:我自己没有尝试过,但这似乎是一个很好的研究方向。我假设您知道如何执行这些基本操作,因此我的解决方案中不会包括这些:
- 加载图像
- 获取加载图像的给定像素的RGB值
- 设置给定像素的RGB值
- 显示加载的图像,和/或将其保存回磁盘
首先,让我们考虑如何描述源和目标颜色。很明显,您不能将它们指定为精确的RGB值,因为照片的颜色会略有变化。例如,您发布的卡车图片中的绿色像素并非都是完全相同的绿色。RGB颜色模型不太擅长表达基本的颜色特征,因此如果将像素转换为HSL,将获得更好的结果。是将RGB转换为HSL并返回的C函数
HSL颜色模型描述颜色的三个方面:
色调-主要感知颜色-即红色、绿色、橙色等
饱和度-颜色的“完整”程度-即从完整颜色到完全没有颜色
亮度-颜色有多亮
例如,如果你想找到一张图片中的所有绿色像素,你将把每个像素从RGB转换成HSL,然后寻找对应于绿色的H值,对“近绿色”颜色有一定的容差。以下是来自维基百科的色调图表:
因此,在您的例子中,您将看到色调为120度+/-一定量的像素。范围越大,选择的颜色就越多。如果你的范围太宽,你会看到黄色和青色像素被选中,因此你必须找到正确的范围,你甚至可能想让你的应用程序控件的用户选择这个范围
除了按色调选择外,您可能还希望允许饱和度和亮度的范围,以便可以选择对要选择着色的像素施加更多限制
最后,您可能希望为用户提供绘制“套索选择”的能力,以便在着色时可以忽略图片的特定部分。这就是你如何告诉应用程序你想要的是绿色卡车的车身,而不是绿色车轮
一旦知道要修改哪些像素,就可以改变它们的颜色了
给像素着色最简单的方法就是改变色调,保留原始像素的饱和度和亮度。因此,例如,如果要使绿色像素为洋红色,则将向选定像素的所有色调值添加180度(确保使用模360数学)
如果你想变得更复杂,你也可以改变饱和度,这将给你一个更广泛的音调范围,你可以去。我认为亮度更好,你可以做一些小的调整,图像看起来仍然很好,但是如果你离原始图像太远,你可能会看到处理像素与背景像素交界处的硬边
一旦你有了彩色的HSL像素,你只需将其转换回RGB并将其写回图像
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)
}
}
我希望如此
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))
}
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)
}
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)
}
}