Click here to Skip to main content
15,914,795 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I made my own implementation of Otsu for my project. I followed the mathematical algorithm to do it. I was trying to use histogram but im having a hard time so i just followed the logic of it. How can I binarize it accurately? My current output is only full black or full white?

What I have tried:

Java
I made my own implementation of Otsu for my project.

After hours of experimenting on how can I make the image to black-white after getting the within class variance. Here is my full working code and some output.

Here is my code:

Otsu.java

        Bitmap tempImg = (Bitmap) original;
        Bitmap OImg = Bitmap.createBitmap(tempImg.getWidth(), tempImg.getHeight(), tempImg.getConfig());

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

        for (int x = 0; x < width; x++) { //original image to grayscale
            for (int y = 0; y < height; y++) {

                colorPixel = tempImg.getPixel(x, y);

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

                R = (R + G + B) / 3;
                G = R;
                B = R;

                OImg.setPixel(x, y, Color.argb(A, R, G,B ));
            }
        }
        return OImg;
    }

    public static Bitmap Botsu(Bitmap gImg){

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

        int width = tempImg.getWidth();
        int height = tempImg.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, ImgPixB = 0, ImgPixF = 0, newPixel = 0;

            // pixel check for histogram

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

                colorPixel = tempImg.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
                    for (int z=0; z<Fx.length; z++){
                        if (Fx[z] == gray){
                            c++;
                        }
                    }
                    if (c==1){
                        Fy[gray] = Fy[gray]+1; //y axis - counter for pixels for each x
                    }
                    else{
                        Fx[x] = gray; //x axis - 0-255
                        Fy[gray] = Fy[gray]+1;
                    }
                }//By[Bx[x]]
                else{ // black - background
                    for (int z=0; z<Bx.length; z++){
                        if (Bx[z] == gray){
                            c++;
                        }
                    }
                    if (c==1){
                        By[gray] = By[gray]+1; //y axis - counter for pixels for each x
                    }
                    else{
                        Bx[x] = gray; //x axis - 0-255
                        By[gray] = By[gray]+1;
                    }
                }
            }
        }

        for (int b=0; b<By.length; b++){
            ImgPixB = ImgPixB + By[b];
        }
        for (int f=0; f<Fy.length; f++){
            ImgPixF = ImgPixF + Fy[f];
        }
        ImgPix = ImgPixB + ImgPixF;

        //bg part hist
        for (int i=0; i<By.length; i++){ //weight
            Bw = Bw + By[i];
        }
        Bw = Bw/ImgPix;
        for (int i=0; i<By.length; i++){ //pixel sum
            Bp = Bp + By[i];
        }
        for (int i = 0; i<Bx.length; i++){ //mean
            Bm = Bm + (Bx[i]*By[Bx[i]]);
        }
        Bm = Bm/Bp;
        for (int i=0; i<Bx.length; i++){ //variance
            Bv = Bv + (Math.pow((Bx[i]-Bm),2)*By[Bx[i]]); // (Bx[i]-Bm) * (Bx[i]-Bm)
        }
        Bv = Bv/Bp;

        //fg part hist
        for (int i=0; i<Fy.length; i++){ //weight
            Fw = Fw + Fy[i];
        }
        Fw = Fw/ImgPix;
        for (int i=0; i<Fy.length; i++){ //pixel sum
            Fp = Fp + Fy[i];
        }
        for (int i = 0; i<Fx.length; i++){ //mean
            Fm = Fm + (Fx[i]*Fy[Fx[i]]);
        }
        Fm = Fm/Fp;
        for (int i=0; i<Fx.length; i++){ //variance
            Fv = Fv + (Math.pow((Fx[i]-Fm),2)*Fy[Fx[i]]); // (Bx[i]-Bm) * (Bx[i]-Bm)
        }
        Fv = Fv/Fp;

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

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

                colorPixel = tempImg.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);
                int gray2 = (int) (Wcv * R + Wcv * G + Wcv * B);
                if (gray2 > 128) {
                    gray2 = 255;
                }
                else if (gray2 <129){
                    gray2 = 0;
                }

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

        return BWimg;


`x[z]` is for x-axis and`y[gray] ` is for y-axis. I based this on the graph on [Lab Book][1]

    x = 0-255
    y = how many pixels is on a certain color shade


OUTPUT: (I added 2 if-else values that i experimented that showed 3 different outputs. Other values will only return few black dots or just pure white image.)

Java
if (gray2 > 128) {
        gray2 = 255;
    }
    else if (gray2 < 129){
        gray2 = 0;
    }

Output 1
Output 2

Java
if (gray2 > 64 && gray2 < 129) {
        gray2 = 255;
    }
    else if (gray2 < 65){
        gray2 = 0;
    }

Output3
Posted
Updated 11-Apr-18 14:46pm
v3

1 solution

Compiling does not mean your code is right! :laugh:
Think of the development process as writing an email: compiling successfully means that you wrote the email in the right language - English, rather than German for example - not that the email contained the message you wanted to send.

So now you enter the second stage of development (in reality it's the fourth or fifth, but you'll come to the earlier stages later): Testing and Debugging.

Start by looking at what it does do, and how that differs from what you wanted. This is important, because it give you information as to why it's doing it. For example, if a program is intended to let the user enter a number and it doubles it and prints the answer, then if the input / output was like this:
Input   Expected output    Actual output
  1            2                 1
  2            4                 4
  3            6                 9
  4            8                16
Then it's fairly obvious that the problem is with the bit which doubles it - it's not adding itself to itself, or multiplying it by 2, it's multiplying it by itself and returning the square of the input.
So with that, you can look at the code and it's obvious that it's somewhere here:
C#
private int Double(int value)
   {
   return value * value;
   }

Once you have an idea what might be going wrong, start using the debugger to find out why. Put a breakpoint on your line:
C#
colorPixel = tempImg.getPixel(x, y);

and run your app. Think about what each line in the code should do before you execute it, and compare that to what it actually did when you use the "Step over" button to execute each line in turn. Did it do what you expect? If so, move on to the next line.
If not, why not? How does it differ?

This is a skill, and it's one which is well worth developing as it helps you in the real world as well as in development. And like all skills, it only improves by use!
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900