Исключая маленькие кусочки пикселей из Image .Net

У меня черное изображение с белыми линиями. Можно ли исключить куски белых пикселей, которые меньше определенного числа? Например: измените цвет фрагментов пикселей, которые сделаны с менее чем 10 пикселей с белого на черный. Исходное изображение:

Изображение на выходе (удаляются небольшие участки белых пикселей):

Сейчас я работаю с библиотекой AForge для C#, но способы решения этой проблемы в C++ также приветствуются (например, Open CV). Намек на то, как эта функциональность может быть названа, также приветствуется.

1 ответ

Не беспокоясь о ваших деталях, это кажется тривиально простым

  1. Используйте растровое изображение в 32 бита и используйте LockBits для получения строк развертки и прямого доступа указателя к массиву.
  2. Сканирование каждого пикселя с 2 для петель
    • Каждый раз, когда вы найдете тот, который соответствует вашему целевому цвету, отсканируйте влево, вправо и вверх и вниз (X) Количество пикселей, чтобы определить, соответствует ли оно вашим требованиям,
    • Если это так, оставьте пиксель, если не измените его.
    • если вам нужна более высокая скорость, вы можете использовать все это в параллельной рабочей нагрузке, также, возможно, вы могли бы сделать больше с массивом масок, чтобы избавить вас от исследования мертвых путей (просто мысль)

Обратите внимание, очевидно, вы можете немного поумнеть

Exmaple

// lock the array for direct access
var bitmapData = bitmap.LockBits(Bounds, ImageLockMode.ReadWrite, Bitmap.PixelFormat);
// get the pointer
var  scan0Ptr = (int*)_bitmapData.Scan0;
// get the stride
var  stride = _bitmapData.Stride / BytesPerPixel;

// local method
void Workload(Rectangle bounds)
{
   // this is if synchronous, Bounds is just the full image rectangle
   var rect = bounds ?? Bounds; 
   var white = Color.White.ToArgb();
   var black = Color.Black.ToArgb();

   // scan all x
   for (var x = rect.Left; x < rect.Right; x++)
   {
      var pX = scan0Ptr + x;

      // scan all y
      for (var y = rect.Top; y < rect.Bottom; y++)
      {            
         if (*(pX + y * stride ) != white)
         {
            // this will turn it to monochrome
            // so add your threshold here, ie some more for loops
            //*(pX + y * Stride) = black;
         }
      }
   }
}

// unlock the bitmap
bitmap.UnlockBits(_bitmapData);

Чтобы распараллелить

Вы можете использовать что-то вроде этого, чтобы разбить ваше изображение на более мелкие регионы

public static List<Rectangle> GetSubRects(this Rectangle source, int size)
{
   var rects = new List<Rectangle>();

   for (var x = 0; x < size; x++)
   {
      var width = Convert.ToInt32(Math.Floor(source.Width / (double)size));
      var xCal = 0;

      if (x == size - 1)
      {
         xCal = source.Width - (width * size);
      }
      for (var y = 0; y < size; y++)
      {

         var height = Convert.ToInt32(Math.Floor(source.Height / (double)size));
         var yCal = 0;

         if (y == size - 1)
         {
            yCal = source.Height - (height * size) ;
         }

         rects.Add(new Rectangle(width * x, height * y, width+ xCal, height + yCal));
      }
   }

   return rects;
}

И это

private static void DoWorkload(Rectangle bounds, ParallelOptions options, Action<Rectangle?> workload)
{
   if (options == null)
   {
      workload(null);
   }
   else
   {
      var size = 5 // how many rects to work on, ie 5 x 5
      Parallel.ForEach(bounds.GetSubRects(size), options, rect => workload(rect));
   }
}

использование

DoWorkload(Bounds, options, Workload);
Другие вопросы по тегам