 egegunes - 2 years ago 128
C Question

# Otsu thresholding

I'm trying to calculate a threshold value using Otsu's method. Sample image is 8-bit, grayscale, bmp file.

Histogram for that image generated by following:

``````/* INITIALIZE ARRAYS */
for(int i = 0; i < 255; i++) occurrence[i] = 0;
for(int i = 0; i < 255; i++) histogram[i] = 0;

/* START AT BEGINNING OF RASTER DATA */
fseek(input_img, (54 + 4 * color_number), SEEK_SET);

/* READ RASTER DATA */
for(int r = 0; r <= original_img.rows - 1; r++) {
for(int c = 0; c <= original_img.cols -1; c++) {
fread(p_char, sizeof(char), 1, input_img);
pixel_value = *p_char;
/* COUNT OCCURRENCES OF PIXEL VALUE */
occurrence[pixel_value] = occurrence[pixel_value] + 1;
total_pixels++;
}
}

for(int i = 0; i <= 255; i++) {
/* TAKES NUMBER OF OCCURRENCES OF A PARTICULAR PIXEL
* AND DIVIDES BY THE TOTAL NUMBER OF PIXELS YIELDING
* A RATIO */
histogram[i] = (float) occurrence[i] / (float) total_pixels;
}
``````

Histogram then passed to function
`otsu_method`
in main:

``````threshold_value = otsu_method(histogram, total_pixels);
``````

Function
`otsu_method`
:

``````int otsu_method(float *histogram, long int total_pixels) {
double omega, myu;
double max_sigma, sigma;
int threshold;

omega = histogram;
myu = 0.0;

for(int i = 1; i < 256; i++) {
omega[i] = omega[i - 1] + histogram[i];
myu[i] = myu[i - 1] + i * histogram[i];
}

threshold = 0;
max_sigma = 0.0;

for(int i = 0; i < 255; i++) {
if(omega[i] != 0.0 && omega[i] != 1.0)
sigma[i] = pow(myu * omega[i], 2) / (omega[i] * (1.0 - omega[i]));
else
sigma[i] = 0.0;
if(sigma[i] > max_sigma) {
max_sigma = sigma[i];
threshold = i;
}
}

printf("Threshold value: %d\n", threshold);

return threshold;
}
``````

And binarize image based on threshold value:

``````void threshold_image(FILE* input_file, FILE* output_file, unsigned long vector_size, int threshold_value) {
unsigned char*   p_char;
unsigned char    dummy;
struct_img       binary_img;
unsigned char*   binary_data;

dummy = '0';
p_char = &dummy;

binary_img.data = malloc(vector_size * sizeof(char));
if(binary_img.data == NULL) printf("Failed to malloc binary_img.data\n");

binary_data = binary_img.data;

/* CONVERT PIXEL TO BLACK AND WHITE BASED ON THRESHOLD VALUE */
for(int i = 0; i < vector_size - 1; i++) {
fread(p_char, sizeof(char), 1, input_file);
if(*p_char < threshold_value) *(binary_data + i) = 0;
else *(binary_data + i) = 255;
fwrite((binary_data + i), sizeof(char), 1, output_file);
}

/* FREE ALLOCATED MEMORY */
free(binary_data);
}
``````

Program output:

``````Reading file 512gr.bmp
Width: 512
Height: 512
File size: 263222
# Colors: 256
Vector size: 262144
Total number of pixels: 262144
Threshold value: 244
``````

I think 244 is not a properly computed threshold value, because when function threshold_image binarize image with that all pixels converted to black.

If I skip
`otsu_method`
and get threshold value from user input function
`threshold_image`
works properly.

Function
`otsu_method`
is copy-pasted code, for this reason I'm not crystal clear about variables or conditions.
I'm learning about image processing and trying to figure out basics. Any information about Otsu's algorithm and any feedback about my code helps. egegunes

I found what caused the problem and changed function otsu_method:

``````int otsu_method(float *histogram, long int total_pixels) {
double probability, mean;
double max_between, between;
int threshold;

/*
probability = class probability
mean = class mean
between = between class variance
*/

for(int i = 0; i < 256; i++) {
probability[i] = 0.0;
mean[i] = 0.0;
between[i] = 0.0;
}

probability = histogram;

for(int i = 1; i < 256; i++) {
probability[i] = probability[i - 1] + histogram[i];
mean[i] = mean[i - 1] + i * histogram[i];
}

threshold = 0;
max_between = 0.0;

for(int i = 0; i < 255; i++) {
if(probability[i] != 0.0 && probability[i] != 1.0)
between[i] = pow(mean * probability[i] - mean[i], 2) / (probability[i] * (1.0 - probability[i]));
else
between[i] = 0.0;
if(between[i] > max_between) {
max_between = between[i];
threshold = i;
}
}

return threshold;
}
``````

What really differs:

``````between[i] = pow(mean * probability[i] - mean[i], 2) / (probability[i] * (1.0 - probability[i]));
``````

Program output:

``````Reading file 512gr.bmp
Width: 512
Height: 512
File size: 263222
# Colors: 256
Vector size: 262144
Total number of pixels: 262144

Threshold value: 117
Probability: 0.416683
Mean: 31.9631
Between varaince: 1601.01
``````
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download