Matlab Image Processing Color Reduction - image

I recently asked a question about using matlab to reduce the number of colors in an image. However, when I attempted this, I was only able to get color approximations which then matched the pixel to the nearest color within the color map.
For example, using a color map with only three colors [red, green, blue], it would scan each color and then map either red green or blue. However, this process did not vary the RGB densities to create realistic looking color.
I'm curious if there is any sort of built in function that would use these three colors and vary the density of them to achieve the average color of a certain "pixel field".
I realize this would lose resolution, but I'm essentially trying to make realistic looking images, using only three colors by varying the amounts of RGB within a certain region.

You are looking for the function rgb2ind and its 'dither' option.

Related

How to detect colors under different illumination conditions

I have a bunch of images of clothes of many colors and I want to detect the colors of each image. Say that I have a blue skirt image in daylight conditions and I can get the correct color through RGB distributions. However, at night it's difficult to tell the color and the "blue" is recognized as "black". It's very hard to make a unified standard to specify colors through RGB distributions.
As such, I am wondering is there a way or algorithm to detect colors under different illuminations?
BTW: I also tried HSV color space and the results were not good.
That's a very hard problem and it's still trying to be solved today. The gist of it is to find a colour quantization using a representative set of basic colours of an image that is robust against different external stimuli... lighting, shade, poor illumination etc.
Unfortunately I can't suggest any one algorithm that would do the work for you for all cases. However, one algorithm that has worked for me in the past was when I was doing work in image retrieval. Specifically, the work by Jiebo Luo and David Crandall from Kodak Research Labs: http://vision.soic.indiana.edu/papers/compoundcolor2004cvpr.pdf
The basic algorithm is to take a look at the ISCC-NBS colour palette set. Also, this link is much more fruitful: https://www.w3schools.com/colors/colors_nbs.asp. It is a set of 267 colours that are representative of the colours that we see in modern society today. Usually when we describe colours, we have a set of one or more adjectives, followed by the dominant hue. For example, that shirt is a darkish pale blue, or a light bright yellow, etc. The beauty of this algorithm is that when the colour in question is subject to different external stimuli, we have all of these adjectives that give meaning to the colour, but at the end of the day, the last part of the colour - the dominant hue - is what we're after.
Each of these colours has an associated RGB value. These colours are transformed into the CIE Lab colour space which form a 267 CIE Lab lookup table.
To classify a particular input colour, you would transform this input's RGB values into the CIE Lab colour space, then determine the closest colour to this lookup table. It has been shown that the Euclidean distance between two colours in the CIE Lab colour space best represents the difference in human perception of colours. Once we determine which location in the lookup table the colour is closest to, we strip out all of the adjectives and see what the dominant hue is and we thus classify that colour accordingly.
For example, if we had a RGB pixel and we converted it to Lab, then found that the closest colour was bright yellow, we would remove the "bright" and the final colour that is representative of that RGB pixel would be yellow.
Therefore, the final algorithm is this:
Find the ISCC-NBS colour set's RGB values and convert to CIE Lab and create a lookup table, which I call LUT1. In Python for example, you could simply make this a 2D list or 2D NumPy array.
Create another lookup that stores the dominant hue for each of the colours in the ISCC-NBS colour set - so strip out all of the adjectives and leave the dominant hue, which I call LUT2. In Python for example, you could create a dictionary where the key is the corresponding row of LUT1 and the value would be the actual basic colour itself. Whether it's a string representation or a RGB triplet representing the basic colour is up to you.
For a pixel in question, find the closest ISCC-NBS colour that matches with LUT1 by the Euclidean distance between this pixel's CIE Lab components and the ones in LUT1.
Once we find this location in LUT1, use the same index to index into LUT2 and get the final colour to classify that input pixel's colour.
Hope this helps!

What does it mean to change the color channel?

