Otsu输出返回全黑或白色,具体取决于黑白像素

时间:2018-04-11 22:22:40

标签: android output image-thresholding

我自己实施的otsu返回了一个高质量的二值化图像,但如果图像有更多的黑色"像素它会返回一个完整的黑色图像,如果图像有"更多的白色"它返回一个完整的白色图像。

我使用drawable,如果我使用相机,它会返回具有相同想法的输出(全黑或全白)。即使图像更黑或更白,我怎样才能正确地对图像进行二值化?

(当我尝试比较并检查输出时,返回全黑或全白的图像可以通过sauvola进行二值化。我没有把sauvola输出放在避免长帖但我可以在需要时发布它。)

以下是Otsu的一些输出:

良好的输出: #1 #2

输出错误: #3 #4 (下图来自相机拍摄) #5

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;

1 个答案:

答案 0 :(得分:1)

我上周二得到了答案但忘记发布了。我把它运行了。

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