首页 > 解决方案 > 基于前景/背景均值计算二值最优阈值 ImageJ

问题描述

我正在研究如何计算 ImageJ 的最佳阈值,并找到了对 Otsu Thresholding 的解释,我认为这对我来说非常有意义。

我一直在努力实现它,经过一番思考,我发现计算权重和平均值的方式有误,现在它找到了 77 的最佳阈值,这对于硬币图像来说看起来不错,因为它几乎完全将背景与硬币分开(您可以自动计算硬币数量,或测量它们的大小等)

具有最佳阈值的新硬币图像

即使它具有不同强度的光,它似乎也可以很好地处理此图像:具有不同强度的 大米图像

我对找到的解决方案感到非常满意,但是如果您有任何反馈或可以找到其他东西,那就太好了!这个作业很难,但我从中学到了很多:)

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;
}

标签: javaimagejimage-thresholdingadaptive-threshold

解决方案


不确定这是否是您的意思?抱歉-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;
}

推荐阅读