Reputation: 157
I'm trying to reduce my grayscale image color from 256 to 4 using this formula
from http://docs.opencv.org/2.4/doc/tutorials/core/how_to_scan_images/how_to_scan_images.html
I assume that n is the reduction factor, for this case, it will be 10 color from the formula. My code is as below.
void Reduction(Mat image1)
{
for (int r = 0;r < image1.rows;r++) {
for (int c = 0;c < image1.cols;c++) {
// get pixel
int tmp = (image1.at<Vec3b>(r, c)[0] + image1.at<Vec3b>(r, c)[1] + image1.at<Vec3b>(r, c)[2])/3 ;
tmp = (tmp/4)* 4;
image1.at<Vec3b>(r, c)[0] = tmp;
image1.at<Vec3b>(r, c)[1] = tmp;
image1.at<Vec3b>(r, c)[2] = tmp;
}
}
}
but from tmp = (tmp/4)*4; or tmp = ( tmp/8)*8;
my image looks the same as the original image;
then i tried changing it to tmp = (tmp/40)*40;
and I got this as the result which is similar to what I wanted for my result.
How does the formula works and what should I edit from my code to accurately get the result I wanted? ( like the expected result above)
Upvotes: 4
Views: 7101
Reputation: 24427
You won't be able to get the 4 color image in your "expected result" image using a variation on the formula you have given, because integer division always rounds down. It produces this result:
input output
0-63 0
64-127 64
128-191 128
192-255 192
So no pixel in the image will never be more than 3/4 of full brightness (light grey), and the target image contains pure white.
Simple rounding to the mid-point of a range won't work either, because the target image contains pure black, as well as pure white, so for black you need to always round down and for white you need to always round up.
You might also want to evenly divide the 256-color range into 4 equal portions, which won't work if you do simple rounding either because black and white will end up covered by a smaller range.
It helps to block out exactly how you want the range divided up. For example, suppose you want to divide it into 4 and then create an evenly spaced range including both white and black:
input output
0-63 0
64-127 85
128-191 170
192-255 255
You can open your expected result image in a paint app and use the eye-dropper tool to verify that these are the correct output values.
The formula for this is:
int new_value = (value / 64) * 85;
Or more generically:
int num_colors = 4;
int divisor = 256 / num_colors;
int max_quantized_value = 255 / divisor;
int new_value = ((value / divisor) * 255) / max_quantized_value;
This way you are guaranteed to get a min new_value of 0 and a max new_value of 255.
Upvotes: 4
Reputation: 1567
Another way to look at color quantization is to think of bits/pixel. Normally a grayscale image is stored using 8-bits for each pixel, hence the resulting range of values are from 0 to 255.
We can reduce the number of colors in an image by quantizing or in other words dropping the Least Significant Bits (LSBs). An 8-bit representation normally looks like this:
V V V V V V V V
When reduced we can drop the LSBs for example:
V V V V V V x x
or
V V V V x x x x
where V represents a binary value and x shows bits that are dropped. In your case you want to reduce to 4 colors which means that you only need two bits to represent your image. In that case each byte will look like this:
V V x x x x x x
This can be done simply by using left shift operator >>
on the uchar
values in a grayscale image (as shown in the attached answer).
Upvotes: 1
Reputation: 41775
This is a color quantization. This is a simple technique to reduce the number of colors in an image that relies on the integer division
Since the starting range has 256
values, if you want to end up with N
colors, you need to integer divide and then multiply by K = 256 / N
.
So in your case, for N=8
you need a K = 256 / 8 = 32
, and for N = 4
you need K = 256 / 4 = 64
.
Upvotes: 4