c++ документация - Обработка изображений:улучшение алгоритма для распознавания «Coca-Cola Can»




уроки opencv (20)

Одним из самых интересных проектов, над которыми я работал в последние пару лет, был проект по обработке изображений . Цель состояла в том, чтобы развить систему, чтобы иметь возможность распознавать банки « Coca-Cola » (обратите внимание, что я подчеркиваю слово «банки», вы увидите, почему через минуту). Вы можете увидеть образец ниже, с возможностью распознавания в зеленом прямоугольнике с масштабом и вращением.

Некоторые ограничения на проект:

  • Фон может быть очень шумным.
  • Банк может иметь любой масштаб или поворот или даже ориентацию (в разумных пределах).
  • Изображение может иметь некоторую степень нечеткости (контуры могут быть не совсем прямыми).
  • На изображении могут быть бутылки Coca-Cola, и алгоритм должен только обнаружить банку !
  • Яркость изображения может сильно различаться (поэтому вы не можете «слишком много» полагаться на распознавание цвета).
  • Банку можно было частично скрывать по бокам или посередине и, возможно, частично скрывать за бутылкой.
  • На изображении вообще не может быть никакой возможности , и в этом случае вам нечего было найти и написать сообщение об этом.

Таким образом, у вас могут возникнуть такие сложные вещи (которые в этом случае полностью завершили мой алгоритм):

Я сделал этот проект некоторое время назад, и мне было очень весело, и у меня была достойная реализация. Вот некоторые подробности о моей реализации:

Язык : выполнен в C ++ с использованием библиотеки OpenCV .

Предварительная обработка : для предварительной обработки изображения, т. Е. Преобразования изображения в более необработанную форму для предоставления алгоритма, я использовал 2 метода:

  1. Изменение цветового домена от RGB до HSV и фильтрация на основе «красного» оттенка, насыщенность выше определенного порога, чтобы избежать оранжевых цветов и фильтрация низкого значения, чтобы избежать темных тонов. Конечным результатом было двоичное черно-белое изображение, в котором все белые пиксели будут представлять пиксели, соответствующие этому пороговому значению. Очевидно, в изображении все еще много дерьма, но это уменьшает количество измерений, с которыми вы должны работать.
  2. Фильтрация шума с использованием медианной фильтрации (с учетом среднего значения пикселей всех соседей и замены пикселя на это значение) для уменьшения шума.
  3. Используя Canny Edge Filter для получения контуров всех элементов после двух шагов прецедента.

Алгоритм : сам алгоритм, который я выбрал для этой задачи, был взят из this удивительной книги по извлечению признаков и называется генерализованным преобразованием хруста (довольно отличается от обычного преобразования Хафа). В основном он говорит несколько вещей:

  • Вы можете описать объект в пространстве, не зная его аналитического уравнения (что здесь и есть).
  • Он устойчив к деформациям изображения, таким как масштабирование и вращение, поскольку он будет в основном проверять изображение для каждой комбинации коэффициента масштабирования и коэффициента поворота.
  • Он использует базовую модель (шаблон), которую алгоритм будет «учиться».
  • Каждый пиксель, оставшийся на контурном изображении, будет голосовать за другой пиксель, который предположительно будет центром (с точки зрения силы тяжести) вашего объекта, исходя из того, что он узнал из модели.

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

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

Результаты : теперь, хотя этот подход работал в основных случаях, в некоторых областях его было крайне мало:

  • Это очень медленно ! Я недостаточно подчеркиваю это. Для обработки 30 тестовых изображений потребовался почти полный день, очевидно, потому что у меня был очень высокий коэффициент масштабирования для вращения и перевода, поскольку некоторые из банок были очень маленькими.
  • Это было полностью потеряно, когда бутылки были на изображении, и почему-то почти всегда находили бутылку вместо банки (возможно, потому, что бутылки были больше, таким образом, было больше пикселей, таким образом, больше голосов)
  • Нечеткие изображения также не были хорошими, поскольку голоса попадали в пиксель в случайных местах вокруг центра, что заканчивалось очень шумной тепловой картой.
  • В-дисперсии в переводе и ротации было достигнуто, но не в ориентации, а это означало, что не может быть признана та, которая не была непосредственно связана с объективом камеры.

