#c_sharp #net #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; }
Ответы
Ответ 1
GetPixel — это очень медленная функция. Всегда используйте LockBits и вручную проходитесь по байтам, особенно если обрабатываете большие области. В качестве альтернативы могу предложить сделать битмапы с бинарными масками ваших двух картинок. На третьем битмапе размером min(b1.width, b2.width) x min(b1.height, b2.height) совместить общую область картинок в режиме AND. Потом пройтись по данным с помощью LockBits и проверить, есть ли хоть какое-то пересечение. Будет ли второй способ быстрее — не знаю, нужно мерять. Он может быть быстрее за счёт оптимизаций в железе/оси, потому что совмещение картинок может быть более быстрым. Ещё один вариант — построить границы в виде многоугольников и искать пересечение, соответственно, многоугольников.Ответ 2
Сравнение с -1 какое-то странное - не понял, чего ты хочешь этим добиться. А по теме - использование GetPixel - это очень медленная операция. Надо делать LockBits, брать Scan0, превращать данные в массив и работать с этим массивом. Ну и не забыть UnlockBits :)Ответ 3
Вам нужен RectangleF и его метод IntersectsWith.
Комментариев нет:
Отправить комментарий