Распознавание изображения из списка с помощью OpenCV SIFT с использованием сопоставления FLANN

Суть приложения в том, чтобы распознать изображение из уже установленного списка изображений. Для списка изображений были извлечены дескрипторы SIFT и сохранены в файлах. Здесь ничего интересного:

std::vector<cv::KeyPoint> detectedKeypoints;
cv::Mat objectDescriptors;

// Extract data
cv::SIFT sift;
sift.detect(image, detectedKeypoints);
sift.compute(image, detectedKeypoints, objectDescriptors);

// Save the file
cv::FileStorage fs(file, cv::FileStorage::WRITE);
fs << "descriptors" << objectDescriptors;
fs << "keypoints" << detectedKeypoints;
fs.release();

Затем устройство делает снимок. Таким же образом извлекаются дескрипторы SIFT. Теперь идея заключалась в том, чтобы сравнить дескрипторы с дескрипторами из файлов. Я делаю это, используя сопоставитель FLANN из OpenCV. Я пытаюсь количественно определить сходство, изображение за изображением. После просмотра всего списка у меня должно быть лучшее совпадение.

const cv::Ptr<cv::flann::IndexParams>& indexParams = new cv::flann::KDTreeIndexParams(1);
const cv::Ptr<cv::flann::SearchParams>& searchParams = new cv::flann::SearchParams(64);

// Match using Flann
cv::Mat indexMat;
cv::FlannBasedMatcher matcher(indexParams, searchParams);
std::vector< cv::DMatch > matches;
matcher.match(objectDescriptors, readDescriptors, matches);

После сопоставления я понимаю, что получаю список ближайших найденных расстояний между векторами признаков. Я нахожу минимальное расстояние и с его помощью могу подсчитать «хорошие совпадения» и даже получить список соответствующих точек:

// Count the number of mathes where the distance is less than 2 * min_dist
int goodCount = 0;
for (int i = 0; i < objectDescriptors.rows; i++)
{
    if (matches[i].distance <  2 * min_dist)
    {
        ++goodCount;
        // Save the points for the homography calculation
        obj.push_back(detectedKeypoints[matches[i].queryIdx].pt);
        scene.push_back(readKeypoints[matches[i].trainIdx].pt);
    }
}

Я показываю простые части кода только для того, чтобы их было легче понять, я знаю, что некоторые из них не должны быть здесь.

Продолжая, я надеялся, что простого подсчета количества хороших совпадений будет достаточно, но оказалось, что в основном я просто указываю на изображение с наибольшим количеством дескрипторов. После этого я попытался вычислить гомографию. Цель состояла в том, чтобы вычислить его и посмотреть, является ли это действительной гомографией или нет. Была надежда, что хорошее совпадение, и только хорошее совпадение, будет иметь омографию, являющуюся хорошим преобразованием. Создание гомографии было выполнено просто с помощью cv::findHomography для obj и scene, которые являются std::vector‹ cv:: Point2f>. Я проверил правильность гомографии, используя код, который нашел в Интернете:

bool niceHomography(cv::Mat H)
{
    std::cout << H << std::endl;

    const double det = H.at<double>(0, 0) * H.at<double>(1, 1) - H.at<double>(1, 0) * H.at<double>(0, 1);
    if (det < 0)
    {
        std::cout << "Homography: bad determinant" << std::endl;
        return false;
    }

    const double N1 = sqrt(H.at<double>(0, 0) * H.at<double>(0, 0) + H.at<double>(1, 0) * H.at<double>(1, 0));
    if (N1 > 4 || N1 < 0.1)
    {
        std::cout << "Homography: bad first column" << std::endl;
        return false;
    }

    const double N2 = sqrt(H.at<double>(0, 1) * H.at<double>(0, 1) + H.at<double>(1, 1) * H.at<double>(1, 1));
    if (N2 > 4 || N2 < 0.1)
    {
        std::cout << "Homography: bad second column" << std::endl;
        return false;
    }

    const double N3 = sqrt(H.at<double>(2, 0) * H.at<double>(2, 0) + H.at<double>(2, 1) * H.at<double>(2, 1));
    if (N3 > 0.002)
    {
        std::cout << "Homography: bad third row" << std::endl;
        return false;
    }

    return true;
}