Можете ли вы помочь мне улучшить свой конкретный алгоритм, используя исключительно функции OpenCV , для решения четырех конкретных проблем?

Я надеюсь, что некоторые люди также узнают что-то из этого, ведь я думаю, что не только люди, которые задают вопросы, должны учиться. :)


Answers

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

Отношение ограничивающего прямоугольника красной области логотипа к общему размеру бутылки / банки отличается. В случае Can, должно быть 1: 1, тогда как будет отличаться от бутылки (с крышкой или без нее). Это должно облегчить различие между ними.

Обновление: горизонтальная кривизна области логотипа будет отличаться между Can и Bottle из-за их разницы в размере. Это может быть особенно полезно, если вашему роботу нужно забрать банку / бутылку, и вы сами решаете захват.


Чтобы ускорить процесс, я бы воспользовался тем, что вас не просят найти произвольный образ / объект, но, в частности, логотип Coca-Cola. Это важно, потому что этот логотип очень свойственен, и он должен иметь характерную, масштабно-инвариантную сигнатуру в частотной области, особенно в красном канале RGB. Другими словами, чередующийся рисунок красно-белого-красного цвета, встречаемый горизонтальной линией развертки (обученный на горизонтально выровненном логотипе), будет иметь отличительный «ритм», проходящий через центральную ось логотипа. Этот ритм будет «ускоряться» или «замедляться» в разных масштабах и ориентациях, но будет оставаться пропорционально эквивалентным. Вы могли бы определить / определить несколько десятков таких строк сканирования, как по горизонтали, так и по вертикали через логотип и еще несколько по диагонали, по шаблону звездообразования. Назовите эти «строки сканирования подписи».

Поиск этой подписи в целевом изображении - это простой вопрос сканирования изображения в горизонтальных полосах. Ищите высокочастотную в красном канале (указывающую переход от красной области к белой), и после того, как она найдена, посмотрите, следует ли за ней один из частотных ритмов, определенных на тренировке. Как только совпадение будет найдено, вы сразу узнаете ориентацию и расположение линии сканирования в логотипе (если вы будете отслеживать эти вещи во время обучения), поэтому определение границ логотипа оттуда тривиально.

Я был бы удивлен, если бы это был не линейно-эффективный алгоритм, а почти так. Очевидно, это не касается дискриминации на бутылочной бутылке, но, по крайней мере, у вас будут свои логотипы.

(Обновление: для распознавания бутылки я бы искал кокс (коричневую жидкость), прилегающий к логотипу, то есть внутри бутылки. Или, в случае пустой бутылки, я бы искал колпачок, который всегда будет иметь одинаковой базовой формы, размера и расстояния от логотипа и обычно будет белого или красного цвета. Найдите сплошную цветовую форму, в которой должен быть колпачок, относительно логотипа. Конечно, нет уверенности в себе, но ваша цель здесь должна быть быстро найти быстрых .)

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


Я не знаю OpenCV, но, глядя на проблему логически, я думаю, что вы могли бы различать бутылку и можете, изменив изображение, которое вы ищете, например, Coca Cola. Вы должны включить до верхней части банки, так как в случае, если есть серебряная подкладка наверху кока-колы, а в случае бутылки такой серебряной подкладки не будет.

Но, очевидно, этот алгоритм потерпит неудачу в тех случаях, когда вершина can скрыта, но в этом случае даже человек не сможет отличить два (если видна только часть кока-колы бутылки / банки)


Я бы обнаружил красные прямоугольники: RGB -> HSV, фильтр красный -> двоичное изображение, close (расширять, затем размывать, известный как imclose в matlab)

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

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


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

