binarization of colours in images - image-processing

I am extracting primitives from pixel-based line diagrams and wish select by colour. Thus in the following
I wish to extract the "blue", the "green" and the "black" primitives. (I am prepared to try to reconstruct primitives which have been split by primitives of another colour).
However the "blues" have a varying amount of white added (similar to a gray scale for black). Thus the commonest colours (rounded to 12-bit for simplicity) with their counts might be
000 881 // black
88f 1089 // white-blue
fff 70475 // white
but there are other degrees of whiteness at lower frequency
// other white-blue
99f 207
// other grey
ddd 196
I believe that the authors will have used only a very limited number of pure colours (e.g. 3-6) in many diagrams and that various rendering tools will have added the white. IOW the colours can be expressed by (0 =< x =< 1)
000 + x(FFF)
00F + x(FF0) // blue
0F0 + x(F0F) // green
However there is no requirement to use primary colours and the set could be any colour with arbitrary amounts of white.
How can I reconstruct the (small) set of different colours? If this is possible I can then select those regions, transform to grey, and binarize in the normal way.
I'd prefer source in Java but I suspect that any code will be adequate;
I have read two useful SO questions
"Rounding" colour values to the nearest of a small set of colours
HCL color to RGB and backward
which use H-C-L and might be a way forward although they don't directly answer my requirements.

You could try using region growing. I think it should fit your needs well. Just change the threshold for when it's the same color. I think it should work well here since there seems to be a big difference between any two colors that are connected as objects.

If your intuition is correct (all pixels being a linear mixture of some color and pure white), in the RGB cube all colors will be aligned on line segments originating from the white corner.
If you pick one representative pixel per different color (as far as possible from white, for better accuracy), you can identify the color of any other pixel by finding the best alignment formed by this pixel, by white and by the representative pixels.
Alignment is tested by computing the cosine of the angle formed (use 3D vectors, the cosine is the dot product over the product of the norms; drop the sign). In theory the cosine should be exactly 1, but due to numerical errors it can be smaller, so just consider the representative color that maximizes the cosine.
Take special care of the white pixels (short distance to the white corner), otherwise they will be randomly assigned to some representative color.

Depending on the number of colors involved and their similarity, a simple threshold of the R, G, and B values would quickly reduce everything to one of 8 colors (black, red, green, blue, cyan, magenta, yellow, or white).

Related

generate colors with the same perceived brightness and saturation

I want to generate a rainbow of colors, with the same perceived brightness, and same perceived saturation.
In essence, I am looking for a formula that takes three parameters: getRgbColor(hue, perceived_brightness, perceived_saturation) and returns the corresponding color, or some sort of error if no color with these constraints exists.
By "same perceived brightness" I mean: an average person seeing these colors on their average monitor would say that these colors appear to be about as bright as one particular shade of gray.
By "same perceived saturation" I mean: an average person seeing these colors on their average monitor would say that these colors appear to be equally colorful, when compared to that shade of gray.
Everyone will perceive colors a bit differently, so I am seeking an average consensus.
According to my understanding, to generate colors of the same "perceived brightness", I could use the CIELAB color space, and set the [L]uminosity. But then I do not know what values to use for a and b, and how to set the saturation, or the hue.
To generate colors of the same "perceived saturation", I think I could use the HSV or HSL color space, and set the [S]aturation. But in those color spaces, the "perceived brightness" does not seem to correspond to the [V]alue or [L]ightness. A shade of blue appears much darker than a shade of yellow with the same value, or the same lightness.
I am using opencv for the graphics output, and I am looking for either a way to calculate these colors in opencv, or a general formula.
With colour values represented in CIE L*a*b*, it is possible to perform a conversion to cylindrical coordinates, i.e. CIE L*C*Hab*, to separate hue and saturation components: https://en.wikipedia.org/wiki/CIELAB_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC

RGB value of a pixel, combined from 2 overlaying pixels

I am creating an animated gif with Water and Land. The Land part has shores, so the water will in some cases be overlaying those shores. However, I wish the shores to still be slightly visible underneath the water. Basically, imagine 1 transparent png which represents water, over another that has sand. The 2 images combined can be viewed as a third image.
My question is - how would I calculate the RGB value of the new pixels, based on the top ones RGBA (with transparency) and the bottom ones RGB values, to mimic a natural look.
I will change the transparency level myself to see what suits me best, but I'm missing a formula.
EDIT:
atm I do have 1 idea - take the percentage of the transparency level of the water, and based on that percentage calculate a new RGB. Do the same for the sand pixels, but with the "remaining" percentage (100-transparency%)
ie (A part is in %, for simplicity)
(R1,G1,B1, 40) (R2,G2,B2) = 40% of first group + 60% of second
Alpha blending is either dead simple (alpha is on 0-255, so the colour is destination * (255 - a) + overlay * a, all over 255) or quite subtle, when you allow the destination to also have alpha. Also it is necessary to implement efficiently for many applications, which is done by pre-multiplying, then hardcoding the division by 255 using
((x+1) * 257) >> 16;
Malcolm McLean gives the correct answer for the case where destination (aka background) is completely opaque, which happens to be the case we are discussing.
Just for completeness, I'd like you give the formula for the general case and the intuition behind it.
First of all, assume our colors are 4-component floating-point vectors, with each channel having values between 0 and 1. Also assume our colors are alpha-premultiplied, that is the r, g and b channels are pre-multiplied by the alpha channel. Then the alpha-blending formula is:
blended = front + back * (1.0 - front.a)
The intuition is: we are taking the front color and adding to it a bit of the back color, namely as much as we can see through the front color.
Note that the blended color is also alpha-premultiplied.

