Перейти к содержимому
Compvision.ru
mrgloom

еще раз о RANSAC

Recommended Posts

Пытаюсь сделать RANSAC с ограничениями, т.к. в opencv их задать нельзя.

сделал только для сдвига, работает.

Затем захотел сделать для сдвига+ поворота.

по идее матрица будет

1 -m dx

m 1 dy

но что то не то похоже.

потом попробовал рещить так же и для полностью аффинного преобразование тоже что то не то.

для аффинного.

беру рэндомно 3 точки и загоняю в солвер линейного уравнения

тут еще вопрос неувязку можно смотреть только по парам, а можно по всем точкам, непонятно как лучше.

еще по идее кол-во итераций должно зависеть от кол-ва точек.

double ransac_shift(std::vector<KeyPoint>& keypoints1,

				  std::vector<KeyPoint>& keypoints2,

				  std::vector<DMatch>& matches,

				  Mat& affine)

{

Mat m; //матрица коэффициентов

	srand(time(NULL));

	int n= matches.size();

	double min_score= INT_MAX;

	double max_dist=0;

	int n_iter=3*1000;

	for(int i=0;i<n_iter;++i)

	{

		int id1= rand()%n; //могут совпадать что плохо

		int id2= rand()%n;

		int id3= rand()%n;


		int i1_1 = matches[id1].queryIdx;

        int i2_1 = matches[id1].trainIdx;

		int i1_2 = matches[id2].queryIdx;

        int i2_2 = matches[id2].trainIdx;

		int i1_3 = matches[id3].queryIdx;

        int i2_3 = matches[id3].trainIdx;


		int x1= keypoints1[i1_1].pt.x;

		int y1= keypoints1[i1_1].pt.y;

		int n_x1= keypoints2[i2_1].pt.x;

		int n_y1= keypoints2[i2_1].pt.y;

		int x2= keypoints1[i1_2].pt.x;

		int y2= keypoints1[i1_2].pt.y;

		int n_x2= keypoints2[i2_2].pt.x;

		int n_y2= keypoints2[i2_2].pt.y;

		int x3= keypoints1[i1_3].pt.x;

		int y3= keypoints1[i1_3].pt.y;

		int n_x3= keypoints2[i2_3].pt.x;

		int n_y3= keypoints2[i2_3].pt.y;


		double m_a[6][6] = {{x1, y1, 1, 0, 0, 0},

							{0, 0, 0, x1, y1, 1},

							{x2, y2, 1, 0, 0, 0},

							{0, 0, 0, x2, y2, 1},

							{x3, y3, 1, 0, 0, 0},

							{0, 0, 0, x3, y3, 1}};

		Mat A= Mat(6, 6, CV_64F, m_a);

		double m_b[6][1] = {{n_x1},{n_y1},{n_x2},{n_y2},{n_x3},{n_y3}};

		Mat b= Mat(6, 1, CV_64F, m_;

		Mat x;

		solve(A,b,x,DECOMP_SVD);


		double m1= x.at<double>(0,0);

		double m2= x.at<double>(1,0);

		double m3= x.at<double>(2,0);

		double m4= x.at<double>(3,0);

		double m5= x.at<double>(4,0);

		double m6= x.at<double>(5,0); 


		//должны считать только для пар или вообще для всех точек?

		int64 sum=0;

		for(int p=0;p<n;++p)

		{

			int i1 = matches[p].queryIdx;

			int i2 = matches[p].trainIdx;


			//трансформируем первые точки во вторые и смотрим невязку

			int x1= keypoints1[i1].pt.x;

			int y1= keypoints1[i1].pt.y;

			int x2= keypoints2[i2].pt.x;

			int y2= keypoints2[i2].pt.y;


			int x_pr=m1*x1+m2*y1+m3;

			int y_pr=m4*x1+m5*y1+m6;


			int dist= sqrt((double)(x_pr-x2)*(x_pr-x2)+(y_pr-y2)*(y_pr-y2));


			if(dist>max_dist)

				max_dist=dist;

			sum+=dist;

		}

		double score= (double)sum/n;

		if(score<min_score)

		{

			min_score= score;

			affine=x;

		}

	}


	//cout<<min_score<<" "<<max_dist;

	return min_score;

}[/code]








еще вопросы:

1. Что считать инлайнерами? те точки которые лежат не более чем dist от спроецированных?

2. как задать критерий "сильности" связи, варианты: кол-во пар, кол-во инлайнеров, в опецв из Lowe предлагают 

вообще такую формулу

[code]// These coeffs are from paper M. Brown and D. Lowe. "Automatic Panoramic Image Stitching // using Invariant Features" matches_info.confidence = matches_info.num_inliers / (8 + 0.3 * matches_info.matches.size());
причем пару то, тоже можно определить по разному, можно просто найти лучшую пару из 2 сета, можно найти из одного в другой и обратно и только такие оставить, а можно использовать критерий уникальности пары(т.е. находяться 2 ближайшие пары для точки и потом смотриться не похожи ли они(если похожи то точка слишком не уникальная))
if (m0.distance < (1.f - match_conf_) * m1.distance)

по идее чем строже критерий мы выбираем, тем меньше аутлайнеров получим и тем меньше точек(меньше считать), но может получиться так что точек получиться мало и это тоже плохо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

показываю так

Mat M= affine.reshape(1,2);

cout<<M<<M.rows<<M.cols<<endl;

Mat im= Mat::zeros(vec_im[j].rows,vec_im[j].cols,vec_im[j].type());

warpAffine(vec_im[j], im, M, im.size());

Mat merged = Mat::zeros(vec_im.rows,vec_im.cols,vec_im.type());

addWeighted(vec_im, 0.5, im, 0.5, 0.0, merged);

imshow("out", merged);

cvWaitKey(0)

может быть матрицу affine надо как то нормировать?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Вот на pudn откопал RANSAC for DUMMIES :)