1: Первая характеристика - цвет, а красный - очень доминирующий. После обнаружения Coca Cola Red есть несколько интересных элементов 1A: насколько велика эта красная область (достаточно ли количества, чтобы определить истинную возможность или нет - 10 пикселей, вероятно, недостаточно), 1B: содержит ли она цвет ярлыка - «Кока-кола» или волна. 1B1: достаточно ли рассмотреть высокую вероятность того, что это ярлык.

Пункт 1 - это вид короткого вырезания - предварительный процесс, если этот сон существует на изображении - двигайтесь дальше.

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

2: Учитывая указанную выше область изображения ID'd в 1 - проверьте окружающие точки [края] рассматриваемого предмета. A: Есть ли что-то сверху или снизу - серебро? B: Бутылка может казаться прозрачной, но также может быть стеклянный стол - так есть стеклянный стол / полка или прозрачная область - если так, то есть несколько возможных вариантов. Бутылка MIGHT имеет красную крышку, она может и не быть, но должна иметь либо форму винтов / винтов для бутылок, либо колпачок. C: Даже если это не удается A и B, оно все еще может быть частичным. Это сложнее, когда оно является частичным, потому что частичная бутылка / частичная может выглядеть одинаково, поэтому некоторая дополнительная обработка измерения края красной области кромка .. маленькая бутылка может быть похожа по размеру ..

3: После вышеупомянутого анализа, когда я посмотрю на надпись и логотип волны - потому что я могу ориентировать мой поиск некоторых букв в словах. Поскольку у вас может не быть всего текста из-за отсутствия всех может, волна будет выравниваться в определенных точках с текстом (на расстоянии), чтобы я мог найти эту вероятность и знать, какие буквы должны существовать в этой точке волны на расстоянии x.


Существует пакет компьютерного зрения под названием HALCON от MVTec, чьи демонстрации могут дать вам хорошие алгоритмические идеи. Существует множество примеров, похожих на вашу проблему, которые вы можете запустить в демонстрационном режиме, а затем посмотреть на операторов в коде и посмотреть, как их реализовать из существующих операторов OpenCV.

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


Если вы не ограничены только камерой, которая не была в одном из ваших ограничений, возможно, вы можете перейти к использованию датчика дальности, такого как Xbox Kinect . С помощью этого вы можете выполнить согласованную сегментацию изображения на основе глубины и цвета. Это позволяет быстрее разделять объекты на изображении. Затем вы можете использовать сопоставление ICP или аналогичные методы, чтобы даже соответствовать форме, а не просто ее контуру или цвет, и учитывая, что она является цилиндрической, это может быть допустимым вариантом для любой ориентации, если у вас есть предыдущее 3D-сканирование цели. Эти методы часто бывают довольно быстрыми, особенно когда они используются для такой конкретной цели, которая должна решить вашу проблему скорости.

Также я мог бы предложить, не обязательно для точности или скорости, но для удовольствия вы могли бы использовать обученную нейронную сеть на своем сегментированном изображении с оттенком, чтобы идентифицировать форму банки. Они очень быстрые и часто могут быть точными до 80/90%. Тренировка будет немного долгим процессом, хотя вам придется вручную идентифицировать банку в каждом изображении.


Это может быть очень наивная идея (или может вообще не работать), но размеры всех кокса могут быть исправлены. Так может быть, если одно и то же изображение содержит как банку, так и бутылку, тогда вы можете рассказать их отдельно по соображениям размера (бутылки будут больше). Теперь из-за недостающей глубины (т. Е. 3D-сопоставления к двумерному отображению) возможно, что бутылка может казаться сжатой и не существует разницы в размерах. Вы можете восстановить некоторую информацию о глубине с помощью stereo-imaging а затем восстановить исходный размер.


Мне нравится ваш вопрос, независимо от того, вне его темы или нет: P

