Исключая маленькие кусочки пикселей из Image .Net
У меня черное изображение с белыми линиями. Можно ли исключить куски белых пикселей, которые меньше определенного числа? Например: измените цвет фрагментов пикселей, которые сделаны с менее чем 10 пикселей с белого на черный. Исходное изображение:
Изображение на выходе (удаляются небольшие участки белых пикселей):
Сейчас я работаю с библиотекой AForge для C#, но способы решения этой проблемы в C++ также приветствуются (например, Open CV). Намек на то, как эта функциональность может быть названа, также приветствуется.
1 ответ
Не беспокоясь о ваших деталях, это кажется тривиально простым
- Используйте растровое изображение в 32 бита и используйте LockBits для получения строк развертки и прямого доступа указателя к массиву.
- Сканирование каждого пикселя с 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);