Сопоставление шаблона с Orb: ошибка с методом batchDistance

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

Сначала я конвертирую pdf-документ в изображение png с помощью инструмента преобразования ImageMagick, затем я разрезаю выходные изображения пополам, потому что они такие большие, и после этого я пытаюсь сопоставить логотип из базы данных с любой из фигур, представленных в полуобрезанное изображение.

Для этого я использую Orb Feature Detector с дескриптором Orb и RobustMatcher (что-то вроде улучшенного алгоритма сопоставления BruteForce, исходный код доступен здесь). Вот фрагмент кода из моей адаптации:

// Read input images
Mat image1 = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
Mat image2 = imread(argv[2], CV_LOAD_IMAGE_GRAYSCALE);

if (!image1.data || !image2.data) {
    std::cout << " --(!) Error reading images " << std::endl;
    exit(1);
}

// Setting up values for ORB Detector
int nfeatures = 800;
//float scaleFactor = 1.10;
int nlevels = 8;
int edgeThreshold = 12;
int firstLevel = 0;
int WTA_K = 2;
int scoreType = 0;
int patchSize = 31;

// Prepare the matcher
RobustMatcher rmatcher;
rmatcher.setConfidenceLevel(0.98);
rmatcher.setMinDistanceToEpipolar(1.0);
rmatcher.setRatio(0.80f);
cv::Ptr<cv::FeatureDetector> pfd = new cv::OrbFeatureDetector(nfeatures, scaleFactor, nlevels, edgeThreshold, firstLevel, WTA_K, scoreType, patchSize);
rmatcher.setFeatureDetector(pfd);
cv::Ptr<cv::DescriptorExtractor> pde = new cv::OrbDescriptorExtractor();
rmatcher.setDescriptorExtractor(pde);

// Match the two images
std::vector<cv::DMatch> matches;
std::vector<cv::KeyPoint> keypoints1, keypoints2;
cv::Mat fundemental = rmatcher.match(image1, image2, matches, keypoints1, keypoints2);

// If nothing could be matched, stop here
if(matches.size() < 4){
    exit(2);
}

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

Ошибка OpenCV: утверждение не удалось (тип == src2.type() && src1.cols == src2.cols && (тип == CV_32F || тип == CV_8U)) в пакетном расстоянии, файл /home/das/Downloads/opencv- 2.4.5/modules/core/src/stat.cpp, строка 1797 завершена после создания экземпляра 'cv::Exception' what(): /home/das/Downloads/opencv-2.4.5/modules/core/ src/stat.cpp:1797: ошибка: (-215) type == src2.type() && src1.cols == src2.cols && (type == CV_32F || type == CV_8U) в функции batchDistance

Прервано (сброшено ядро)

Я проверил эту ошибку, и оказалось, что src1.cols != src2.cols, и быстрое исправление для этого состояло бы в том, чтобы проверить условие, прежде чем пытаться сопоставить изображения. Проблема в том, что при этом я пропускаю много изображений, и это было бы нормально, только если бы я работал с видеопотоком... но я не работаю, и следующее изображение не имеет ничего общего с предыдущим, и Я не могу определить, присутствовал ли мой логотип в документе.

Вот код из stat.cpp, строки с 1789 по 1826: (утверждение находится в начале строки 1797)

