根据前景/背景均值计算二进制最佳阈值ImageJ

时间:2019-01-30 11:27:59

标签: java imagej image-thresholding adaptive-threshold

我正在研究如何计算ImageJ的最佳阈值,并发现this explanation of the Otsu Thresholding,这对我来说很有意义。

我一直在努力实现它,经过一番思考之后,我发现计算权重和均值的方法有一个错误,现在它找到了最佳阈值77,这对于硬币图像来说对我来说很好几乎可以将硬币的背景与硬币完全分开(并且您可以自动对硬币进行计数,或者测量硬币的大小,以ectr为单位)

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

1 个答案:

答案 0 :(得分:1)

不确定这是您的意思吗?抱歉-对SO>还是很新。<< / p>

unsigned char foo[] = { 1,2,3,4,5 };
print_1_array(stdout, foo, sizeof foo);