Интересный в стороне; Я только что закончил тему в своей области, где мы рассмотрели робототехнику и компьютерное зрение. Наш проект на семестр был невероятно похож на тот, который вы описываете.

Мы должны были разработать робот, который использовал Xbox Kinect для обнаружения бутылок и банок для коксов при любой ориентации в различных условиях освещения и окружающей среды. Наше решение включало использование полосового фильтра на канале Hue в сочетании с преобразованием окружности hough. Мы смогли немного ограничить окружающую среду (мы могли бы выбрать, где и как расположить робота и датчик Kinect), иначе мы собирались использовать преобразования SIFT или SURF.

Вы можете прочитать о нашем подходе на моем блоге на тему :)


Глядя на форму

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

Глядя на основные моменты

Одним из способов отличить бутылки и банки - это материал. Бутылка изготовлена ​​из пластика, тогда как банда изготовлена ​​из алюминиевого металла. В достаточно хорошо освещенных ситуациях просмотр зеркальности будет одним из способов сказать этикетку с этикеткой на этикетке.

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


Несколько лет спустя я ответил на этот вопрос. Поскольку в последние 5 лет современное искусство подтолкнуло CNN к своим пределам, я бы не стал использовать OpenCV для выполнения этой задачи сейчас! ( Я знаю, что вам особенно нужны функции OpenCv в вопросе ). Я считаю, что алгоритмы обнаружения объектов, такие как Faster-RCNN, YOLO, SSD и т. Д., Будут иметь эту проблему со значительным разницей по сравнению с функциями OpenCV. Если бы я сейчас решил эту проблему (через 6 лет !!), я бы определенно использовал Faster-RCNN .


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

  1. Извлечь функции (ключевые точки, дескрипторы, такие как SIFT, SURF) логотипа
  2. Сопоставьте точки с образцом модели логотипа (используя Matcher, например Brute Force)
  3. Оцените координаты твердого тела (проблема PnP - SolvePnP)
  4. Оцените положение крышки в соответствии с жестким корпусом
  5. Сделайте обратную проекцию и вычислите положение пикселя изображения (ROI) колпачка бутылки (я предполагаю, что у вас есть внутренние параметры камеры)
  6. Проверьте, существует ли колпачок или нет. Если есть, то это бутылка

Обнаружение крышки - еще одна проблема. Это может быть сложным или простым. Если бы я был вами, я бы просто проверил цветную гистограмму в ROI для простого решения.

Пожалуйста, дайте отзыв, если я ошибаюсь. Благодарю.


Глубокое обучение

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

Если вы не соберете очень большой набор данных, выполните трюк использования глубоких функций обучения для небольшого набора данных. Идеально использовать комбинацию векторных машин поддержки (SVM) с глубокими нейронными сетями.

После того, как вы загрузите изображения в ранее обученную модель глубокого обучения (например, GoogleNet), вместо использования (окончательного) уровня нейронной сети для выполнения классификаций используйте данные предыдущего уровня (s) в качестве функций для обучения вашего классификатора.

OpenCV и Google Net: http://docs.opencv.org/trunk/d5/de7/tutorial_dnn_googlenet.html

OpenCV и SVM: http://docs.opencv.org/2.4/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.html


Интересная проблема: когда я взглянул на изображение бутылки, я подумал, что это тоже может быть. Но, как человек, я сделал это, чтобы сказать разницу, что я тогда заметил, что это тоже бутылка ...

Итак, чтобы разделить банки и бутылки, как насчет просто сканирования бутылок в первую очередь? Если вы найдете его, замаскируйте этикетку, прежде чем искать банки.

Не слишком сложно реализовать, если вы уже делаете банки. Реальный недостаток - это удвоение времени обработки. (Но, думая заранее о реальных приложениях, вы все равно захотите делать бутылки ;-)


Альтернативный подход состоял бы в том, чтобы извлечь функции (ключевые точки), используя масштабируемое по шкале свойство (SIFT) или ускоренные надежные функции (SURF).

