tutorial rectangulos reconocimiento personas objetos introduccion español deteccion curso contornos caracteres artificial c++ opencv matching feature-detection

c++ - rectangulos - reconocimiento de objetos opencv java



Mejora la coincidencia de puntos de característica con OpenCV (3)

Además de la prueba de razón, puede:

Solo use coincidencias simétricas:

void symmetryTest(const std::vector<cv::DMatch> &matches1,const std::vector<cv::DMatch> &matches2,std::vector<cv::DMatch>& symMatches) { symMatches.clear(); for (vector<DMatch>::const_iterator matchIterator1= matches1.begin();matchIterator1!= matches1.end(); ++matchIterator1) { for (vector<DMatch>::const_iterator matchIterator2= matches2.begin();matchIterator2!= matches2.end();++matchIterator2) { if ((*matchIterator1).queryIdx ==(*matchIterator2).trainIdx &&(*matchIterator2).queryIdx ==(*matchIterator1).trainIdx) { symMatches.push_back(DMatch((*matchIterator1).queryIdx,(*matchIterator1).trainIdx,(*matchIterator1).distance)); break; } } } }

y dado que es una imagen estéreo, usa la prueba de ransac:

void ransacTest(const std::vector<cv::DMatch> matches,const std::vector<cv::KeyPoint>&keypoints1,const std::vector<cv::KeyPoint>& keypoints2,std::vector<cv::DMatch>& goodMatches,double distance,double confidence,double minInlierRatio) { goodMatches.clear(); // Convert keypoints into Point2f std::vector<cv::Point2f> points1, points2; for (std::vector<cv::DMatch>::const_iterator it= matches.begin();it!= matches.end(); ++it) { // Get the position of left keypoints float x= keypoints1[it->queryIdx].pt.x; float y= keypoints1[it->queryIdx].pt.y; points1.push_back(cv::Point2f(x,y)); // Get the position of right keypoints x= keypoints2[it->trainIdx].pt.x; y= keypoints2[it->trainIdx].pt.y; points2.push_back(cv::Point2f(x,y)); } // Compute F matrix using RANSAC std::vector<uchar> inliers(points1.size(),0); cv::Mat fundemental= cv::findFundamentalMat(cv::Mat(points1),cv::Mat(points2),inliers,CV_FM_RANSAC,distance,confidence); // confidence probability // extract the surviving (inliers) matches std::vector<uchar>::const_iterator itIn= inliers.begin(); std::vector<cv::DMatch>::const_iterator itM= matches.begin(); // for all matches for ( ;itIn!= inliers.end(); ++itIn, ++itM) { if (*itIn) { // it is a valid match goodMatches.push_back(*itM); } } }

Quiero unir puntos de características en imágenes estéreo. Ya he encontrado y extraído los puntos de característica con diferentes algoritmos y ahora necesito una buena coincidencia. En este caso estoy usando los algoritmos FAST para detección y extracción y BruteForceMatcher para hacer coincidir los puntos de característica.

El código coincidente:

vector< vector<DMatch> > matches; //using either FLANN or BruteForce Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(algorithmName); matcher->knnMatch( descriptors_1, descriptors_2, matches, 1 ); //just some temporarily code to have the right data structure vector< DMatch > good_matches2; good_matches2.reserve(matches.size()); for (size_t i = 0; i < matches.size(); ++i) { good_matches2.push_back(matches[i][0]); }

Como hay muchas coincidencias falsas, calculé la distancia mínima y máxima y eliminé todas las coincidencias que son demasiado malas:

//calculation of max and min distances between keypoints double max_dist = 0; double min_dist = 100; for( int i = 0; i < descriptors_1.rows; i++ ) { double dist = good_matches2[i].distance; if( dist < min_dist ) min_dist = dist; if( dist > max_dist ) max_dist = dist; } //find the "good" matches vector< DMatch > good_matches; for( int i = 0; i < descriptors_1.rows; i++ ) { if( good_matches2[i].distance <= 5*min_dist ) { good_matches.push_back( good_matches2[i]); } }

El problema es que recibo muchas coincidencias falsas o solo unas pocas (ver las imágenes a continuación).

muchos partidos con malos resultados http://codemax.de/upl/badMatchesFAST.png solo unos pocos buenos partidos http://codemax.de/upl/goodMatchesFAST.png

Creo que no es un problema de programación, sino más bien una coincidencia. Por lo que he entendido, BruteForceMatcher solo considera la distancia visual de los puntos característicos (que se almacenan en el FeatureExtractor ), no la distancia local (posición xey), que en mi caso también es importante. ¿Alguien ha tenido alguna experiencia con este problema o una buena idea para mejorar los resultados?

EDITAR

Cambié el código, que me da las 50 mejores coincidencias. Después de esto, realizo el primer partido para verificar si está en un área específica. Si no lo es, tomo el siguiente partido hasta que encuentre un partido dentro del área dada.

vector< vector<DMatch> > matches; Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(algorithmName); matcher->knnMatch( descriptors_1, descriptors_2, matches, 50 ); //look if the match is inside a defined area of the image double tresholdDist = 0.25 * sqrt(double(leftImageGrey.size().height*leftImageGrey.size().height + leftImageGrey.size().width*leftImageGrey.size().width)); vector< DMatch > good_matches2; good_matches2.reserve(matches.size()); for (size_t i = 0; i < matches.size(); ++i) { for (int j = 0; j < matches[i].size(); j++) { //calculate local distance for each possible match Point2f from = keypoints_1[matches[i][j].queryIdx].pt; Point2f to = keypoints_2[matches[i][j].trainIdx].pt; double dist = sqrt((from.x - to.x) * (from.x - to.x) + (from.y - to.y) * (from.y - to.y)); //save as best match if local distance is in specified area if (dist < tresholdDist) { good_matches2.push_back(matches[i][j]); j = matches[i].size(); } }

Creo que no obtengo más coincidencias, pero con esto puedo eliminar más coincidencias falsas:

menos pero mejores características http://codemax.de/upl/img001.png


Al comparar todos los algoritmos de detección de características encontré una buena combinación, lo que me da muchas más coincidencias. Ahora estoy usando FAST para la detección de características, SIFT para la extracción de características y BruteForce para la coincidencia. Combinado con el cheque, si las coincidencias están dentro de una región definida, obtengo muchas coincidencias, vea la imagen:

una gran cantidad de buenas coincidencias con FAST y SIFT http://codemax.de/upl/FASTandSIFT.png

El código relevante:

Ptr<FeatureDetector> detector; detector = new DynamicAdaptedFeatureDetector ( new FastAdjuster(10,true), 5000, 10000, 10); detector->detect(leftImageGrey, keypoints_1); detector->detect(rightImageGrey, keypoints_2); Ptr<DescriptorExtractor> extractor = DescriptorExtractor::create("SIFT"); extractor->compute( leftImageGrey, keypoints_1, descriptors_1 ); extractor->compute( rightImageGrey, keypoints_2, descriptors_2 ); vector< vector<DMatch> > matches; Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce"); matcher->knnMatch( descriptors_1, descriptors_2, matches, 500 ); //look whether the match is inside a defined area of the image //only 25% of maximum of possible distance double tresholdDist = 0.25 * sqrt(double(leftImageGrey.size().height*leftImageGrey.size().height + leftImageGrey.size().width*leftImageGrey.size().width)); vector< DMatch > good_matches2; good_matches2.reserve(matches.size()); for (size_t i = 0; i < matches.size(); ++i) { for (int j = 0; j < matches[i].size(); j++) { Point2f from = keypoints_1[matches[i][j].queryIdx].pt; Point2f to = keypoints_2[matches[i][j].trainIdx].pt; //calculate local distance for each possible match double dist = sqrt((from.x - to.x) * (from.x - to.x) + (from.y - to.y) * (from.y - to.y)); //save as best match if local distance is in specified area and on same height if (dist < tresholdDist && abs(from.y-to.y)<5) { good_matches2.push_back(matches[i][j]); j = matches[i].size(); } } }


Un método alternativo para determinar coincidencias de características de alta calidad es la prueba de relación propuesta por David Lowe en su documento sobre SIFT (página 20 para obtener una explicación). Esta prueba rechaza las coincidencias pobres al calcular la proporción entre la mejor y la segunda mejor coincidencia. Si la relación está por debajo de cierto umbral, la coincidencia se descarta como de baja calidad.

std::vector<std::vector<cv::DMatch>> matches; cv::BFMatcher matcher; matcher.knnMatch(descriptors_1, descriptors_2, matches, 2); // Find two nearest matches vector<cv::DMatch> good_matches; for (int i = 0; i < matches.size(); ++i) { const float ratio = 0.8; // As in Lowe''s paper; can be tuned if (matches[i][0].distance < ratio * matches[i][1].distance) { good_matches.push_back(matches[i][0]); } }