Otsu 输出 returns 全黑或全白取决于黑白像素

Otsu output returns full black or white depending on black and white pixels

我自己实现的 otsu returns 质量好的二值化图像,但如果图像有 "more black" 像素,它 returns 是全黑图像,如果图像有 "more white" 像素 returns 全白图像。

我正在使用 drawable,如果我使用相机,它 returns 输出具有相同的想法(全黑或全白)。即使图像有更多的黑色或更多的白色,我如何正确地二值化图像?

(returns全黑或全白的图像可以通过sauvola二值化,因为我尝试比较和检查输出。我没有放sauvola输出以避免长post 但如果需要我可以 post。)

以下是 Otsu 上的一些输出:

输出良好:

错误输出: (下图为相机拍摄)

大津二值化代码

Bitmap BWimg = Bitmap.createBitmap(gImg.getWidth(), gImg.getHeight(), gImg.getConfig());

    int width = gImg.getWidth();
    int height = gImg.getHeight();
    int A, R, G, B, colorPixel;

    // histo-thresh

    double Wcv = 0;
    int[] Bx = new int[256];
    int[] By = new int[256];
    int[] Fx = new int[256];
    int[] Fy = new int[256];
    double Bw = 0, Bm = 0, Bv = 0, Bp = 0;
    double Fw = 0, Fm = 0, Fv = 0, Fp = 0;
    int c = 0, ImgPix = 0;

    // pixel check for histogram

    for (int x = 0; x < width; x++) {
        for (int y = 0; y < height; y++) {

            colorPixel = gImg.getPixel(x, y);

            A = Color.alpha(colorPixel);
            R = Color.red(colorPixel);
            G = Color.green(colorPixel);
            B = Color.blue(colorPixel);

            int gray = (int) (0.2989 * R + 0.5870 * G + 0.1140 * B);
            if (gray > 128) { // white - foreground
                Fx[gray] = gray;
                Fy[gray] = Fy[gray] + 1;
                Fw = Fw + 1;
                Fp = Fp + 1;
            }
            else { // black - background
                Bx[gray] = gray;
                By[gray] = By[gray] + 1;
                Bw = Bw + 1;
                Bp = Bp + 1;
            }
            ImgPix = ImgPix + 1;
        }
    }

    //BG hist
    Bw = Bw / ImgPix; //BG weight

    int i;
    for (i = 0; i < Bx.length; i++) { //BG mean
        Bm = Bm + (Bx[i] * By[i]);
        Bm = Bm / Bp;
    }
    for (i = 0; i < Bx.length; i++) { //BG variance
        Bv = Bv + (Math.pow((Bx[i] - Bm), 2) * By[i]); // (Bx[i]-Bm) * (Bx[i]-Bm)
    }
    Bv = Bv / Bp;


    //FG hist
    Fw = Fw / ImgPix; //BG weight

    for (i = 0; i < Bx.length; i++) { //BG mean
        Fm = Fm + (Fx[i] * Fy[i]);
    }
    Fm = Fm / Fp;

    for (i = 0; i < Bx.length; i++) { //BG variance
        Fv = Fv + (Math.pow((Fx[i] - Fm), 2) * Fy[i]); // (Fx[i]-Fm) * (Fx[i]-Fm)
    }
    Fv = Fv / Fp;

    // within class variance
    Wcv = (Bw * Bv) + (Fw * Fv);

    //int gray2 = 0;

    for (int x = 0; x < width; x++) {
        for (int y = 0; y < height; y++) {

            colorPixel = gImg.getPixel(x, y);

            A = Color.alpha(colorPixel);
            R = Color.red(colorPixel);
            G = Color.green(colorPixel);
            B = Color.blue(colorPixel);

            //int gray2 = (int) ((0.2989 * R) + (0.5870 * G) + (0.1140 * B));
            int gray2 = (R + G + B);
            if (gray2 > Wcv) {
                gray2 = 255;
            }
            else {
                gray2 = 0;
            }

            BWimg.setPixel(x, y, Color.argb(A, gray2, gray2, gray2));
        }
    }

    return BWimg;

