# Otsu's method problem?

I have a problem with Otsu's method. I would like to implement histogram to compute how many ones' and zeros'. For Otsu's method, I have a code from a book and it is running without problem. This is the picture

.

I've implemented a code to compute the histogram. This is the output of my code.

------------------
0 : 14332
1 : 2102
2 : 1387
3 : 745
4 : 221
5 : 117
6 : 27
7 : 9
248 : 6
249 : 12
250 : 48
251 : 162
252 : 396
253 : 830
254 : 1377
255 : 28554
------------------


Here's my code:

I = imread('images.jpg');
level = graythresh(I);
BW = im2bw(I, level);
imshow(BW)
imwrite(BW, 'img.jpg');


This is my C++ code.

#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv\cv.h>
#include <map>
#include <iomanip>

std::map<int, int> computeHistogram(const cv::Mat& image)
{
std::map<int, int> histogram;

for ( int row = 0; row < image.rows; ++row)
{
for ( int col = 0; col < image.cols; ++col)
{
++histogram[(int)image.at<uchar>(row, col)];

}
}

return histogram;
}

void printHistogram(const std::map<int, int>& histogram)
{
std::map<int, int>::const_iterator histogram_iter;
std::cout << "\n------------------\n";
for( histogram_iter = histogram.begin(); histogram_iter != histogram.end(); ++histogram_iter)
{
std::cout << std::setw(5) << histogram_iter->first <<  " : " << histogram_iter->second << "\n";
}
std::cout << "------------------\n";
}

int main(int argc, char **argv)
{
printHistogram(computeHistogram(img));
return 0;
}


Why this is the result? What I'm expecting is how many 255 and 0 (black and white only). Moreover, if I run another picture, I get another results with the range 0-255.

• I don't understand where is the threshold in you implmentation – Gilad Jan 17 '15 at 16:47

jpg is a compressed storage format and no matter how binary your image is, you will almost always end up with gray values in the resulting image (due to compression). Please save it as png and try again.

(Also note that you still have 0s and 255s as the dominant bins, because jpg generally degrades around the edges, which constitute a small portion in the image.)

• you are absolutely right. I've changed it to .png and this is what I got.  ------------------ 0 : 16886 255 : 33439 ------------------ – CroCo Apr 5 '14 at 20:45

There's obviously more than just 0 and 255 valued pixels. I'd suggest implementing a thresholding preprocessor. This way you can convert anything close to white to completely white, and anything close to black to completely black. Not sure what language you're using but here's an example of what I mean.

for (i = 0; i < columnsSize, i++){
for (j = 0; j < rowsSize, j++){
if (image(i, j) < 100)   image(i,j) = 0;
else  image(i,j) = 255;
}
}


Better yet, thresholding + counter

int black = 0;
int white = 0;
for (i = 0; i < columnsSize, i++){
for (j = 0; j < rowsSize, j++){
if (image(i, j) < 100)   {image(i,j) = 0; black++}
else  {image(i,j) = 255; white++}
}
}

• I couldn't tag C++ because I don't have enough reputation. I'm using C++ and the part of the code for this matter as following /* Threshold */ pp = x->data[0]; for (i=0; i<n; i++) if (*pp < t) *pp++ = 0; else *pp++ = 255; where t is threshold. This is why I asked I don't know why this happens. – CroCo Apr 2 '14 at 22:19
• Sounds like a syntax error rather than technique. For better assistance showing this code would get you better help. – Iancovici Apr 2 '14 at 23:36
• please check out this link. dsp.stackexchange.com/questions/15441/… – CroCo Apr 5 '14 at 2:48
• @CroCo the problem is that you're not thresholding like I was telling you in this answer. Re read what I posted, I'm implying you want to binaries this image. Yo do this by reading every pixel and if it's under a threshold, set it to 0, if it's above threshold then set it to 255. – Iancovici Apr 5 '14 at 2:58