Страницы

Поиск по вопросам

вторник, 19 марта 2019 г.

Перекрытие изображений Bitmap

Есть два Bitmap'а с произвольными изображениями на белом фоне. Нужно узнать, перекрываются ли эти изображения?
Вариант решения - сравнивать изображения по пикселям. Если пиксели с одинаковыми "координатами" заполнены на обоих рисунках, то изображения перекрываются.
static bool IsBitmapsIntersect(Bitmap bitmap1, Bitmap bitmap2) { for (var i = 0; i < Math.Min(bitmap1.Width, bitmap2.Width); i++) { for (var j = 0; j < Math.Min(bitmap1.Height, bitmap2.Height); j++) { if (bitmap1.GetPixel(i, j).ToArgb() != -1 && bitmap2.GetPixel(i, j).ToArgb() != -1) { return true; } } }
return false; }
Есть ли какие-нибудь более быстрые/правильные решения этой задачи?
UPD
Воспользовался советом @Discord. В итоге сделал обертку над Bitmap и GetPixel:
class BitmapInfo { private readonly byte[] _argbBytes;
private readonly int _pixelSize;
private readonly int _stride;
private readonly int _width;
private readonly int _height;
public BitmapInfo(Bitmap bitmap) { var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
_stride = Math.Abs(bitmapData.Stride); _argbBytes = new byte[_stride * bitmapData.Height]; Marshal.Copy(bitmapData.Scan0, _argbBytes, 0, _argbBytes.Length);
bitmap.UnlockBits(bitmapData);
_width = bitmap.Width; _height = bitmap.Height;
_pixelSize = Image.GetPixelFormatSize(bitmap.PixelFormat) / 8; }
public int Width { get { return _width; } }
public int Height { get { return _height; } }
public int GetPixel(int x, int y) { var startIndex = x * _stride + y * _pixelSize; int result = 0;
for (var i = _pixelSize - 1; i >= 0; i--) { result <<= 8; result |= _argbBytes[startIndex + i]; }
return result; } }
static bool IsBitmapsIntersect2(Bitmap bitmap1, Bitmap bitmap2) { var bitmapInfo1 = new BitmapInfo(bitmap1); var bitmapInfo2 = new BitmapInfo(bitmap2);
for (var i = 0; i < Math.Min(bitmapInfo1.Width, bitmapInfo2.Width); i++) { for (var j = 0; j < Math.Min(bitmapInfo1.Height, bitmapInfo2.Height); j++) { if (bitmapInfo1.GetPixel(i, j) != -1 && bitmapInfo2.GetPixel(i, j) != -1) { return true; } } }
return false; }


Ответ

GetPixel — это очень медленная функция. Всегда используйте LockBits и вручную проходитесь по байтам, особенно если обрабатываете большие области.
В качестве альтернативы могу предложить сделать битмапы с бинарными масками ваших двух картинок. На третьем битмапе размером min(b1.width, b2.width) x min(b1.height, b2.height) совместить общую область картинок в режиме AND. Потом пройтись по данным с помощью LockBits и проверить, есть ли хоть какое-то пересечение.
Будет ли второй способ быстрее — не знаю, нужно мерять. Он может быть быстрее за счёт оптимизаций в железе/оси, потому что совмещение картинок может быть более быстрым.
Ещё один вариант — построить границы в виде многоугольников и искать пересечение, соответственно, многоугольников.

Комментариев нет:

Отправить комментарий