Should I use HSV/HSB or RGB and why?

I have to detect leukocytes cells in an image that contains another blood cells, but the differences can be distinguished through the color of cells, leukocytes have more dense purple color, can be seen in the image below.
What color methode I've to use RGB/HSV ? and why ?!
sample image:
Usually when making decisions like this I just quickly plot the different channels and color spaces and see what I find. It is always better to start with a high quality image than to start with a low one and try to fix it with lots of processing
In this specific case I would use HSV. But unlike most color segmentation I would actually use the Saturation Channel to segment the images. The cells are nearly the same Hue so using the hue channel would be very difficult.
hue, (at full saturation and full brightness) very hard to differentiate cells
saturation huge contrast
Green channel, actually shows a lot of contrast as well (it surprised me)
the red and blue channels are hard to actually distinguish the cells.
Now that we have two candidate representations the saturation or the Green channel, we ask which is easier to work with? Since any HSV work involves us converting the RGB image, we can dismiss it, so the clear choice is to simply use the green channel of the RGB image for segmentation.
edit
since you didn't include a language tag I would like to attach some Matlab code I just wrote. It displays an image in all 4 color spaces so you can quickly make an informed decision on which to use. It mimics matlabs Color Thresholder colorspace selection window
function ViewColorSpaces(rgb_image)
% ViewColorSpaces(rgb_image)
% displays an RGB image in 4 different color spaces. RGB, HSV, YCbCr,CIELab
% each of the 3 channels are shown for each colorspace
% the display mimcs the New matlab color thresholder window
% http://www.mathworks.com/help/images/image-segmentation-using-the-color-thesholder-app.html
hsvim = rgb2hsv(rgb_image);
yuvim = rgb2ycbcr(rgb_image);
%cielab colorspace
cform = makecform('srgb2lab');
cieim = applycform(rgb_image,cform);
figure();
%rgb
subplot(3,4,1);imshow(rgb_image(:,:,1));title(sprintf('RGB Space\n\nred'))
subplot(3,4,5);imshow(rgb_image(:,:,2));title('green')
subplot(3,4,9);imshow(rgb_image(:,:,3));title('blue')
%hsv
subplot(3,4,2);imshow(hsvim(:,:,1));title(sprintf('HSV Space\n\nhue'))
subplot(3,4,6);imshow(hsvim(:,:,2));title('saturation')
subplot(3,4,10);imshow(hsvim(:,:,3));title('brightness')
%ycbcr / yuv
subplot(3,4,3);imshow(yuvim(:,:,1));title(sprintf('YCbCr Space\n\nLuminance'))
subplot(3,4,7);imshow(yuvim(:,:,2));title('blue difference')
subplot(3,4,11);imshow(yuvim(:,:,3));title('red difference')
%CIElab
subplot(3,4,4);imshow(cieim(:,:,1));title(sprintf('CIELab Space\n\nLightness'))
subplot(3,4,8);imshow(cieim(:,:,2));title('green red')
subplot(3,4,12);imshow(cieim(:,:,3));title('yellow blue')
end
you could call it like this
rgbim = imread('http://i.stack.imgur.com/gd62B.jpg');
ViewColorSpaces(rgbim)
and the display is this
in DIP and CV is this always a valid question
But it has no universal answer because each task is unique so use what is better suited for it. To choose correctly you need to know the pros/cons of each so here is some summary:
RGB
this is easy to handle and you can easyly access r,g,b bands. For many cases is better to check just single band instead of whole color or mix the colors to emphasize wanted feature or even dampening unwanted one. It is hard to compare colors in RGB due to intensity encoded into bands directly. To remedy that you can use normalization but that is slow (need per pixel sqrt). You can do arithmetics on RGB colors directly.
Example of task better suited for RGB:
finding horizont in high altitude photo
HSV
is better suited for color recognition because CV algorithms using HSV has very similar visual perception to human perception so if you want to recognize areas of distinct colors HSV is better. The conversion between RGB/HSV takes a bit of time which can be for big resolutions or hi fps apps a problem. For standard DIP/CV tasks is this usually not the case.
Example of task better suited for HSV:
Compare RGB colors
Take a look at:
HSV histogram
to see the distinct color separation in HSV. The segmentation of image based on color is easy on HSV. You can not do arithmetics on HSV colors directly instead need to convert to RGB and back

