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




opencv документация (16)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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


В качестве альтернативы всем этим приятным решениям вы можете обучить свой собственный классификатор и сделать ваше приложение устойчивым к ошибкам. Например, вы можете использовать Haar Training , предоставляя большое количество положительных и отрицательных изображений вашей цели.

Полезно извлекать только банки и их можно комбинировать с обнаружением прозрачных объектов.


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

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


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

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


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

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

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

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


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

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

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

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


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

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

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


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


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

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

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


Разве не сложно даже людям различать бутылку и банку во втором изображении (при условии, что прозрачная область бутылки скрыта)?

Они почти одинаковы, за исключением очень маленькой области (т. Е. Ширина в верхней части банки немного небольшая, в то время как обертка бутылки имеет одинаковую ширину, но незначительное изменение справа?)

Первое, что пришло мне в голову, - проверить красную бутылку. Но это все еще проблема, если нет вершины для бутылки или если она частично скрыта (как упоминалось выше).

Во-вторых, я думал о прозрачности бутылки. В OpenCV есть несколько работ по поиску прозрачных объектов в изображении. Проверьте приведенные ниже ссылки.

Особенно посмотрите на это, чтобы увидеть, как точно они обнаруживают стекло:

См. Их результат внедрения:

Они говорят, что это реализация статьи «Геодезическая активная контурная основа для поиска стекла» К. МакГенри и Дж. Понсе, CVPR 2006 .

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

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

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

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

  1. Он работает, только если ваша бутылка пуста. В этом случае вам придется искать красную область между двумя черными цветами (если жидкость Coca Cola черная).
  2. Другая проблема, если прозрачная часть покрыта.

Но, в любом случае, если на фотографиях нет упомянутых выше проблем, похоже, это лучше.


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

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


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

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

Что вокруг логотипа? Для банки можно увидеть металл, который, несмотря на эффекты освещения, не меняет своего основного цвета. До тех пор, пока мы знаем угол метки, мы можем сказать, что прямо над ним, поэтому мы смотрим на разницу между ними:

Здесь, что выше и ниже логотипа, абсолютно темный, непрозрачный по цвету. Относительно легко в этом отношении.

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

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

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

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

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

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

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

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

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

РЕДАКТИРОВАТЬ

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


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


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

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


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

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

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

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

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


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

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

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





opencv