(книжка и матлабовские исходники)

RANSAC.RAR

Нашел сайт, с которого это взято:

http://vision.ece.ucsb.edu/~zuliani/Research/RANSAC/RANSAC.shtml

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

ну это видимо отсюда

http://vision.ece.ucsb.edu/~zuliani/Research/RANSAC/RANSAC.shtml

еще есть несколько модификаций тут

http://graphics.cs.msu.ru/en/science/research/machinelearning/ransactoolbox

и еще

http://code.google.com/p/groupsac/

у меня такое ощущение что всё таки у меня проблема в solve

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Если с solve, то это можно проверить обратной подстановкой.

Или производную посчитать в точке решения, она должна быть близка к нулю.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

int x_pr=m1*x1+m2*y1+m3;

int y_pr=m4*x1+m5*y1+m6;

int dist= sqrt((double)(x_pr-n_x1)*(x_pr-n_x1)+(y_pr-n_y1)*(y_pr-n_y1));

проблема вот в чём, из-за аутлайнеров, получается дикая матрица гомографии и получаются слишком большие числа x_pr и y_pr и переполнение и получается dist отрицательный.

непонятно как это можно красиво разрешить.

либо проверять dist на отрицательность, либо проверять матрицу гомографии каким либо образом, либо работать с типами данных которые поддерживают большие числа.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

т.е. всё таки наверно матрицу гомографии легче ограничить как то.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

а почему int то везде?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

да можно и дабл, только что если и дабл переполниться? мне кажется легче как то ограничить матрицу.

только для сдвига код работает

Mat m;

srand(time(NULL));

int n= matches.size();

double min_score= INT_MAX;

double max_dist=0;

int n_iter=10*1000;

for(int i=0;i<n_iter;++i)

