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;
}
}
}
my expected result is
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)
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
.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With