2013-02-12 51 views
3

因此,我使用WriteableBitmapEx作爲Windows RT上的應用程序。我試圖用sobel操作符在圖像上實現邊緣檢測。我使用.Convolute()成功地將兩個內核用於x和y檢測到圖像上,但現在我堅持將兩個圖像添加到一個。 問題是,這兩個圖像的所有像素似乎都具有透明度值0(所以ARGB中的A)。我可以在沒有問題的情況下自行顯示這兩個圖像,但添加它們只會給我一張黑色圖片。 所以我的問題是:Sobel operator&Convolution with WriteableBitmapEx

  • 爲什麼卷積後的每個像素的透明度設置爲0?
  • 爲什麼我仍然可以顯示圖像而不是全黑?
  • 爲什麼當我添加兩個圖像時是黑色的?
  • 有沒有更好的方法來組合兩個圖像? Blit unfortunatley似乎不支持這種像素添加。但ForEach真的很慢...

爲了驗證,這裏是我的代碼到目前爲止。我可以同時顯示wbmpY和wbmpX,但是finalbmp完全是黑色的。

public int[,] sobelY = new int[3, 3] { { 1, 2, 1 }, { 0, 0, 0 }, { -1, -2, -1 } }; 
    public int[,] sobelX = new int[3, 3] { { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 } }; 

    public void trim(WriteableBitmap wbmp) 
    { 
     var graybmp = wbmp.Clone(); 
     graybmp.ForEach(toGrayscale); 

     var wbmpY = graybmp.Clone(); 
     var wbmpX = graybmp.Clone(); 

     wbmpY = wbmpY.Convolute(sobelY, 1, 0); 
     wbmpX = wbmpX.Convolute(sobelX, 1, 0); 

     var finalbmp = combineSobel(wbmpX, wbmpY);   
    } 

    public WriteableBitmap combineSobel(WriteableBitmap img, WriteableBitmap img2) 
    { 
     int height = img.PixelHeight; 
     int width = img.PixelWidth; 
     WriteableBitmap result = img.Clone(); 
     for (int x = 0; x < width; x++) 
     { 
      for (int y = 0; y < height; y++) 
      { 
       Color imgColor = img.GetPixel(x, y); 
       Color img2Color = img2.GetPixel(x, y); 
       Color newColor = Color.FromArgb(
        Math.Min((byte)Math.Sqrt(Math.Pow(imgColor.A, 2) + Math.Pow(img2Color.A, 2)), (byte)255), 
        Math.Min((byte)Math.Sqrt(Math.Pow(imgColor.R, 2) + Math.Pow(img2Color.R, 2)), (byte)255), 
        Math.Min((byte)Math.Sqrt(Math.Pow(imgColor.G, 2) + Math.Pow(img2Color.G, 2)), (byte)255), 
        Math.Min((byte)Math.Sqrt(Math.Pow(imgColor.B, 2) + Math.Pow(img2Color.B, 2)), (byte)255) 
       ); 

       result.SetPixel(x, y, newColor); 
      } 
     } 
     return result; 
    } 

回答

2

卷積適用於所有可用的通道。不僅紅色,綠色和藍色(這是你想要在這種情況下)處理,但也是alpha通道。這會導致零值(100%透明)。請看下面的例子:

 
1 0 -1  255 255 255 
2 0 -2 over 255 255 255 
1 0 -1  255 255 255 
 
1*255 0*255 -1*255 255 0 -255 
2*255 0*255 -2*255 = 510 0 -510 
1*255 0*255 -1*255 255 0 -255 

2*255 + 510 + 3*0 - 2*255 - 510 = 0 for all pixels 

技術上說,這一切都很好,它不會在alpha通道檢測到任何邊緣。但在功能上,這不是你想要的這種情況。如果不需要此行爲,則可以跳過處理Alpha通道(如果源允許),或者將alpha重設爲255。

我要推測將在屏幕上顯示的黑色圖像,因爲我沒有使用過的技術經驗。許多框架首先將圖像重置爲純色(假設在這種情況下它是黑色的)。這是必需的,以便在處理透明圖像(或其中的一部分)時先前的圖像不會流血。將複雜(透明)的圖像添加到此純色中,將產生相同的純色。因此,圖像將全部顯示爲黑色。

注意:combineSobel使用所有通道,但由於之前將其轉換爲灰度,因此可能需要優化顏色的創建。

0

有在你的代碼2個問題:

1)我想和迴旋的方法不適合我的工作 - 它只是創建一個空的圖像。我想這不是你的錯。當你合併2個空的圖像時,你會得到空的圖像。

2)你的聯合實施有一個小問題。您可以設置透明度爲255不開方計算,你的R,G做,B

希望這有助於

1

是否有合併兩種圖像的更好的辦法? Blit unfortunatley似乎不支持這種像素添加。但是ForEach真的很慢...

,您應該使用不安全的代碼,因此,檢查了這一點:Why is my unsafe code block slower than my safe code?

隨着速度的事情,想想你調用16個功能(4xMath.Min,4xMath.Pow,4xMath.Sqrt)爲每個像素。這是一個巨大的開銷。 Math.Pow([0,255],2)+ Mat.Pow([0,255],2)導致[0,2 * Math.Pow(0,255),2)的範圍中的像素值在[0,255] 的範圍內。 255,2)] => [0130 050] 我將構建的查找表是這樣的:

byte[] LUT4Sqrt = new byte[130051]; 

for (int i = 0; i < 130051; i++) 
{ 
    LUT4Sqrt[i] = (byte)(Math.Sqrt(i)); 
} 

爲Math.Pow查找表可太製成。