Fast way of getting the dominant color of an image - algorithm

I have a question about how to get the dominant color of an image (a photo). I thought of this algorithm: loop through all pixels and get their color, either red, green, yellow, orange, blue, magenta, cyan, white, grey or black (with some margin of course) and it's darkness (light, dark or normal) and afterwards check which colors occurred the most. I think this is slow and not very precise. Is there a better way?
If it matters, it's a UIImage taken from an iPhone or iPod touch camera which is at most 5 Mpx. The reason it has to be fast is that simply showing a progress indicator doesn't make very much sense as this is for an app for people with bad sight, or no sight at all. Because it's for a mobile device, it may not take very much memory (at most 50 MB).

Your general approach should work, but I'd highlight some details.
Instead of your given list of colors, generate a number of color "bins" in the color spectrum to count pixels. Here's another question that has some algorithms for that: Generating spectrum color palettes Make the number of bins configurable, so you can experiment to get the results you want.
Next, for each pixel you're considering, you need to find the "nearest" color bin to increment. You'll need to define "nearest"; see this article on "color difference": http://en.wikipedia.org/wiki/Color_difference
For performance, you don't need to look at every pixel. Since image elements usually cover large areas (e.g., the sky, grass, etc.), you can get the result you want by only sampling a few pixels. I'd guess that you could get good results sampling every 10th pixel, or even every 100th. You can experiment with that factor as well.
[Editor's note: The paragraph below was edited to accommodate Mike Fairhurst's comment.]
Averaging pixels can also be done, as in this demo:jsfiddle.net/MUsT8/

Related

detect the color of text

How to detect color from given text (image)? E.g. I've got this image
You can clearly see the text color is black (rgb 0, 0, 0). This is how it looks when I zoom the image:
Now we can see there are at least 5 different colors.. How can I detect the color that human eye sees? Obviously I might take the most common color from all pixels of the image (excluding the background), but this doesn't always work (e.g. on much smaller text size where the letters are actually 1-2 pixel thick such as:
.
Create a histogram of the text-image (excluding the background of course).
Check if there is a significant and clear peak (you can decide thresholds yourself or empirically). If there is one, that's the colour you are looking for.
If there is no significant peak, which looks like the case in "Search" text, take an average of all the pixel's colour. Roughly, this should be faint (approximation) of the original colour. Now, list the colour of all the (insignificant) peaks and try matching one by one hue/colour of this average. The peak which has hue/colour closest to the average should be your candidate.
Happy coding

anyway to remove algorithmically discolorations from aerial imagery

