2013-02-12 6 views
3

Так что я использую WriteableBitmapEx для приложения в Windows RT. Я пытаюсь реализовать обнаружение краев на изображении с помощью оператора sobel. Я успешно применил оба ядра для обнаружения x и y на изображении с помощью .Convolute(), но теперь я застрял, добавляя оба изображения к одному. Проблема заключается в том, что все пиксели обоих изображений имеют значение 0 для прозрачности (поэтому A в ARGB). Я могу отображать оба изображения самостоятельно без проблем, но добавление их дает мне просто черную картинку. Итак, мои вопросы:Оператор Sobel & Convolution с 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

Свертка применяется ко всем доступным каналам. Обработаны не только красные, зеленые и синие (которые вы хотите в этом случае), но также и альфа-канал. Это приводит к альфа-значению нуля (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 

Технически это все хорошо, он не обнаруживает каких-либо краев над альфа-каналом. Однако функционально это не то, что вы хотите в этом случае. Если это поведение нежелательно, вы можете пропустить обработку альфа-канала (если источник позволяет вам) или сбросить альфа-значение до 255.

Я собираюсь рассказать о черном изображении, которое будет отображаться на экране, потому что у меня нет опыта использования технологии. Многие фреймворки сначала возвращают изображение в сплошной цвет (если в этом случае он черный). Это необходимо, чтобы предыдущее изображение не пробивалось, если вы имеете дело с прозрачными изображениями (или его частями). Добавление свернутого (прозрачного) изображения на этот сплошной цвет приведет к тому же сплошному цвету. Поэтому изображение будет показано черным.

Примечание: combosobel использует все каналы, но так как раньше он был преобразован в оттенки серого, вы можете оптимизировать создание цветов.

0

есть 2 проблемы в вашем коде:

1) Я попробовал и свернутый метод не работает для меня - это просто создает пустое изображение. Наверное, это не твоя вина. Когда вы объединяете 2 пустых изображения, вы получаете пустой.

2) Существует проблема с вашей комбинацией. Вы можете установить прозрачность до 255 без известково квадратный корень, как вы делаете на г, г, б

надеюсь, что это помогает

1

Есть ли лучший способ объединения двух изображений? Blit unfortunatley, похоже, не поддерживает этот тип добавления пикселей. Но ForEach действительно медленный ...

Вы должны использовать небезопасный код по этой причине, проверьте это: Why is my unsafe code block slower than my safe code?

По вопросу о скорости, подумайте о том, что вы называете 16 функций (4xMath.Min, 4xMath.Pow, 4xMath.Sqrt) для каждого пикселя. Это огромные накладные расходы.

Пиксельные значения находятся в диапазоне [0,255] Math.Pow ([0,255], 2) + Mat.Pow ([0,255], 2) приводит к диапазону [0,2 * Math.Pow (255,2)] => [0130 050] Я хотел бы построить таблицу поиска, как это:

byte[] LUT4Sqrt = new byte[130051]; 

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

просмотра таблицы для Math.pow может быть сделана слишком.