Самый распространённый способ выделить объект — это цвет.
Цвет — это свойство тел отражать или испускать видимое излучение определенного спектрального состава и интенсивности.
Везде и всюду нас окружают цветовые индикаторы.
Светофоры, белые и жёлтые линии дорожной разметки, корпоративные цвета продуктов, дорожные указатели и различные индикаторы.
Например, для слабовидящих людей приклеивают жёлтые круги на дверях магазинов (жёлтый – последний цвет, которые они видят);
чтобы не перепутать, например, стеклянную витрину со стеклянной дверью.
Так же появляются жёлтые полосы на ступеньках пешеходных переходов. Покрываются жёлтой краской бордюры. Этот цвет один из самых ярких и людям с плохим зрением становится легче ориентироваться в городе.
Одной из важных проблем поиска по цвету — это влияние множества факторов.
Например, освещённость. Нельзя так же забывать, что видимый цвет — это результат взаимодействия спектра излучаемого света и поверхности. Т.е. если белый лист освещать светом красной лампочки, то и лист будет казаться красным.
Трихроматическая теория (сетчатка глаза имеет 3 вида рецепторов света, ответственных за цветное зрение) полагает, что достаточно всего трёх чисел, чтобы описать цвет (красный, синий, зелёный).
Т.е. используя три значения R, G, B
Цветовые пространства бывают линейные и нелинейные.
К линейным относится RGB
Нелинейные: HSV, LAB
Удобство HSV состоит в том, что координаты выбраны с учетом человеческого восприятия:
Hue (Тон)
Saturation(Насыщенность),
Value (Intensity) (Интенсивность)
Рассмотрим практическую задачу системы машинного зрения.
сама задача прозвучала на робофоруме
и упрощенно её можно сформулировать так:
Над колесом игорной рулетки установлена камера.
Требуется программа распознавания номера, в который попал шарик.
Исходные данные:
* шарик лежит во внешнем углу ячейки.
* номера на всех колесах располагаются одинаково.
* цвет номеров строго чередуется (красное-чёрное)
* номер 0 (Zero) зелёного цвета.
Один из возможных алгоритмов решения задачи — это найти зелёный сектор Zero и отсчитать от него сектор в котором детектируется белый шарик.
Т.о., в первом приближении, задача состоит в нахождении цветных объектов на картинке.
Я порылся в интернете и нашёл вот такую фотографию колеса игорной рулетки:
Попробуем с ней поработать.
Напишем программу, которая считывает картинку (в качестве первого параметра), разбивает её на слои (cvSplit()), над каждым из которых можно проделать пороговое преобразование (cvInRangeS()), причём значения интервалов удобным образом изменяются с помощью ползунков.
Результирующее значение выводится в окошке «rgb and» и представляет собой логическое И — cvAnd() между получившимися пороговыми картинками.
Как видите сектор Zero очень даже хорошо выделяется.
Должен отметить важный момент — хотя работа со статической картинкой, фактически, ничем не отличается от работы с кадром видеопотока, но, на самом деле, работа с видеоданными требует отдельного тестирования; т.к. видеокартинка динамична, имеет различные шумы и т.д.
Простым вариантом может быть использование видеороликов, снятых камерой, которая будет использоваться в дальнейшем.
В данном случае — для тестирования можно просто сохранить видеролик с youtub-а :)
Итак, сектор Zero выделяется хорошо, но попытка выделить по цвету шарик не даст ожидаемого результата. Разумеется, можно добиться, чтобы шарик был виден, но так же будут видны белые числа номеров, а ещё блики (на оси рулетки и металлической ленте).
Как и предложили на форуме, эти ложные срабатывания можно устранить, если работать только с заданной частью изображния, где их нет.
Т.е. сначала мы ждём, когда в заданном секторе будет задетектировано Zero, а далее мы отсчитываем сектора рулетки, до тех пор, пока не будет задетектирован шарик.
— разделяет многоканальный массив на одноканальные массивы или выделяет отдельные цветовые плоскости
src — исходный массив(изображение)
dst0..dst3 — массивы(изображения) для сохранения результатов
— объединяет несколько одноканальных массивов в один многоканальный массив
src0..src2 — исходные массивы(изображения)
dst — массив(изображение) для сохранения результатов
-выполняет по-элементую операцию конъюнкции (логического И (AND)) над элементами двух массивов.
src1 — первый исходный массив(изображение) (если NULL, то считается, что массив состоит из 1)
src2 — второй исходный массив(изображение)
dst — массив(изображение) для сохранения результата
mask — маска (8-битный 1-канальный массив)
— определяет минимальное и максимальное значения массива, а так же их местоположение
arr — массив(изображение) для поиска (одноканальный или многоканальный с установленным COI)
min_val — указатель на переменную для сохранения минимального значения
max_val — указатель на переменную для сохранения максимального значения
min_loc — указатель на точку местоположения минимума
max_loc — указатель на точку местоположения максимума
mask — маска для выбора подмассива
CVAPI(void) cvMoveWindow( const char* name, int x, int y );
— перемещает окно
name — название окна
x,y — новые координаты верхнего левого угла окна
заодно укажем на функцию изменения размера окна:
CVAPI(void) cvResizeWindow( const char* name, int width, int height );
— изменяет размер окна
name — название окна
width, height — новые ширина и высота окна
Интересно, что у меня получились совершенно другие настройки. Я пишу на c#, используя openCVSharp. Но не думаю, что из-за этого могла появиться такая разница :)
Комментарии (3)
RSS свернуть / развернутьJohnJ
К: 42, 151
З: 125, 244
С: 0, 58
А с указанными в статье данными вообще получается ерунда: выделяется коричневая область круга, что внутри циферблата.
JohnJ
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.