我正在研究如何计算 ImageJ 的最佳阈值并找到了 this explanation of the Otsu Thresholding ,我认为它非常适合我使用。
虽然我一直在努力实现它,但经过一番思考后,我发现权重和均值的计算方式有误,现在它找到了最佳阈值 77,对于硬币图像来说,这对我来说看起来不错,因为它几乎完全将背景与硬币分开(您将能够自动计算硬币的数量,或测量它们的大小,等等)
new coin image with optimal threshold
它似乎也适用于此图像,即使它具有不同的光强度: rice image with varying intensities
我对找到的解决方案感到非常满意,但如果您有任何反馈或可以找到其他解决方案,那就太好了!这个作业很难,但我从中学到了很多东西:)
public float calculateMeanFG(int[] histogram, int t) {
float sumI = 0;
int total = 0;
//cumulate the histogram for < 256
for (int i = t; i < 256; i++) {
sumI += histogram[i] * i;
total = i;
}
return sumI / total;
}
public float calculateMeanBG(int[] histogram, int t) {
float sumI = 0;
//cumulate the histogram for < t
for (int i = 0; i < t; i++) {
sumI += histogram[i] * i;
}
return sumI;
}
public float calculateWeightFG(int[] histogram, int t, int total) {
int sum = 0;
for (int i = t; i < 256; i++) {
sum += histogram[i];
}
return sum / total;
}
public int[] getHistogram(ImageProcessor ip, int height, int width) {
byte[] outP = ((byte[]) ip.getPixels()).clone();
int[][] inDataArr = new int[width][height];
int[] histogram = new int[256];
int idx = 0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// fill in values
inDataArr[x][y] = outP[idx];
if (inDataArr[x][y] < 0) {
inDataArr[x][y] += 256;
} // if
histogram[inDataArr[x][y]] += 1; // count grayscale occurrences
idx++;
} // for x
} // for y
return histogram;
}
public int[][] convergeOptThresh(int[][] imgArr, int width, int height) {
int BG_VAL = 0;
int FG_VAL = 255;
int[] histogram = getHistogram(ip, height, width);
// total number of pixels
int total = imgArr.length;
// cumulative hist
float sum = 0;
for (int i = 0; i < 256; i++)
sum += i * histogram[i];
float sumBG = 0; // sum background
float weightBG = 0;
float weightFG = 0;
float varMax = 0;
int threshold = 0;
for (int t = 0; t < 256; t++) {
weightBG = calculateMeanBG(histogram, t);
weightBG /= total;
weightFG = calculateWeightFG(histogram, t, total);
if ((int)weightFG == 0)
break;
sumBG += (float) (t * histogram[t]);
float meanBG = sumBG / t;
float meanFG = calculateMeanFG(histogram, t);
// calculate between class variance
float varBetween = weightBG * weightFG * (meanBG - meanFG) * (meanBG - meanFG);
// check if new max found
if (varBetween > varMax) {
varMax = varBetween;
threshold = t;
}
}
IJ.log("optimal threshold: " + threshold);
int[][] retArr = new int[width][height];
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
if (imgArr[x][y] <= threshold) {
retArr[x][y] = BG_VAL;
} else {
retArr[x][y] = FG_VAL;
}
}
}
return retArr;
}
最佳答案
不确定这是否是您的意思?抱歉 - 对 SO 还是陌生 >.<
public float calculateMeanFG(int[] histogram, int t) {
float sumI = 0;
int total = 0;
//cumulate the histogram for < 256
for (int i = t; i < 256; i++) {
sumI += histogram[i] * i;
total = i;
}
return sumI / total;
}
public float calculateMeanBG(int[] histogram, int t) {
float sumI = 0;
//cumulate the histogram for < t
for (int i = 0; i < t; i++) {
sumI += histogram[i] * i;
}
return sumI;
}
public float calculateWeightFG(int[] histogram, int t, int total) {
int sum = 0;
for (int i = t; i < 256; i++) {
sum += histogram[i];
}
return sum / total;
}
public int[] getHistogram(ImageProcessor ip, int height, int width) {
byte[] outP = ((byte[]) ip.getPixels()).clone();
int[][] inDataArr = new int[width][height];
int[] histogram = new int[256];
int idx = 0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// fill in values
inDataArr[x][y] = outP[idx];
if (inDataArr[x][y] < 0) {
inDataArr[x][y] += 256;
} // if
histogram[inDataArr[x][y]] += 1; // count grayscale occurrences
idx++;
} // for x
} // for y
return histogram;
}
public int[][] convergeOptThresh(int[][] imgArr, int width, int height) {
int BG_VAL = 0;
int FG_VAL = 255;
int[] histogram = getHistogram(ip, height, width);
// total number of pixels
int total = imgArr.length;
// cumulative hist
float sum = 0;
for (int i = 0; i < 256; i++)
sum += i * histogram[i];
float sumBG = 0; // sum background
float weightBG = 0;
float weightFG = 0;
float varMax = 0;
int threshold = 0;
for (int t = 0; t < 256; t++) {
weightBG = calculateMeanBG(histogram, t);
weightBG /= total;
weightFG = calculateWeightFG(histogram, t, total);
if ((int)weightFG == 0)
break;
sumBG += (float) (t * histogram[t]);
float meanBG = sumBG / t;
float meanFG = calculateMeanFG(histogram, t);
// calculate between class variance
float varBetween = weightBG * weightFG * (meanBG - meanFG) * (meanBG - meanFG);
// check if new max found
if (varBetween > varMax) {
varMax = varBetween;
threshold = t;
}
}
IJ.log("optimal threshold: " + threshold);
int[][] retArr = new int[width][height];
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
if (imgArr[x][y] <= threshold) {
retArr[x][y] = BG_VAL;
} else {
retArr[x][y] = FG_VAL;
}
}
}
return retArr;
}
关于java - 基于前景/背景均值计算二值最优阈值ImageJ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54439550/