特征提取是計算機視覺的核心技術,通過識別圖像中具有代表性的關鍵點及其描述信息,實現圖像匹配、對象識別、姿態估計等高級任務。本章將系統講解從基礎的圖像金字塔、角點檢測,到復雜的 ORB 和 SIFT 特征提取與匹配,最終實現基于特征的對象檢測完整流程。
一、圖像金字塔
圖像金字塔是多尺度表示圖像的有效方法,通過構建不同分辨率的圖像集合,實現多尺度特征提取。
1.1 高斯金字塔
高斯金字塔通過下采樣(縮小)構建,每一層都是對上層圖像進行高斯模糊后再隔點采樣得到。
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;// 構建高斯金字塔
vector<Mat> buildGaussianPyramid(const Mat& img, int levels) {vector<Mat> pyramid;pyramid.push_back(img.clone()); // 第0層(原始圖像)Mat current = img;for (int i = 1; i < levels; ++i) {Mat down;// 高斯模糊并下采樣(尺寸減半)pyrDown(current, down);pyramid.push_back(down);current = down;}return pyramid;
}// 顯示高斯金字塔
void showGaussianPyramid(const vector<Mat>& pyramid) {// 創建一個大圖像拼接所有金字塔層int totalHeight = 0;int maxWidth = 0;for (const auto& layer : pyramid) {totalHeight += layer.rows;maxWidth = max(maxWidth, layer.cols);}Mat display(totalHeight, maxWidth, CV_8UC3, Scalar(0, 0, 0));int y = 0;for (size_t i = 0; i < pyramid.size(); ++i) {const Mat& layer = pyramid[i];// 將當前層復制到顯示圖像layer.copyTo(display(Rect(0, y, layer.cols, layer.rows)));// 顯示層索引string text = "Level " + to_string(i);putText(display, text, Point(10, y + 30), FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 255, 0), 2);y += layer.rows;}imshow("高斯金字塔", display);
}
1.2 拉普拉斯金字塔
拉普拉斯金字塔通過高斯金字塔各層與上層上采樣后的差值構建,用于表示圖像的細節信息。
// 構建拉普拉斯金字塔
vector<Mat> buildLaplacianPyramid(const vector<Mat>& gaussianPyramid) {vector<Mat> laplacianPyramid;for (size_t i = 0; i < gaussianPyramid.size() - 1; ++i) {Mat up;// 上采樣高斯金字塔上層pyrUp(gaussianPyramid[i + 1], up, gaussianPyramid[i].size());// 當前層減去上采樣結果得到拉普拉斯層Mat laplacian = gaussianPyramid[i] - up;laplacianPyramid.push_back(laplacian);}// 最后一層為高斯金字塔的頂層laplacianPyramid.push_back(gaussianPyramid.back().clone());return laplacianPyramid;
}// 從拉普拉斯金字塔重建圖像
Mat reconstructFromLaplacian(const vector<Mat>& laplacianPyramid) {Mat current = laplacianPyramid.back();for (int i = laplacianPyramid.size() - 2; i >= 0; --i) {Mat up;pyrUp(current, up, laplacianPyramid[i].size());current = up + laplacianPyramid[i];}return current;
}
1.3 圖像金字塔應用
// 多尺度特征檢測示例
void multiScaleFeatureDetection(const Mat& img) {// 構建3層高斯金字塔vector<Mat> gaussian = buildGaussianPyramid(img, 3);// 在不同尺度上檢測邊緣vector<Mat> edges;for (const auto& layer : gaussian) {Mat gray, edge;cvtColor(layer, gray, COLOR_BGR2GRAY);Canny(gray, edge, 50, 150);// 轉換為彩色以便顯示Mat edgeColor;cvtColor(edge, edgeColor, COLOR_GRAY2BGR);edges.push_back(edgeColor);}// 顯示結果imshow("原始圖像", img);showGaussianPyramid(gaussian);// 顯示多尺度邊緣Mat edgeDisplay;vconcat(edges, edgeDisplay);imshow("多尺度邊緣檢測", edgeDisplay);
}int main() {Mat img = imread("building.jpg");if (img.empty()) {cout << "圖像加載失敗!" << endl;return -1;}// 高斯金字塔示例vector<Mat> gaussian = buildGaussianPyramid(img, 4);showGaussianPyramid(gaussian);// 拉普拉斯金字塔示例vector<Mat> laplacian = buildLaplacianPyramid(gaussian);// 從拉普拉斯金字塔重建圖像Mat reconstructed = reconstructFromLaplacian(laplacian);imshow("原始圖像", img);imshow("從拉普拉斯重建", reconstructed);// 多尺度特征檢測multiScaleFeatureDetection(img);waitKey(0);destroyAllWindows();return 0;
}
圖像金字塔關鍵應用:
- 多尺度特征檢測(確保不同大小的物體都能被檢測到)
- 圖像融合與拼接
- 目標跟蹤(適應目標大小變化)
- 特征匹配(提高匹配魯棒性)
二、角點檢測
角點是圖像中亮度變化劇烈的點或在兩個邊緣交叉處的點,是最常用的局部特征之一。
2.1 Harris 角點檢測
Harris 角點檢測基于圖像灰度的局部變化,通過計算自相關矩陣的特征值來判斷是否為角點。
// Harris角點檢測
Mat detectHarrisCorners(const Mat& gray, double qualityLevel = 0.01, double k = 0.04) {Mat dst, dstNorm, dstScaled;// 檢測Harris角點cornerHarris(gray, dst, 2, 3, k, BORDER_DEFAULT);// 歸一化結果normalize(dst, dstNorm, 0, 255, NORM_MINMAX, CV_32FC1, Mat());convertScaleAbs(dstNorm, dstScaled);// 繪制角點Mat result = gray.clone();cvtColor(result, result, COLOR_GRAY2BGR);for (int i = 0; i < dstNorm.rows; ++i) {for (int j = 0; j < dstNorm.cols; ++j) {if ((int)dstNorm.at<float>(i, j) > qualityLevel * 255) {circle(result, Point(j, i), 5, Scalar(0, 0, 255), 2);}}}return result;
}
Harris 角點響應函數:
R = det(M) - k*(trace(M))2
其中,M
是自相關矩陣,det(M)
是行列式,trace(M)
是跡,k
是經驗常數(通常取 0.04~0.06)。
R > 0
且較大:角點R ≈ 0
:邊緣R < 0
且較小:平坦區域
2.2 Shi-Tomasi 角點檢測
Shi-Tomasi 角點檢測是 Harris 算法的改進,使用兩個特征值中的最小值作為響應函數,提高了角點檢測的穩定性。
// Shi-Tomasi角點檢測
Mat detectShiTomasiCorners(const Mat& gray, int maxCorners = 100, double qualityLevel = 0.01, double minDistance = 10) {vector<Point2f> corners;// 參數設置TermCriteria criteria(TermCriteria::EPS | TermCriteria::MAX_ITER, 30, 0.001);// 檢測Shi-Tomasi角點goodFeaturesToTrack(gray, corners, maxCorners, qualityLevel, minDistance, Mat(), 3, false, 0.04);// 繪制角點Mat result = gray.clone();cvtColor(result, result, C