Алгоритм обнаружения пробелов в краях c # GDI - PullRequest
7 голосов
/ 01 февраля 2009

Я ищу решение для обнаружения граничных пробелов растрового изображения c # из библиотеки C # управляемого GDI +.

Изображения будут либо прозрачными , либо белыми , большинство изображений с разрешением 400x имеют разрешение 8000x8000 пикселей с пробелами около 2000 пикселей по краям.

Какой самый эффективный способ определения ребер, x, y, координаты высоты и ширины ? Я пытался идти пиксель за пикселем, но это было очень медленно.

Обновление до решения - добавлены левые / правые / верхние / нижние границы

Проблемы с изображениями по центру изображения, теперь обрезка любых прозрачных (0%) или белых (#FFFFFF) пикселей.

var top = bitmap.Height;
var left = bitmap.Width;
var right = 0;
var bottom = 0;

...

var pData = pData0 + (y * data.Stride) + (x * 4);
var xyAlpha = pData[3];
var xyBlue = pData[0];
var xyGreen = pData[1];
var xyRed = pData[2];
if ((xyAlpha > 0) || (xyRed != 255 && xyGreen != 255 && xyBlue != 255)) {
    if (y < top)
        top = y;
    if (y > bottom)
        bottom = y;
    if (x < left)
        left = x;
    if (x > right)
        right = x;
}

...

var cropWidth = right - left;
var cropHeight = bottom - top;
var cropX = top;
var cropY = left;

var cacheBitmap = new Bitmap(cropWidth, cropHeight, PixelFormat.Format32bppArgb);
using (var cacheGraphics = Graphics.FromImage(cacheBitmap)) {
    cacheGraphics.DrawImage(context.Image, new Rectangle(0, 0, cropWidth, cropHeight), cropX, cropY, cropWidth, cropHeight, GraphicsUnit.Pixel);
}

Ответы [ 2 ]

9 голосов
/ 01 февраля 2009

Отличным ресурсом GDI + является Боб Пауэллс GDI + FAQ !

Вы не сказали, как вы получили доступ к пикселям на изображении, поэтому я предполагаю, что вы использовали медленные методы GetPixel. Вы можете использовать указатели и LockBits для более быстрого доступа к пикселям: см. Объяснение Боба Пауэллса о LockBits - Для этого потребуется небезопасный блок кода - если вы не хотите этого или у вас нет FullTrust, вы можете воспользоваться трюком, объясненным здесь: Обработка изображений без указателей в .NET от J. Dunlap

Приведенный ниже код использует подход LockBits (для PixelFormat.Format32bppArgb) и заполнит начальную и конечную точки значением, в котором обнаружены первый и последний пиксели изображения, которые не имеют цвета, описанного в цвете аргумента. , Этот метод также игнорирует полностью прозрачные пиксели, что полезно, если вы хотите определить область изображения, где начинается видимый «контент».

    Point start = Point.Empty;
    Point end = Point.Empty;

    int bitmapWidth = bmp.Width;
    int bitmapHeight = bmp.Height;

    #region find start and end point
    BitmapData data = bmp.LockBits(new Rectangle(0, 0, bitmapWidth, bitmapHeight), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
    try
    {
        unsafe
        {
            byte* pData0 = (byte*)data.Scan0;
            for (int y = 0; y < bitmapHeight; y++)
            {
                for (int x = 0; x < bitmapWidth; x++)
                {
                    byte* pData = pData0 + (y * data.Stride) + (x * 4);

                    byte xyBlue = pData[0];
                    byte xyGreen = pData[1];
                    byte xyRed = pData[2];
                    byte xyAlpha = pData[3];


                    if (color.A != xyAlpha
                            || color.B != xyBlue
                            || color.R != xyRed
                            || color.G != xyGreen)
                    {
                        //ignore transparent pixels
                        if (xyAlpha == 0)
                            continue;
                        if (start.IsEmpty)
                        {
                            start = new Point(x, y);
                        }
                        else if (start.Y > y)
                        {
                            start.Y = y;
                        }
                        if (end.IsEmpty)
                        {
                            end = new Point(x, y);
                        }
                        else if (end.X < x)
                        {
                            end.X = x;
                        }
                        else if (end.Y < y)
                        {
                            end.Y = y;
                        }
                    }
                }
            }
        }
    }
    finally
    {
        bmp.UnlockBits(data);
    }
    #endregion
2 голосов
/ 01 февраля 2009

Сначала я бы удостоверился, что использовал метод LockBits, описанный Патриком. Во-вторых, я бы проверил пиксели на средних линиях, чтобы быстро определить края. Под средними линиями я подразумеваю, например, если вы скажете, например, изображение 2000x1000, вы сначала посмотрите на горизонтальную линию № 500 (из 1000), чтобы найти левую и правую границы, а затем вдоль вертикальной линии № 1000 (из 2000). найти верхний и нижний пределы. Так должно быть очень быстро.

...