Распознавание знака бесконечности

1,00
р.
Как можно распознать знак бесконечности (именно его) на фото или видео?
Буду признателен, если приведете код к ответу.
UPD: Объясните, как, например, с помощью контурного анализа понять, есть ли на фотографии знак бесконечности. Пример ниже (в центре может быть полное соединение, человека может быть видно - он может держать лист, цвет не важен).


Ответ
OpenCV предоставляет множество инструментов для распознавания образов, в том числе и посредством контурного анализа. В третьей версии фреймворка практически всё, что касается сравнения контуров было выделено в отдельный модуль с говорящим названием Shape Distance and Matching.
Автор вопроса не уточнил, с какими фигурами (наборами фигур) будет сравниваться знак бесконечности, и отметил лишь, что интерес представляет только факт похожести кандидата искомому объекту.
Очевидно, что само по себе понятие "бесконечность" машине ничего не скажет, а потому придётся предложить ей некий образ в виде эталона. Пусть этот образ будет выглядеть так (файл model1.jpg):

Между тем, чтобы убедиться, что раскрытый далее метод позволяет различать и другие фигуры, добавим к эталонной модели ещё несколько различных изображений (файлы model2.jpg, model3.jpg и model4.jpg соответственно):


На самом деле все изображения одинакового размера и приведены в уменьшенном виде лишь с целью экономии места на странице.
Начнём с выделения объекта, изображение которого предоставил автор вопроса:
cv::Mat tst_src_mat = cv::imread("test.jpg", cv::IMREAD_GRAYSCALE) if(tst_src_mat.empty()) return
cv::Mat tst_bin_mat cv::threshold(tst_src_mat, tst_bin_mat, 0, 255 , cv::THRESH_OTSU | cv::THRESH_BINARY_INV)
После проведения бинаризации окажется, что помимо объекта интереса на изображении в левом нижнем углу присутствует и артефакт:

Можно от него избавиться посредством простого и в чём-то философского подхода - не обращать внимания, оставив в поле зрения лишь тот контур, что наоборот - представляет интерес. Это можно сделать, например, ориентируясь на максимальную площадь и соответствующий индекс в векторе:
std::vector > tst_cs cv::findContours(tst_bin_mat.clone(), tst_cs , cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE)
int ci = -1 double max_area = 0. for(int i = 0, n = tst_cs.size() i < n ++i) { const double area = cv::contourArea(tst_cs.at(i)) if(area > max_area) {max_area = area ci = i } }
if(ci == -1) return
Далее следует нюанс, который подразумевает, что любые сравниваемые контуры должны иметь одинаковое количество точек в своём составе. Разумеется, что различные фигуры таковому правилу обычно следовать не будут, а значит придётся "на ручнике" им в этом помочь, просто добавив необходимое количество точек, но только с теми координатами, что и так уже имеются в фигуре:
const int num_pts = 300
for(int i = tst_cs.at(ci).size()-1, d = 0 i < num_pts ++i) tst_cs[ci].push_back(tst_cs[ci][d++])
Константа num_pts - это произвольное число. Оно в принципе зависит от того, с какой сложностью фигур предстоит работа. В идеале оно должно быть равно максимальному количеству точек у самого э-э-э... многоточечного контура из сравниваемых.
Пожалуй, настало время перейти к ранее рассмотренным эталону и изображениям сильно отличающихся от тестового фигур:
// Герой настоящей статьи, который собственно // и будет производить сравнение контуров. cv::Ptr sc = cv::createShapeContextDistanceExtractor()
for(int i = 0 i < 4 ++i) { std::string fname = std::string("model") + std::to_string(i+1) + std::string(".jpg")
cv::Mat src_mat = cv::imread(fname, cv::IMREAD_GRAYSCALE) if(src_mat.empty()) return -1
cv::Mat bin_mat cv::threshold(src_mat, bin_mat, 0, 255 , cv::THRESH_OTSU | cv::THRESH_BINARY_INV)
std::vector > cs cv::findContours(bin_mat.clone(), cs , cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE)
for(int i = cs.at(0).size()-1, d = 0 i < num_pts ++i) cs[0].push_back(cs[0][d++])
std::cout << fname << " - " << sc->computeDistance(tst_cs[ci], cs[0]) << std::endl } <br>Результатом работы кода окажутся такие значения:
model1.jpg - 2.84489 model2.jpg - 112.033 model3.jpg - 32.8308 model4.jpg - 524.659
Изображение model1.jpg содержит знак бесконечности, а соответственно имеет и наименьшую дистанцию различия с тестовой фигурой. Изображения со знаком "собаки" (model2.jpg) и "серпа с молотом" (model4.jpg) в виду очевидных различий завершают список непохожести. Но кто бы мог подумать, что "бэтмену" (model3.jpg) здесь достанется второе место. А впрочем, если приглядеться, вполне возможно уловить общие с бесконечностью черты.