аватар question@mail.ru · 01.01.1970 03:00

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

"

n

Как можно распознать знак бесконечности (именно его) на фото или видео?

n

Буду признателен, если приведете код к ответу.

n

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

аватар question@mail.ru · 01.01.1970 03:00

"

OpenCV предоставляет множество инструментов для распознавания образов, в том числе и посредством контурного анализа. В третьей версии фреймворка практически всё, что касается сравнения контуров было выделено в отдельный модуль с говорящим названием .

Автор вопроса не уточнил, с какими фигурами (наборами фигур) будет сравниваться знак бесконечности, и отметил лишь, что интерес представляет только факт похожести кандидата искомому объекту.

Очевидно, что само по себе понятие ""бесконечность"" машине ничего не скажет, а потому придётся предложить ей некий образ в виде эталона. Пусть этот образ будет выглядеть так (файл 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()) retu;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_EXTEAL, 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) retu;

Далее следует нюанс, который подразумевает, что любые сравниваемые контуры должны иметь одинаковое количество точек в своём составе. Разумеется, что различные фигуры таковому правилу обычно следовать не будут, а значит придётся ""на ручнике"" им в этом помочь, просто добавив необходимое количество точек, но только с теми координатами, что и так уже имеются в фигуре:

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()) retu -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_EXTEAL, 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) здесь достанется второе место. А впрочем, если приглядеться, вполне возможно уловить общие с бесконечностью черты.

"

Последние

Похожие