您的位置:首页 > 运维架构

OpenCV学习笔记__角点检测

2015-09-29 12:55 423 查看
1、Harris角点检测

引言:

a.图像特征类型可以被分为如下三种:

    - <1>边缘
    - <2>角点 (感兴趣关键点)
    - <3>斑点(Blobs)(感兴趣区域)

b.在当前的图像处理领域,角点检测算法可归纳为三类:

    - <1>基于灰度图像的角点检测
    - <2>基于二值图像的角点检测
    - <3>基于轮廓曲线的角点检测

定义:角点位于两条边缘的交点处,代表了两个边缘变化的方向上的点,,所以他们是可以精确定位的二维特征,甚至可以达到亚像素的精度。且其图像梯度有很高的变化,这种变化是可以用来帮助检测角点的。需要注意的是,角点与位于相同强度区域上的点不同,与物体轮廓上的点也不同,因为轮廓点难以在相同的其他物体上精确定位。角点通常被定义为两条边的交点,更严格的说,角点的局部邻域应该具有两个不同区域的不同方向的边界。而实际应用中,大多数所谓的角点检测方法检测的是拥有特定特征的图像点,而不仅仅是“角点”。这些特征点在图像中有具体的坐标,并具有某些数学特征,如局部最大或最小灰度、某些梯度特征等。

另外,关于角点的具体描述可以有几种:

    - 一阶导数(即灰度的梯度)的局部最大所对应的像素点;
    - 两条及两条以上边缘的交点;
    - 图像中梯度值和梯度方向的变化速率都很高的点;
    - 角点处的一阶导数最大,二阶导数为零,指示物体边缘变化不连续的方向。

cornerHarris 函数用于在OpenCV中运行Harris角点检测算子处理图像

    - 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可,且需为单通道8位或者浮点型图像。
    - 第二个参数,OutputArray类型的dst,函数调用后的运算结果存在这里,即这个参数用于存放Harris角点检测的输出结果,和源图片有一样的尺寸和类型。
    - 第三个参数,int类型的blockSize,表示邻域的大小,更多的详细信息在cornerEigenValsAndVecs()中有讲到。
    - 第四个参数,int类型的ksize,表示Sobel()算子的孔径大小。
    - 第五个参数,double类型的k,Harris参数。
    - 第六个参数,int类型的borderType,图像像素的边界模式,注意它有默认值BORDER_DEFAULT。更详细的解释,参考borderInterpolate( )函数。

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>

using namespace cv;
using namespace std;

/// 定义全局变量
Mat src, src_gray;
int thresh = 200;
int max_thresh = 255;

char* source_window = "Source image";
char* corners_window = "Corners detected";

/// 函数声明
void cornerHarris_demo(int, void*);

/// 主函数
int main(int argc, char** argv)
{
/// 加载原始图像以及将它转换为灰度图像
src = imread("e:\\1.jpg");
cvtColor(src, src_gray, CV_BGR2GRAY);

/// 创建一个窗口和滑动条
namedWindow(source_window, CV_WINDOW_AUTOSIZE);
createTrackbar("Threshold: ", source_window, &thresh, max_thresh, cornerHarris_demo);
imshow(source_window, src);

cornerHarris_demo(0, 0);

waitKey(0);
return(0);
}

/** 函数 cornerHarris_demo */
void cornerHarris_demo(int, void*)
{

Mat dst, dst_norm, dst_norm_scaled;
dst = Mat::zeros(src.size(), CV_32FC1);

/// 参数
int blockSize = 2;
int apertureSize = 3;
double k = 0.04;

/// 进行角点检测
cornerHarris(src_gray, dst, blockSize, apertureSize, k, BORDER_DEFAULT);

/// 归一化与转换
normalize(dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat());
convertScaleAbs(dst_norm, dst_norm_scaled);//将归一化后的图线性变换成8位无符号整型

/// 符合阈值条件的,将角点绘制出来
for (int j = 0; j < dst_norm.rows; j++)
{
for (int i = 0; i < dst_norm.cols; i++)
{
if ((int)dst_norm.at<float>(j, i) > thresh)
{
circle(dst_norm_scaled, Point(i, j), 5, Scalar(0), 2, 8, 0);
}
}
}
/// 显示最终效果
namedWindow(corners_window, CV_WINDOW_AUTOSIZE);
imshow(corners_window, dst_norm_scaled);
}






2、Shi-Tomasi 角点检测(对Harris算法的改进)
函数:
goodFeaturesToTrack(image,corners,maxCorners,qualityLevel,minDistance,noArray( ),blockSize,false,k)

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;

#define WINDOW_NAME "【Shi-Tomasi角点检测】"

Mat g_srcImage, g_grayImage;
int g_maxCornerNumber = 33;
int g_maxTrackbarNumber = 500;
RNG g_rng(12345);//初始化随机数生成器

int main()
{
//【1】载入源图像并将其转换为灰度图
g_srcImage = imread("e:\\1.jpg");
cvtColor(g_srcImage, g_grayImage, CV_BGR2GRAY);

//【2】创建窗口和滑动条,并进行显示和回调函数初始化
namedWindow(WINDOW_NAME, CV_WINDOW_AUTOSIZE);
createTrackbar("最大角点数", WINDOW_NAME, &g_maxCornerNumber, g_maxTrackbarNumber, on_GoodFeaturesToTrack);
imshow(WINDOW_NAME, g_srcImage);
on_GoodFeaturesToTrack(0, 0);

waitKey(0);
return(0);
}