subtract one color from another in RGB color space

I would like to subtract color from another. For example, I have two image 100X100 pixel, one with color R:236 G:226 B:43, and another R:63 G:85 B:235. I would like to cut color R:236 G:226 B:43 from R:63 G:85 B:235. But I know it can't subtract like the mathematically method, by layer R:236-63, G:226-85, B:43-235 because i found that the color that less than 0 and more than 255 can't define.
I found another color space in RYB color space.but i don't know how it really work.
Thank you for your help.
You cannot actually subtract colors. But you surely can detect their difference. I suppose this is what you need, anyway.
Here are some thoughts and remarks:
Convert your images to HSV colorspace which transforms RGB values to
Hue, Saturation and Brightness (Value).
All your images should be around a yellowish color (near 60 deg. on
the Hue circle) so they should all have about the same Hue with
minor differences.
Typically if all images are taken at constant lighting conditions
they should have the same Value (brightness).
Saturation, which corresponds to the mixture of white in a color,
typically represents how intense you perceive a color to be. This
would typically be of about the same value for all your images in
constant lighting conditions.
According to your first description, the main difference should be detected in the Hue channel.
A good thing about HSV is that H (hue) is represented by a counterclockwise circle and colors are just positions on this circle, so positive and negative values all make sense (search google for a description of HSV colorspace to get a view of how it looks and works).
You may either detect differences by a subtraction that will lead you to a value either positive either negative, or by taking the absolute value of the subtraction, which will just give a measure of the difference of the two values of Hue (but without any information on the direction of the difference). If you need the direction of the difference you should just stick to a plain subtraction.
For example:
Hue_1 - Hue_2 = Hue_3 (typically a small value for your problem)
if Hue_3 > 0 this means that Hue_1 is a bit towards Green if
Hue_3 < 0 this means that Hue_1 is a bit towards Red
Of course you may also need to take a look at the differences in the other channels, S and V to see if colors are more saturated or more bright, but I cannot be sure you need to do this since we haven't seen any images here.
Of course you can do a lot more sophisticated things...Like apply clustering or classification techniques on the detected hues and classify them to classes according to your problem needs...

Algorithm for determining the prominant colour of a photograph

When we look at a photo of a group of trees, we are able to identify that the photo is predominantly green and brown, or for a picture of the sea we are able to identify that it is mostly blue.
Does anyone know of an algorithm that can be used to detect the prominent color or colours in a photo?
I can envisage a 3D clustering algorithm in RGB space or something similar. I was wondering if someone knows of an existing technique.
Convert the image from RGB to a color space with brightness and saturation separated (HSL/HSV)
http://en.wikipedia.org/wiki/HSL_and_HSV
Then find the dominating values for the hue component of each pixel. Make a histogram for the hue values of each pixel and analyze in which angle region the peaks fall in. A large peak in the quadrant between 180 and 270 degrees means there is a large portion of blue in the image, for example.
There can be several difficulties in determining one dominant color. Pathological example: an image whose left half is blue and right half is red. Also, the hue will not deal very well with grayscales obviously. So a chessboard image with 50% white and 50% black will suffer from two problems: the hue is arbitrary for a black/white image, and there are two colors that are exactly 50% of the image.
It sounds like you want to start by computing an image histogram or color histogram of the image. The predominant color(s) will be related to the peak(s) in the histogram.
You might want to change the image from RGB to indexed, then you could use a regular histogram and detect the pics (Matlab does this with rgb2ind(), as you probably already know), and then the problem would be reduced to your regular "finding peaks in an array".
Then
n = hist(Y,nbins) bins the elements in vector Y into 10 equally spaced containers and returns the number of elements in each container as a row vector.
Those values in n will give you how many elements in each bin. Then it's just a matter of fiddling with the number of bins to make them wide enough, and with how many elements in each would make you count said bin as a predominant color, then taking the bins that contain those many elements, calculating the index that corresponds with their middle, and converting it to RGB again.
Whatever you're using for your processing probably has similar functions to those
Average all pixels in the image.
Remove all pixels that are farther away from the average color than standard deviation.
GOTO 1 with remaining pixels until arbitrarily few are left (1 or maybe 1%).
You might also want to pre-process the image, for example apply high-pass filter (removing only very low frequencies) to even out lighting in the photo — http://en.wikipedia.org/wiki/Checker_shadow_illusion

Resources