void cv::batchDistance( InputArray _src1, InputArray _src2,
                    OutputArray _dist, int dtype, OutputArray _nidx,
                    int normType, int K, InputArray _mask,
                    int update, bool crosscheck )
{
Mat src1 = _src1.getMat(), src2 = _src2.getMat(), mask = _mask.getMat();
int type = src1.type();
CV_Assert( type == src2.type() && src1.cols == src2.cols &&
           (type == CV_32F || type == CV_8U));
CV_Assert( _nidx.needed() == (K > 0) );

if( dtype == -1 )
{
    dtype = normType == NORM_HAMMING || normType == NORM_HAMMING2 ? CV_32S : CV_32F;
}
CV_Assert( (type == CV_8U && dtype == CV_32S) || dtype == CV_32F);

K = std::min(K, src2.rows);

_dist.create(src1.rows, (K > 0 ? K : src2.rows), dtype);
Mat dist = _dist.getMat(), nidx;
if( _nidx.needed() )
{
    _nidx.create(dist.size(), CV_32S);
    nidx = _nidx.getMat();
}

if( update == 0 && K > 0 )
{
    dist = Scalar::all(dtype == CV_32S ? (double)INT_MAX : (double)FLT_MAX);
    nidx = Scalar::all(-1);
}

if( crosscheck )
{
    CV_Assert( K == 1 && update == 0 && mask.empty() );
    Mat tdist, tidx;
    batchDistance(src2, src1, tdist, dtype, tidx, normType, K, mask, 0, false);

Вот мне интересно, что означает это утверждение? Что такое файлы src1 и src2 в stat.cpp? Почему они должны иметь одинаковое количество столбцов?

Я попытался перейти на Surf-детектор и экстрактор, но все равно получаю ошибку.

Если у кого-то есть идея, не стесняйтесь писать, я приветствую любые советы или уведомления!

Заранее спасибо.

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

Теперь у меня более точный вопрос: как мне убедиться, что src1.cols == src2.cols? Чтобы ответить на этот вопрос, я думаю, мне следует знать, какие преобразования применяются к моим cv::Mat image1 и image2 до вызова batchDistance(...), чтобы найти условие для image1 и image2, которое гарантирует, что src1.cols == src2.cols, поэтому мой код будет выглядеть так:

// Match the two images
std::vector<cv::DMatch> matches;
std::vector<cv::KeyPoint> keypoints1, keypoints2;
    if( CONDITION_ON_IMAGE1&IMAGE2_TO_ENSURE_SRC1.COLS==SRC2.COLS ){
    cv::Mat fundemental = rmatcher.match(image1, image2, matches, keypoints1, keypoints2);
    }

person Danish Ashfaq    schedule 02.07.2013    source источник
comment
Вы пытались вставить меньшее изображение в пустое изображение с размером, соответствующим другому? Это может быть быстрое и грязное решение...   -  person morynicz    schedule 02.07.2013
comment
Это работает ! У меня больше нет ошибки. Но надежность обнаружения упала... Значит, для работы алгоритма должна быть корреляция между размерами исходных изображений. Вопрос в том, что это может быть за связь?   -  person Danish Ashfaq    schedule 03.07.2013
comment
Что ж, давайте посмотрим... Чем больше изображение, тем большее количество пикселей можно обнаружить. Лучшее качество функций. Так далее...   -  person morynicz    schedule 03.07.2013
comment
@morynicz Да, но я имел в виду что-то вроде соотношения двух входных изображений, которое должно быть примерно одинаковым, или размер изображения шаблона должен составлять не менее 10% от размера изображения документа. Не знаю, какое-то следствие этого утверждения...   -  person Danish Ashfaq    schedule 04.07.2013
comment
Чтобы узнать, какие преобразования выполняются на изображениях, вам нужно проанализировать код modules/ml/src/matcher.cpp. Строки 366 и 420 содержат вызов batchDistance.   -  person morynicz    schedule 05.07.2013


Ответы (1)


  1. Чтобы избавиться от ошибок, вы можете поиграть с копированием и вставкой изображений в пустое изображение необходимого размера, но это только быстрое и грязное решение для утверждения.
  2. Чтобы детектор и дескриптор работали правильно, вам, возможно, придется узнать, как они работают. Возможно, тогда Вам удастся получить изображения, которые будут работать. После прочтения этой статьи создается впечатление, что ORB будут проблемы с масштабированием (об этом говорится в заключении). Это означает, что вам нужно будет найти обходной путь для этого (например, пирамиды изображений или другой способ проверки изображения в нескольких масштабах) или использовать другой экстрактор и дескриптор, который не зависит от масштаба и поворота.
person morynicz    schedule 04.07.2013
comment
Решение №1 неприемлемо: в некоторых случаях любое маленькое изображение с большим количеством пустого пространства вокруг определяется как совпадение... Решение №2 сложное: я не могу гарантировать наличие логотипа на отсканированных документах того же размера, что и моя база данных. Обходной путь для этого — разрешить обновление базы данных с использованием одного и того же логотипа разного размера. - person Danish Ashfaq; 04.07.2013
comment
Я думаю, что Вы думаете в правильном направлении. Возможно, вы захотите взглянуть на пирамиды изображений. Я не эксперт по извлечению признаков и дескрипторам, но после некоторого чтения кажется, что получение инвариантности масштаба достигается путем изменения разрешения анализируемого изображения пару раз и поиска признаков на каждом масштабе (SIFT делает это, если я это понимаю правильно). - person morynicz; 04.07.2013
comment
Ясно, что большая база данных — это то, что нужно: точность обнаружения превосходит все, что я ожидал! Но у меня все еще есть ошибка на некоторых изображениях, и я все еще не мог понять, как ее избежать. - person Danish Ashfaq; 05.07.2013
comment
Что ж, я последовал вашему совету и позаботился о масштабировании изображений, прежде чем пытаться их сопоставить: я избавился от ошибки, не потеряв точности. Однако решение не было простым копированием и вставкой на пустое изображение, мне нужно было определить условие соотношения двух изображений: если изображение слишком растянуто в одном направлении, я просто игнорирую его. Это работает для моей цели. Спасибо, что указали мне правильное направление :) - person Danish Ashfaq; 09.07.2013
comment
@morynicz У меня есть аналогичная проблема, о которой я задавал вопрос здесь: stackoverflow.com/questions/45534183/. Я был бы очень признателен, если бы вы могли взглянуть на него. - person fi12; 08.08.2017