2011-09-16 12 views
7

Czytanie DIP Druga edycja autorstwa Gonzaleza i Woodsa i spróbuj zabrać mi ręce za pomocą maski Laplacian (strona 129 & 130) używając wxImage.implementacja laplacian 3x3

float kernel [3][3]= {{1, 1, 1},{1,-8, 1},{1, 1, 1}}; 

tutaj jest przetwarzanie pętle:

unsigned char r,g,b;      

float rtotal, gtotal, btotal; rtotal = gtotal = btotal = 0.0; 
//ignore the border pixel    

for(int i = 1; i<imgWidth-1; i++) 
{ 

    for(int j = 1; j<imgHeight-1; j++) 
    { 

    rtotal = gtotal=btotal =0.0; 


     for(int y = -1; y<=1;y++) 

     { 

      for(int x = -1; x<=1;x++) 

      { 

      // get each channel pixel value 

      r = Image->GetRed(i+y,j+x); 

      g = Image->GetGreen(i+y,j+x); 

      b = Image->GetBlue(i+y,j+x); 

      // calculate each channel surrouding neighbour pixel value base 

      rtotal += r* kernel[y+1][x+1]; 

      gtotal += g* kernel[y+1][x+1] ; 

      btotal += b* kernel[y+1][x+1]; 

      } 

    } 
      //edit1: here is how to sharpen the image 
      // original pixel - (0.2 * the sum of pixel neighbour) 
      rtotal = loadedImage->GetRed(x,y) - 0.2*rtotal; 

    gtotal = loadedImage->GetGreen(x,y) - 0.2*gtotal; 

    btotal = loadedImage->GetBlue(x,y) - 0.2*btotal; 
    // range checking 

    if (rtotal >255) rtotal = 255; 

     else if (rtotal <0) rtotal = 0; 

    if(btotal>255) btotal = 255; 

     else if(btotal < 0) btotal = 0; 

    if(gtotal > 255) gtotal = 255; 

     else if (gtotal < 0) gtotal =0; 

    // commit new pixel value 

    Image->SetRGB(i,j, rtotal, gtotal, btotal); 

Zgłosiłem to do obrazu, North Pole (szary obraz) i wszystko dostaję to kropelka czarnych i białych pikseli!

Jakieś pomysły, w przypadku których mógłbym przegapić coś w pętlach for?

Edit1: Na koniec uzyskaj odpowiedź po rozejrzeniu się po Google. Ten dsp jest zdecydowanie trudny! Dodałem do powyższego kodu, to wyostrzy obraz.

Cheers

+0

To byłoby dobre pytanie dla dsp.stackexchange.com – Dima

Odpowiedz

5

Po pierwsze, wynik zawiłości z Lapleckiem może mieć wartości ujemne. Rozważmy piksel o wartości 1 otoczonej zerami. Rezultatem splotu w tym pikselu będzie -8.

Po drugie, zakres wyniku będzie wynosić od [-8 * 255, 8 * 255], co zdecydowanie nie mieści się w 8 bitach. Zasadniczo, gdy sprawdzasz zakres, tracisz większość informacji, a większość twoich wynikowych pikseli kończy się na 0 lub 255.

Co musisz zrobić, to zapisać wynik w tablicy typ, który jest podpisany i wystarczająco szeroki, aby obsłużyć zasięg. Następnie, jeśli chcesz wyprowadzić obraz 8-bitowy, musisz przeskalować wartości tak, aby -8 * 255 odwzorować na 0, a 8 * 255 odwrotnie do 255. Możesz też zmienić jego skalę tak, aby najmniejsza wartość mapowała do 0 i największą wartość mapy do 255.

EDIT: w tym konkretnym przypadku, można wykonać następujące czynności:

rtotal = (rtotal + 8 * 255)/(16 * 255) * 255; 

który upraszcza do

rtotal = (rtotal + 8 * 255)/16; 

byłoby map rtotal w zakresie od 0 do 255 bez obcięcia. Powinieneś zrobić to samo dla gtotal i btotal.

+0

Dzięki za odpowiedź. Ale nie rozumiem, że kiedy wykonuję obliczenia sąsiada, zapisuję to do r/g/btotal, które jest wartością float, powinno być wystarczająco duże, prawda? O ile widzę, wartość maksymalna jednego sąsiada może wynosić 8 * 255 lub -8 * 255, tak jak wspomniałeś powyżej, co stanowi (-) 2040 * 9 (łącznie dziewięciu sąsiadów) = (-) 18360. Patrzę na zakres zmiennoprzecinkowy w C++ i mówi, że zakres zmiennoprzecinkowy wynosi 7digitów. Teraz jednak w pełni rozumiem, dlaczego mam duży blog z białym i czarnym pikselem, ponieważ przegapiłem inne obliczenia. Zobacz moje wydanie OP. Dzięki! – bili

+0

Fakt, że używasz float dla r/g/btotal jest w porządku. Problem pojawia się, gdy wartość r/g/btotal zostanie obcięta w zakresie od 0 do 255. Zamiast ustawiania wszystkiego poniżej 0 na 0 i wszystkiego powyżej 255 do 255, należy skalować wartość. Obcinasz zakres, podczas gdy powinieneś kompresować zasięg. – Dima

+0

Tak, rozumiem teraz. Powinienem skalować wartość zamiast ją obcinać. tyvm! – bili

1

Czy nie powinieneś podzielić przez liczbę pikseli w masce po obliczeniu sumy ważonej, tworząc w ten sposób średnią ważoną? Bez tego, suma dziewięciu wartości pikseli (nawet po pomnożeniu przez niezbyt jasne wartości maski) z łatwością przekroczy 255.

+2

Suma wartości w macierzy maski wynosi zero, więc nie, nie będzie żadnego ogólnego wzmocnienia, które spowodowałoby przepełnienie.Musisz jednak zadbać o większy typ w obliczeniach pośrednich, albo możesz przelać 8-bitową wartość podczas obliczania sumy. Dla każdego piksela Laplacian zamienia go na sumę wszystkich swoich sąsiadów minus ośmiokrotność pierwotnej wartości piksela, co jest operacją różnicowania. Służy do wykrywania krawędzi. –

+0

Dziękuję. Zajrzę teraz do tego. – bili

+0

@Jason R: Zróbcie odpowiedź - myślę, że właśnie to się tutaj wydarzyło. –

2

Myślę, że twój problem polega na tym, że r, gib są typu unsigned int i że, w zależności od na którym kompilatorze używasz i jak się optymalizuje, domyślnie rzutujesz je na linie w liniach rtotal += r* kernel[y+1][x+1]; itd. Ale jeśli kompilator rzuca inaczej niż oczekiwałeś, to obliczenie wartości środkowej nie zadziała, ponieważ unsigned int nie może być ujemne .

Rozwiązanie: zmień r, gib, aby zmienić wartość na pływającą.

Nie spowoduje to żadnej różnicy, ale istnieje niewielki błąd w liniach r = Image->GetRed(i+y,j+x);, ponieważ i jest pętlą nad poziomem, a j pętlą do pionu.

+0

Po pomnożeniu liczby zmiennoprzecinkowej przez niepodpisany znak, kompilator zawsze będzie promował niepodpisany znak char na wartości zmiennoprzecinkowe. Ale nie pasuje do 8 bitów na końcu, a wartości ujemne są zdecydowanie problemem. – Dima

+0

powodem, dla którego r, g, b jest znakiem bez znaku, jest to, że funkcje GetRed/Green/Blue zwracają znak bez znaku. – bili