2011-09-16 18 views
7

我正在閱讀Gonzalez和Woods的DIP第2版,並嘗試使用wxImage來處理拉普拉斯面具(第129頁& 130)。implement laplacian 3x3

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

這裏是處理循環:

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

我申請的是到北極的圖片(灰色圖像)和我得到的是黑色和白色像素的斑點!

任何想法,我可能錯過了什麼for循環?

編輯1:終於看到周圍的谷歌後得到的答案。這dsp的東西絕對是棘手的!我添加到上面的代碼中,它會銳化圖像。

乾杯

+0

這將是一個很好的問題dsp.stackexchange.com – Dima

回答

5

首先,拉普拉斯算子的卷積結果可能具有負值。考慮一個值爲1的像素,它被0包圍。該像素卷積的結果將是-8。其次,結果範圍將在[-8 * 255,8 * 255]之間,這絕對不適合8位。從本質上講,當你進行範圍檢查時,你正在失去大部分信息,並且大多數結果像素最終會變爲0或者255.

你需要做的是將結果存儲在一個數組中類型是有符號的,並且足夠寬以處理範圍。然後,如果您希望輸出8位圖像,則需要重新調整值,以使-8 * 255映射到0,並將8 * 255映射到255.或者,您可以重新調整它以使最小值映射到0,最大值映射到255

編輯:在這種特殊情況下,你可以做到以下幾點:

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

其簡化爲

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

這RTOTAL映射到範圍介於0到255之間而不截斷。您應該對gtotalbtotal也這樣做。

+0

感謝您的回答。但我不明白的是,當我做鄰居計算然後將它存儲到r/g/btotal這是一個浮點值它應該足夠大嗎?就我所知,一個鄰居最大值可以是8 * 255或-8 * 255,就像你上面說的那樣,它是( - )2040 * 9(九個鄰居在一起)=( - )18360。我在C++中查找float範圍,它說float的範圍是7digits。但是,現在我完全明白爲什麼我有一個白色和黑色像素的大博客是因爲我錯過了其他計算。見我的版OP。謝謝! – bili

+0

您使用r/g/btotal的float值的事實很好。當你將r/g/btotal的值截斷到0到25​​5之間時,會發生問題。而不是將0以下的所有內容都設置爲0,並且255以上的所有內容都應該是255。您正在截斷範圍,而您應該壓縮範圍。 – Dima

+0

是的,我現在明白了。我應該縮放值而不是截斷它。 tyvm! – bili

1

你不應該由在掩模的像素數計算的加權和,從而產生一個加權平均後分?如果沒有這個,九個像素值的總和(即使乘以不太亮的掩碼值)將很容易超過255.

+2

掩碼矩陣中的值的總和爲零,所以不會有任何會導致溢出的整體增益。儘管如此,在中間計算中您需要注意使用更大類型的數據,否則在計算總和時可能會溢出8位數值。對於每個像素,拉普拉斯算子用其所有鄰居的總和減去原始像素值的八倍來取代它,這是一種差異化操作。它用於邊緣檢測。 –

+0

謝謝。我現在會研究它。 – bili

+0

@Jason R:做出答案 - 我想這正是發生在這裏的事情。 –

2

我認爲你的問題是,r,g和b是unsigned int類型,你正在使用哪種編譯器以及它是如何優化的,你可以隱式地將它們轉換爲浮點數rtotal += r* kernel[y+1][x+1];等等。但是如果編譯器的轉換與你的期望不同,那麼計算中間值將不起作用,因爲unsigned int不能爲負數。

解決方案:將r,g和b更改爲float。

它不會有任何區別,但r = Image->GetRed(i+y,j+x);行中有一個很小的錯誤,因爲我正在循環水平和j循環到垂直。

+0

當float乘以一個無符號字符時,編譯器將始終將unsigned char提升爲float。但最終不適合8位,負值肯定是問題。 – Dima

+0

r,g,b是unsigned char的原因是GetRed/Green/Blue函數返回無符號字符。 – bili