You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

基于前景/背景均值的ImageJ最优二值阈值计算实现与优化问询

分享我在ImageJ中实现Otsu阈值法的过程与代码

最近在研究如何在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; 
            } 
            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; 
}

这次作业难度不小,但整个过程让我收获特别多,期待大家的建议!

内容的提问来源于stack exchange,提问作者gizmo

火山引擎 最新活动