영상처리
Auto Threshold (Huang2) C++
park__
2024. 12. 10. 16:56
Java -> C++ 로 변경
Code
int Huang2(float* histo, int n_length) {
// Implements Huang's fuzzy thresholding method
// Uses Shannon's entropy function (one can also use Yager's entropy function)
// Huang L.-K. and Wang M.-J.J. (1995) "Image Thresholding by Minimizing
// the Measures of Fuzziness" Pattern Recognition, 28(1): 41-51
// Reimplemented (to handle 16-bit efficiently) by Johannes Schindelin Jan 31, 2011
// find first and last non-empty bin
int first = 1, last;
for (first = 0; first < n_length && histo[first] == 0; first++)
; // do nothing
for (last = n_length - 1; last > first && histo[last] == 0; last--)
; // do nothing
if (first == last)
return 0;
// calculate the cumulative density and the weighted cumulative density
double* S = nullptr;
double* W = nullptr;
double* Smu = nullptr;
S = new double[last + 1];
W = new double[last + 1];
int start = max(1, first);
S[start - 1] = histo[start - 1];
W[start - 1] = histo[start - 1];
for (int i = start; i <= last; i++)
{
S[i] = S[i - 1] + histo[i];
W[i] = W[i - 1] + i * histo[i];
}
// precalculate the summands of the entropy given the absolute difference x - mu (integral)
double C = last - first;
int Smu_length = last + 1 - first;
Smu = new double[Smu_length];
for (int i = 1; i < Smu_length; i++)
{
double mu = 1 / (1 + abs(i) / C);
Smu[i] = -mu * log(mu) - (1 - mu) * log(1 - mu);
}
// calculate the threshold
int bestThreshold = 0;
double bestEntropy = DBL_MAX;
for (int threshold = first; threshold <= last; threshold++)
{
double entropy = 0;
int mu = (int)round(W[threshold] / S[threshold]);
for (int i = first; i <= threshold; i++)
entropy += Smu[abs(i - mu)] * histo[i];
mu = (int)round((W[last] - W[threshold]) / (S[last] - S[threshold]));
for (int i = threshold + 1; i <= last; i++)
entropy += Smu[abs(i - mu)] * histo[i];
if (bestEntropy > entropy) {
bestEntropy = entropy;
bestThreshold = threshold;
}
}
if (S)
delete[] S;
if (W)
delete[] W;
if (Smu)
delete[] Smu;
return bestThreshold;
}
사용 예시
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 = Huang2((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