Рассчитать бинарный оптимальный порог ImageJ на основе среднего / заднего фона
Я исследовал, как рассчитать оптимальный порог для ImageJ, и нашел это объяснение порогового значения Otsu, которое, как мне показалось, имело смысл для меня.
Хотя я боролся с его реализацией, и после некоторой мысли я нашел ошибку в способе вычисления веса и среднего, и теперь он находит оптимальный порог 77, который для изображения монеты мне подходит, так как он почти полностью отделяет фон от монет (и вы сможете автоматически считать монеты или измерять их по размеру, ectr)
новое изображение монеты с оптимальным порогом
он также, кажется, работает очень хорошо с этим изображением, даже если он имеет различную интенсивность света: изображение риса с различной интенсивностью
Я очень доволен своим решением, но если у вас есть какие-либо отзывы или вы можете найти что-то еще, это было бы здорово! Это домашнее задание было тяжелым, но я многому научился у него:)
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;
}
1 ответ
Не уверен, что ты это имел ввиду? извините- еще новичок в 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;
}