Pixel color matching estimate - iphone

For image scanning purposes, I'd like a pixel (which I can get from a UIImage) to match (for a certain percentage) to a pre-set color.
Say pink. When I scan the image for pixels that are pink, I want a function to return a percentage of how much the RGB value in the pixel looks like my pre-set RGB value. This way I'd like all (well, most) pink pixels to become 'visible' to me, not just exact matches.
Is anyone familiar with such an approach? How would you do something like this?
Thanks in advance.
UPDATE: thank you all for your answers so far. I accepted the answer from Damien Pollet because it helped me further and I came to the conclusion that calculating the vector difference between two RGB colors does it perfectly for me (at this moment). It might need some tweaking over time but for now I use the following (in objective c):
float difference = pow( pow((red1 - red2), 2) + pow((green1 - green2), 2) + pow((blue1 - blue2), 2), 0.5 );
If this difference is below 85, I accept the color as my target color. Since my algorithm needs no precision, I'm ok with this solution :)
UPDATE 2: on my search for more I found the following URL which might be quite (understatement) useful for you if you are looking for something similar.
http://www.sunsetlakesoftware.com/2010/10/22/gpu-accelerated-video-processing-mac-and-ios

I would say just compute the vector difference to your target color, and check that it's norm is less than some threshold. I suspect some color spaces are better than others at this, maybe HSL or L*ab, since they separate the brightness from the color hue itself, and so might represent a small perceptual difference by a smaller color vector...
Also, see this related question

Scientific answer: You should convert both colors to the LAB color space and calculate the euclidian distance there. That value is also called deltaE.
The LAB space was developed (using test persons) for exactly that reaason: so that different color pairs with equal distances in tnis space correspond to equal perceived color differences.
However, it sounds like you are not looking for matching a specific color, but rather a color range (lets say all skin tones). That might require more user input than just a reference color + a deltaE tollerance:
a reference color with 3 tollerances for hue, saturation and brightness
a cloud of refence color samples
...

Related

Changes Brightness in color replacement

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.
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.
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
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:
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:
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:
The dark red one that I tried to keep the metallic feeling in it:
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)
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 ;) .

Perl - Ratio of homogeneous areas of an image

I would like to check whether an image has a lot of homogeneous areas. Therefore I would like to get some kind of value of an image that declares a ratio for images depending on the amount/size of homogeneous areas (e.g. that value could have a range from 0 to 5).
Instead of a value there could be some kind of classification as well.
[many homogeneous areas -> value/class 5 ; few homogeneous areas -> value/class 0]
I would like to do that in perl. Is there a package/function or something like that?
What you want seems to be an area of image processing research which I am not familiar with. However, GraphicsMagick's mogrify utility has a -segment option:
Use -segment to segment an image by analyzing the histograms of the color components and identifying units that are homogeneous with the fuzzy c-means technique. The scale-space filter analyzes the histograms of the three color components of the image and identifies a set of classes. The extents of each class is used to coarsely segment the image with thresholding. The color associated with each class is determined by the mean color of all pixels within the extents of a particular class. Finally, any unclassified pixels are assigned to the closest class with the fuzzy c-means technique.
I don't know if this is any use to you. You might have to hit the library on this one, and read some research. You do have access to this through PerlMagick as well. However, it does not look like it gives access to the internals, but just produces an image based on parameters.
In my tests (without really understanding what the parameters do), photos turned entirely black, whereas PNG images with large areas of similar colors were reduced to a sort of an average color. Whether you can use that fact to develop a measure is an open question I am not going to investigate ;-)

How get a random UIColor but restrict it to subset of the colors

I know how get a random UIColor, but I wonder if exist a way to only return colors with some specific quality of it. I don't know if exist a specific term, but for example, I need to get only opaque colors, dark tones... colors that are good for backgrounds with bright text/ images on it.
I could hand-pick some, but in my case i want to provide a very good defaults for a large list of icons backgrounds.
UPDATE:
My solution based on the answer here:
float r = arc4random() % 12;
return [UIColor colorWithHue:(30*r)/360 saturation:0.5f brightness:0.8f alpha:1.0f];
I get a very small list of possible answers, but this give me a good start.
What I would do is use the HSV/HSL colour space and then convert the results to RGB. Keep a constant value and saturation (S and V) whose qualities you like, and then alter the hue (H) value for the number of colours you want. Convert the results to RGB and you'll have a nice set of colours that appear to work well together. You can create any set of nice colours that are 'saturated', 'bright', 'dark', etc. just by picking nice combinations of S and V for your needs (low V is dark, high V is bright, low S is unsaturated, high S is saturated).
Take a look at this wiki page for a discussion on converting HSV to RGB. I'd recommend you start with saturation (S) at 0.5 and value (V) at 0.8. Then, to generate nice colours, do the HSV -> RGB conversion for H values of 0, 30, 60, 90... all the way up to 360. It will generate a nice palette of colours that look good together. Later, you can adjust your S and V values if you want different colour 'qualities'.
Using a random color as a background is indeed a suboptimal solution as it will lead to visibility and readability problems of the text and information of your icon. There is some research going on in automatically finding an appropriate color that matches your foreground colors, leading to a harmonic result in terms of visual perception of the image. Have a look at http://cs.nyu.edu/~sorkine/ProjectPages/Harmonization/

UISlider to represent the color spectrum

I have a UISlider that is supposed to update the color of a textlabel. Now I want the user to be able to choose between all colors in the spectrum (sort of all anyway). I was thinking of using this UISlider to represent the colors and when dragging the slider the value/color changes.
I know the spectrum is not sequential like: [0,0,0]...[255,0,0]...[255,1,0]...[255,255,0] etc.
So: any tip on how I can implement this?
Color is at least a two or three dimensional selection. And a slider only provides a scalar output. If you want a smoothly changing selection using only a scalar parameter, you might try drawing a path line on some color chart (or a functional representation thereof) and select a point on that path parametrically.
Yes, color is a multidimensional value, but there are different ways to slice those dimensions. I think a hue, saturation, brightness constructor, rather than RGB, will give you exactly the effect you want. For example, often I will generate a random color with [UIColor colorWithHue:<random float in [0,1]> saturation:1.f brightness:1.f alpha:1.f].
Slide hue linearly from 0 to 1, with saturation and brightness fixed at the most legible (or whatever) values.

Histogram of image

I have 2 images that look nearly identical. The histogram for one (256 bins) has intensities distributed pretty evenly throughout. The other has intensities at the lowest and highest bin. Why would this be? Then wouldnt it appear binary (thats not the case)?
Think about it this way: Imagine you are taking a histogram of two grayscale images with each pixel represented by a color value 0-255. One image contains pixels that all have gray levels of 128. The second image contains a "checkerboard" pattern (pixels alternate between 0 and 255). If you step back far enough that you no longer see individual pixels, they will appear identical to the naked eye. Your brain "averages" the alternating black and white pixels into a field of gray.
This is what your images are doing. The first image has colors distributed evenly throughout the range and the second image has concentrations of specific colors, but if you calculate an average color for the image (and also for sub-sections within the image) you should see similar values for both.
Never trust in your eyes! They will always lie to you.
Consider this silly example that can be illustrative here. An X-Ray 'photo' is nothing more than black and white dots. But as they are small and mixed along the image, your eyes see different shades of gray.
The same can happen in a digital image, where, although the pixels may have the same size, then can be black and white and 'distributed' in the image in such a way that you see it as having more graylevels. This is called halftone.
Without seeing the images it's hard to say, but it sounds like the second may be slightly clipped.
The difference also could just be a slight difference in contrast in the images that's no visible to the naked eye.