Смысл приложения заключается в распознавании изображения из уже заданного списка изображений. В списке изображений были извлечены и сохранены в файлах дескрипторы 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);
}
}
Я показываю легкие части кода, чтобы сделать его более легким для понимания, я знаю, что некоторые из них не обязательно должны быть здесь.
Продолжая, я надеялся, что простого подсчета количества подходящих совпадений будет достаточно, но оказалось, что в основном я просто указываю на изображение с наибольшим количеством дескрипторов. После этого я пытался вычислить гомографию. Цель состояла в том, чтобы вычислить это и посмотреть, является ли это действительной гомографией или нет. Надежда заключалась в том, что хороший матч и только хороший матч позволят получить гомографию, которая будет хорошей трансформацией. Создание гомографии было сделано просто с помощью резюме :: findHomography на OBJ а также сцена которые станд :: вектор< резюме :: 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 а также сцена друг с другом дали схожие результаты.
Другие вещи, которые я пробовал, были SURF-дескрипторы вместо SIFT, BFMatcher (грубая сила) вместо FLANN, получая N наименьшее расстояние для каждого изображения вместо числа в зависимости от минимального расстояния или получения расстояний в зависимости от глобального максимального расстояния. Ни один из этих подходов не дал мне определенных хороших результатов, и я чувствую себя застрявшим сейчас.
Моей единственной следующей стратегией будет повышение резкости изображений или даже их преобразование в двоичные изображения с использованием некоторого локального порога или некоторых алгоритмов, используемых для сегментации. Я ищу любые предложения или ошибки, которые каждый может увидеть в моей работе.
Я не знаю, относится ли это к делу, но я добавил несколько изображений, на которых я тестирую это. Много раз в тестовых изображениях большинство векторов SIFT получаются из кадра (более высокая контрастность), чем картина. Вот почему я думаю, что резкость изображений может сработать, но я не хочу углубляться, если что-то, что я сделал ранее, неверно.
Галерея изображений Вот с описаниями в заголовках. Изображения имеют довольно высокое разрешение, пожалуйста, просмотрите их, если они могут дать некоторые подсказки.
Вы можете попытаться проверить, если при сопоставлении линии между исходным изображением и целевым изображением относительно параллельны. Если это не правильное соответствие, то у вас будет много шума, и линии не будут параллельными.
Посмотрите на прикрепленное изображение, которое показывает правильное соответствие (с использованием SURF и BF) — все линии в основном параллельны (хотя я должен отметить, что это простой пример).
Вы идете правильным путем.
Во-первых, используйте второе ближайшее соотношение вместо вашего «хорошего совпадения по 2 * min_dist» https://stackoverflow.com/a/23019889/1983544.
Во-вторых, используйте гомографию по-другому. Когда вы находите гомографию, у вас есть не только H, матрица, но и количество соответствий, соответствующих ей. Проверьте, является ли это какое-то разумное число, скажем> = 15. Если меньше, чем объект не соответствует.
В-третьих, если у вас большие изменения точки обзора, SIFT или SURF не могут сопоставить изображения. Попробуйте вместо этого использовать моды (http://cmp.felk.cvut.cz/wbs/ это двоичные файлы Windows и Linux, а также документ с описанием алгоритма) или ASIFT (намного медленнее и намного хуже, но с открытым исходным кодом) http://www.ipol.im/pub/art/2011/my-asift/
Или, по крайней мере, используйте MSER или Hessian-Affine детектор вместо SIFT (сохраняя SIFT в качестве дескриптора).