{

    int id1= rand()%n;


    int i1_1 = matches[id1].queryIdx;

    int i2_1 = matches[id1].trainIdx;


    //2->1

    int n_x1= keypoints1[i1_1].pt.x;

    int n_y1= keypoints1[i1_1].pt.y;

    int x1= keypoints2[i2_1].pt.x;

    int y1= keypoints2[i2_1].pt.y;


    double m_a[2][2] = {{1, 0},{0, 1}};

    Mat A= Mat(2, 2, CV_64F, m_a);

    //cout<<A<<" "<<A.rows<<"x"<<A.cols<<endl;

    double m_b[2][1] = {{n_x1-x1},{n_y1-y1}};

    Mat b= Mat(2, 1, CV_64F, m_;

    //cout<<b<<" "<<b.rows<<"x"<<b.cols<<endl;

    Mat x;

    solve(A,b,x,DECOMP_SVD/*DECOMP_QR*/);

    //cout<<x<<" "<<x.rows<<"x"<<x.cols<<endl;

    //cout<<A*x<<endl;


    double m1= x.at<double>(0,0);

    double m2= x.at<double>(1,0);


    int sum=0;

    for(int p=0;p<n;++p)

    {

        int i1 = matches[p].queryIdx;

        int i2 = matches[p].trainIdx;


        int n_x1= keypoints1[i1].pt.x;

        int n_y1= keypoints1[i1].pt.y;

        int x1= keypoints2[i2].pt.x;

        int y1= keypoints2[i2].pt.y;


        int x_pr=x1+m1;

        int y_pr=y1+m2;


        double dist= sqrt((double)(x_pr-n_x1)*(x_pr-n_x1)+(y_pr-n_y1)*(y_pr-n_y1));


        if(dist>max_dist)

            max_dist=dist;

        sum+=dist;

    }

    double score= (double)sum/n;

    if(score<min_score)

    {

        min_score= score;

        affine=x;

    }

}

Mat t(6,1,CV_64F);

t.at<double>(0,0)= 1;

t.at<double>(1,0)= 0;

t.at<double>(2,0)= affine.at<double>(0,0);

t.at<double>(3,0)= 0;

t.at<double>(4,0)= 1;

t.at<double>(5,0)= affine.at<double>(1,0);

affine= t;[/code]


 



для сдвига и поворота я всё таки не уверен будет 3 или 4 параметра, но для 4 параметров вроде бы работает, но не идеально, возможно это именно погрешность в точках, надо еще потестировать на искуственных примерах.



[code]double m_a[4][4] = {{x1, -y1, 1, 0}, {y1, x1, 0, 1}, {x2, -y2, 1, 0}, {y2, x2, 0, 1},}; Mat A= Mat(4, 4, CV_64F, m_a); //cout<<A<<" "<<A.rows<<"x"<<A.cols<<endl; double m_b[4][1] = {{n_x1},{n_y1},{n_x2},{n_y2}}; Mat b= Mat(4, 1, CV_64F, m_B); //cout<<b<<" "<<b.rows<<"x"<<b.cols<<endl; Mat x; solve(A,b,x,DECOMP_SVD/*DECOMP_QR*/); //cout<<x<<" "<<x.rows<<"x"<<x.cols<<endl; //cout<<A*x<<endl; double m1= x.at<double>(0,0); double m2= x.at<double>(1,0); double m3= x.at<double>(2,0); double m4= x.at<double>(3,0); int sum=0; for(int p=0;p<n;++p) { int i1 = matches[p].queryIdx; int i2 = matches[p].trainIdx; int n_x1= keypoints1[i1].pt.x; int n_y1= keypoints1[i1].pt.y; int x1= keypoints2[i2].pt.x; int y1= keypoints2[i2].pt.y; int x_pr=m1*x1+(-m2)*y1+m3; int y_pr=m2*x1+m1*y1+m4; double dist= sqrt((double)(x_pr-n_x1)*(x_pr-n_x1)+(y_pr-n_y1)*(y_pr-n_y1)); if(dist>max_dist) max_dist=dist; sum+=dist; } double score= (double)sum/n; if(score<min_score) { min_score= score; affine=x; } } Mat t(6,1,CV_64F); t.at<double>(0,0)= affine.at<double>(0,0); t.at<double>(1,0)= -affine.at<double>(1,0); t.at<double>(2,0)= affine.at<double>(2,0); t.at<double>(3,0)= affine.at<double>(1,0); t.at<double>(4,0)= affine.at<double>(0,0); t.at<double>(5,0)= affine.at<double>(3,0); affine= t;
а для аффинного, даже если убрать ошибки с выходом за границы, то получается что изображение сжимается на облако точек, непонятно почему.
Mat m;

    srand(time(NULL));

    int n= matches.size();

    double min_score= INT_MAX;

    double max_dist=0;

    int n_iter=10*1000;

    for(int i=0;i<n_iter;++i)

    {

        int id1= rand()%n;

        int id2= rand()%n;

        int id3= rand()%n;


        int i1_1 = matches[id1].queryIdx;

        int i2_1 = matches[id1].trainIdx;

        int i1_2 = matches[id2].queryIdx;

        int i2_2 = matches[id2].trainIdx;

        int i1_3 = matches[id3].queryIdx;

        int i2_3 = matches[id3].trainIdx;


        int n_x1= keypoints1[i1_1].pt.x;

        int n_y1= keypoints1[i1_1].pt.y;

        int x1= keypoints2[i2_1].pt.x;

        int y1= keypoints2[i2_1].pt.y;

        int n_x2= keypoints1[i1_2].pt.x;

        int n_y2= keypoints1[i1_2].pt.y;

        int x2= keypoints2[i2_2].pt.x;

        int y2= keypoints2[i2_2].pt.y;

        int n_x3= keypoints1[i1_3].pt.x;

        int n_y3= keypoints1[i1_3].pt.y;

        int x3= keypoints2[i2_3].pt.x;

        int y3= keypoints2[i2_3].pt.y;


        //affine

        double m_a[6][6] = {{x1, y1, 1, 0, 0, 0},

                            {0, 0, 0, x1, y1, 1},

                            {x2, y2, 1, 0, 0, 0},

                            {0, 0, 0, x2, y2, 1},

                            {x3, y3, 1, 0, 0, 0},

                            {0, 0, 0, x3, y3, 1}};

        Mat A= Mat(6, 6, CV_64F, m_a);

        //cout<<A<<" "<<A.rows<<"x"<<A.cols<<endl;

        double m_b[6][1] = {{n_x1},{n_y1},{n_x2},{n_y2},{n_x3},{n_y3}};

        Mat b= Mat(6, 1, CV_64F, m_;

        //cout<<b<<" "<<b.rows<<"x"<<b.cols<<endl;

        Mat x;

        solve(A,b,x,DECOMP_SVD);

        //cout<<x<<" "<<x.rows<<"x"<<x.cols<<endl;


        double m1= x.at<double>(0,0);

        double m2= x.at<double>(1,0);

        double m3= x.at<double>(2,0);

        double m4= x.at<double>(3,0);

        double m5= x.at<double>(4,0);

        double m6= x.at<double>(5,0); 


        int sum=0;

        for(int p=0;p<n;++p)

        {

            int i1 = matches[p].queryIdx;

            int i2 = matches[p].trainIdx;


            int n_x1= keypoints1[i1].pt.x;

            int n_y1= keypoints1[i1].pt.y;

            int x1= keypoints2[i2].pt.x;

            int y1= keypoints2[i2].pt.y;


            int x_pr=m1*x1+m2*y1+m3;

            int y_pr=m4*x1+m5*y1+m6;


            int dist= sqrt((double)(x_pr-n_x1)*(x_pr-n_x1)+(y_pr-n_y1)*(y_pr-n_y1));



            if(dist>max_dist)

                max_dist=dist;

            sum+=dist;

        }

        double score= (double)sum/n;

        if(score<min_score)

        {

            min_score= score;

            affine=x;

        }

    }[/code]

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

вот что пишут про проверку матрицы гомографии

http://stackoverflow.com/questions/10972438/detecting-garbage-homographies-from-findhomography-in-opencv

только непонятно почему такие критерии

да еще кстати если у нас модель нелинейная, то мы должны использовать какой то солвер\минимайзер вместо solve для решения системы линейных уравнений.

так вот как должна ставиться задача? кол-во уравнений = кол-ву переменых, но сами уравнения нелинейные и в какой форме их пихать в солвер?

вот тут понятнее, надо будет попробовать

http://www.mathworks.com/help/optim/ug/fsolve.html

в videostab global_motiom.cpp

вроде как раз рассмотрены разные случаи

сама функция findHomography сейчас как то непонятно реализована в fundum.cpp

CvHomographyEstimator::runKernel

вроде бы решает лин. систему

а потом видимо уточнение

CvHomographyEstimator::refine через CvLevMarq solver

кстати где то можно посмотреть как менялись исходники opencv может быть findHomography в старых версиях была как то по другому реализована?

еще обнаружился какой то странный файл

circlesgrid.cpp который непонятно что делает.

я так понимаю это связано с

http://en.wikipedia.org/wiki/Relative_neighborhood_graph

http://en.wikipedia.org/wiki/Maximum_common_subgraph_isomorphism_problem

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

встроеный метод LMEDS почему то не хочет работать, сжимает изображение в полоску.

SurfFeaturesFinder finder(1);

vector<ImageFeatures> vec_features;

for(int i=0;i<vec_im.size();++i)

{

ImageFeatures t;

finder(vec_im[i],t);

t.img_idx = i;

vec_features.push_back(t);

}

finder.collectGarbage();


//LMEDS

	int k=0;

	for(int i=0;i<vec_features.size();++i)

	{

		++k;

		for(int j=k;j<vec_features.size();++j)

		{

			Ptr<DescriptorMatcher> matcher = new BFMatcher(NORM_L2);

			vector<Point2f> prev_keys, curr_keys;

			std::vector<DMatch> matches;

			matcher->match(vec_features[i].descriptors, vec_features[j].descriptors, matches);

			for (int p = 0; p < (int)matches.size(); ++p)

			{

				prev_keys.push_back(vec_features[i].keypoints[matches[p].queryIdx].pt);

				curr_keys.push_back(vec_features[j].keypoints[matches[p].trainIdx].pt);

			}

			Mat M = findHomography(prev_keys, curr_keys, CV_LMEDS);

			cout<<M<<" "<<M.rows<<"x"<<M.cols<<endl;

			cout<<M(Rect(0,0,3,2))<<endl;

			Mat im= Mat::zeros(vec_im[j].rows,vec_im[j].cols,vec_im[j].type());

			warpAffine(vec_im[j], im, M(Rect(0,0,3,2)), im.size());

			imshow("im", im);

			Mat merged = Mat::zeros(vec_im[i].rows,vec_im[i].cols,vec_im[i].type());

			addWeighted(vec_im[i], 0.5, im, 0.5, 0.0, merged); //+ можно еще выводить тчоки для дебага

			imshow("out", merged);

			cvWaitKey(0);

		}

	}
хотя так тоже не работает
Mat M = findHomography(prev_keys, curr_keys, CV_RANSAC);
видимо ошибка в чем то другом. вообщем не работало потому, что этот код даёт плохие соответствия
Ptr<DescriptorMatcher> matcher = new BFMatcher(NORM_L2);

			vector<Point2f> prev_keys, curr_keys;

			std::vector<DMatch> matches;

			matcher->match(vec_features[i].descriptors, vec_features[j].descriptors, matches);

но даже с более строгой процедурой нахождения пар findHomography по дефолту плохо работает(дает не точный результат).

возможно мало итераций.

возможно имеет смысл как то постепенно приближаться к решению от простой модели до самой сложной?(от сдвига до перспективной)

по наблидениям determinant(M) при плохой матрице около 0, а при хорошей около 1, правда может быть и 1,5 при сильно неточном совмещении.

видимо надо ориентироваться на determinant(M)~1 т.е. малое искажение от единичной матрицы 3х3.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Посмотрите в примерах:

opencv\samples\cpp\tutorial_code\features2D\SURF_Homography.cpp

Если в вашей версии нет, то вот код:


/**
* @file SURF_Homography
* @brief SURF detector + descriptor + FLANN Matcher + FindHomography
* @author A. Huaman
*/

#include <stdio.h>
#include <iostream>
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/nonfree/features2d.hpp"

using namespace std;
using namespace cv;

void readme();

/**
* @function main
* @brief Main function
*/
int main( int argc, char** argv )
{
if( argc != 3 )
{ readme(); return -1; }

Mat img_object = imread( argv[1], IMREAD_GRAYSCALE );
Mat img_scene = imread( argv[2], IMREAD_GRAYSCALE );

if( !img_object.data || !img_scene.data )
{ std::cout<< " --(!) Error reading images " << std::endl; return -1; }

//-- Step 1: Detect the keypoints using SURF Detector
int minHessian = 400;

SurfFeatureDetector detector( minHessian );

std::vector<KeyPoint> keypoints_object, keypoints_scene;

detector.detect( img_object, keypoints_object );
detector.detect( img_scene, keypoints_scene );

//-- Step 2: Calculate descriptors (feature vectors)
SurfDescriptorExtractor extractor;

Mat descriptors_object, descriptors_scene;

extractor.compute( img_object, keypoints_object, descriptors_object );
extractor.compute( img_scene, keypoints_scene, descriptors_scene );

//-- Step 3: Matching descriptor vectors using FLANN matcher
FlannBasedMatcher matcher;
std::vector< DMatch > matches;
matcher.match( descriptors_object, descriptors_scene, matches );

double max_dist = 0; double min_dist = 100;

//-- Quick calculation of max and min distances between keypoints
for( int i = 0; i < descriptors_object.rows; i++ )
{ double dist = matches[i].distance;
if( dist < min_dist ) min_dist = dist;
if( dist > max_dist ) max_dist = dist;
}

printf("-- Max dist : %f \n", max_dist );
printf("-- Min dist : %f \n", min_dist );

//-- Draw only "good" matches (i.e. whose distance is less than 3*min_dist )
std::vector< DMatch > good_matches;

for( int i = 0; i < descriptors_object.rows; i++ )
{ if( matches[i].distance < 3*min_dist )
{ good_matches.push_back( matches[i]); }
}

Mat img_matches;
drawMatches( img_object, keypoints_object, img_scene, keypoints_scene,
good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );


//-- Localize the object from img_1 in img_2
std::vector<Point2f> obj;
std::vector<Point2f> scene;

for( size_t i = 0; i < good_matches.size(); i++ )
{
//-- Get the keypoints from the good matches
obj.push_back( keypoints_object[ good_matches[i].queryIdx ].pt );
scene.push_back( keypoints_scene[ good_matches[i].trainIdx ].pt );
}

Mat H = findHomography( obj, scene, RANSAC );

//-- Get the corners from the image_1 ( the object to be "detected" )
std::vector<Point2f> obj_corners(4);
obj_corners[0] = Point(0,0); obj_corners[1] = Point( img_object.cols, 0 );
obj_corners[2] = Point( img_object.cols, img_object.rows ); obj_corners[3] = Point( 0, img_object.rows );
std::vector<Point2f> scene_corners(4);

perspectiveTransform( obj_corners, scene_corners, H);


//-- Draw lines between the corners (the mapped object in the scene - image_2 )
Point2f offset( (float)img_object.cols, 0);
line( img_matches, scene_corners[0] + offset, scene_corners[1] + offset, Scalar(0, 255, 0), 4 );
line( img_matches, scene_corners[1] + offset, scene_corners[2] + offset, Scalar( 0, 255, 0), 4 );
line( img_matches, scene_corners[2] + offset, scene_corners[3] + offset, Scalar( 0, 255, 0), 4 );
line( img_matches, scene_corners[3] + offset, scene_corners[0] + offset, Scalar( 0, 255, 0), 4 );

//-- Show detected matches
imshow( "Good Matches & Object detection", img_matches );

waitKey(0);

return 0;
}

/**
* @function readme
*/
void readme()
{ std::cout << " Usage: ./SURF_Homography <img1> <img2>" << std::endl; }

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

это то понятно, я имел ввиду внутри функкции findhomography, вроде до того как они перешли на ООП там было всё более понятно, т.к. сейчас я не смог разобраться в том что сделано в fundum.cpp, видимо там какие то более общие формулы.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

похоже это плохой\слабый критерий

 //-- Draw only "good" matches (i.e. whose distance is less than 3*min_dist )

  std::vector< DMatch > good_matches;


  for( int i = 0; i < descriptors_object.rows; i++ )

  { if( matches[i].distance < 3*min_dist )

    { good_matches.push_back( matches[i]); }

  }

проблема в том что как я понимаю индекс строиться для каждой пары, а по идее для 1 изображения могли бы построить 1 раз и матчить его с n изображениями.
void match_flann(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo& matches_info)

{

	double match_conf= 0.3f;


    CV_Assert(features1.descriptors.type() == features2.descriptors.type());

    CV_Assert(features2.descriptors.depth() == CV_8U || features2.descriptors.depth() == CV_32F);


    matches_info.matches.clear();


    Ptr<flann::IndexParams> indexParams = new flann::KDTreeIndexParams();

    Ptr<flann::SearchParams> searchParams = new flann::SearchParams();


    if (features2.descriptors.depth() == CV_8U)

    {

        indexParams->setAlgorithm(cvflann::FLANN_INDEX_LSH);

        searchParams->setAlgorithm(cvflann::FLANN_INDEX_LSH);

    }


    FlannBasedMatcher matcher(indexParams, searchParams);

    vector<vector<DMatch>> pair_matches;

    set<pair<int,int>> matches;


    // Find 1->2 matches

    matcher.knnMatch(features1.descriptors, features2.descriptors, pair_matches, 2);

    for (size_t i = 0; i < pair_matches.size(); ++i)

    {

        if (pair_matches[i].size() < 2)

            continue;

        const DMatch& m0 = pair_matches[i][0];

        const DMatch& m1 = pair_matches[i][1];

        if (m0.distance < (1.f - match_conf) * m1.distance)

        {

            matches_info.matches.push_back(m0);

            matches.insert(make_pair(m0.queryIdx, m0.trainIdx));

        }

    }


    // Find 2->1 matches

    pair_matches.clear();

    matcher.knnMatch(features2.descriptors, features1.descriptors, pair_matches, 2);

    for (size_t i = 0; i < pair_matches.size(); ++i)

    {

        if (pair_matches[i].size() < 2)

            continue;

        const DMatch& m0 = pair_matches[i][0];

        const DMatch& m1 = pair_matches[i][1];

        if (m0.distance < (1.f - match_conf) * m1.distance)

            if (matches.find(make_pair(m0.trainIdx, m0.queryIdx)) == matches.end())

                matches_info.matches.push_back(DMatch(m0.trainIdx, m0.queryIdx, m0.distance));

    }

}

и я всё таки не могу понять зачем 1->2 ищут, а потом 2->1.

возможно это связано с тем, что там идет приблизительный поиск, а не точный.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
и я всё таки не могу понять зачем 1->2 ищут, а потом 2->1

Видимо чтобы получить более точное решение, там же ищется аппроксимация knn, при помощи дерева, а не точное решение.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×