OpenCV 中提供了多種常用的特征提取算法,廣泛應用于圖像匹配、拼接、SLAM、物體識別等任務。以下是 OpenCV 中幾個主流特征提取算法的 用法總結與代碼示例,涵蓋 C++ 和 Python 兩個版本。
常用特征提取算法列表
算法 | 特點 | 是否需額外模塊 |
---|---|---|
SIFT(尺度不變特征) | 穩定性強、可旋轉縮放 | xfeatures2d 模塊 |
SURF(加速穩健特征) | 快速但專利保護 | xfeatures2d 模塊 |
ORB(Oriented FAST + BRIEF) | 免費、高速 | OpenCV 主模塊 |
AKAZE | 適用于非線性尺度空間 | OpenCV 主模塊 |
BRISK | 二進制描述子、適用于實時應用 | OpenCV 主模塊 |
示例一:ORB 特征提取與匹配
Python 版:
import cv2# 加載圖像
img1 = cv2.imread("image1.jpg", cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread("image2.jpg", cv2.IMREAD_GRAYSCALE)# 創建 ORB 檢測器
orb = cv2.ORB_create()# 檢測關鍵點和計算描述子
kp1, des1 = orb.detectAndCompute(img1, None)
kp2, des2 = orb.detectAndCompute(img2, None)# 創建匹配器
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(des1, des2)# 排序并繪制前 20 個匹配點
matches = sorted(matches, key=lambda x: x.distance)
matched_img = cv2.drawMatches(img1, kp1, img2, kp2, matches[:20], None, flags=2)cv2.imshow("ORB Matches", matched_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
C++ 版:
#include <opencv2/opencv.hpp>
#include <opencv2/features2d.hpp>int main()
{cv::Mat img1 = cv::imread("image1.jpg", cv::IMREAD_GRAYSCALE);cv::Mat img2 = cv::imread("image2.jpg", cv::IMREAD_GRAYSCALE);cv::Ptr<cv::ORB> orb = cv::ORB::create();std::vector<cv::KeyPoint> kp1, kp2;cv::Mat des1, des2;orb->detectAndCompute(img1, cv::noArray(), kp1, des1);orb->detectAndCompute(img2, cv::noArray(), kp2, des2);cv::BFMatcher matcher(cv::NORM_HAMMING, true);std::vector<cv::DMatch> matches;matcher.match(des1, des2, matches);std::sort(matches.begin(), matches.end(),[](const cv::DMatch& m1, const cv::DMatch& m2) {return m1.distance < m2.distance;});cv::Mat img_matches;cv::drawMatches(img1, kp1, img2, kp2, matches, img_matches);cv::imshow("ORB Matches", img_matches);cv::waitKey(0);return 0;
}
示例二:SIFT 特征提取(需額外模塊)
Python 版:
import cv2sift = cv2.SIFT_create()
img = cv2.imread("image.jpg", cv2.IMREAD_GRAYSCALE)
kp, des = sift.detectAndCompute(img, None)img_kp = cv2.drawKeypoints(img, kp, None, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow("SIFT Features", img_kp)
cv2.waitKey(0)
注意:SIFT 在 OpenCV 4.x 中已開放為免費使用,需
pip install opencv-contrib-python
。
C++ 版:
#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>int main()
{cv::Mat img = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);cv::Ptr<cv::SIFT> sift = cv::SIFT::create();std::vector<cv::KeyPoint> keypoints;cv::Mat descriptors;sift->detectAndCompute(img, cv::noArray(), keypoints, descriptors);cv::Mat output;cv::drawKeypoints(img, keypoints, output, cv::Scalar::all(-1), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);cv::imshow("SIFT", output);cv::waitKey(0);return 0;
}
示例三:AKAZE 特征提取
Python 版:
import cv2akaze = cv2.AKAZE_create()
img = cv2.imread("image.jpg", cv2.IMREAD_GRAYSCALE)
kp, des = akaze.detectAndCompute(img, None)img_kp = cv2.drawKeypoints(img, kp, None, color=(0,255,0))
cv2.imshow("AKAZE", img_kp)
cv2.waitKey(0)
C++ 版:
#include <opencv2/opencv.hpp>int main()
{cv::Mat img = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);cv::Ptr<cv::AKAZE> akaze = cv::AKAZE::create();std::vector<cv::KeyPoint> keypoints;cv::Mat descriptors;akaze->detectAndCompute(img, cv::noArray(), keypoints, descriptors);cv::Mat output;cv::drawKeypoints(img, keypoints, output);cv::imshow("AKAZE", output);cv::waitKey(0);return 0;
}
示例四:SURF 特征提取
小提示
SURF 屬于專利算法(由 Hessian Matrix 加速構建特征),因此默認在 opencv-python
中 不可用,需要使用 opencv-contrib
版本:
- Python:
pip install opencv-contrib-python
- C++: 編譯 OpenCV 時需啟用
opencv_contrib
,并啟用xfeatures2d
模塊。
Python 示例
import cv2
import numpy as np# 讀取圖像
img = cv2.imread("image.jpg", cv2.IMREAD_GRAYSCALE)# 創建 SURF 對象(閾值越高,檢測特征點越少)
surf = cv2.xfeatures2d.SURF_create(hessianThreshold=400)# 檢測并計算特征點和描述子
keypoints, descriptors = surf.detectAndCompute(img, None)# 繪制關鍵點
img_kp = cv2.drawKeypoints(img, keypoints, None, (0,255,0), flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)cv2.imshow("SURF Features", img_kp)
cv2.waitKey(0)
cv2.destroyAllWindows()
C++ 示例
#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>int main()
{cv::Mat img = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);if (img.empty()) {std::cerr << "Cannot load image!" << std::endl;return -1;}// 創建 SURF 檢測器cv::Ptr<cv::xfeatures2d::SURF> surf = cv::xfeatures2d::SURF::create(400); // Hessian thresholdstd::vector<cv::KeyPoint> keypoints;cv::Mat descriptors;surf->detectAndCompute(img, cv::noArray(), keypoints, descriptors);cv::Mat output;cv::drawKeypoints(img, keypoints, output, cv::Scalar::all(-1), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);cv::imshow("SURF", output);cv::waitKey(0);return 0;
}
特征提取算法比較總結
算法 | 是否開源 | 描述子類型 | 匹配類型 | 特點 |
---|---|---|---|---|
SIFT | ? | 浮點(128維) | L2(歐氏距離) | 穩定性好,適合圖像拼接 |
SURF | ?(專利) | 浮點 | L2 | 快速但已過時 |
ORB | ? | 二值(256位) | Hamming(漢明) | 快速,適合實時系統 |
AKAZE | ? | 二值或浮點 | Hamming/L2 | 穩定性與速度兼顧 |
BRISK | ? | 二值 | Hamming | 實時性強 |
小結
- 推薦優先使用 ORB 或 AKAZE(開源 + 高速);
- 高精度圖像處理可考慮 SIFT;
- 所有算法都可配合
BFMatcher
或FLANN
進行匹配; - 選擇依據:速度要求、匹配精度、是否支持縮放旋轉。