2015-09-08 1 views
1

Вот функция, которая принимает прозрачное и белое изображение и пытается превратить его в массив bool.Почему этот черно-белый растровый рисунок в Bool Array создает правильные изображения, но устанавливает неправильное количество bools (C#)

Мой блок-код дает мне 2 изображения, которые я ожидал бы (см. Ниже), но «numberOfMasked» всегда выше, чем я ожидаю. Например, если «maskBuffer» имеет один отмеченный пиксель (см. Ниже mask_image_test.bmp), то хотя «mask_bool_test70.bmp») создает изображение с отмеченным одним пикселем. По какой-то причине фактическое количество балов, отмеченных как истинное, намного выше и, по-видимому, случайное. Я видел, что он варьируется от 25 до 70.

public static bool[] ConvertImageToBoolAray(Bitmap maskbuffer) 
    { 
     bool[] mask = null; 
     int w = maskbuffer.Width; 
     int h = maskbuffer.Height; 

     #region unit_test 
      maskbuffer.Save("mask_image_test.bmp"); 
     #endregion 

     lock (maskbuffer) 
     { 
      BitmapData bmpData = maskbuffer.LockBits(new Rectangle(0, 0, w, h), 
       ImageLockMode.ReadOnly, 
       PixelFormat.Format8bppIndexed); 

      const int numBmpChannel = 1; 
      int maskIndex = 0; 
      int bmpIndex = 0; 

      unsafe 
      { 

       byte* pixels = (byte*) bmpData.Scan0; 
       int numPixels = w*h; 

       mask = new bool[numPixels]; 

       for (; 
        maskIndex < numPixels; 
        bmpIndex += numBmpChannel, maskIndex++) 
       { 
        byte red = pixels[bmpIndex]; 
        bool masked = red != 0; 
        mask[maskIndex] = masked; 
       } 

      } 
      maskbuffer.UnlockBits(bmpData); 
     } 

     #region unit_test 
      byte[] boolAsByte = Array.ConvertAll(mask, b => b ? (byte)1 : (byte)0); 
      Bitmap maskBitmap = GLImageConvertor.ConvertByteBufferToBitmap(boolAsByte, w, h, PixelFormat.Format8bppIndexed); 
      int numberOfMasked = mask.Count(b => b); 
      maskBitmap.Save("mask_bool_test" + numberOfMasked + ".bmp"); 
     #endregion 


     return mask; 
    } 

У кого-нибудь есть идеи для этого странного поведения?

Отладка показывает, что в «пиксельной» памяти есть фрагменты байтов, которые я бы не ожидал, я ожидал бы, что один байт установлен в «FF», но вместо этого у меня есть случайные части данных.

mask_image_test.bmp:

mask_image_test.bmp

mask_bool_test70.bmp:

mask_bool_test70.bmp

+0

ли вы отладки это? – nvoigt

+0

Да, извините, я должен был добавить более подробно, сделаю – chrispepper1989

ответ

1

Там разница между Stride и Width, которые вы должны рассмотреть в вашем алгоритме.

Шаг - это ширина одного ряда пикселей (строка развертки), округленная до четырехбайтовой границы.

Поскольку 70 не делится на 4, есть некоторые запасные пиксели, возможно заполненные случайными данными.

Вам нужно что-то вроде

int count = 0; 
int stride = bmpData.Stride; 

for (int column = 0; column < bmpData.Height; column++) 
{ 
    for (int row = 0; row < bmpData.Width; row++) 
    { 
     red = pixels[(column * stride) + (row * 3) + 2]); 
    } 
} 
+0

проклятье! Я знал, что это просто! Я полностью забыл о шаге! – chrispepper1989

+0

Я добавил свою версию ниже, из интереса, почему вы добавляете 2? Я предполагаю, что вы * 3 должны учитывать возможные изображения RGB? в моем случае это одноканальное изображение – chrispepper1989

+1

@ chrispepper1989: да, это правда, я принял изображение RGB - вероятно, я недостаточно читал ваш код. Красный находится на +2, G при +1 и B при +0.Спасибо за отправку собственного ответа. Это может помочь другим. –

