Détection et description de caractéristiques C++ OpenCV
La détection et la description de caractéristiques sont une technologie essentielle en vision par ordinateur, utilisée pour extraire des points clés à partir d'images et calculer leurs descripteurs. Ces points clés et descripteurs peuvent être utilisés pour des tâches telles que la mise en correspondance d'images, la reconnaissance d'objets et la reconstruction 3D.
Étapes principales
Détection de caractéristiques: Détecte des points clés dans une image (tels que des coins, des contours, etc.).
Description de caractéristiques: Calcule un descripteur pour chaque point clé afin de représenter les caractéristiques locales autour du point clé.
Mise en correspondance de caractéristiques: Trouve des points clés similaires dans différentes images en comparant les descripteurs.
- Détection et description de caractéristiques : trouver des points clés similaires dans deux images via la mise en correspondance de caractéristiques, utilisé pour l'assemblage d'images, la génération de panoramas, etc.
- Reconnaissance d'objets : extraire les caractéristiques de l'image cible, les mettre en correspondance avec les caractéristiques de la base de données et réaliser la reconnaissance d'objets.
- Reconstruction 3D : calculer la pose de la caméra et reconstruire une scène 3D en mettant en correspondance des points caractéristiques dans des images multi-vues.
- Suivi en temps réel : détecter et suivre des points caractéristiques dans des séquences vidéo, utilisé dans des applications telles que SLAM (localisation et cartographie simultanées).
Algorithmes courants de détection et de description de caractéristiques
OpenCV propose une variété d'algorithmes de détection et de description de caractéristiques. Voici quelques-uns des plus courants :
| Algorithme | Caractéristiques | Scénarios applicables |
|---|---|---|
| SIFT | Scale-Invariant Feature Transform, robuste aux changements de rotation, d'échelle et de luminosité. | Appariement d'images, reconnaissance d'objets |
| SURF | Version accélérée de SIFT, calcul plus rapide, mais légèrement moins robuste aux changements de rotation et d'échelle. | Appariement d'images en temps réel |
| ORB | Basé sur la détection de points clés FAST et les descripteurs BRIEF, rapide et adapté aux applications en temps réel. | Appariement d'images en temps réel, SLAM |
| FAST | Algorithme rapide de détection de coins, détecte uniquement les points clés, ne génère pas de descripteurs. | Détection de coins en temps réel |
| BRIEF | Descripteur binaire, calcul rapide, mais moins robuste aux rotations et aux changements d'échelle. | Appariement d'images en temps réel |
| AKAZE | Algorithme de détection et de description de caractéristiques basé sur un espace d'échelle non linéaire, robuste aux rotations et aux changements d'échelle. | Appariement d'images, reconnaissance d'objets |
Détection de coins
Les coins sont des points dans une image où la luminosité change brusquement, généralement situés aux bords des objets ou dans les zones riches en texture. La détection de coins est la base de la détection de caractéristiques. Les algorithmes courants de détection de coins incluent la détection de coins de Harris et la détection de coins de Shi-Tomasi.
Détection de coins de Harris
La détection de coins de Harris est un algorithme classique de détection de coins. Il détermine si un pixel est un coin en calculant la matrice d'autocorrélation pour chaque pixel de l'image. Les valeurs propres de la matrice d'autocorrélation reflètent la structure locale du pixel : si les deux valeurs propres sont grandes, le pixel est probablement un coin ; si une valeur propre est grande et l'autre petite, le pixel peut être un bord ; si les deux valeurs propres sont petites, le pixel peut se trouver dans une région plate.
Dans OpenCV, vous pouvez utiliser lacv::cornerHarrisfonction pour implémenter la détection de coins de Harris :
Exemple
int main() {
cv::Mat src = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
cv::Mat dst, dst_norm;
// Détection de coins de Harris
cv::cornerHarris(src, dst, 2, 3, 0.04);
// Normaliser et afficher le résultat
cv::normalize(dst, dst_norm, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat());
cv::imshow("Coins de Harris", dst_norm);
cv::waitKey(0);
return 0;
}
Détection de coins Shi-Tomasi
La détection de coins Shi-Tomasi est une amélioration par rapport à la détection de coins de Harris. Elle détermine si un pixel est un coin en calculant la valeur propre minimale pour chaque pixel de l'image. Comparée à la détection de coins de Harris, la détection de coins Shi-Tomasi est plus stable et nécessite moins de calculs.
Dans OpenCV, vous pouvez utiliser lacv::goodFeaturesToTrackfonction pour implémenter la détection de coins Shi-Tomasi :
Exemple
int main() {
cv::Mat src = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
std::vector<cv::Point2f> corners;
// Détection de coins Shi-Tomasi
cv::goodFeaturesToTrack(src, corners, 100, 0.01, 10);
// Dessiner les coins
for (size_t i = 0; i < corners.size(); i++) {
cv::circle(src, corners[i], 5, cv::Scalaire(0, 0, 255), 2);
}
cv::imshow("Shi-Tomasi Corners", src);
cv::waitKey(0);
return 0;
}
Détection de points caractéristiques
La détection de points caractéristiques est l'extraction de points ayant des propriétés distinctives dans une image. Ces points sont généralement invariants à la rotation, à la mise à l'échelle et à l'éclairage. Les algorithmes courants de détection de points caractéristiques incluent SIFT, SURF et ORB.
Algorithme SIFT
SIFT (Scale-Invariant Feature Transform) est un algorithme de détection de points caractéristiques basé sur l'espace d'échelle. Il est invariant à la rotation de l'image, à la mise à l'échelle et aux variations de luminosité. L'algorithme SIFT détecte les points extrêmes dans une image et calcule des histogrammes d'orientation de gradient pour ces points afin de générer des descripteurs de caractéristiques.
Dans OpenCV, vous pouvez utiliser lacv::xfeatures2d::SIFTClasse pour implémenter la détection de points caractéristiques SIFT :
Exemple
#include <opencv2/xfeatures2d.hpp>
int main() {
cv::Mat src = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
std::vector<cv::KeyPoint> keypoints;
cv::Mat descriptors;
// Détection de points caractéristiques SIFT
cv::Ptr<cv::xfeatures2d::SIFT> sift = cv::xfeatures2d::SIFT::create();
sift->detectAndCompute(src, cv::noArray(), keypoints, descriptors);
// Dessiner les points caractéristiques
cv::Mat output;
cv::drawKeypoints(src, keypoints, output);
cv::imshow("Points caractéristiques SIFT", output);
cv::waitKey(0);
return 0;
}
Algorithme SURF
SURF (Speeded-Up Robust Features) est une amélioration de l'algorithme SIFT. Il utilise les images intégrales et la matrice hessienne pour accélérer le processus de détection des points caractéristiques. L'algorithme SURF améliore considérablement la vitesse de calcul tout en conservant une grande précision de détection.
Dans OpenCV, vous pouvez utiliser lacv::xfeatures2d::SURFclasse pour implémenter la détection de points caractéristiques SURF :
Exemple
#include <opencv2/xfeatures2d.hpp>
int main() {
cv::Mat src = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
std::vector<cv::KeyPoint> keypoints;
cv::Mat descriptors;
// Détection de points caractéristiques SURF
cv::Ptr<cv::xfeatures2d::SURF> surf = cv::xfeatures2d::SURF::create();
surf->detectAndCompute(src, cv::noArray(), keypoints, descriptors);
// Dessiner les points caractéristiques
cv::Mat output;
cv::drawKeypoints(src, keypoints, output);
cv::imshow("Points clés SURF", output);
cv::waitKey(0);
return 0;
}
Algorithme ORB
ORB (Oriented FAST and Rotated BRIEF) est un algorithme de détection de points caractéristiques qui combine la détection de coins FAST et le descripteur BRIEF. L'algorithme ORB a une grande efficacité de calcul et convient aux applications en temps réel.
Dans OpenCV, vous pouvez utiliser lacv::ORBclasse pour implémenter la détection de points caractéristiques ORB :
Exemple
int main() {
cv::Mat src = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
std::vector<cv::KeyPoint> keypoints;
cv::Mat descriptors;
// Détection de points caractéristiques ORB
cv::Ptr<cv::ORB> orb = cv::ORB::create();
orb->detectAndCompute(src, cv::noArray(), keypoints, descriptors);
// Dessiner les points caractéristiques
cv::Mat output;
cv::drawKeypoints(src, keypoints, output);
cv::imshow("Points clés ORB", output);
cv::waitKey(0);
return 0;
}
Appariement de caractéristiques
L'appariement de caractéristiques est le processus de mise en correspondance de points caractéristiques entre deux images. Les algorithmes courants d'appariement de caractéristiques incluent BFMatcher (Brute-Force Matcher) et le matcheur FLANN.
BFMatcher
BFMatcher (Brute-Force Matcher) est un algorithme simple d'appariement de caractéristiques qui trouve les meilleurs points correspondants en calculant la distance euclidienne entre les descripteurs de caractéristiques. BFMatcher convient aux cas où le nombre de points caractéristiques est faible.
Dans OpenCV, vous pouvez utiliser lacv::BFMatcherclasse pour implémenter BFMatcher :
Exemple
#include <opencv2/xfeatures2d.hpp>
int main() {
cv::Mat src1 = cv::imread("image1.jpg", cv::IMREAD_GRAYSCALE);
cv::Mat src2 = cv::imread("image2.jpg", cv::IMREAD_GRAYSCALE);
std::vector<cv::KeyPoint> keypoints1, keypoints2;
cv::Mat descriptors1, descriptors2;
// Détection de points caractéristiques SIFT
cv::Ptr<cv::xfeatures2d::SIFT> sift = cv::xfeatures2d::SIFT::create();
sift->detectAndCompute(src1, cv::noArray(), keypoints1, descriptors1);
sift->detectAndCompute(src2, cv::noArray(), keypoints2, descriptors2);
// Appariement BFMatcher
cv::BFMatcher matcher(cv::NORM_L2);
std::vector<cv::DMatch> matches;
matcher.match(descriptors1, descriptors2, matches);
// Dessiner les résultats de correspondance
cv::Mat output;
cv::drawMatches(src1, keypoints1, src2, keypoints2, matches, output);
cv::imshow("Correspondances BFMatcher", output);
cv::waitKey(0);
return 0;
}
Comparateur FLANN
FLANN (Fast Library for Approximate Nearest Neighbors) est un algorithme de recherche approximative des plus proches voisins qui accélère le processus de mise en correspondance des caractéristiques en construisant des arbres KD ou des arbres K-means. Le comparateur FLANN est adapté aux cas comportant un grand nombre de points caractéristiques.
Dans OpenCV, vous pouvez utiliser lacv::FlannBasedMatcherclasse pour implémenter le comparateur FLANN :
Exemple
#include <opencv2/xfeatures2d.hpp>
int main() {
cv::Mat src1 = cv::imread("image1.jpg", cv::IMREAD_GRAYSCALE);
cv::Mat src2 = cv::imread("image2.jpg", cv::IMREAD_GRAYSCALE);
std::vector<cv::KeyPoint> keypoints1, keypoints2;
cv::Mat descriptors1, descriptors2;
// Détection de points caractéristiques SIFT
cv::Ptr<cv::xfeatures2d::SIFT> sift = cv::xfeatures2d::SIFT::create();
sift->detectAndCompute(src1, cv::noArray(), keypoints1, descriptors1);
sift->detectAndCompute(src2, cv::noArray(), keypoints2, descriptors2);
// comparateur FLANN
cv::FlannBasedMatcher matcher;
std::vector<cv::DMatch> matches;
matcher.match(descriptors1, descriptors2, matches);
// Dessiner les résultats de correspondance
cv::Mat output;
cv::drawMatches(src1, keypoints1, src2, keypoints2, matches, output);
cv::imshow("Correspondances FLANN", output);
cv::waitKey(0);
return 0;
}
Mise en correspondance et filtrage des points caractéristiques
Dans les applications pratiques, les résultats de mise en correspondance des points caractéristiques peuvent contenir des paires de correspondances incorrectes. Pour améliorer la précision de la mise en correspondance, il est généralement nécessaire de filtrer les résultats de correspondance. Les méthodes de filtrage courantes incluent le filtrage basé sur la distance et le filtrage basé sur les contraintes géométriques.
Filtrage basé sur la distance
Le filtrage basé sur la distance supprime les paires de correspondances avec des distances plus grandes en définissant un seuil. Dans OpenCV, vous pouvez utiliser lacv::DescriptorMatcher::radiusMatchfonction pour mettre en œuvre le filtrage basé sur la distance.
Exemple
#include <opencv2/xfeatures2d.hpp>
int main() {
cv::Mat src1 = cv::imread("image1.jpg", cv::IMREAD_GRAYSCALE);
cv::Mat src2 = cv::imread("image2.jpg", cv::IMREAD_GRAYSCALE);
std::vector<cv::KeyPoint> keypoints1, keypoints2;
cv::Mat descriptors1, descriptors2;
// Détection de points caractéristiques SIFT
cv::Ptr<cv::xfeatures2d::SIFT> sift = cv::xfeatures2d::SIFT::create();
sift->detectAndCompute(src1, cv::noArray(), keypoints1, descriptors1);
sift->detectAndCompute(src2, cv::noArray(), keypoints2, descriptors2);
// Appariement BFMatcher
cv::BFMatcher matcher(cv::NORM_L2);
std::vector<std::vector<cv::DMatch>> matches;
matcher.radiusMatch(descriptors1, descriptors2, matches, 50.0);
// Dessiner les résultats de correspondance
cv::Mat output;
cv::drawMatches(src1, keypoints1, src2, keypoints2, matches, output);
cv::imshow("Correspondances filtrées", output);
cv::waitKey(0);
return 0;
}
Filtrage basé sur les contraintes géométriques
Le filtrage basé sur les contraintes géométriques supprime les paires de correspondances qui ne satisfont pas aux contraintes géométriques en calculant la matrice fondamentale ou la matrice d'homographie. Dans OpenCV, vous pouvez utiliser lacv::findFundamentalMatoucv::findHomographyfonction pour mettre en œuvre le filtrage basé sur les contraintes géométriques.
Exemple
#include <opencv2/xfeatures2d.hpp>
int main() {
cv::Mat src1 = cv::imread("image1.jpg", cv::IMREAD_GRAYSCALE);
cv::Mat src2 = cv::imread("image2.jpg", cv::IMREAD_GRAYSCALE);
std::vector<cv::KeyPoint> keypoints1, keypoints2;
cv::Mat descriptors1, descriptors2;
// Détection de points caractéristiques SIFT
cv::Ptr<cv::xfeatures2d::SIFT> sift = cv::xfeatures2d::SIFT::create();
sift->detectAndCompute(src1, cv::noArray(), keypoints1, descriptors1);
sift->detectAndCompute(src2, cv::noArray(), keypoints2, descriptors2);
// Appariement BFMatcher
cv::BFMatcher matcher(cv::NORM_L2);
std::vector<cv::DMatch> matches;
matcher.match(descriptors1, descriptors2, matches);
// Filtrage basé sur les contraintes géométriques
std::vector<cv::Point2f> points1, points2;
for (size_t i = 0; i < matches.size(); i++) {
points1.push_back(keypoints1[matches[i].queryIdx].pt);
points2.push_back(keypoints2[matches[i].trainIdx].pt);
}
cv::Mat mask;
cv::findHomography(points1, points2, cv::RANSAC, 3, mask);
// Filtrer les paires correspondantes
std::vector<cv::DMatch> good_matches;
for (size_t i = 0; i < matches.size(); i++) {
if (mask.at<uchar>(i)) {
good_matches.push_back(matches[i]);
}
}
// Dessiner les résultats de correspondance
cv::Mat output;
cv::drawMatches(src1, keypoints1, src2, keypoints2, good_matches, output);
cv::imshow("Correspondances filtrées", output);
cv::waitKey(0);
return 0;
}