Does it mean to control the combination between an image and a color overlay applied to it depending on the color space used (RGB, RGBA, CMYK, Lab, Grayscale, HSL, HSLA)? Or does it mean to change the color layer used in combination with other layers to form the final image? (if so, what could be changed in what regard?).
RGB are abbreviations for three color channels (red, green and blue). They represent specific frequencies of light. Inside each color channel is a range of intensity and a level of saturation. This model of colors is commonly taught in school and is how most people understand colors and mixing them. A different way to represent colors is HSL which stands for Hue, Saturation and Level. Here the Hue is the frequency of the color, while the Saturation can be like the contrast level, and Level is the amount of black. HSL (A stands for Alpha or transparency) is actually a much more programmer centric way of working with color (although most programmers seem to learn the RGB Hex values for colors). There is a great website called Mothereffing HSL which lets you play with HSL values to better understand them. CMYK is for pigments (which mix differently than light) and is found on printers. Same basic idea as RGB just with Cyan Magenta Yellow and Black. Now because light and pigments don't mix the same way there is a lot of work devoted to converting one color system to another (so you can see on your screen what will eventually come out of your printer). These systems are not perfectly aligned however so the goal is to get acceptability close.
All of these colors when presented on a graph are called the color space.

I have a true colored image, how to select the 256 colors from? [duplicate]

I am playing with computer graphics programming for the first time. I want to convert RGB (24-bit) images to indexed-palette (8-bit) images (like GIF). My initial thought is to use k-means (with k=256).
How would one go about picking the optimal palette for a given image? This is a learning experience for me, so I would prefer an overview-type answer to source code.
Edit: Dithering is currently off-topic. I am only referring to "simple" color conversion, psycho-visual/perceptual models aside; color-space is also currently off-topic, though moving between color-spaces is what got me thinking about this in the first place :)
http://en.wikipedia.org/wiki/Color_quantization
Octree
Median-cut
K-means
Gamut subdivision
http://www.cs.berkeley.edu/~dcoetzee/downloads/scolorq/
The reference links people have provided are good, and there are several solutions to this problem, but since I've been working on this problem recently (with complete ignorance as to how others have solved it), I offer my approach in plain English:
Firstly, realize that (human perceived) color is 3-dimensional. This is fundamentally because the human eye has 3 distinct receptors: red, green, and blue. Likewise your monitor has red, green, and blue pixel elements. Other representations, like, hue, saturation, luminance (HSL) can be used, but basically all representations are 3-dimensional.
This means RGB color space is a cube, with red, green, and blue axes. From a 24-bit source image, this cube has 256 discrete levels on each axis. A naive approach to reducing the image to 8-bit is to simply reduce the levels per axis. For instance, an 8x8x4 cube palette with 8 levels for red and green, 4 levels for blue is easily created by taking the high 3 bits of the red and green values, and the high 2 bits of the blue value. This is easy to implement, but has several disadvantages. In the resulting 256 color palette, many entries will not be used at all. If the image has detail using very subtle color shifts, these shifts will disappear as the colors snap into the same palette entry.
An adaptive palette approach needs to account for not just averaged/common colors in the image, but which areas of color space have the greatest variance. That is, an image that has thousands of subtle shades of light green requires a different palette than an image that has thousands of pixels of exactly the same shade of light green, since the latter would ideally use a single palette entry for that color.
To this end, I took an approach that results in 256 buckets containing exactly the same number of distinct values each. So if the original image contained 256000 distinct 24-bit colors, this algorithm results in 256 buckets each containing 1000 of the original values. This is accomplished by binary spatial partitioning of color space using the median of distinct values present (not the mean).
In English, this means we first divide the whole color cube into the half of pixels with less than the median red value and the half with more than the median red value. Then, divide each resulting half by green value, then by blue, and so on. Each split requires a single bit to indicate the lower or higher half of pixels. After 8 splits, variance has effectively been split into 256 equally important clusters in color space.
In psuedo-code:
// count distinct 24-bit colors from the source image
// to minimize resources, an array of arrays is used
paletteRoot = {colors: [ [color0,count],[color1,count], ...]} // root node has all values
for (i=0; i<8; i++) {
colorPlane = i%3 // red,green,blue,red,green,blue,red,green
nodes = leafNodes(paletteRoot) // on first pass, this is just the root itself
for (node in nodes) {
node.colors.sort(colorPlane) // sort by red, green, or blue
node.lo = { colors: node.colors[0..node.colors.length/2] }
node.hi = { colors: node.colors[node.colors.length/2..node.colors.length] }
delete node.colors // free up space! otherwise will explode memory
node.splitColor = node.hi.colors[0] // remember the median color used to partition
node.colorPlane = colorPlane // remember which color this node split on
}
}
You now have 256 leaf nodes, each containing the same number of distinct colors from the original image, clustered spatially in the color cube. To assign each node a single color, find the weighted average using the color counts. The weighting is an optimization that improves perceptual color matching, but is not that important. Make sure to average each color channel independently. The results are excellent. Note that it is intentional that blue is divided once less than red and green, since the blue receptors in the eye are less sensitive to subtle changes than red and green.
There are other optimizations possible. By using HSL you could instead put the higher quantizing in the luminance dimension instead of blue. Also the above algorithm will slightly reduce overall dynamic range (since it ultimately averages color values), so dynamically expanding the resulting palette is another possibility.
EDIT:
updated to support palette of 256 colors
If you need simplest method then I would suggest histogram based approach:
Calculate histograms of R/G/B channels
Define 4 intensity ranges
For each channel in intensity range
Split histogram into 4 equal parts
For each histogram part
Extract most frequent value of that part
Now you will have 4*4^3=256 colors palette. When assigning pixel to palette color, just calculate average intensity of pixel to see what intensity region you must use. After that just map one of those 64 colors of intensity region to pixel value.
Good luck.
This might be a little late to answer, but try this:
make a set of each color in the image,
sort them according to red, then green then blue (if preceding channels are equal), (they are now into a list)
suppress nearby colors if they are too similar, ie distance in rgb space is smaller than 4.
if they are still to much colors, suppress the least used ones.
Each time you supress a color, you will have to add into a hash_map the colors and it's destination.

