Pull to refresh

Comments 52

Приятно читать о CV, мало, кто этим занимается.

Не хотите опубликовать статью о багах в OpenCV? Я бы дополнил в комментах. Было бы полезно тем, кто только знакомится с либой, а то не ожидаешь вначале, что это возможно)
Я обычно EmguCV пользуюсь, на С++ не удобно всё таки разрабатывать.
А для тех кто с CV только знакомиться всё же есть шикарный robocraft.ru/page/opencv/, который закрывает 90% того, что нужно для первых 2-3 тестовых проектов.
Только хотел поблагодарить за отличный ресурс, как увидел, что у меня уже открыта одна из страниц с него: в Гугле наткнулся. Но всё равно спасибо: мог и не увидеть, что там целый курс.

А сам я начал изучать CV с locv.ru, тоже довольно полезный сайт.
О найденных в OpenCV багах вы всегда можете написать тут.
А для новичков(и не только) владеющих Аглийским есть такие ресурсы: docs.opencv.org, answers.opencv.org.
Я думаю, что речь не о багах как таковых, а об ошибках, которые можно допустить. Например с системой типов в OpenCV бывает на выходе получаешь очень странные артефакты, о которых лучше знать чем их дебажить.
эм… а можно поподробней, какого рода артефакты и когда выплывают?)
Чтобы не звучать голословным и сразу представить пример бага в одном маленьком кусочке кода:

Код
#include <cv.h>
#include <highgui.h>
using namespace cv;
using namespace std;
 
int main(int argc, char const *argv[])
{
  Mat test = imread("/home/igor/Downloads/Lenna.png", CV_LOAD_IMAGE_GRAYSCALE);
  Mat floatImage(test.size(), CV_32F);
  for (int r = 0; r < floatImage.rows; ++r)
  {
    for (int c = 0; c < floatImage.cols; ++c)
    {
      floatImage.at<int>(r, c) = test.at<int>(r, c);
    }
  }
  imwrite("test.png", floatImage);
  return 0;
}


Ожидаемый результат

Что получилось то получилось

И да, я понимаю почему так происходит. Это просто пример, как новичку запустить странный баг в свой год.
Результат бывает выглядит даже еще более причудливо. Когда, к примеру, картинка сохранятся, но записывается в каждый третий пиксель изображения из-за разницы в размере типов.
Ябы сказал, что это скорей один из способов выстрелить себе в ногу разрабатывая на C++, чем баг библиотеки. Но если у вас есть идеи как это реализовать более красиво, вы можете сделать Pull Request в OpenCV и он будет рассмотрен.
Да как бы претензий нет. Все довольно логично, но это некоторая особенность, о которой стоит знать заранее и тогда это сэкономит просто тьму времени. И я считаю, что лучше, чтобы типы были непривязаны к системе на которой запускается код, а потому и так сделано хорошо :)
Да и силенок у меня пока маловато, чтобы вот так сразу делать Pull Request в довольно устоявшуюся часть библиотеки.
А тайна того, что изображено на картинке с преобразованием Хафа, будет раскрыта в итоге?