I don't know much about image processing so please bear with me if this is not possible to implement.
I have several sets of aerial images of the same area originating from different sources. The pictures have been taken during different seasons, under different lighting conditions etc. Unfortunately some images look patchy and suffer from discolorations or are partially obstructed by clouds or pix-elated, as par example picture1 and picture2
I would like to take as an input several images of the same area and (by some kind of averaging them) produce 1 picture of improved quality. I know some C/C++ so I could use some image processing library.
Can anybody propose any image processing algorithm to achieve it or knows any research done in this field?
I would try with a "color twist" transform, i.e. a 3x3 matrix applied to the RGB components. To implement it, you need to pick color samples in areas that are split by a border, on both sides. You should fing three significantly different reference colors (hence six samples). This will allow you to write the nine linear equations to determine the matrix coefficients.
Then you will correct the altered areas by means of this color twist. As the geometry of these areas is intertwined with the field patches, I don't see a better way than contouring the regions by hand.
In the case of the second picture, the limits of the regions are blurred so that you will need to blur the region mask as well and perform blending.
In any case, don't expect a perfect repair of those problems as the transform might be nonlinear, and completely erasing the edges will be difficult. I also think that colors are so washed out at places that restoring them might create ugly artifacts.
For the sake of illustration, a quick attempt with PhotoShop using manual HLS adjustment (less powerful than color twist).
The first thing I thought of was a kernel matrix of sorts.
Do a first pass of the photo and use an edge detection algorithm to determine the borders between the photos - this should be fairly trivial, however you will need to eliminate any overlap/fading (looks like there's a bit in picture 2), you'll see why in a minute.
Do a second pass right along each border you've detected, and assume that the pixel on either side of the border should be the same color. Determine the difference between the red, green and blue values and average them along the entire length of the line, then divide it by two. The image with the lower red, green or blue value gets this new value added. The one with the higher red, green or blue value gets this value subtracted.
On either side of this line, every pixel should now be the exact same. You can remove one of these rows if you'd like, but if the lines don't run the length of the image this could cause size issues, and the line will likely not be very noticeable.
This could be made far more complicated by generating a filter by passing along this line - I'll leave that to you.
The issue with this could be where there was development/ fall colors etc, this might mess with your algorithm, but there's only one way to find out!

Algorithm to detect the change in visible luminosity in an image

I want a formula to detect/calculate the change in visible luminosity in a part of the image,provided i can calculate the RGB, HSV, HSL and CMYK color spaces.
E.g: In the above picture we will notice that the left side of the image is more bright when compared to the right side , which is beneath a shade.
I have had a little think about this, and done some experiments in Photoshop, though you could just as well use ImageMagick which is free. Here is what I came up with.
Step 1 - Convert to Lab mode and discard the a and b channels since the Lightness channel holds most of the brightness information which, ultimately, is what we are looking for.
Step 2 - Stretch the contrast of the remaining L channel (using Levels) to accentuate the variation.
Step 3 - Perform a Gaussian blur on the image to remove local, high frequency variations in the image. I think I used 10-15 pixels radius.
Step 4 - Turn on the Histogram window and take a single row marquee and watch the histogram change as different rows are selected.
Step 5 - Look out for a strongly bimodal histogram (two distimct peaks) to identify the illumination variations.
This is not a complete, general purpose solution, but may hold some pointers and cause people who know better to suggest improvememnts for you!!! Note that the method requires the image to have a some areas of high uniformity like the whiteish horizontal bar across your input image. However, nearly any algorithm is going to have a hard time telling the difference between a sheet of white paper with a shadow of uneven light across it and the same sheet of paper with a grey sheet of paper laid on top of it...
In the images below, I have superimposed the histogram top right. In the first one, you can see the histogram is not narrow and bimodal because the dotted horizontal selection marquee is across the bar-code area of the image.
In the subsequent images, you can see a strong bimodal histogram because the dotted selection marquee is across a uniform area of image.
The first problem is in "visible luminosity". It me mean one of several things. This discussion should be a good start. (Yes, it has incomplete and contradictory answers, as well.)
Formula to determine brightness of RGB color
You should make sure you operate on the linear image which does not have any gamma correction applied to it. AFAIK Photoshop does not degamma and regamma images during filtering, which may produce erroneous results. It all depends on how accurate results you want. Photoshop wants things to look good, not be precise.
In principle you should first pick a formula to convert your RGB values to some luminosity value which fits your use. Then you have a single-channel image which you'll need to filter with a Gaussian filter, sliding average, or some other suitable filter. Unfortunately, this may require special tools as photoshop/gimp/etc. type programs tend to cut corners.
But then there is one thing you would probably like to consider. If you have an even brightness gradient across an image, the eye is happy and does not perceive it. Rather large differences go unnoticed if the contrast in the image is constant across the image. Unfortunately, the definition of contrast is not very meaningful if you do not know at least something about the content of the image. (If you have scanned/photographed documents, then the contrast is clearly between ink and paper.) In your sample image the brightness changes quite abruptly, which makes the change visible.
Just to show you how strange the human vision is in determining "brightness", see the classical checker shadow illusion:
http://en.wikipedia.org/wiki/Checker_shadow_illusion
So, my impression is that talking about the conversion formulae is probably the second or third step in the process of finding suitable image processing methods. The first step would be to try to define the problem in more detail. What do you want to accomplish?

Get dominant colors from image discarding the background

What is the best (result, not performance) algorithm to fetch dominant colors from an image. The algorithm should discard the background of the image.
I know I can build an array of colors and how many they appear in the image, but I need a way to determine what is the background and what is the foreground, and keep only the second (foreground) in mind while read the dominant colors.
The problem is very hard especially for gradient backgrounds or backrounds with patterns (not plain)
Isolating the foreground from the background is beyond the scope of this particular answer, but...
I've found that applying a pixelation filter to an image will draw out a really good set of 'average' colours.
Before
After
I sometimes use this approach to derive a pallete of colours with a particular mood. I first find a photograph with the general tones I'm after, pixelate and then sample from the resulting image.
(Thanks to Pietro De Grandi for the image, found on unsplash.com)
The colour summarizer is a pretty sweet spot for info on this subject, not to mention their seemingly free XML Web API that will produce descriptive colour statistics for an image of your choosing, reporting back the following formatted with swatches in HTML or as XML...
what is the average color hue, saturation and value in my image?
what is the RGB colour that is most representative of the image?
what do the RGB and HSV histograms look like?
what is the image's human readable colour description (e.g. dark pure blue)?
The purpose of this utility is to generate metadata that summarizes an
image's colour characteristics for inclusion in an image database,
such as Flickr. In particular this tool is being used to generate
metadata for Flickr's Color Fields group.
In my experience though.. this tool still misses the "human-readable" / obvious "main" color, A LOT of the time. Silly machines!
I would say this problem is closer to "impossible" than "very hard". The only approach to it that I can think of would be to make the assumption that the background of an image is likely to consist of solid blocks of similar colors, while the foreground is likely to consist of smaller blocks of dissimilar colors.
If this assumption is generally true, then you could scan through the whole image and weight pixels according to how similar or dissimilar they are to neighboring pixels. In other words, if a pixel's neighbors (within some arbitrary radius, perhaps) were all similar colors, you would not incorporate that pixel into the overall estimate. If the neighbors tend to be very different colors, you would weight the pixel heavily, perhaps in proportion to the degree of difference.
This may not work perfectly, but it would definitely at least tend to exclude large swaths of similar colors.
As far as my knowledge of image processing algorithms extends , there is no certain way to get the "foreground"; it is only possible to get the borders between objects. You'll probably have to make do with an average, or your proposed array count method. In that, you'll want to give colours with higher saturation a higher "score" as they're much more prominent.

White balance algorithm [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 3 years ago.
Improve this question
I'm doing some image processing and I need an automatic white balancing algorithm that's not too intensive in terms of CPU computation time. Any recommendations?
EDIT: and if it's relevant to efficiency, I'll be implementing it in Java with color images as an array of integers.
GIMP apparently uses a very simple algorithm for automatic white balancing.
http://docs.gimp.org/en/gimp-layer-white-balance.html
The White Balance command automatically adjusts the colors of the active layer by stretching the Red, Green and Blue channels separately. To do this, it discards pixel colors at each end of the Red, Green and Blue histograms which are used by only 0.05% of the pixels in the image and stretches the remaining range as much as possible. The result is that pixel colors which occur very infrequently at the outer edges of the histograms (perhaps bits of dust, etc.) do not negatively influence the minimum and maximum values used for stretching the histograms, in comparison with Stretch Contrast. Like “Stretch Contrast”, however, there may be hue shifts in the resulting image.
There is a bit more tweaking than is described here since my first attempt at implementing this works seems to work for most photos but other photos seem to have artifacts or contain too much of either red green or blue :/
A relatively simple algorithm is to average the hues (in HSV or HSL) of the brightest and darkest pixels on the screen. In a pinch, go with the brightest pixel only. If the hues between brightest and darkest are too different, go with the bright pixel. If the dark is near black go with the bright pixel.
Why even look at the dark pixel? Sometimes the dark is not near black, and hints at the ambient light or fog or haze.
This will make sense to you if you're a heavy Photoshop user. Highlights in a photo are unrelated (or weakly related) to the underlying color of the object. They are your best representation of the color cast of the light, unless the image is so overexposed that everything has overwhelmed the CCDs.
Then adjust the hues of all pixels.
You'll need fast RGB to HSV and HSV to RGB functions. (But maybe you can work in RGB for the pixel corrections with a LUT or linear interpolation.)
You don't want to go by average pixel color or most popular color. That way lies madness.
To quickly find the brightest color (and the darkest one), you can work in RGB, but you should have multipliers for green, red, and blue. On an RGB monitor, 255 green is brighter than 255 red which is brighter than 255 blue. I used to have good multipliers in my head, but alas, they have fled my memory. You can probably google for them.
This will fail in an image which has no highlights. A matte painted wall, for example. But I don't know what you can do about that.
There are many improvements to make to this simple algorithm. You can average multiple bright pixels, grid the image and grab bright and dark pixels from each cell, etc. You'll find some obvious tweaks after implementing the algorithm.
#Charles Ma has suggested to use the Gimp white balance algorithm. In python and numpy this could look like this:
# white balance for every channel independently
def wb(channel, perc = 0.05):
mi, ma = (np.percentile(channel, perc), np.percentile(channel,100.0-perc))
channel = np.uint8(np.clip((channel-mi)*255.0/(ma-mi), 0, 255))
return channel
image = cv2.imread("foo.jpg", 1) # load color
imWB = np.dstack([wb(channel, 0.05) for channel in cv2.split(img)] )
it's fast, simple and provides pretty decent results
White balancing algorithms are hard. Even digital cameras get the wrong once in a while, even though they know a lot of extra info about the picture - such as whether the flash was used, and the light level.
For starters, I would just average red, green, and blue, and use that as the white balance point. Set limits on it - stay within the ranges for tungsten, flourescent, and daylight. It won't be perfect, but when its wrong, it will be relatively easy to explain why.
One recently published algorithm is the Color Distribution algorithm:
D. Cheng, D.K. Prasad, and M.S. Brown,
"Illuminant Estimation for Color Constancy: Why spatial domain methods work and the role of the color distribution"
Journal of the Optical Society of America A 31(5):1049-1058 (2014)
DOI, PDF
In the paper there is also the reference to the Matlab source code (Internet Archive). It's a simple algorithm that can be easily programmed and the results show it to be very fast.
If you need additional fast and at the same time accurate white balancing (color constancy) algorithms, you should check this site.
There are several algorithms with their respective source coded that might be just the ones you look for.

Resources