Одним из самых интересных проектов, над которыми я работал в последние пару лет, был проект об обработке изображений. Цель состояла в том, чтобы разработать систему, способную распознавать "банки" Coca-Cola (обратите внимание, что я подчеркиваю слово "банки", через минуту вы поймете, почему). Вы можете увидеть образец ниже, с банкой, распознанной в зеленом прямоугольнике с масштабом и вращением.
Некоторые ограничения на проект:
- Фон может быть очень шумным.
- У банки может быть любой масштаб или вращение или даже ориентация (в разумных пределах).
- Изображение может иметь некоторую степень размытости (контуры могут быть не совсем прямыми).
- На изображении могут быть бутылки с кока-колой, а алгоритм должен определять только банку!
- Яркость изображения может сильно различаться (поэтому вы не можете слишком полагаться на распознавание цвета).
- Банка может быть частично спрятана по бокам или в середине и, возможно, частично спрятана за бутылкой.
- На изображении может не быть банок, и в этом случае вам ничего не нужно найти и написать сообщение, в котором говорится об этом.
Таким образом, вы можете получить такие хитрые вещи, которые (в этом случае мой алгоритм полностью провалился):
Я сделал этот проект некоторое время назад, и мне было очень весело, и у меня была достойная реализация. Вот некоторые подробности о моей реализации:
Язык: Выполнено в C++ с использованием библиотеки OpenCV.
Предварительная обработка: Для предварительной обработки изображения, т.е. преобразования изображения в более сырую форму, чтобы придать алгоритму, я использовал 2 метода:
- Изменение цветовой области с RGB на HSV и фильтрация по "красному" оттенку, насыщенность выше определенного порога, чтобы избежать появления оранжевых цветов, и фильтрация низкого значения, чтобы избежать темных тонов. Конечным результатом было двоичное черно-белое изображение, где все белые пиксели будут представлять пиксели, которые соответствуют этому порогу. Очевидно, что на изображении все еще много дерьма, но это уменьшает количество измерений, с которыми вам приходится работать.
- Шумовая фильтрация с использованием медианной фильтрации (принимая значение медианного пикселя всех соседей и заменяя пиксель на это значение), чтобы уменьшить шум.
- С помощью фильтра Canny Edge Detection Filter можно получить контуры всех элементов после 2 предыдущих шагов.
Алгоритм: сам алгоритм, который я выбрал для этой задачи, был взят из этой удивительной книги по извлечению признаков и называется Обобщенное преобразование Хафа (довольно сильно отличается от обычного преобразования Хафа). В основном это говорит о нескольких вещах:
- Вы можете описать объект в космосе, не зная его аналитического уравнения (что имеет место здесь).
- Он устойчив к деформациям изображения, таким как масштабирование и вращение, поскольку он в основном будет проверять ваше изображение на каждую комбинацию коэффициента масштабирования и коэффициента вращения.
- Он использует базовую модель (шаблон), которую алгоритм будет "изучать".
- Каждый пиксель, оставшийся в контурном изображении, будет голосовать за другой пиксель, который предположительно будет центром (в терминах силы тяжести) вашего объекта, основываясь на том, что он узнал из модели.
В конце концов, вы получите тепловую карту голосов, например, здесь все пиксели контура банки будут голосовать за ее гравитационный центр, так что у вас будет много голосов в одном пикселе, соответствующем в центре, и вы увидите пик на тепловой карте, как показано ниже:
Как только вы это сделаете, простая основанная на пороге эвристика может дать вам местоположение центрального пикселя, из которого вы можете получить масштаб и вращение, а затем построить вокруг себя маленький прямоугольник (окончательный масштаб и коэффициент поворота, очевидно, будут относительно вашего оригинальный шаблон). По крайней мере, в теории...
Результаты: теперь, хотя этот подход работал в основных случаях, в некоторых областях его не хватало:
- Это очень медленно ! Я недостаточно подчеркиваю это. Почти 30 дней понадобилось для обработки 30 тестовых изображений, очевидно, потому что у меня был очень высокий коэффициент масштабирования для поворота и перемещения, поскольку некоторые банки были очень маленькими.
- Он был полностью утерян, когда на изображении были бутылки, и по какой-то причине почти всегда находил бутылку вместо банки (возможно, потому что бутылки были больше, таким образом, имели больше пикселей, таким образом, больше голосов)
- Нечеткие изображения также были бесполезны, так как голоса оказались в пикселях в случайных местах вокруг центра, что привело к очень шумной тепловой карте.
- Была достигнута разница в перемещении и повороте, но не в ориентации, что означало, что банка, которая не была обращена непосредственно к объективу камеры, не была распознана.
Можете ли вы помочь мне улучшить мой конкретный алгоритм, используя исключительно функции OpenCV, для решения четырех указанных проблем?
Я надеюсь, что некоторые люди также узнают что-то из этого, ведь я думаю, что не только люди, которые задают вопросы, должны учиться. :)