- 操作系统:ubuntu22.04
- OpenCV版本:OpenCV4.9
- IDE:Visual Studio Code
- 编程语言:C++11
算法描述
计算图像块的特征值和特征向量用于角点检测。
对于每一个像素 p ,函数 cornerEigenValsAndVecs 考虑一个 blockSize × blockSize 的邻域 S§ 。它计算邻域内的协变矩阵 M ,公式如下:
M = [ ∑ S ( p ) ( d I / d x ) 2 ∑ S ( p ) d I / d x d I / d y ∑ S ( p ) d I / d x d I / d y ∑ S ( p ) ( d I / d y ) 2 ] M = \begin{bmatrix} \sum _{S(p)}(dI/dx)^2 & \sum _{S(p)}dI/dx dI/dy \\ \sum _{S(p)}dI/dx dI/dy & \sum _{S(p)}(dI/dy)^2 \end{bmatrix} M=[∑S(p)(dI/dx)2∑S(p)dI/dxdI/dy∑S(p)dI/dxdI/dy∑S(p)(dI/dy)2]
其中导数使用 Sobel 操作符进行计算。
之后,它找到 M 的特征向量和特征值,并将它们存储在目标图像中,格式为 (λ1, λ2, x1, y1, x2, y2),其中
- λ1, λ2 是未排序的 M 的特征值;
- x1, y1 是对应于 λ1 的特征向量;
- x2, y2 是对应于 λ2 的特征向量。
该函数的输出可以用于稳健的边缘或角点检测。
函数原型
void cv::cornerEigenValsAndVecs
(InputArray src,OutputArray dst,int blockSize,int ksize,int borderType = BORDER_DEFAULT
)
参数
- 参数src:输入单通道 8 位或浮点图像。
- 参数dst:用于存储结果的图像。它与 src 大小相同,类型为 CV_32FC(6)。
- 参数blockSize:邻域大小(参见下面的详细信息)。
- 参数ksize:Sobel 操作符的孔径参数。
- 参数borderType:像素外推方法。参见 BorderTypes。不支持 BORDER_WRAP。
代码示例
#include <opencv2/opencv.hpp>
#include <iostream>int main()
{// 加载图像cv::Mat img = cv::imread("/media/dingxin/data/study/OpenCV/sources/images/hawk.jpg", cv::IMREAD_GRAYSCALE);if (img.empty()){std::cout << "Error opening image" << std::endl;return -1;}// 计算特征值和特征向量cv::Mat eigen;int blockSize = 3; // 邻域大小int ksize = 3; // Sobel 梯度算子的大小cv::cornerEigenValsAndVecs(img, eigen, blockSize, ksize);// 显示特征值cv::Mat eigenVal1(img.rows, img.cols, CV_32F);cv::Mat eigenVal2(img.rows, img.cols, CV_32F);cv::Mat eigenVec1(img.rows, img.cols, CV_32FC2);cv::Mat eigenVec2(img.rows, img.cols, CV_32FC2);// 分离特征值和特征向量for (int y = 0; y < img.rows; ++y){for (int x = 0; x < img.cols; ++x){// 获取每个像素处的特征值和特征向量const cv::Vec4f& eigenRow = eigen.at<cv::Vec4f>(y, x);eigenVal1.at<float>(y, x) = eigenRow[0]; // 第一个特征值eigenVal2.at<float>(y, x) = eigenRow[1]; // 第二个特征值eigenVec1.at<cv::Vec2f>(y, x) = cv::Vec2f(eigenRow[2], eigenRow[3]); // 第一个特征向量eigenVec2.at<cv::Vec2f>(y, x) = cv::Vec2f(eigenRow[4], eigenRow[5]); // 第二个特征向量}}// 显示特征值图像cv::normalize(eigenVal1, eigenVal1, 0, 255, cv::NORM_MINMAX, CV_8U);cv::imshow("Original Image", img);cv::imshow("Eigen Value 1", eigenVal1);cv::normalize(eigenVal2, eigenVal2, 0, 255, cv::NORM_MINMAX, CV_8U);cv::imshow("Eigen Value 2", eigenVal2);cv::waitKey(0);return 0;
}