特征提取是计算机视觉的核心技术,通过识别图像中具有代表性的关键点及其描述信息,实现图像匹配、对象识别、姿态估计等高级任务。本章将系统讲解从基础的图像金字塔、角点检测,到复杂的 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))²
其中,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