1. Harris 角点检测
介绍: 角点是很容易在图像中定位的局部特征,并且大量存在于人造物体中(例如墙壁、门、桌子等),角点的价值在于它是两条边缘线的接合点,是一种二维特征,可以被精确地检测(即使是亚像素级精度)。
实现原理:
例子代码:
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
Mat srcImg, grayImg;
int thresholdValue = 130;
int maxCount = 255;
void HarrisDemo(int, void *){
Mat dstImg, normDstImg, normScaleDst;
dstImg = Mat::zeros(grayImg.size(), CV_32FC1);
int blockSize = 2; //领域尺寸
int ksize = 3; //口径尺寸
double k = 0.04; //Harris 参数
cornerHarris(grayImg, dstImg, blockSize, ksize, k, BORDER_DEFAULT); //角点检测
normalize(dstImg, normDstImg, 0, 255, NORM_MINMAX, CV_32FC1, Mat()); //归一化
convertScaleAbs(normDstImg, normScaleDst);
Mat resultImg = srcImg.clone();
for (int i = 0; i < resultImg.rows; i++)
{
uchar *currentRow = normScaleDst.ptr(i); //用指针的方式拿出整个一行的数据,也可以用之前的方式
for (int j = 0; j < resultImg.cols; j++)
{
int value = (int)*currentRow;
if (value > thresholdValue)
{
circle(resultImg, Point(j, i), 2, Scalar(0, 0, 255), 2, 8, 0);
}
currentRow++;
}
}
imshow("HarrisCornerDetection Result", resultImg);
}
void test(){
srcImg = imread("home.jpg");
if (srcImg.empty())
{
cout << "could not load image...\n" << endl;
}
namedWindow("Original image", CV_WINDOW_AUTOSIZE);
namedWindow("HarrisCornerDetection Result", CV_WINDOW_AUTOSIZE);
imshow("Original image", srcImg);
cvtColor(srcImg, grayImg, COLOR_BGR2GRAY); //转为灰度图像
createTrackbar("Threshold Value", "HarrisCornerDetection Result", &thresholdValue, maxCount, HarrisDemo);
HarrisDemo(0, 0);
}
int main(){
test();
waitKey(0);
return 0;
}
效果图
2. Shi - Tomasi 角点检测
介绍:跟 Harris 角点检测的理论几乎完全一致,唯一不同的是在使用矩阵特征值 λ?λ? 计算角度响应的时候。
例子代码:
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
//Shi - Tomasi
Mat srcImg, grayImg;
int thresholdValue = 25;
int maxCorners = 200;
RNG rng(12345);
void ShiTomasiDemo(int, void *){
if (thresholdValue < 5)
{
thresholdValue = 5; //最少保留5个角点
}
vector<Point2f> corners; //装载角点
//函数需要的参数
double quelityLevel = 0.01;
double minDistance = 10;
int blockSize = 3;
bool useHarris = false;
double k = 0.04;
Mat resultImg = srcImg.clone(); //复制灰度图像的图
goodFeaturesToTrack(grayImg, corners, thresholdValue, quelityLevel, minDistance, Mat(), blockSize, useHarris, k);
cout << "Number of Detected Corners:" << corners.size() << endl;
for (int i = 0; i < corners.size(); i++)
{
circle(resultImg, corners[i], 2, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), 2, 8, 0);
}
imshow("ShiTomasi Detector", resultImg);
}
void test(){
srcImg = imread("home.jpg");
if (srcImg.empty())
{
cout << "could not load image...\n" << endl;
}
namedWindow("Original image", CV_WINDOW_AUTOSIZE);
namedWindow("ShiTomasi Detector", CV_WINDOW_AUTOSIZE);
imshow("Original image", srcImg);
cvtColor(srcImg, grayImg, CV_BGR2GRAY);
createTrackbar("Threshold Value", "ShiTomasi Detector", &thresholdValue, maxCorners, ShiTomasiDemo);
ShiTomasiDemo(0, 0);
}
int main(){
test();
waitKey(0);
return 0;
}
效果图
3. 自定义角点检测器
- 基于 Harris 与 Shi - Tomasi 角点检测
- 首先通过计算矩阵 M 得到 λ?λ? 两个特征值根据他们得到角点响应值
- 然后自己设置阈值实现计算出阈值得到有响应值角点位置
例子代码:
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
//自定义角点检测
Mat srcImg, grayImg;
//harris corner response
Mat harrisDst, harrisRspImg;
double harrisMinRsp;
double harrisMaxRsp;
//shi-tomasi corner response
Mat shitomasiRsp;
double shitomasiMinRsp;
double shitomasiMaxRsp;
int smQualityLevel = 30;
// quality level
int qualityLeve = 30;
int maxCount = 100;
void CustomHarrisDemo(int, void *){
if (qualityLeve < 10)
{
qualityLeve = 10; //最少10个
}
Mat resultImg = srcImg.clone();
float t = harrisMinRsp + (((double)qualityLeve) / maxCount)*(harrisMaxRsp - harrisMinRsp);
for (int i = 0; i < srcImg.rows; i++)
{
for (int j = 0; j < srcImg.cols; j++)
{
float v = harrisRspImg.at<float>(i, j);
if (v > t)
{
circle(resultImg, Point(j, i), 2, Scalar(0, 0, 255), 2, 8, 0);
}
}
}
imshow("Custom Harris Corners Detector", resultImg);
}
void CustomShiTomasiDemo(int, void *){
if (qualityLeve < 20)
{
qualityLeve = 20; //最少20个
}
Mat resultImg = srcImg.clone();
float t = shitomasiMinRsp + (((double)smQualityLevel) / maxCount)*(shitomasiMaxRsp - shitomasiMinRsp);
for (int i = 0; i < srcImg.rows; i++)
{
for (int j = 0; j < srcImg.cols; j++)
{
float v = shitomasiRsp.at<float>(i, j);
if (v > t)
{
circle(resultImg, Point(j, i), 2, Scalar(0, 0, 255), 2, 8, 0);
}
}
}
imshow("Custom Shi-Tomasi Corners Detector", resultImg);
}
void test(){
srcImg = imread("home.jpg");
if (srcImg.empty())
{
cout << "could not load image...\n" << endl;
}
namedWindow("Original image", CV_WINDOW_AUTOSIZE);
imshow("Original image", srcImg);
cvtColor(srcImg, grayImg, CV_BGR2GRAY);
//计算特征值
int blockSize = 3;
int ksize = 3;
double k = 0.04;
harrisDst = Mat::zeros(srcImg.size(), CV_32FC1);
harrisRspImg = Mat::zeros(srcImg.size(), CV_32FC1);
cornerEigenValsAndVecs(grayImg, harrisDst, blockSize, ksize, 4);
//计算响应
for (int i = 0; i < harrisDst.rows; i++)
{
for (int j = 0; j < harrisDst.cols; j++)
{
double lambda1 = harrisDst.at<Vec6f>(i, j)[0];
double lambda2 = harrisDst.at<Vec6f>(i, j)[1];
harrisRspImg.at<float>(i, j) = lambda1*lambda2 - k*pow((lambda1 + lambda2), 2);
}
}
minMaxLoc(harrisRspImg, &harrisMinRsp, &harrisMaxRsp, 0, 0, Mat());
namedWindow("Custom Harris Corners Detector", CV_WINDOW_AUTOSIZE);
createTrackbar("Quality Value", "Custom Harris Corners Detector", &qualityLeve, maxCount, CustomHarrisDemo);
CustomHarrisDemo(0, 0);
//计算最小特征值
shitomasiRsp = Mat::zeros(srcImg.size(), CV_32FC1);
cornerMinEigenVal(grayImg, shitomasiRsp, blockSize, ksize, 4);
minMaxLoc(shitomasiRsp, &shitomasiMinRsp, &shitomasiMaxRsp, 0, 0, Mat());
namedWindow("Custom Shi-Tomasi Corners Detector", CV_WINDOW_AUTOSIZE);
createTrackbar("Quality Value", "Custom Shi-Tomasi Corners Detector", &smQualityLevel, maxCount, CustomShiTomasiDemo);
CustomShiTomasiDemo(0, 0);
}
int main(){
test();
waitKey(0);
return 0;
}
效果图
4. 亚像素级别角点检测
作用:提高检测精准度。
- 插值方法
- 基于图像矩计算
- 曲线拟合方法 - (高斯曲线、多项式和椭圆曲面)。
例子代码:
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
//亚像素级别焦点检测
int maxCorners = 20;
int maxCount = 50;
Mat srcImg, grayImg;
void subPixelDemo(int, void *){
if (maxCorners < 5)
{
maxCorners = 5;
}
vector<Point2f> corners;
double qualityLevel = 0.01;
double minDistance = 10;
int blockSize = 3;
double k = 0.04;
goodFeaturesToTrack(grayImg, corners, maxCorners, qualityLevel, minDistance, Mat(), blockSize, false, k);
cout << "number of corners:" << corners.size() << endl;
Mat resultImg = srcImg.clone();
for (int i = 0; i < corners.size(); i++)
{
circle(resultImg, corners[i], 2, Scalar(0, 0, 255), 2, 8, 0);
}
imshow("subPixel Result", resultImg);
//亚像素计算(拟合)
Size winSize = Size(5, 5);
Size zerozone = Size(-1, -1);
TermCriteria tc = TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER, 40, 0.001); //条件
cornerSubPix(grayImg, corners, winSize, zerozone, tc);
for (int i = 0; i < corners.size(); i++)
{
cout << (i + 1) << ".point[x,y]=" << corners[i].x << "," << corners[i].y << endl;
}
return;
}
void test(){
srcImg = imread("home.jpg");
if (srcImg.empty())
{
cout << "could not load image...\n" << endl;
}
namedWindow("Original image", CV_WINDOW_AUTOSIZE);
imshow("Original image", srcImg);
cvtColor(srcImg, grayImg, CV_BGR2GRAY);
namedWindow("subPixel Result", CV_WINDOW_AUTOSIZE);
createTrackbar("Cornerss:", "subPixel Result", &maxCorners, maxCount, subPixelDemo);
subPixelDemo(0, 0);
}
int main(){
test();
waitKey(0);
return 0;
}
效果图
获取例子所用的图片可以关注微信OpenCV图像处理算法获得哦,里面也会写我学习图像处理历程,欢迎大佬来交流!!!