Поиск линии пикселей одного цвета C++

144
13 мая 2019, 23:10

Есть изображения(ровная прямая линия может быть в любой стороны):

Необходимо вычислить с какой стороны находиться эта прямая(условно) линия и повернуть изображение, чтобы она была ВНИЗУ. Пробовал искать наибольшую длину, когда пиксели идут друг за другом, но получается очень медленно, так как 4 цикла на каждую нужно.

            for (int X = 0; X < image.height()/2; X++) {
            for (int Y = 0; Y < image.width(); Y++) {
                if (QColor(image.pixel(X,Y)).name()=="#ffffff")
                {
                    int i = Y+1;
                    int max_buffer;
                    while(QColor(image.pixel(X,i)).name()=="#ffffff")
                    {
                        max_buffer++;
                        i++;
                    }
                    if(max_buffer>max_top)
                    {
                        max_top = max_buffer;
                    }
                }
            }
        }

Это цикл только для вверха, еще 3 для других сторон и затем сравнивать что больше и т.д. Читал, что можно методом квадратов это реализовать и сделать более оптимизировано. UPADETE:Изображение уже является бинарным(черно-белым, монохромным)!

Answer 1

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

Если направление среза произвольно, можно посчитать для изображения моменты Ху и оценить ориентацию. Иx вычисление есть, например, в OpenCV.

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

 ll sumx = 0;
 ll sumy = 0;
 ll sumv = 0;
 for (int y = 0; y < image.height(); y++) {
        for (int x = 0; x < image.width(); x++) {
            sumx += value[y][x] * x;
            sumy += value[y][x] * y;
            sumv += value[y][x];
        }
 }
 masscenterx = sumx / sumv;
 masscentery = sumy / sumv;
Answer 2

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

  1. Встаем на край изображения в середину грани (будет 4 случая - x=0, y=h/2; x=w, y=h/2; x=w/2, y=0; x=w/2, y=h, где w и h соответственно ширина и высота изображения), далее для простоты разбираем для первого случая
  2. Движемся в центр изображения (в рассматриваемом случае в сторону увеличения x) и ищем белый пиксель
  3. Когда белый пиксель найден, проходим от 0 до высоты картинки по найденной x белого пикселя и считаем количество белых пикселей на этой линии, запоминаем.

Повторяем аналогично для четырех граней, искомая плоская грань соответствует той, где найденное количество белых пикселей максимальной.

Изображение для наглядности алгоритма:

Добавлю, что у вас очень большой оверхед на сравнение цвета, сначала конвертация в QColor, потом конвертация в QString и потом сравнение строк. Я бы навскидку написал что-нибудь типа

QRgb pixel = image.pixel(X, Y);
if (qRed(pixel) == 255 && qGreen(pixel) == 255 && qBlue(pixel) == 255)
    ...

З.Ы. Немного подумал, по идее алгоритм устойчив к небольшому повороту изображения, но надо потестировать

З.Ы.Ы. Есть второй вариант алгоритма, можно посчитать набор расстояний от края картинки до первого встреченного белого пикселя, на какой грани разница между этими расстояниями будет минимальна, та грань является искомой. Какой из двух вариантов оптимальнее, предположить не могу, надо тестировать.

READ ALSO
Ошибка: метод не определен в классе

Ошибка: метод не определен в классе

Есть два Java файла с одного пакетаПри при использование метода выдает ошибку "The method Print(String) is undefined for the type Hello"

158
Как работают синглтоны Java?

Как работают синглтоны Java?

Читая книгу "Программирование под Android" Брайна Харди, я столкнулся со следующим кодомСуществует класс синглтон:

119
Тест на javarush.net -застрял

Тест на javarush.net -застрял

Вроде все верно, но что-то не такЗадача на английском закоментирована в коде

149
ResourceMap в java

ResourceMap в java

В интернете не нашел ни описания, ни документации этой функцииЧто она делает? И есть ли другие аналоги ResourceMap? Например, я где то слышал что...

117