Он реализован в OpenCV 2.3.1.

Вы можете найти хороший пример кода, используя функции в Feature2D + Homography, чтобы найти известный объект

Оба алгоритма инвариантны к масштабированию и вращению. Поскольку они работают с функциями, вы также можете обрабатывать occlusion (если видны достаточно ключевых точек).

Источник изображения: пример учебника

Обработка занимает несколько сотен мс для SIFT, SURF бит быстрее, но он не подходит для приложений реального времени. ORB использует FAST, который слабее относительно инвариантности вращения.

Оригинальные документы


Если вы заинтересованы в том, чтобы быть в реальном времени, то вам нужно добавить фильтр предварительной обработки, чтобы определить, что сканируется с помощью сверхпрочного материала. Хороший быстрый, очень реальном времени, фильтр предварительной обработки, который позволит вам сканировать вещи, которые, скорее всего, будут кока-колой, может не выглядеть, чем прежде, чем перейти к более случайным вещам, это примерно так: поиск изображения для самых больших патчей цвета, которые являются определенной точностью от sqrt(pow(red,2) + pow(blue,2) + pow(green,2)) вашей кока-колы. Начните с очень строгой цветоустойчивости и проведите свой путь до более мягких цветовых допусков. Затем, когда ваш робот исчерпал выделенное время для обработки текущего кадра, он использует найденные в настоящее время бутылки для ваших целей. Обратите внимание, что вам нужно будет настроить цвета RGB в sqrt(pow(red,2) + pow(blue,2) + pow(green,2)) чтобы получить их в самый раз.

Кроме того, это gona кажется действительно глупым, но вы обязательно -oFast оптимизацию компилятора, когда вы скомпилировали свой C-код?


Вам нужна программа, которая учит и улучшает точность классификации органически из опыта.

Я предлагаю глубокое обучение, с глубоким обучением это становится тривиальной проблемой.

Вы можете перепрофилировать начальную модель v3 на Tensorflow:

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

В этом случае вы будете обучать сверточную нейронную сеть, чтобы классифицировать объект так же, как или кока-кола может или нет.


Пожалуйста, взгляните на трекер Zendek Kalal's Predator . Это требует некоторой подготовки, но он может активно изучать, как отслеживаемый объект смотрит на разные ориентации и масштабы и делает это в реальном времени!

Исходный код доступен на его сайте. Это в MATLAB , но, возможно, есть реализация Java, уже сделанная членом сообщества. Я успешно выполнил повторную реализацию трекерной части TLD в C #. Если я правильно помню, TLD использует Ferns в качестве детектора ключевой точки. Вместо этого я использую SURF или SIFT (уже предложенный @stacker), чтобы повторно захватить объект, если он был потерян трекером. Отслеживание отслежывателя позволяет легко создавать со временем динамический список шаблонов sift / surf, которые со временем позволяют повторно захватить объект с очень высокой точностью.

Если вы заинтересованы в моей реализации C # трекера, не стесняйтесь спрашивать.


Существует множество цветовых дескрипторов, используемых для распознавания объектов, в приведенной ниже статье сравниваются многие из них. Они особенно эффективны в сочетании с SIFT или SURF. Только SURF или SIFT не очень полезны для изображения кока-колы, потому что они не распознают множество точек интереса, вам нужна информация о цвете, чтобы помочь. Я использую BIC (Border / Interior Pixel Classi fiation) с SURF в проекте, и он отлично работал для распознавания объектов.

Цветные дескрипторы для поиска веб-изображений: сравнительное исследование


Google для «конвейера рендеринга рендеринга». Первые пять статей предоставляют хорошие экспозиции.

Переход ключа из вершин в пиксели (на самом деле, фрагменты, но вы не будете слишком далеко, если считаете «пиксели») находится на стадии растеризации, которая возникает после того, как все вершины были преобразованы из координат мира в координаты экрана и обрезается.





c++ algorithm image-processing opencv