Есть два 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 и проверить, есть ли хоть какое-то пересечение.
Будет ли второй способ быстрее — не знаю, нужно мерять. Он может быть быстрее за счёт оптимизаций в железе/оси, потому что совмещение картинок может быть более быстрым.
Ещё один вариант — построить границы в виде многоугольников и искать пересечение, соответственно, многоугольников.
Комментариев нет:
Отправить комментарий