9

I am working on replacing certain color in image by User's selected color. I am using OpenCV for color replacement.

Here in short I have described from where I took help and what I got.

  1. How to change a particular color in an image? I have followed the step or taken basic idea from answer of above link. In correct answer of that link that guy told you only need to change hue for colour replacement.

  2. after that I run into the issue similar like color replacement in image for iphone application (i.e. It's good code for color replacement for those who are completely beginners)
    from that issue I got the idea that I also need to change "Saturation" also.


Now I am running into issues like

"When my source image is too light(i.e. with high brightness) and I am replacing colour with some dark colour then colours looks light in replaced image instead of dark due to that it seems like Replaced colour does not match with colour using that we done replacement"

This happens because I am not considering the brightness in replacement. Here I am stuck what is the formula or idea to change brightness?

Suppose I am replacing the brightness of image with brightness of destination colour then It would look like flat replacemnt and image will lose it's actual shadow or edges.

Edit:
When I am considering the brightness of source(i.e. the pixel to be processed) in replacment then I am facing one issue. let me explain as per scenario of my application.

for example I am changing the colour of car(like whiteAngl explain) after that I am erasing few portion of the newly coloured car. Again I am doing recolour on erased portion but now what happended is colour done after erase and colour before erase doesn't match because both time I am getting different lightness because both time my pixel of to be processed is changed and due to that lightness of colour changed in output. How to overcome this issue

Any help will be appreciated

Coloured Image Erased Few portion Recoloured

Community
  • 1
  • 1
Iducool
  • 3,543
  • 2
  • 24
  • 45

2 Answers2

12

Without seeing the code you have tried, it's not easy to guess what you have done wrong. To show you with a concrete example how this is done let's change the ugly blue color of this car:

enter image description here

This short python script shows how we can change the color using the HSV color space:

import cv2
orig = cv2.imread("original.jpg")
hsv = cv2.cvtColor(orig, cv2.COLOR_BGR2HSV)
hsv[:,:,0] += 100
bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
cv2.imwrite('changed.jpg', bgr)

and you get: enter image description here

On wikipedia you see the hue is between 0 to 360 degrees but for the values in OpenCV see the documentation. You see I added 100 to hue of every pixel in the image. I guess you want to change the color of a portion of your image, but probably you get the idea from the above script.

Here is how to get the requested dark red car. First we get the red one: red card

The dark red one that I tried to keep the metallic feeling in it: dark red car

As I said, the equation you use to shift the light of the color depends on the material you want to have for the object. Here I came up with a quick and dirty equation to keep the metallic material of the car. This script produces the above dark red car image from the first light blue car image:

import cv2
orig = cv2.imread("original.jpg")
hls = cv2.cvtColor(orig, cv2.COLOR_BGR2HLS)
hls[:,:,0] += 80 # change color from blue to red, hue
for i in range(1,50): # 50 times reduce lightness 
 # select indices where lightness is greater than 0 (black) and less than very bright 
 # 220-i*2 is there to reduce lightness of bright pixel fewer number of times (than 50 times), 
 # so in the first iteration we don't reduce lightness of pixels which have lightness >= 200, in the second iteration we don't touch pixels with lightness >= 198 and so on
 ind = (hls[:,:,1] > 0) & (hls[:,:,1] < (220-i*2))
 # from the lightness of the selected pixels we subtract 1, using trick true=1 false=0
 # so the selected pixels get darker
 hls[:,:,1] -= ind
bgr = cv2.cvtColor(hls, cv2.COLOR_HLS2BGR)
cv2.imwrite('changed.jpg', bgr)
fireant
  • 14,080
  • 4
  • 39
  • 48
  • As far as I know in openCV: Hue ranges from:0->180, Sat:0->255 and Brightness->0 to 255 – Iducool Apr 05 '13 at 10:08
  • 2
    Now try changing the color to a very dark red and see what you get. – Mark Ransom Apr 06 '13 at 03:59
  • hm.. that's easy, I didn't understand the OP's question well the first time. See my updated answer. – fireant Apr 07 '13 at 07:18
  • that's easy.... by manually changing the equation to make it match to this specific dark color. Now, make it brighter with the same function ? And make it match the color (R,G,B)=(10,192,150) ? :) I find this answer really lacks generality :s – nbonneel Apr 07 '13 at 07:41
  • well, that's easy too, I'm busy now, later when find the time will write the script for that too :) – fireant Apr 07 '13 at 07:42
  • Please add some description in you answer also so I can try your solution too. I am not getting what is 80 and other hardcode values are – Iducool Apr 07 '13 at 09:13
  • +1 for good answer but now awarding bounty because it is not generic solution it is easy to change colour by such hardcode values. – Iducool Apr 11 '13 at 05:04
  • I got very busy, in a few days will update my answer with a generalized approach and some extra explanation. – fireant Apr 11 '13 at 06:14
  • Is it possible achieve similar results on Android using opencv? – Suraj Pohwani Jan 24 '19 at 18:41
1

You are right : changing only the hue will not change the brightness at all (or very weakly due to some perceptual effects), and what you want is to change the brightness as well. And as you mentioned, setting the brightness to the target brightness will loose all pixel values (you will only see changes in saturation). So what's next ?

What you can do is to change the pixel's hue plus try to match the average lightness. To do that, just compute the average brightness B of all your pixels to be processed, and then multiply all your brightness values by Bt/B where Bt is the brightness of your target color.

Doing that will both match the hue (due to the first step) and the brightness due to the second step, while preserving the edges (because you only modified the average brightness).

This is a special case of histogram matching, where here, your target histogram has a single value (the target color) so only the mean can be matched in a reasonable way.

And if you're looking for a "credible source" as stated in your bounty request, I am a postdoc at Harvard and will be presenting a paper on color histogram matching at Siggraph this year ;) .

nbonneel
  • 3,286
  • 4
  • 29
  • 39
  • Congratulation for your position at Harvard. I think you're missing the point that the reflected light depends on the material as well and not only the color of an object. – fireant Apr 07 '13 at 07:28
  • @Shambool No : I think your initial answer was missing the point that when the target color is dark, changing the hue /only/ doesn't make the pixel darker as desired. You have just edited your answer to add an offset to the luminance as well ; however, an offset can lead to negative values or loose contrast (and is anyway not the correct approach to adjusting the brightess of an object). You also manually changed the offset, without accounting for the /desired/ color to match to (how am-I supposed to know that the desired color is darker by 80 in luminance?) – nbonneel Apr 07 '13 at 07:34
  • Well, to prove my approach works I have added the output image and you see clearly that "an offset can lead to negative values or loose contrast" is incorrect. Because I don't simply add an offset! – fireant Apr 07 '13 at 07:39
  • Regarding your second question, for a given pixel if user enters the desired color H/L, then you simply compare with current H/L of the pixel and voila, you have the difference. – fireant Apr 07 '13 at 07:41
  • Please see my updated question I have added my concern about this solution – Iducool Apr 07 '13 at 09:12
  • See I have added images what type of output I am getting. You can see once I will do erase operation and then recolour colour becomes different. – Iducool Apr 08 '13 at 12:07
  • imho, your answer is still not understandable : you have some hard coded constants that need to be manually replaced for whatever color correction that need to be done, it is not general (ie., it doesn't match a desired color, but a specific color that *you* chose), it is very hacky (why all that?), ... I unfortunately won't have time to provide some code in the next few days though. – nbonneel Apr 08 '13 at 19:22