图像特征类型可以分为三种:
边缘,角点,斑点。
其中,角点是个很特殊的存在,他们在图像中可以轻松定位,因为角点位于两条边缘的交点,代表了两条边缘变化的方向上的点,所以他们是可以精确定位的二维特征,甚至可以达到亚像素精度。
角点定义:如果某一点在任意方向的一个微小变动都会引起灰度很大的变化,则称为角点。
角点通常被定义为两条边的交点,更严格的说,角点的局部邻域应该具有两个不同区域的不同方向的边界
1,一阶导数(灰度的梯度)的局部最大化所对应的像素点
2,两天及两条以上边缘的交点
3,图像中梯度值和梯度方向的变化速率都很高的点
4,角点处的一阶导数最大,二阶导数为0,指示物体边缘变化不连续的方向
角点检测算法分为三类:
1,基于灰度图像的角点检测
2,基于二值图像的角点检测
3,基于轮廓曲线的角点检测
角点检测(Corner Detection)是计算机视觉系统中用来获得图像特征的一种方法,广泛应用于运动检测、图像匹配、视频跟踪、三维建模和目标识别等领域中。也称为特征点检测。
角点响应函数R为:
R=λ1*λ2-k(λ1+λ2)的平方,k在0.04-0.06之间
Harris角点检测:
角点响应函数R为:
R=λ1*λ2-k(λ1+λ2)的平方,k在0.04-0.06之间
API:
void cornerHarris(InputArray src, 源图像,填Mat类的对象即可,且需为单通道8位或者浮点型图像
OutputArray dst, 这个参数用于存放Harris角点检测的输出结果,和源图片有一样的尺寸和类型。
int blockSize, 领域的大小即计算y1y2时候矩阵的大小
int ksize, 表示Sobel()算子的孔径大小
double k, k在0.04-0.06之间
intborderType=BORDER_DEFAULT 图像像素的边界模式
)
步骤:
代码:
#include
#include
#include
#include
#include
using namespace cv;
using namespace std;
Mat src,graysrc;
int thresh_v = 130;
int thresh_max = 255;
void m_harris(int, void*) {
Mat dst,nordst,scadst,retdst;
dst = Mat::zeros(src.size(), CV_32FC1);
cornerHarris(graysrc, dst, 2, 3, 0.04);
normalize(dst, nordst, 0, 255, NORM_MINMAX,CV_32FC1 );// 检测出的元素值范围不确定,而且有正有负,归一化
convertScaleAbs(nordst, scadst, 1, 0);// 将元素值取绝对值,且将输出图像深度变为 CV_8U
retdst = src.clone();
for (int row = 0; row < retdst.rows; row++) {
uchar* curRow = scadst.ptr(row);
for (int col = 0; col < retdst.cols; col++) {
int value = (int)*curRow;
if (value > thresh_v) { // 过滤,角点响应值 大于 阈值才显示
circle(retdst, Point(col, row), 2, Scalar(0, 0, 255), 2);
}
curRow++;
}
}
imshow("output", retdst);
}
int main() {
src = imread("C:/Users/Administrator/Desktop/pic/1-H.jpg");
cvtColor(src, graysrc, CV_BGR2GRAY);
imshow("input", src);
m_harris(0, 0);
createTrackbar("yuzhi", "output", &thresh_v, thresh_max, m_harris);
waitKey(0);
}
Shi-Tomasi 角点检测
Shi-Tomasi 算法是Harris 算法的改进。Harris 算法最原始的定义是将矩阵 M 的行列式值与 M 的迹相减,再将差值同预先给定的阈值进行比较。后来Shi 和Tomasi 提出改进的方法,若两个特征值中较小的一个大于最小阈值,则会得到强角点。
唯一不同的是在使用矩阵 特征值 λ1 λ2 计算角度响应的时候
R = min(λ1, λ2)
API:
void goodFeaturesToTrack( // Shi-Tomasi角点检测
InputArray image, // 灰度图像
OutputArray corners, // 检测出来的角点在输入图像的Point
int maxCorners, // -maxCorners 表示返回角点的数目,如果检测出来的角点数目大于最大数目则返回响应值最强前maxCorners数目。
double qualityLevel, // -qualityLevel表示最小可接受的向量值1500, 0.01, 15
double minDistance, // -minDistance两个角点之间的最小距离(欧几里得距离)
InputArray mask = noArray(),
int blockSize = 3, // -blockSize 计算导数微分不同的窗口大小
bool useHarrisDetector = false, // -useHarrisDetector是否使用Harris角点检测,设置为false的时候 下一个参数 k 无效
double k = 0.04 // 最好 0.04~0.06
);
代码:
#include
#include
#include
#include
#include
using namespace cv;
using namespace std;
Mat src, graysrc;
int thresh_v = 5;
int thresh_max = 255;
void shi_tomasi(int, void*) {
vector corners;
Mat dst = src.clone();
goodFeaturesToTrack(graysrc, corners, thresh_v, 0.01, 10);
for (int i = 0; i < corners.size(); i++) {
circle(dst, corners[i], 2, Scalar(255, 0, 233), 2);
}
imshow("output", dst);
}
int main() {
src = imread("C:/Users/Administrator/Desktop/pic/1-H.jpg");
imshow("input", src);
cvtColor(src, graysrc, CV_BGR2GRAY);
shi_tomasi(0, 0);
createTrackbar("yuhzi", "output", &thresh_v, thresh_max, shi_tomasi);
waitKey(0);
}
亚像素级别角点检测
提高检测精准度
理论与现实总是不一致的,实际情况下几乎所有的角点不会是一个真正的准确像素点。
检测出的点(100, 5) 实际上可能是(100.234, 5.789),可以使用亚像素定位确定准确位置
- 跟踪
- 三维重建
- 相机校正
亚像素定位方法
- 插值方法
- 基于图像矩计算
- 曲线拟合方法 -(高斯曲面(最常用)、多项式、椭圆曲面)
代码:
#include
#include
#include
#include
#include
using namespace cv;
using namespace std;
Mat src, graysrc;
int thresh_v = 50;
int thresh_max = 255;
void sub_dip(int, void*) {
vector corners;
goodFeaturesToTrack(graysrc, corners, thresh_v, 0.01, 10);
cout << "corner_size:" << corners.size() << endl;
Mat dst = src.clone();
for (int i = 0; i < corners.size(); i++) {
cout << i << ".point[x,y]=" << corners[i].x << "," << corners[i].y << endl;
circle(dst, corners[i], 2, Scalar(0, 255, 255), 2);
}
imshow("output", dst);
Size winsize = Size(5, 5);//窗口不要太大,不然亚像素可能会被干扰
Size zerozone = Size(-1, -1);// 拟合时使用 零区域
//TermCriteria类是用来作为迭代算法的终止条件的,参数:类型(EPS表示迭代到阈值终止),
//第二个参数为迭代的最大次数,最后一个是特定的阈值
TermCriteria tc = TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER, 40, 0.001);
cornerSubPix(graysrc, corners, winsize, zerozone, tc);//亚像素定位,为后续计算提供更高精确度的值
cout << "subpix corner_size:" << corners.size() << endl;
for (size_t i = 0; i < corners.size(); i++) {
cout << i << ".point[x,y]=" << corners[i].x << "," << corners[i].y << endl;// 亚像素定位出来的,精确度较高,浮点值
}
}