Problem z binaryzacją obrazu

0

Witam

Mam problem z przeprowadzeniem binaryzacji obrazu.

Najpierw wczytuje obraz kolorowy ,zmieniam go do skali szarości :

public BufferedImage binaryzacja()
    {
        BufferedImage bF = null;
        try{
            bF = new BufferedImage(this.width,this.height,BufferedImage.TYPE_INT_RGB);
            for (int i = 0; i < this.height; i++) {
                for (int j = 0; j < this.width; j++) {
                    int pxl = this.tab[i * this.width + j];
                    int b = (pxl & 0x000000ff);
                    int g = ((pxl >> 8) & 0x000000ff);
                    int r = ((pxl >> 16) & 0x000000ff);
                    int c = (int) (0.299 * r + 0.587 * g + 0.114 * b);
                    pxl = c | c << 8 | c << 16 | 0xff << 24;
                    //System.out.print(pxl+"\n");
                    bF.setRGB(j, i, pxl);
                }
            }
        }
        catch(Exception io){}
        return bF;
    }

chcialbym zbinaryzowac obraz sprawdzając próbki pixeli , w jakim zakresie się znajdują (powinny od 0 do 255), jednak po wywołaniu System.out.print(pxl+"\n"); , widzę ,że są to bardzo duże ujemne liczby. W jaki sposób można zamienic te próbki do przedzialu od 0:255 by wprosty sposób dokonac binaryzacji

z góry thx

0

bajt | 0xFF

catch(Exception io){}
wtf...

0
fexec napisał(a)

Witam

Mam problem z przeprowadzeniem binaryzacji obrazu.

Najpierw wczytuje obraz kolorowy ,zmieniam go do skali szarości :

public BufferedImage binaryzacja()
    {
        BufferedImage bF = null;
        try{
            bF = new BufferedImage(this.width,this.height,BufferedImage.TYPE_INT_RGB);
            for (int i = 0; i < this.height; i++) {
                for (int j = 0; j < this.width; j++) {
                    int pxl = this.tab[i * this.width + j];
                    int b = (pxl & 0x000000ff);
                    int g = ((pxl >> 8) & 0x000000ff);
                    int r = ((pxl >> 16) & 0x000000ff);
                    int c = (int) (0.299 * r + 0.587 * g + 0.114 * b);
                    pxl = c | c << 8 | c << 16 | 0xff << 24;
                    //System.out.print(pxl+"\n");
                    bF.setRGB(j, i, pxl);
                }
            }
        }
        catch(Exception io){}
        return bF;
    }

chcialbym zbinaryzowac obraz sprawdzając próbki pixeli , w jakim zakresie się znajdują (powinny od 0 do 255), jednak po wywołaniu System.out.print(pxl+"\n"); , widzę ,że są to bardzo duże ujemne liczby. W jaki sposób można zamienic te próbki do przedzialu od 0:255 by wprosty sposób dokonac binaryzacji

z góry thx

Na zmienną c zapisujesz odcień szarości:
int c = (int) (0.299 * r + 0.587 * g + 0.114 * b);
Jej wartość jest w przedziale od 0 do ok. 262, więc całkiem blisko docelowego przedziału. Jeśli chcesz zamienić obrazek na czarno-biały, to dla wartości c poniżej np. 131 zapisuj kolor czarny, a dla wartości powyżej tego progu - kolor biały. Zacznij od przyglądania się c zamiast pxl.

Pozdrawiam,
efrac

0

Kolega powyżej machnął się przy sprawdzaniu bo zakres c wynosi 0-255 po obcięciu do int.

Z tej wartości zależnie od kaprysu użytkownika można skalować do formatu jednobitowego ustalając próg od 1 do 254, średnio 128 dla idealnie stonowanych obrazów. Dzięki zmiennemu progowi obraz wynikowy będzie jaśniejszy lub ciemniejszy, co pozwoli użytkownikowi dobrać go tak aby najistotniejsze dla niego kontury obrazu pozostały widoczne.

Można też podejść do tego automatem przez policzenie średniej c dla wszystkich pikseli obrazu, która stanie się znormalizowaną wartością progową i będzie działać dobrze dla większości obrazów (tzn. średnio najwięcej szczegółów pozostanie widocznych). Jeżeli obraz będzie prześwietlony, to średnia będzie wysoka uszczegóławiając mniej jasne regiony, a jeżeli będzie niedoświetlony, to średnia będzie niska uszczegóławiając jaśniejsze regiony.

Obliczenia da się również zoptymalizować używając arytmetyki stałoprzecinkowej. Należy pomnożyć każdą ze składowych piksela przez 299+7=306, 587+14=601, 114+3=117 (co łącznie daje 1024), a następnie przesunąć wyniki składowych o 10 bitów w prawo (co da taki sam efekt jak podzielenie przez 1024). W efekcie każda składowa RGB zostanie bardzo szybko przeskalowana bez użycia bardzo czasochłonnego mnożenia zmiennoprzecinkowego (i konwersji) przy dokładnie takim samym efekcie:
int c = 306*r + 601*g + 117*b >>> 10;
Ma to o tyle duże znaczenie, że obliczeń tych są miliony bo wykonują się w najdłuższych pętlach.

Można też przez policzenie częstości występowania poszczególnych wartości c (256 od 0 do 255) w całym obrazie czyli policzenie histogramu odrzucić częstości występowania wartości skrajnych (np. od wartości 14 do 196 może występować 90% pikseli obrazu) i skalować średnią od wyliczonego zakresu (w tym przykładzie 14-196 da średnią progową = 105). A przynajmniej tak się to robi w profesjonalnych programach graficznych (wystarczy rzucić okiem na narzędzie nazywane Tone Balance).

1 użytkowników online, w tym zalogowanych: 0, gości: 1