1、显示关键点
关键点:图像中含有特殊信息的像素点,主要含有像素点位置、角度等信息。
一次性用空心圆绘制所有关键点:
drawKeypoints(img, keypoints, img, Scalar(0, 0, 0));
(输入图像,关键点向量 KeuyPoint类型,输出图像,关键点颜色)
class KeyPoint{
float angle; //关键点的角度
int class_id; //关键点的分类号
int octave; //特征点来源
Point2f pt; //*关键点的坐标*
float response;//最强关键点的响应,可用于进一步分类和二次采样
float size; //关键点邻域的直径
}
#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
#include<math.h>
#include <opencv2/imgproc.hpp>
#include<vector>
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
//QuickDemo qd;
//qd.myFilter_demo(src);
//system("color F0");
Mat img = imread("D:/images/dog.png",IMREAD_COLOR);
if (img.empty()) {
cout << "请输入正确的图像文件" << endl;
return -1;
}
Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
//生成关键点
vector<KeyPoint> keypoints;
RNG rng(10086);
for (int i = 0; i < 100; i++) {
float pty = rng.uniform(0, img.rows - 1);
float ptx = rng.uniform(0, img.cols - 1);
KeyPoint keypoint; //对KeyPoint类进行赋值
keypoint.pt.x = ptx;
keypoint.pt.y = pty;
keypoints.push_back(keypoint); //保存到关键点向量中
}
//绘制关键点
drawKeypoints(img, keypoints, img, Scalar(0, 0, 0));
drawKeypoints(gray, keypoints, gray, Scalar(255, 255, 255));
imshow("img", img);
imshow("gray", gray);
waitKey(0);
//destroyAllWindows();
return 0;
}
2、Harris角点检测
角点/特征点:从图像中提取能够表示图像特性或者局部特性的像素点,如灰度梯度最大值对应的像素点、两条直线或者曲线的交点、一阶梯度的导数最大值和梯度方向变化率最大的像素点、一阶导数值最大但是二阶导数值为0的点等。特征点是关键点和描述子的组合。
定义
角点/特征点:从图像中提取能够表示图像特性或者局部特性的像素点,如灰度梯度最大值对应的像素点、两条直线或者曲线的交点、一阶梯度的导数最大值和梯度方向变化率最大的像素点、一阶导数值最大但是二阶导数值为0的点等。
特征点是关键点和描述子的组合。
Harris角点:像素值的局部最大峰值
首先,我们选择一个合适大小的像素框,如途中金黄色区域。我们试图通过对框中像素值的变化去探究是否为角点。
第一个 flat,我们在上下左右以及对角线移动像素框时,会发现框中的值几乎没有变化,全部为黑色值0;
第二个 edge,我们在上下移动时,发现像素框中值没有变化,但是左右移动时以及对角线移动时会发生变化;
第三个 corner,我们不论上下移动还是左右移动还是对角线移动,都会发生变化,所以其为角点。
nerHarris(gray, harris, blockSize, apertureSize, 0.04);
该函数用于计算角点Harris评价系数R,通过对系数大小的比较,确定该点是否为Harris角点。
R较大时,说明两个特征向量相似,则该点为角点;R<0时,说明两个特征向量相差较大,则该点位于直线上;当|R|较小时,说明两个特征值较小,则该点位于平面。
(输入单通道灰度图,输出的R矩阵,邻域大小,提取信息的Sobel算子半径,权重系数k,像素外推法标志)
由于该函数的结果R,取值范围较广且有正有负,通常需要进行normalize()归一化到指定区域后,再通过阈值判断该像素点是否是Harris角点。阈值根据实际情况而定。
#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
#include<math.h>
#include <opencv2/imgproc.hpp>
#include<vector>
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
//QuickDemo qd;
//qd.myFilter_demo(src);
//system("color F0");
Mat img = imread("D:/images/dog.png",IMREAD_COLOR);
if (img.empty()) {
cout << "请输入正确的图像文件" << endl;
return -1;
}
Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
//计算Harris评价系数
Mat harris;
int blockSize = 2; //邻域半径
int apertureSize = 3;
cornerHarris(gray, harris, blockSize, apertureSize, 0.04);
//归一化以便进行数值比较和结果显示
Mat harrisn;
normalize(harris, harrisn,0,255,NORM_MINMAX);
//将图像数据类型变成CV_8U
convertScaleAbs(harrisn, harrisn);
//寻找Harris角点
vector<KeyPoint> keypoints;
for (int row = 0; row < harrisn.rows; row++) {
for (int col = 0; col < harrisn.cols; col++) {
int R = harrisn.at<uchar>(row, col);
if (R > 125) {
//将角点存入KeyPoint中
KeyPoint keypoint;
keypoint.pt.y = row;
keypoint.pt.x = col;
keypoints.push_back(keypoint);
}
}
}
drawKeypoints(img, keypoints, img,Scalar(255,255,255));
imshow("Harris角点", img);
imshow("系数矩阵", harrisn);
waitKey(0);
//destroyAllWindows();
return 0;
}
引用:【计算机视觉】哈里斯角点检测 Harris Corner Detection-CSDN博客
3、Shi-Tomas角点检测
Harris角点评价系数是两个特征向量的组合,因此Harris角点评价系数不能完全的概况两个特征向量之间的大小关系。
因此Shi和Tomas对Harris角点的判定指标进行调整,将特征向量的最小值作为角点的评价系数。当R大于某一阈值时,则将该点认定为角点。
goodFeaturesToTrack(gray, corners, maxCorners, quality_level, minDistance, Mat(), 3, false);
与Harris角点检测函数相比,该函数的阈值与最佳角点相对应,避免了绝对阈值在不同图像中效果不理想的情况。且该函数可直接输出角点坐标,无需根据输出结果再次判断是否为角点。
(输入图像,检测到的角点,寻找角点数目的最大值,角点阈值与最佳角点的关系,两角点间的最小欧氏距离,检测角点的掩码矩阵,计算梯度协方差矩阵的尺寸,是否使用Harris角点检测的标志)
#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
#include<math.h>
#include <opencv2/imgproc.hpp>
#include<vector>
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
//QuickDemo qd;
//qd.myFilter_demo(src);
//system("color F0");
Mat img = imread("D:/images/dog.png",IMREAD_COLOR);
if (img.empty()) {
cout << "请输入正确的图像文件" << endl;
return -1;
}
Mat img2;
img.copyTo(img2);
Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
//提取角点
int maxCorners = 100; //检测角点数目
double quality_level = 0.01; //质量等级,或者是指阈值与最佳角点的比例关系
double minDistance = 0.04; //两个角点之间的最小欧氏距离
vector<Point2f> corners;
goodFeaturesToTrack(gray, corners, maxCorners, quality_level, minDistance, Mat(), 3, false);
//绘制角点
vector<KeyPoint> keypoints;
RNG rng(10086);
for (int i = 0; i < corners.size(); i++) {
//第一种方式绘制角点
int b = rng.uniform(0, 256);
int g = rng.uniform(0, 256);
int r = rng.uniform(0, 256);
circle(img, corners[i], 5, Scalar(b, g, r), 2, 8, 0);
//将角点存放在KeyPoint类中
KeyPoint keypoint;
keypoint.pt = corners[i];
keypoints.push_back(keypoint);
}
drawKeypoints(img2, keypoints, img2,Scalar(255,255,255));
imshow("用circle()绘制角点的结果", img);
imshow("用绘制关键点函数绘制角点的结果", img2);
waitKey(0);
//destroyAllWindows();
return 0;
}
使用circle()绘制角点:可以自由调整大小、可单独给每一个圆形指定颜色
使用drawKeypoints()绘制角点:实现方式简单,不用反复调用,但圆形大小固定,不易于辨识
4、亚像素级别角点检测
#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
#include<math.h>
#include <opencv2/imgproc.hpp>
#include<vector>
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
//QuickDemo qd;
//qd.myFilter_demo(src);
system("color F0");
Mat img = imread("D:/images/dog.png",IMREAD_COLOR);
if (img.empty()) {
cout << "请输入正确的图像文件" << endl;
return -1;
}
Mat img2;
img.copyTo(img2);
Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
//提取角点
int maxCorners = 100; //检测角点数目
double quality_level = 0.01; //质量等级,或者是指阈值与最佳角点的比例关系
double minDistance = 0.04; //两个角点之间的最小欧氏距离
vector<Point2f> corners;
goodFeaturesToTrack(gray, corners, maxCorners, quality_level, minDistance, Mat(), 3, false);
//计算亚像素级别角点坐标
vector<Point2f> cornerSub = corners; //角点备份,防止被函数修改
Size winsize = Size(5, 5);
Size zerosize = Size(-1, -1);
TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 40, 0.001);
cornerSubPix(gray, cornerSub, winsize, zerosize, criteria);
//输出初始坐标和精细坐标
for (size_t i = 0; i < corners.size(); i++) {
string str = to_string(i);
str = "第" + str + "个角点初始坐标:";
cout << str << corners[i] << " 精细后坐标:" << cornerSub[i] << endl;
}
//绘制角点
vector<KeyPoint> keypoints;
RNG rng(10086);
for (int i = 0; i < corners.size(); i++) {
//第一种方式绘制角点
int b = rng.uniform(0, 256);
int g = rng.uniform(0, 256);
int r = rng.uniform(0, 256);
circle(img, corners[i], 5, Scalar(b, g, r), 2, 8, 0);
//将角点存放在KeyPoint类中
KeyPoint keypoint;
keypoint.pt = corners[i];
keypoints.push_back(keypoint);
}
/*
drawKeypoints(img2, keypoints, img2,Scalar(255,255,255));
imshow("用circle()绘制角点的结果", img);
imshow("用绘制关键点函数绘制角点的结果", img2);
waitKey(0);
//destroyAllWindows();*/
return 0;
}