Я не понимаю математику, стоящую за этим, поэтому во время тестирования я иногда заменял эту функцию простой проверкой, был ли определитель гомографии положительным. Проблема в том, что у меня были проблемы здесь. Гомографии были либо все плохие, либо хорошие, когда не должны были быть (когда я проверял только определитель).

Я решил, что должен использовать гомографию и для ряда точек просто вычислить их положение в целевом изображении, используя их положение в исходном изображении. Затем я бы сравнил эти средние расстояния, и в идеале я бы получил очень очевидное меньшее среднее расстояние в случае правильного изображения. Это не сработало совсем. Все расстояния были колоссальными. Я думал, что мог бы использовать гомографию наоборот, чтобы вычислить правильную позицию, но переключение obj и scene друг с другом дало аналогичные результаты.

Другие вещи, которые я пробовал: дескрипторы SURF вместо SIFT, BFMatcher (грубая сила) вместо FLANN, получение n наименьших расстояний для каждого изображения вместо числа в зависимости от минимального расстояния или получение расстояний в зависимости от глобальное максимальное расстояние. Ни один из этих подходов не дал мне определенных хороших результатов, и сейчас я чувствую себя застрявшим.

Моей единственной следующей стратегией будет повышение резкости изображений или даже превращение их в бинарные изображения с использованием некоторого локального порога или некоторых алгоритмов, используемых для сегментации. Я ищу любые предложения или ошибки, которые кто-либо может увидеть в моей работе.

Я не знаю, актуально ли это, но я добавил несколько изображений, на которых тестирую это. Много раз в тестовых изображениях большинство векторов SIFT исходили из кадра (более контрастного), чем из картины. Вот почему я думаю, что повышение резкости изображений может сработать, но я не хочу углубляться, если что-то, что я сделал ранее, окажется неправильным.

Галерея изображений находится здесь с описаниями в заголовках. Изображения имеют довольно высокое разрешение, пожалуйста, просмотрите, если это может дать некоторые подсказки.


person octafbr    schedule 14.05.2014    source источник
comment
Эй, я пытаюсь сделать приложение, похожее на ваше. Вы нашли решение своей проблемы?   -  person dephinera    schedule 25.01.2015
comment
Логика была хороша, вы можете следовать ей. Возможно, вы захотите посмотреть гомографию, я думаю, мне пришлось это изменить. Однако я больше не могу делиться кодом, извините.   -  person octafbr    schedule 27.01.2015


Ответы (2)


Вы можете попробовать проверить, являются ли при сопоставлении линии между исходным изображением и целевым изображением относительно параллельными. Если это не правильное совпадение, то у вас будет много шума, и линии не будут параллельны.

Посмотрите на прикрепленное изображение, которое показывает правильное совпадение (с использованием SURF и BF) - все линии в основном параллельны (хотя я должен отметить, что это простой пример).

введите здесь описание изображения

person GilLevi    schedule 14.05.2014

Вы идете правильным путем.

Во-первых, используйте второе ближайшее соотношение вместо вашего «хорошего совпадения на 2 * min_dist» .

Во-вторых, используйте гомографию по-другому. Когда вы находите гомографию, у вас есть не только H-матрица, но и число соответствий, ей соответствующих. Проверьте, является ли это разумным числом, скажем >=15. Если меньше, то объект не соответствует.

В-третьих, если у вас сильное изменение точки зрения, SIFT или SURF не смогут сопоставить изображения. Вместо этого попробуйте использовать MODS (http://cmp.felk.cvut.cz/wbs/ вот бинарники для Windows и Linux, а также бумажка с описанием алгоритма) или ASIFT (гораздо медленнее и гораздо хуже совпадает, но с открытым исходным кодом) http://www.ipol.im/pub/art/2011/my-asift/

Или, по крайней мере, используйте детектор MSER или Hessian-Affine вместо SIFT (сохранив SIFT в качестве дескриптора).

person old-ufo    schedule 14.05.2014