1

Как Томас отметил, что я не принимая во внимание походкой! Не думал, что C# будет собирать лишние байты в растровом изображении. Но, конечно же, в этом случае ширина! = Шаг (ширина 111, а шаг 112). Я решил написать простой вариант, который позволяет избежать необработанный буфер полностью, чтобы избежать липких проблем (и я не мог быть обеспокоен с использованием буфера больше)

public static bool[] ConvertImageToBoolAray(Bitmap maskbuffer) 
    { 
     bool[] mask = null; 
     int w = maskbuffer.Width; 
     int h = maskbuffer.Height; 

     #region unit_test 
     //maskbuffer.Save("mask_image_test.bmp"); 
     #endregion 

     lock (maskbuffer) 
     { 
      int numPixels = w * h; 
      mask = new bool[numPixels]; 

      for (int y = 0; y < maskbuffer.Height; ++y) 
      { 
       for (int x = 0; x < maskbuffer.Width; ++x) 
       { 
        Color color = maskbuffer.GetPixel(x, y); 
        int index = x + (y*maskbuffer.Width); 
        mask[index] = color.A != 0; 
       } 
      } 
     } 

     #region unit_test 
     //byte[] boolAsByte = Array.ConvertAll(mask, b => b ? (byte)1 : (byte)0); 
     // Bitmap maskBitmap = GLImageConvertor.ConvertByteBufferToBitmap(boolAsByte, w, h, PixelFormat.Format8bppIndexed); 
     // int numberOfMasked = mask.Count(b => b); 
     // maskBitmap.Save("mask_bool_test" + numberOfMasked + ".bmp"); 
     #endregion 


     return mask; 
    } 

Если кто-то хочет, чтобы отправить правильный сырец версию буфера, пожалуйста идти вперед, и я буду отмечать ваш как лучший ответ.

--- Update --- добавлена ​​переработанная версия, чтобы использовать буфер непосредственно

private static bool[] ConvertImageToBoolArayUnsafe(Bitmap maskbuffer) 
    { 
     bool[] mask = null; 
     int w = maskbuffer.Width; 
     int h = maskbuffer.Height; 

     #region unit_test 
      //maskbuffer.Save("mask_image_test.bmp"); 
     #endregion 

     lock (maskbuffer) 
     { 
      BitmapData bmpData = maskbuffer.LockBits(new Rectangle(0, 0, w, h), 
       ImageLockMode.ReadOnly, 
       PixelFormat.Format8bppIndexed); 


      int stride = bmpData.Stride; 
      unsafe 
      { 

       byte* pixels = (byte*) bmpData.Scan0; 


       mask = new bool[w * h]; 

       for (int y = 0; y < h; ++y) 
       { 
        for (int x = 0; x < w; ++x) 
        { 
         int imageIndex = x + (y * stride); 
         byte color = pixels[imageIndex]; 
         int maskIndex = x + (y * w); 
         mask[maskIndex] = color != 0; 
        } 
       } 

      } 
      maskbuffer.UnlockBits(bmpData); 
     } 

     #region unit_test 
      // byte[] boolAsByte = Array.ConvertAll(mask, b => b ? (byte)1 : (byte)0); 
      // Bitmap maskBitmap = GLImageConvertor.ConvertByteBufferToBitmap(boolAsByte, w, h, PixelFormat.Format8bppIndexed); 
      // int numberOfMasked = mask.Count(b => b); 
      // maskBitmap.Save("mask_bool_test" + numberOfMasked + ".bmp"); 
     //check equality to safe version (as that is correct) 
     #endregion 


     return mask; 
    } 
+1

GetPixel() очень медленный ... Вместе с Parallel.For я достиг 100-го улучшения производительности –

+0

избили меня тоже, я просто писал его :) good show sir – chrispepper1989

+0

Я удивлен, что параллель для этого полезна в этом случае, думал бы, что массив не будет потокобезопасным. – chrispepper1989