Image palette reduction

I am playing with computer graphics programming for the first time. I want to convert RGB (24-bit) images to indexed-palette (8-bit) images (like GIF). My initial thought is to use k-means (with k=256).
How would one go about picking the optimal palette for a given image? This is a learning experience for me, so I would prefer an overview-type answer to source code.
Edit: Dithering is currently off-topic. I am only referring to "simple" color conversion, psycho-visual/perceptual models aside; color-space is also currently off-topic, though moving between color-spaces is what got me thinking about this in the first place :)
http://en.wikipedia.org/wiki/Color_quantization
Octree
Median-cut
K-means
Gamut subdivision
http://www.cs.berkeley.edu/~dcoetzee/downloads/scolorq/
The reference links people have provided are good, and there are several solutions to this problem, but since I've been working on this problem recently (with complete ignorance as to how others have solved it), I offer my approach in plain English:
Firstly, realize that (human perceived) color is 3-dimensional. This is fundamentally because the human eye has 3 distinct receptors: red, green, and blue. Likewise your monitor has red, green, and blue pixel elements. Other representations, like, hue, saturation, luminance (HSL) can be used, but basically all representations are 3-dimensional.
This means RGB color space is a cube, with red, green, and blue axes. From a 24-bit source image, this cube has 256 discrete levels on each axis. A naive approach to reducing the image to 8-bit is to simply reduce the levels per axis. For instance, an 8x8x4 cube palette with 8 levels for red and green, 4 levels for blue is easily created by taking the high 3 bits of the red and green values, and the high 2 bits of the blue value. This is easy to implement, but has several disadvantages. In the resulting 256 color palette, many entries will not be used at all. If the image has detail using very subtle color shifts, these shifts will disappear as the colors snap into the same palette entry.
An adaptive palette approach needs to account for not just averaged/common colors in the image, but which areas of color space have the greatest variance. That is, an image that has thousands of subtle shades of light green requires a different palette than an image that has thousands of pixels of exactly the same shade of light green, since the latter would ideally use a single palette entry for that color.
To this end, I took an approach that results in 256 buckets containing exactly the same number of distinct values each. So if the original image contained 256000 distinct 24-bit colors, this algorithm results in 256 buckets each containing 1000 of the original values. This is accomplished by binary spatial partitioning of color space using the median of distinct values present (not the mean).
In English, this means we first divide the whole color cube into the half of pixels with less than the median red value and the half with more than the median red value. Then, divide each resulting half by green value, then by blue, and so on. Each split requires a single bit to indicate the lower or higher half of pixels. After 8 splits, variance has effectively been split into 256 equally important clusters in color space.
In psuedo-code:
// count distinct 24-bit colors from the source image
// to minimize resources, an array of arrays is used
paletteRoot = {colors: [ [color0,count],[color1,count], ...]} // root node has all values
for (i=0; i<8; i++) {
colorPlane = i%3 // red,green,blue,red,green,blue,red,green
nodes = leafNodes(paletteRoot) // on first pass, this is just the root itself
for (node in nodes) {
node.colors.sort(colorPlane) // sort by red, green, or blue
node.lo = { colors: node.colors[0..node.colors.length/2] }
node.hi = { colors: node.colors[node.colors.length/2..node.colors.length] }
delete node.colors // free up space! otherwise will explode memory
node.splitColor = node.hi.colors[0] // remember the median color used to partition
node.colorPlane = colorPlane // remember which color this node split on
}
}
You now have 256 leaf nodes, each containing the same number of distinct colors from the original image, clustered spatially in the color cube. To assign each node a single color, find the weighted average using the color counts. The weighting is an optimization that improves perceptual color matching, but is not that important. Make sure to average each color channel independently. The results are excellent. Note that it is intentional that blue is divided once less than red and green, since the blue receptors in the eye are less sensitive to subtle changes than red and green.
There are other optimizations possible. By using HSL you could instead put the higher quantizing in the luminance dimension instead of blue. Also the above algorithm will slightly reduce overall dynamic range (since it ultimately averages color values), so dynamically expanding the resulting palette is another possibility.
EDIT:
updated to support palette of 256 colors
If you need simplest method then I would suggest histogram based approach:
Calculate histograms of R/G/B channels
Define 4 intensity ranges
For each channel in intensity range
Split histogram into 4 equal parts
For each histogram part
Extract most frequent value of that part
Now you will have 4*4^3=256 colors palette. When assigning pixel to palette color, just calculate average intensity of pixel to see what intensity region you must use. After that just map one of those 64 colors of intensity region to pixel value.
Good luck.
This might be a little late to answer, but try this:
make a set of each color in the image,
sort them according to red, then green then blue (if preceding channels are equal), (they are now into a list)
suppress nearby colors if they are too similar, ie distance in rgb space is smaller than 4.
if they are still to much colors, suppress the least used ones.
Each time you supress a color, you will have to add into a hash_map the colors and it's destination.