Я бы предположил, что там пять пар горизонтальных линий. Пары эти равноудалены друг от друга. Но расстояние между линиями в каждой паре понемногу увеличивается сверху вниз. Но меня смущает то, что «ромбы» между яркими точками не черные, и самая нижняя яркая точка. Либо на исходном изображении есть еще что-то, либо я в чем-то неверно понял это преобразование…
Думаю, что там 5 длинных отрезков и один вдвое короче (отрезки выровнены по одному из краёв). Отрезки двойные, с разной толщиной линий (сплошной, толстый+тонкий, два одинаковых...) «Подвох», вероятно, в том, что нарисованы не y=a*x+b, а более логичные x*cos(a)+y*sin(a)=b.
Во второй сверху группе отрезков вообще три… Это какой-то штрих-код. И что-то ещё явно есть. Может быть, какая-нибудь тонкая рамка.
Обратное преобразование?
Ожидал чего-то попроще) Спасибо.
Второй вариант был ещё банальнее: кто-то в инете найдёт картинку поиском, я её не сам делал:)
Ага, с подвохом правильно угадали. Обычно считают именно x*cos(a)+y*sin(a)=b, так как там критической точки нет. Хотя я иногда и y=a*x+b делал, разбив пространство на два подпространства. Мне было лениво для скорости в очередной раз таблицу синусов-косинусов делать.
Плюсег кинуть не могу: я вам его уже давным-давно кинул:)
Очень хорошая статья, спасибо.
А для поиска номеров на автомобилях каким способом лучше пользоваться? Примитивами Хаара?
Преобразование Хафа, как мне кажется, не очень подходит, т.к. на большом изображении будет много «шумных» линий от очертаний домов, дороги, столбов, машин,…
Иногда для распознавания номеров используют feature detection + какойнибудь классификатор на них обученный(Latent SVM например).
Кстати, а вы случайно не знаете чего-нибудь про Latent SVM почитать? Я знаю, что он есть в OpenCV, но в мануалах про его структуру поверхностно написано, а в инете на его счет как-то мало описаний и неполные они.
Ну там основная идея в том, что процесс обучения у нас итеративный, при осуществлении которого мы фиксируем разные латентные переменные и решаем задачу квадратичного программирования. Вообще я особо не углублялся в его изучение, но насколько я могу судить — этот алгоритм является модификацией алгоритма MI-SVM о котором можно почитать например тут. А по самому Latent SVM можно почитать тут но я не уверен что это источник хороший.
Там два основных способа. Первый через Хаара, второй через поиск рамки контурным анализом. Зависит от того, есть ли у вас мощный ИК-прожектор в системе, или нет.
Тогда лучше всего либо Хааром, либо каким-нибудь другим обученным детектором, как выше BelBES ответил.
Как лучше решать задачу поиска «уголка шахматной доски» (точки, где смыкаются два тёмных и два светлых угла)? Отношение яркостей светлого к тёмному — от 1.5 и выше, причём на шкале яркостей они могут находиться где угодно (от 1% до 100% максимальной яркости картинки). Размер области, где цвета каждого угла однородны — от 10*10 до 100*100 пикселей и больше, в последнем случае границы между светлым и тёмным могут быть сильно размыты. Величина минимального угла (из-за перекоса) — от 30 градусов, он может быть как светлым, так и тёмным. Сейчас я для поиска проверяю окрестности каждой точки по критерию «являются ли они центрально-симметричными и самоподобными, и насколько велик разброс яркостей», но это получается довольно долго. В какую сторону лучше смотреть?
Первый глупый вопрос: а пробовали метод из OpenCV? Он, конечно, работает только когда доска неплохо и равномерно освещена, но работает хорошо. Мы обычно когда ректификации камеры производим — то им пользуемся (даже когде в самом проекте не используем OpenCV вообще).
Второй вопрос. А классические детекторы углов? (1 2 ) пробовали?
В принципе, в ситуации, когда мне хорошие углы нужно было искать делал так: проходил изображение детектором границ. Для всех точек, которые были определены как граница строил 2 окружности (10 пикселей и 15 пикселей радиусом) и смотрел что эти окружности пересекали. Если получалось 4 точки на каждой окружности — проверял порождают ли они 2 прямых пересекающихся в центре. Но такой детектор был конкретно заточен под мою задачу.
С окружностями пробовал. Правда, делал наоборот — по окружности считал вероятную границу между чёрным и белым, потом проверял, получается ли 4 «достаточно чёрных» и «достаточно белых» отрезка (с возможными серыми зонами между ними). Если получалось правильное чередование, искал наиболее вероятные точки перехода и соединял прямыми. Не помню, почему забраковал. Кажется, поленился посчитать все точки перехода внутри окружности и аппроксимации прямых по ним, и просто взял точку пересечения прямых. В итоге не хватило точности. А может быть, окружностей было слишком много, и надо было как-то отсеивать те из них, которые давали одинаковый результат — и дошел до критерия, что раскраска окружности должна быть центрально-симметричной.
С детекторами углов плохо. Насколько я понял, многие из них предполагают, что угол один. А у меня всегда пара симметричных с общей вершиной. Какие-то критерии пробовал, но они давали огромное количество ложных срабатываний на пёстрых областях. С понятием «граница» тоже не лучше: для больших досок переход от чёрного к белому (от уровня 10% до 90%) может занимать 4-5 пикселей. А масштабирование применять дорого. Хотя боюсь, что придётся.
Ещё мысль. Для каждой гипотезы центра x0;y0 считаем интеграл по разности симметричных относительно x0;y0 пикселей для квадрата x0-l;y0-l;x0+l;y0+l. Каждая вершина это центр симметрии, так что такой интеграл должен стремиться к нулю. Главное правильно выбрать l, чтобы оно было меньше размера клетки.
Но оно будет работать только если доска на плоскости и нет сильного наклона доски по отношению к камере.
Да, на втором этапе это у меня примерно так и делается. И наклон доски здесь нисколько не мешает: проекция прямой это всегда прямая. Хуже, когда точка оказывается в зоне больших угловых искажений (как на краю поля зрения «рыбьего глаза»).
Я не про поворот, а про наклон вперёд назад. Прямые то останутся прямыми, но симметричны будут уже разные точки изображений. Там в окрестности границ должны начаться проблемы.
Я тоже про наклон. Даже если физическое расстояние от центра до точек, изображение которых симметрично относительно изображения центра, будет разным, это не отменяет того, что изображения границ останутся прямыми. И изображение уголка будет выглядеть, как два чёрных и два белых угла. Дальних углов клеток у меня всё равно нет — есть только окрестность одного уголка.
постороить вектора градиентов, по ним опрелить поворот шахмотной доски в изображении, а потом пробежаться вейвлетом Хаара повёрнутый на соответствующий угол?
А зачем поворачивать вейвлеты? О_о картинку не проще повернуть?
ну или так. Просто я обычно работаю с системами реального времени, и повернуть картинку размера фулХД на произвольный угол обычно значительно дольше чем пересчитать фильтр.
Пожалуй вы правы, так оно быстрее будет.
А если не тайна, что за системы вы разрабатываете?
Ну если точнее то пока не разрабатываю, а только собираюсь. Системы автосопровождения подвижных объектов. При условии что камера тоже находится на подвижном объекте, сопровождаемый объект может быть любой на сложном фоне, время обработки не должно превышать 10 микросекунд и точность зачастую должна быть субпиксельная — задача становится очень нетривиальной. Тут ещё ко всему прочему добавляется анализ движения, предсказание и так далее. Вот и собираю информацию, наработки, экспериментирую)
10 микросекунд на обработку? Это с какой частотой у вас камера снимает?
Извините, опечатался. Конечно же 10 миллисекунд. Камеры работают от 50Гц до 1кГц, в зависимости от задач. Но в любом случае, чем меньше задержка, тем менее инертная система получается. А это особенно важно при работе на узких углах зрения когда весь кадр меньше одного градуса, а момент двигателей, поворачивающих камеру, увы, не такой большой как хотелось бы.
На каком расстоянии, что за объекты? Чувствую схожие проблемы. Что за камера снимает фуллХД с частотой 1 кгц?
Увы, не могу разглашать эту информацию(
Ну 10 миллисекунды — это ни оч ем не говорящая цифра без привязки к железу, на котором необходим такой FPS)
Задача случаем не связанна с сопровождением пешеходов?)
Железо — один 300-мегагерцовый ДСП, с поддержкой плавающей точки. Обычно без ОС. При необходимости ПЛИС для первичной обработки.