我上周二得到了答案,但忘了 post。我明白了 运行.

@Morrison Chang 感谢您对我的代码的一点推动和澄清

    Bitmap BWimg = Bitmap.createBitmap(gImg.getWidth(), gImg.getHeight(), gImg.getConfig());

    int width = gImg.getWidth();
    int height = gImg.getHeight();
    int A, R, G, B, colorPixel;

    double Wcv = 0, th = 0;
    int[] tPXL = new int[256];
    int[][] pxl = new int[width][height];
    double Bw, Bm, Bv, Fw, Fm, Fv;
    int np, ImgPix = 0, fth = 0;

    // pixel check for histogram //
    for (int x = 0; x < width; x++) {
        for (int y = 0; y < height; y++) {

            colorPixel = gImg.getPixel(x, y);

            A = Color.alpha(colorPixel);
            R = Color.red(colorPixel);
            G = Color.green(colorPixel);
            B = Color.blue(colorPixel);

            int gray = (int) ( (0.2126 * R) + (0.7152 * G) + (0.0722 * B) ); // (int) ( (0.299 * R) + (0.587 * G) + (0.114 * B) );
            pxl[x][y] = gray;
            tPXL[gray] = tPXL[gray] + 1;
            ImgPix = ImgPix + 1;
        }
    }

    // ----- histo-variance ----- //
    for (int t = 0; t < 256; t++){
        Bw = 0; Bm = 0; Bv = 0;
        Fw = 0; Fm = 0; Fv = 0;
        np = 0;

        if (t == 0){ // all white/foreground as t0 ----- //
             Fw = 1;

            for (int d = 0; d < 256; d++) { //mean
                Fm = Fm + (d * tPXL[d]);
            }
            Fm = Fm / ImgPix;

            for (int e = 0; e < 256; e++) { //variance
                Fv = Fv + (Math.pow((e - Fm), 2) * tPXL[e]);
            }
            Fv = Fv / ImgPix;

        }

        else { // main thresholding
            for (int d = 0; d < (t-1); d++){ // BG weight & mean + BG pixel
                Bw = Bw + tPXL[d];
                Bm = Bm + (d * tPXL[d]);
                np = np + tPXL[d];
            }
            Bw = Bw / ImgPix;
            Bm = Bm / np;

            for (int e = 0; e < (t-1); e++) { //BG variance
                Bv = Bv + (Math.pow((e - Bm), 2) * tPXL[e]);
            }
            Bv = Bv / np;

            for (int j = t; j < 256; j++) { // FG weight & mean + BG pixel
                Fw = Fw + tPXL[j];
                Fm = Fm + (j * tPXL[j]);
                np = ImgPix - np;
            }
            Fw = Fw / ImgPix;
            Fm = Fm / np;

            for (int k = t; k < 256; k++) { //FG variance
                Fv = Fv + (Math.pow((k - Fm), 2) * tPXL[k]);
            }
            Fv = Fv / np;

        }

        // within class variance
        Wcv = (Bw * Bv) + (Fw * Fv);

        if (t == 0){
            th = Wcv;
        }
        else if (Wcv < th){
            th = Wcv;
            fth = t;
        }
    }

    // set binarize pixel
    for (int x = 0; x < width; x++) {
        for (int y = 0; y < height; y++) {

            int fnpx = pxl[x][y];
            colorPixel = gImg.getPixel(x, y);

            A = Color.alpha(colorPixel);

            if (fnpx > fth) { //R > fth
                fnpx = 255;
                BWimg.setPixel(x, y, Color.argb(A, fnpx, fnpx, fnpx));
            }

            else {
                fnpx = 0;
                BWimg.setPixel(x, y, Color.argb(A, fnpx, fnpx, fnpx));
            }
        }
    }

    return BWimg;