Organizing Images By Color

Maybe you've noticed but Google Image search now has a feature where you can narrow results by color. Does anyone know how they do this? Obviously, they've indexed information about each image.
I am curious what the best methods of analyzing an image's color data to allow simple color searching.
Thanks for any and all ideas!
Averaging the colours is a great start. Just downscale your image to 10% of the original size using a Bicubic or Bilinear filter (or something advanced anyway). This will vastly reduce the colour noise and give you a result which is closer to how humans perceive the image. I.e. a pixel-raster consisting purely of yellow and blue pixels would become clean green.
If you don't blur or downsize the image, you might still end up with an average of green, but the deviation would be huge.
The Google feature offers 12 colors with which to match images. So I would calculate the Lab coordinate of each of these swatches and plot the (a*, b*) coordinate of each of these colors on a two dimensional space. I'd drop the L* component because luminance (brightness) of the pixel should be ignored. Using the 12 points in the (a*, b*) space, I'd calculate a partitioning using a Voronoi Diagram. Then for a given image, I'd take each pixel, calculate its (a*, b*) coordinate. Do this for every pixel in the image and so build up the histogram of counts in each Voronoi partition. The partition that contains the highest pixel count would then be considered the image's 'color'.
This would form the basis of the algorithm, although there would be refinements related to ignoring black and white background regions which are perceptually not considered to be part of the subject of the image.
Average color of all pixels? Make a histogram and find the average of the 'n' peaks?

Resources