Как определить, где заканчивается изображение? - PullRequest
0 голосов
/ 01 марта 2019

Я получаю изображения одинакового размера, но с разным количеством информации.Примеры ниже (красные границы - мои).Фон всегда белый.

Я пытаюсь определить, где заканчивается информация на изображении - на какой высоте пикселя (и обрезать соответственно).Другими словами, найдите первый небелой пиксель снизу.

Есть ли лучший способ сделать это, кроме извлечения BitmapData из объекта Image и прохождения по всем пикселям?

enter image description here enter image description here

Ответы [ 2 ]

0 голосов
/ 01 марта 2019

Просто добавьте предложение, просмотрев ваши изображения и ваше решение (ниже), и ваш метод в порядке, но вы можете повысить эффективность.

Чем больше вы знаете о своем изображении, тем лучше;вы уверены, что фон всегда белый (согласно вашему сообщению, код является более общей утилитой, но следующее предложение все еще может работать);Можете ли вы быть уверены, что самая дальняя точка в небелом пикселе будет найдена , если строка не пуста?

Например;в ваших двух изображениях самый длинный не белый пиксель в строке составляет около 60 пикселей. Если это универсально верно для ваших данных, вам не нужно сканировать всю строку изображения, что сделает цикл for:

   for (int y = bitmap.Height - 1; y >= 0; y--) {
        for (int x = 0; x < 60; x++) {
            Color color = bitmap.GetPixel(x, y);
            if (color.R != backColor.R || color.G != backColor.G || color.B != backColor.B) {
                foundContentOnRow = y;
                break;
            }
        }
    }

(Вы можете сделать это параметром в функции, чтобы вы могли легко управлять им при необходимости).

Представьте, например, что первая не белая строка была на 80 пикселей ниже.Чтобы найти его в настоящее время, вы делаете 640 x 300 = 192 000 проверок.Если бы вы могли с уверенностью сказать, что вы знаете, что строка пуста в пределах 100 пикселей (завышенная оценка на основе представленных данных), то это будет 100 * 300 = 30 000 проверок на изображение.

Если вы всегда знали,что первые 10 пикселей изображения всегда были пустыми, вы могли бы немного побриться (скажем, 3000 проверок).

Обдумав настройку, в которой вы знали, что первый небелой пиксель был между 10 и 60в пикселях (диапазон 50) вы можете найти его в строке 80 в 50 x 300 = 15 000 проверок, что является хорошим сокращением.

Конечно, обратная сторона предположений состоит в том, что, если что-то изменится, ваши предположения могут оказаться недействительными, но если данные останутся довольно постоянными, это может быть полезно, особенно если вы делаете это для большого количества изображений.

0 голосов
/ 01 марта 2019

В итоге я использовал следующий код для обрезки изображения.Надеюсь, кто-то найдет это полезным.

class Program {
    static void Main(string[] args) {
        Image full = Image.FromFile("foo.png");
        Image cropped = full.TrimOnBottom();
    }
}

public static class ImageUtilities {
    public static Image TrimOnBottom(this Image image, Color? backgroundColor = null, int margin = 30) {
        var bitmap = (Bitmap)image;
        int foundContentOnRow = -1;

        // handle empty optional parameter
        var backColor = backgroundColor ?? Color.White;

        // scan the image from the bottom up, left to right
        for (int y = bitmap.Height - 1; y >= 0; y--) {
            for (int x = 0; x < bitmap.Width; x++) {
                Color color = bitmap.GetPixel(x, y);
                if (color.R != backColor.R || color.G != backColor.G || color.B != backColor.B) {
                    foundContentOnRow = y;
                    break;
                }
            }

            // exit loop if content found
            if (foundContentOnRow > -1) {
                break;
            }
        }

        if (foundContentOnRow > -1) {
            int proposedHeight = foundContentOnRow + margin;

            // only trim if proposed height smaller than existing image
            if (proposedHeight < bitmap.Height) {
                return CropImage(image, bitmap.Width, proposedHeight);
            }
        }

        return image;
    }

    private static Image CropImage(Image image, int width, int height) {
        Rectangle cropArea = new Rectangle(0, 0, width, height);
        Bitmap bitmap = new Bitmap(image);
        return bitmap.Clone(cropArea, bitmap.PixelFormat);
    }
}
...