void on_GoodFeaturesToTrack(int, void*)
{
//【1】对变量小于等于1时的处理
if (g_maxCornerNumber <= 1) { g_maxCornerNumber = 1; }

//【2】Shi-Tomasi算法(goodFeaturesToTrack函数)的参数准备
vector<Point2f> corners;
double qualityLevel = 0.01;//角点检测可接受的最小特征值
double minDistance = 10;//角点之间的最小距离
int blockSize = 3;//计算导数自相关矩阵时指定的邻域范围
double k = 0.04;//权重系数
Mat copy = g_srcImage.clone();	//复制源图像到一个临时变量中,作为感兴趣区域

//【3】进行Shi-Tomasi角点检测
goodFeaturesToTrack(g_grayImage,//输入图像
corners,//检测到的角点的输出向量
g_maxCornerNumber,//角点的最大数量
qualityLevel,//角点检测可接受的最小特征值
minDistance,//角点之间的最小距离
Mat(),//感兴趣区域
blockSize,//计算导数自相关矩阵时指定的邻域范围
false,//不使用Harris角点检测
k);//权重系数

//【4】输出文字信息
cout << "\t>此次检测到的角点数量为:" << corners.size() << endl;

//【5】绘制检测到的角点
int r = 4;
for (int i = 0; i < corners.size(); i++)
{
//以随机的颜色绘制出角点
circle(copy, corners[i], r, Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255),
g_rng.uniform(0, 255)), -1, 8, 0);
}

//【6】显示(更新)窗口
imshow(WINDOW_NAME, copy);
}





***3、定制化创建角点检测子

    - 使用 OpenCV 函数 cornerEigenValsAndVecs 来计算像素对应的本征值和本征向量来确定其是否是角点。
    - 使用OpenCV 函数 cornerMinEigenVal 通过最小化本征值来进行角点检测。
    - 用上述两个函数实现一个定制化的Harris detector,类似Shi-Tomasi检测子。

4、亚像素级的角点检测

    - 使用OpenCV函数 cornerSubPix 寻找更精确的角点位置 (不是整数类型的位置,而是更精确的浮点类型位置).

    即进行几何测量。
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>

using namespace cv;
using namespace std;

/// Global variables
Mat src, src_gray;

int maxCorners = 10;
int maxTrackbar = 25;

RNG rng(12345);
char* source_window = "Image";

/// Function header
void goodFeaturesToTrack_Demo(int, void*);

/** @function main */
int main(int argc, char** argv)
{
/// Load source image and convert it to gray
src = imread("e:\\1.jpg");
cvtColor(src, src_gray, CV_BGR2GRAY);

/// Create Window
namedWindow(source_window, CV_WINDOW_AUTOSIZE);

/// Create Trackbar to set the number of corners
createTrackbar("Max  corners:", source_window, &maxCorners, maxTrackbar, goodFeaturesToTrack_Demo);

imshow(source_window, src);

goodFeaturesToTrack_Demo(0, 0);

waitKey(0);
return(0);
}

/**
* @function goodFeaturesToTrack_Demo.cpp
* @brief Apply Shi-Tomasi corner detector
*/
void goodFeaturesToTrack_Demo(int, void*)
{
if (maxCorners < 1) { maxCorners = 1; }

/// Parameters for Shi-Tomasi algorithm
vector<Point2f> corners;
double qualityLevel = 0.01;
double minDistance = 10;
int blockSize = 3;
bool useHarrisDetector = false;
double k = 0.04;

/// Copy the source image
Mat copy;
copy = src.clone();

/// Apply corner detection
goodFeaturesToTrack(src_gray,
corners,
maxCorners,
qualityLevel,
minDistance,
Mat(),
blockSize,
useHarrisDetector,
k);

/// Draw corners detected
cout << "** Number of corners detected: " << corners.size() << endl;
int r = 4;
for (int i = 0; i < corners.size(); i++)
{
circle(copy, corners[i], r, Scalar(rng.uniform(0, 255), rng.uniform(0, 255),
rng.uniform(0, 255)), -1, 8, 0);
}

/// Show what you got
namedWindow(source_window, CV_WINDOW_AUTOSIZE);
imshow(source_window, copy);

/// Set the neeed parameters to find the refined corners
Size winSize = Size(5, 5);
Size zeroZone = Size(-1, -1);
TermCriteria criteria = TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 40, 0.001);

/// Calculate the refined corner locations
cornerSubPix(src_gray, corners, winSize, zeroZone, criteria);

/// Write them down
for (int i = 0; i < corners.size(); i++)
{
cout << " -- Refined Corner [" << i << "]  (" << corners[i].x << "," << corners[i].y << ")" << endl;
}
}
得到的窗口和之前的Shi-Tomasi 角点检测一致,区别在于在控制台窗口中输出了检测到的浮点型亚像素角点精确坐标值。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: