java - 基于前景/背景均值计算二值最优阈值ImageJ

标签 java imagej image-thresholding adaptive-threshold

我正在研究如何计算 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/

相关文章:

java - 如何使用 mongodb 的 morphia 更新/保存包含引用的文档?

python - 将图像转换为二进制不显示足球场的白线

python - 我可以在 OpenCV 中为 Otsu 阈值添加偏差吗?

command-line - 从命令行运行斐济?

java - 从命令行制作 ImageJ .jar

python - opencv 阈值 THRESH_BINARY 对彩色图像有何作用?

java - Stream#limit 可以返回比预期更少的元素吗?

java - 无法让 Angular $http 工作

Javamail 发送带附件的邮件可以在 Windows 上运行,但不能在 Linux 上运行

java - 在另一个程序中调用 IMAGEJ 插件