noobieprgrmmr Ответов: 1

Как я могу улучшить результат моего самостоятельно реализованного алгоритма otsu?


Я сделал свою собственную реализацию Оцу для своего проекта. Я следовал математическому алгоритму, чтобы сделать это. Я пытался использовать гистограмму, но мне было трудно, поэтому я просто следовал ее логике. Как я могу точно бинаризовать его? Мой текущий выход только полностью черный или полностью белый?

Что я уже пробовал:

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


Вывод: (я добавил 2 значения if-else, которые я экспериментировал, которые показали 3 разных выхода. Другие значения вернут только несколько черных точек или просто чистое белое изображение.)

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

Выход 1
Выход 2

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

Выход3

1 Ответов

Рейтинг:
2

OriginalGriff

Компиляция не означает, что ваш код верен! :смеяться:
Подумайте о процессе разработки как о написании электронного письма: успешная компиляция означает, что вы написали письмо на правильном языке - например, на английском, а не на немецком, - а не то, что письмо содержало сообщение, которое вы хотели отправить.

Итак, теперь вы входите во вторую стадию разработки (на самом деле это четвертая или пятая, но вы перейдете к более ранним стадиям позже): тестирование и отладка.

Начните с рассмотрения того, что он делает, и как это отличается от того, что вы хотели. Это важно, потому что это дает вам информацию о том, почему он это делает. Например, если программа предназначена для того, чтобы позволить пользователю ввести число, а затем удвоить его и напечатать ответ, то если бы ввод / вывод был таким:

Input   Expected output    Actual output
  1            2                 1
  2            4                 4
  3            6                 9
  4            8                16
Тогда совершенно очевидно, что проблема заключается в бите, который удваивает его - он не прибавляет себя к себе или умножает его на 2, он умножает его на себя и возвращает квадрат входного сигнала.
Таким образом, вы можете посмотреть на код, и очевидно, что он находится где-то здесь:
private int Double(int value)
   {
   return value * value;
   }

Как только у вас появится идея, что может пойти не так, начните использовать отладчик, чтобы выяснить, почему. Поставить точку останова на строке:
colorPixel = tempImg.getPixel(x, y);

и запустите свое приложение. Подумайте о том, что должна делать каждая строка кода перед ее выполнением, и сравните это с тем, что она действительно делала, когда вы использовали кнопку "Step over" для выполнения каждой строки по очереди. Он сделал то, что вы ожидали? Если да, то переходите к следующей строке.
Если нет, то почему? Чем это отличается?

Это навык, и его стоит развивать, поскольку он помогает вам как в реальном мире, так и в развитии. И, как и все навыки, он только улучшается при использовании!