Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change a particular color in an image?

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.

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

enter image description here

like image 530
Aravindhan Avatar asked Nov 08 '11 06:11

Aravindhan


2 Answers

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.

@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.

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

enter image description here

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.

enter image description here

enter image description here

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.

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

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.

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.

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.

like image 131
William T. Avatar answered Oct 05 '22 05:10

William T.


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


Here is the sketch of a possible solution using OpenCV:

  • Convert the image from RGB to HSV using cvCvtColor (we only want to change the hue).
  • Isolate a color with cvThreshold specifying a certain tolerance (you want a range of colors, not one flat color).
  • 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.
  • Mask the color with cvInRangeS and use the resulting mask to apply the new hue.
  • cvMerge the new image with the new hue with an image composed by the saturation and brightness channels that you saved in step one.

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.

like image 40
Jano Avatar answered Oct 05 '22 06:10

Jano