Не совсем. Для понимания моя задача больше всего похожа на сопровождение движущихся машин, мотоциклов или просто людей с полицейского вертолёта. По телевизору такие кадры часто показывают))
Суровая железка, на таком, при жлении, можно и Tegra K1 обогнать на всяких вычислениях оптического потока)

Не смотрели в сторону алгоритмов типа TLD для решения этой задачи?
Ахаха, нет, всё намного банальнее) Кстате никогда не стал бы ставить на прицел линукс, всёж там больше подходит операционная система реального времени)
Спасибо вам за статью о IR без сисек. Наконец-то можно будет прочитать, не отвлекаясь.
А недавно распиаренный deep learning применяется сейчас в вашей практике?

Действительно ли он может заметно улучшить распознавание по вашему мнению?
Ага, «в задаче распознавания дорожных знаков сверточные нейронные сети недавно превзошли человека»: ни один нормальный человек ни хрена не может понять, что это за фигня на фотографиях, а нейронная сеть уверенно распознаёт :) :) :)
Я его ни разу не применял. Вообще везде где я участвовал очень странные отношения с нейросетями были. Слишком уж они непредсказуемые. А там где они работали — обычно SVM или AdaBoost их превосходил от пары процентов до десятков.
Only those users with full accounts are able to leave comments. Log in, please.