Как можно распознать знак бесконечности (именно его) на фото или видео?
Буду признателен, если приведете код к ответу.
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<std::vector<cv::Point> > 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<cv::ShapeContextDistanceExtractor> 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<std::vector<cv::Point> > 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; }
Результатом работы кода окажутся такие значения:
model1.jpg — 2.84489
model2.jpg — 112.033
model3.jpg — 32.8308
model4.jpg — 524.659
Изображение model1.jpg содержит знак бесконечности, а соответственно имеет и наименьшую дистанцию различия с тестовой фигурой. Изображения со знаком «собаки» (model2.jpg) и «серпа с молотом» (model4.jpg) в виду очевидных различий завершают список непохожести. Но кто бы мог подумать, что «бэтмену» (model3.jpg) здесь достанется второе место. А впрочем, если приглядеться, вполне возможно уловить общие с бесконечностью черты.
Данный ответ устарел и соответствует вопросу в его изначальной версии.
Как обучают детей алфавиту? Показывают картинки в букваре, произносят соответствующие им звуки. Как затем дети начинают распознавать символы букв, встречая их не в букваре? Очевидно, что на этот момент времени они уже достаточно затратили ресурсов, чтобы запомнить практически все возможные особенности форм начертания этих самых символов.
Как шимпанзе обнаруживает бананы? Наверное в большей мере потому, что ей в своё время показали его, выделив в качестве самостоятельного и очень вкусного объекта.
Любимая, я тебя поведу к самому краю Вселенной! Я подарю тебе эту
звезду, светом нетленным будет она озарять нам путь в бесконечность…
На что надеялась Любимая, принимая предложение двигать в бесконечность? Вероятнее всего, что заложенные ранее ассоциации позволили ей понять, что это будет как минимум приятное путешествие.
А что же машина? А у машины нет того опыта, что получают ребёнок, шимпанзе и Любимая. С машиной придётся работать, чтобы она могла начать различать бесконечность, нарисованную на бумаге в виде знака, бесконечность бананового чревоугодия и бесконечность пути под светом нетленным.
Заценив масштаб трагедии, сколько сделано и сколько всего ещё нужно сделать, разработчики (некоторые уже на Седьмой день) начинают понимать, что необходимо срочно сужать поле деятельности, ограничив творческий потенциал локальными изменениями.
Кто-то выбирает набор изображений с конкретным начертанием символа бесконечности на определённом фоне, чтобы иметь возможность работать с контурами. Кто-то выбирает видеоряд, но всё с теми же конкретизирующими выборку условиями. В любом случае, творец более не ограничивает себя стремлением объять необъятное, а если даже и спросит у соседей, ковыряющихся в своих мирах, помощи, то максимально конкретизирует вопрос, предложив им на рассмотрение пару примеров собственного виденья предмета. И все довольны.