영상처리
Auto Threshold (Li) C++
park__
2024. 12. 10. 16:12
Java -> C++ 로 변경
Code
int Li(float* histo, int n_length) {
// Implements Li's Minimum Cross Entropy thresholding method
// This implementation is based on the iterative version (Ref. 2) of the algorithm.
// 1) Li C.H. and Lee C.K. (1993) "Minimum Cross Entropy Thresholding"
// Pattern Recognition, 26(4): 617-625
// 2) Li C.H. and Tam P.K.S. (1998) "An Iterative Algorithm for Minimum
// Cross Entropy Thresholding"Pattern Recognition Letters, 18(8): 771-776
// 3) Sezgin M. and Sankur B. (2004) "Survey over Image Thresholding
// Techniques and Quantitative Performance Evaluation" Journal of
// Electronic Imaging, 13(1): 146-165
// http://citeseer.ist.psu.edu/sezgin04survey.html
// Ported to ImageJ plugin by G.Landini from E Celebi's fourier_0.8 routines
int threshold;
int ih;
int num_pixels;
int sum_back; /* sum of the background pixels at a given threshold */
int sum_obj; /* sum of the object pixels at a given threshold */
int num_back; /* number of background pixels at a given threshold */
int num_obj; /* number of object pixels at a given threshold */
double old_thresh;
double new_thresh;
double mean_back; /* mean of the background pixels at a given threshold */
double mean_obj; /* mean of the object pixels at a given threshold */
double mean; /* mean gray-level in the image */
double tolerance; /* threshold tolerance */
double temp;
tolerance = 0.5;
num_pixels = 0;
for (ih = 0; ih < n_length; ih++)
num_pixels += histo[ih];
/* Calculate the mean gray-level */
mean = 0.0;
for (ih = 0; ih < n_length; ih++) //0 + 1?
mean += ih * histo[ih];
mean /= num_pixels;
/* Initial estimate */
new_thresh = mean;
do
{
old_thresh = new_thresh;
threshold = (int)(old_thresh + 0.5); /* range */
/* Calculate the means of background and object pixels */
/* Background */
sum_back = 0;
num_back = 0;
for (ih = 0; ih <= threshold; ih++)
{
sum_back += ih * histo[ih];
num_back += histo[ih];
}
mean_back = (num_back == 0 ? 0.0 : (sum_back / (double)num_back));
/* Object */
sum_obj = 0;
num_obj = 0;
for (ih = threshold + 1; ih < n_length; ih++)
{
sum_obj += ih * histo[ih];
num_obj += histo[ih];
}
mean_obj = (num_obj == 0 ? 0.0 : (sum_obj / (double)num_obj));
/* Calculate the new threshold: Equation (7) in Ref. 2 */
//new_thresh = simple_round ( ( mean_back - mean_obj ) / ( Math.log ( mean_back ) - Math.log ( mean_obj ) ) );
//simple_round ( double x ) {
// return ( int ) ( IS_NEG ( x ) ? x - .5 : x + .5 );
//}
//
//#define IS_NEG( x ) ( ( x ) < -DBL_EPSILON )
//DBL_EPSILON = 2.220446049250313E-16
temp = (mean_back - mean_obj) / (log(mean_back) - log(mean_obj));
if (temp < -2.220446049250313E-16)
new_thresh = (int)(temp - 0.5);
else
new_thresh = (int)(temp + 0.5);
/* Stop the iterations when the difference between the
new and old threshold values is less than the tolerance */
} while (abs(new_thresh - old_thresh) > tolerance);
return threshold;
}
사용 예시
std::string str_image_path;
cv::Mat raw_img = cv::imread(str_image_path, -1);
cv::Mat raw_img_8bit;
// 8Bit 1Channel 만 가능...
raw_img.convertTo(raw_img_8bit, CV_8UC1, 256.0 / 65536.0);
int histSize = 256;
float range[] = { 0, 255 };
const float* histRange = { range };
cv::Mat hist;
cv::calcHist(&raw_img_8bit, 1, 0, cv::Mat(), hist, 1, &histSize, &histRange);
int n_length = raw_img.rows * raw_img.cols;
uint8_t threshold_value = Li((float*)hist.data, 256);
cv::Mat threshold_img;
cv::threshold(raw_img_8bit, threshold_img, threshold_value, 255, cv::THRESH_BINARY);
imageJ 관련 문서 : https://imagej.net/plugins/auto-threshold
github link : https://github.com/fiji/Auto_Threshold/blob/master/src/main/java/fiji/threshold/Auto_Threshold.java