角点 (corners) 的定义有两个版本:一是 两条边缘的交点,二是 邻域内具有两个主方向的特征点。

一般而言,角点是边缘曲线上曲率为极大值的点,或者 图像亮度发生剧烈变化的点。例如,从人眼角度来看,下图的 $E$ 和 $F$ 便是典型的角点

1  检测思路

在图像中定义一个局部小窗口,然后沿各个方向移动这个窗口,则会出现 a) b) c) 三种情况,分别对应平坦区、边缘和角点

a)  窗口内的图像强度,在窗口向各个方向移动时,都没有发生变化,则窗口内都是 “平坦区”,不存在角点

b)  窗口内的图像强度,在窗口向某一个 (些) 方向移动时,发生较大变化;而在另一些方向不发生变化,那么,窗口内可能存在 “边缘”

c)  窗口内的图像强度,在窗口向各个方向移动时,都发生了较大的变化,则认为窗口内存在 “角点”

a)  flat region                         b)  edge                                     c)  corner

2  Harris 角点

2.1  公式推导

图像在点 $(x,y) $ 处的灰度值为 $I(x, y)$,当在 $x$ 方向上平移 $u$,且 $y$ 方向上平移 $v$ 时,图像灰度值的变化为

 $ \qquad E(u,v) = \sum\limits_{x,y}  \, \underbrace{w(x,y)}_\text{window function} \; [\underbrace{I(x+u, y+v)}_\text{shifted intensity} - \underbrace{I(x, y)}_\text{intensity}]^2 $

一阶泰勒级数近似展开得

$ \qquad \sum\limits_{x,y}  \; [I(x+u, y+v) - I(x, y)]^2 \approx \sum\limits_{x,y}  \; [I(x, y) +uI_x + vI_y - I(x, y)]^2 = \sum\limits_{x,y}  \; [u^2I_x^2 + 2uvI_x I_y + v^2I_y^2 ] $

写成矩阵形式

$ \qquad E(u,v) \approx \begin{bmatrix} u & v \end{bmatrix} \left ( \displaystyle \sum_{x,y} w(x,y) \begin{bmatrix} I_x^{2} & I_{x}I_{y} \\ I_xI_{y} & I_{y}^{2} \end{bmatrix} \right ) \begin{bmatrix} u \\ v \end{bmatrix}$

则有

$ \qquad E(u,v) \approx \begin{bmatrix} u & v \end{bmatrix} M \begin{bmatrix} u \\ v \end{bmatrix}$,    假定  $ M = \displaystyle \sum_{x,y} w(x,y) \begin{bmatrix} I_x^{2} & I_{x}I_{y} \\ I_xI_{y} & I_{y}^{2} \end{bmatrix}$

2.2  判别方法

定义一个角点响应值$\qquad R = det(M) - k(trace(M))^{2} = \lambda_{1} \lambda_{2} - k (\lambda_{1}+\lambda_{2})^2 $

根据响应值的大小,判断小窗口内是否包含角点:

1) “平坦区”:|R| 小的区域,即 $\lambda_1$ 和 $\lambda_2$ 都小;

2)  “边缘”: R <0 的区域,即 $\lambda_1 >> \lambda_2$ 或反之;

3)  “角点”: R 大的区域,即 $\lambda_1$ 和 $\lambda_2$ 都大且近似相等

为了便于直观理解,绘制成 $\lambda_1-\lambda_2$ 平面如下图:

2.3  cornerHarris()

OpenCV 中 Harris 角点检测的函数为:

void cv::cornerHarris (
InputArray src, // 输入图像 (单通道,8位或浮点型)
OutputArray dst, // 输出图像 (类型 CV_32FC1,大小同 src)
int blockSize, // 邻域大小
int ksize, // Sobel 算子的孔径大小
double k, // 经验参数,取值范围 0.04 ~ 0.06
int borderType = BORDER_DEFAULT // 边界模式
)

2.4  代码示例

#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp" using namespace cv;
// Harris corner parameters
int kThresh = 150;
int kBlockSize = 2;
int kApertureSize = 3;
double k = 0.04; int main()
{
// read image
Mat src, src_gray;
src = imread("building.jpg");
if(src.empty())
return -1; cvtColor(src, src_gray, COLOR_BGR2GRAY); Mat dst, dst_norm, dst_norm_scaled;
// Harris corner detect
cornerHarris(src_gray, dst, kBlockSize, kApertureSize, k); normalize(dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1);
convertScaleAbs(dst_norm, dst_norm_scaled); // draw detected corners
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) > kThresh)
{
circle(src, Point(i, j), 2, Scalar(0,255,0));
}
}
} imshow("harris corner", src); waitKey(0);
}

检测结果:

3  Shi-Tomasi 角点

Shi-Tomasi 角点是 Harris 角点的改进,在多数情况下,其检测效果要优于 Harris。二者的区别在于,Shi-Tomasi 选取 $\lambda_1$ 和 $\lambda_2$ 中的最小值,作为新的角点响应值 $R$

$\qquad R = min(\lambda_1, \lambda_2)  $

则相应的 $\lambda_1-\lambda_2$ 平面为:

3.1  goodFeaturesToTrack()

OpenCV 中 Shi-Tomasi 角点检测函数为:

void cv::goodFeaturesToTrack (
InputArray image, // 输入图像 (单通道,8位或浮点型32位)
OutputArray corners, // 检测到的角点
int maxCorners, // 最多允许返回的角点数量
double qualityLevel, //
double minDistance, // 角点间的最小欧拉距离
InputArray mask = noArray(), //
int blockSize = 3, //
bool useHarrisDetector = false, //
double k = 0.04 //
)

3.2  代码示例

#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp" using namespace cv;
using namespace std; int kMaxCorners = 1000;
double kQualityLevel = 0.1;
double kMinDistance = 1; int main()
{
// read image
Mat src, src_gray;
src = imread("building.jpg");
if (src.empty())
return -1; cvtColor(src, src_gray, COLOR_BGR2GRAY);
// Shi-Tomasi corner detect
vector<Point2f> corners;
goodFeaturesToTrack(src_gray, corners, kMaxCorners, kQualityLevel, kMinDistance); // draw and show detected corners
for (size_t i = 0; i < corners.size(); i++)
{
circle(src, corners[i], 2.5, Scalar(0, 255, 0));
}
imshow("Shi-Tomasi corner", src); waitKey(0);
}

检测结果:

4  角点检测的实现

在 OpenCV 中分析 cornerHarris() 函数的源码,得到实现步骤如下:sobel 算子求解 dx 和 dy  ->  矩阵 M  -> boxFilter  -> 每个像素的角点响应值 R

代码实现:

#include <iostream>
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp" using namespace cv;
using namespace std; int kApertureSize = 3;
int kBlockSize = 2;
double k = 0.04;
int kThresh = 150; int main()
{
// read image
Mat src, src_gray;
src = imread("chessboard.png");
if (src.empty())
return -1; cvtColor(src, src_gray, COLOR_BGR2GRAY);

  // scale
int depth = src_gray.depth();
double scale = (double)(1 << (2* kBlockSize)); if (depth == CV_8U)
scale *= 255.0;
scale = 1.0 / scale; // 1) dx, dy
Mat Dx, Dy;
Sobel(src_gray, Dx, CV_32F, 1, 0, kApertureSize, scale);
Sobel(src_gray, Dy, CV_32F, 0, 1, kApertureSize, scale); // 2) cov
Size size = src_gray.size();
Mat cov(size, CV_32FC3); for (int i = 0; i < size.height; i++)
{
float* cov_data = cov.ptr<float>(i);
const float* dxdata = Dx.ptr<float>(i);
const float* dydata = Dy.ptr<float>(i); for (int j=0; j < size.width; j++)
{
float dx = dxdata[j];
float dy = dydata[j]; cov_data[j * 3] = dx * dx;
cov_data[j * 3 + 1] = dx * dy;
cov_data[j * 3 + 2] = dy * dy;
}
} // 3) boxfilter
boxFilter(cov, cov, cov.depth(), Size(kBlockSize, kBlockSize)); // 4) R
Mat dst(size,CV_32FC1);
Size size_cov = cov.size(); for (int i = 0; i < size_cov.height; i++)
{
const float* ptr_cov = cov.ptr<float>(i);
float* ptr_dst = dst.ptr<float>(i); for (int j=0; j < size_cov.width; j++)
{
float a = ptr_cov[j * 3];
float b = ptr_cov[j * 3 + 1];
float c = ptr_cov[j * 3 + 2];
ptr_dst[j] = (float)(a * c - b * b - k * (a + c) * (a + c));
}
} // 5) normalize
Mat dst_norm, dst_norm_scaled;
normalize(dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1);
convertScaleAbs(dst_norm, dst_norm_scaled); // 6) draw detected corners
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) > 150)
{
circle(src, Point(i, j), 2, Scalar(0, 255, 0));
}
}
} imshow("Harris corner", src); waitKey(0);
}

5  亚像素角点检测

亚像素角点的提取函数 cornerSubPix(),常用于相机标定中,定义如下:

5.1  cornerSubpix()

void cv::cornerSubPix(
InputArray image, // 输入图象(单通道,8位或浮点型)
InputOutputArray corners, // 亚像素精度的角点坐标
Size winSize, // 搜索窗口尺寸的 1/2
Size zeroZone, //
TermCriteria criteria // 迭代终止准则
)

5.2  代码示例

#include <iostream>

#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp" using namespace cv;
using namespace std; int kMaxCorners = 40;
double kQualityLevel = 0.01;
double kMinDistance = 50; int main()
{
// 1) read image
Mat src, src_gray;
src = imread("chessboard.png");
if (src.empty())
return -1; cvtColor(src, src_gray, COLOR_BGR2GRAY);
// 2) Shi-Tomasi corner detect
vector<Point2f> corners;
goodFeaturesToTrack(src_gray, corners, kMaxCorners, kQualityLevel, kMinDistance); // 3) draw and show detected corners
for (size_t i = 0; i < corners.size(); i++)
{
circle(src, corners[i], 3, Scalar(0, 255, 0));
}
imshow("Shi-Tomasi corner", src); TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 40, 0.001);
// 4) find corner positions in subpixel
cornerSubPix(src_gray, corners, Size(5, 5), Size(-1, -1), criteria);
// 5) output subpixel corners
for (size_t i = 0; i < corners.size(); i++)
{
cout << "Corner[" << i << "]: (" << corners[i].x << "," << corners[i].y << ")" << endl;
}
waitKey(0);
}

输入棋盘格5行8列,对应7x4个角点,图像的分辨率为 600*387,则所有角点的理论坐标如下表:

        

角点的图象坐标值输出如下:

参考资料:

《图像局部不变性特征与描述》 第 3 章

https://www.cnblogs.com/ronny/p/4009425.html

http://www.cse.psu.edu/~rtc12/CSE486/

OpenCV Tutorials / feature2d module / Harris corner detector

OpenCV-Python Tutorials / Feature Detection and Description / Shi-Tomasi Corner Detector & Good Features to Track

OpenCV Tutorials / feature2d module / Creating your own corner detector

OpenCV Tutorials / feature2d module / Detecting corners location in subpixels

OpenCV 之 角点检测的更多相关文章

  1. 【OpenCV】角点检测:Harris角点及Shi-Tomasi角点检测

    角点 特征检测与匹配是Computer Vision 应用总重要的一部分,这需要寻找图像之间的特征建立对应关系.点,也就是图像中的特殊位置,是很常用的一类特征,点的局部特征也可以叫做“关键特征点”(k ...

  2. OpenCV Shi-Tomasi角点检测子

    Shi-Tomasi角点检测子 目标 在这个教程中我们将涉及: 使用函数 goodFeaturesToTrack 来调用Shi-Tomasi方法检测角点. 理论 代码 这个教程的代码如下所示.源代码还 ...

  3. OpenCV Harris 角点检测子

    Harris 角点检测子 目标 本教程中我们将涉及: 有哪些特征?它们有什么用? 使用函数 cornerHarris 通过 Harris-Stephens方法检测角点. 理论 有哪些特征? 在计算机视 ...

  4. Opencv Shi-Tomasi角点检测

    #include <iostream>#include <opencv2/opencv.hpp> using namespace std;using namespace cv; ...

  5. Opencv Harris角点检测

    #include <iostream>#include <opencv2/opencv.hpp> using namespace std;using namespace cv; ...

  6. OPENCV(6) —— 角点检测

    图像特征的类型通常指边界.角点(兴趣点).斑点(兴趣区域).角点就是图像的一个局部特征,应用广泛.harris角点检测是一种直接基于灰度图像的角点提取算法,稳定性高,尤其对L型角点检测精度高,但由于采 ...

  7. opencv::自定义角点检测

    #include <opencv2/opencv.hpp> #include <iostream> #include <math.h> using namespac ...

  8. opencv笔记6:角点检测

    time:2015年10月09日 星期五 23时11分58秒 # opencv笔记6:角点检测 update:从角点检测,学习图像的特征,这是后续图像跟踪.图像匹配的基础. 角点检测是什么鬼?前面一篇 ...

  9. opencv: 角点检测源码分析;

    以下6个函数是opencv有关角点检测的函数 ConerHarris, cornoerMinEigenVal,CornorEigenValsAndVecs, preConerDetect, coner ...

随机推荐

  1. OpenStack Train版-13.安装块存储服务cinder(控制节点)

    Cinder的核心功能是对卷的管理,允许对卷.卷的类型.卷的快照.卷备份进行处理.它为后端不同的存储设备提供给了统一的接口,不同的块设备服务厂商在Cinder中实现其驱动,可以被Openstack整合 ...

  2. 从 MFC 移植程序到 wxWidgets 界面库 ——《定时执行专家 5.0》的界面实现

    时隔十年的更新,最大的变化就是从 MFC 移植到 wxWidgets,界面也全部重现设计,图标也都进行了更换.wxWidgets(最新版  3.1.4,经典的开源.跨平台 C++ GUI类库)特有的 ...

  3. 爬虫入门六 总结 资料 与Scrapy实例-bibibili番剧信息

    title: 爬虫入门六 总结 资料 与Scrapy实例-bibibili番剧信息 date: 2020-03-16 20:00:00 categories: python tags: crawler ...

  4. wordpress 主题安装 您点击的链接已过期 nginx 出现413 Request Entity Too Large

    1 nginx 出现413 Request Entity Too Large 问题是限制上传大小,解决: 1.打开nginx配置文件 nginx.conf, 路径一般是:/etc/nginx/ngin ...

  5. 51nod-1065 最小正子段和 【贪心 + 思维】

    N个整数组成的序列a[1],a[2],a[3],-,a[n],从中选出一个子序列(a[i],a[i+1],-a[j]),使这个子序列的和>0,并且这个和是所有和>0的子序列中最小的. 例如 ...

  6. asp.net 从Excel表导入数据到数据库中

    http://www.cnblogs.com/hfzsjz/archive/2010/12/31/1922901.html http://hi.baidu.com/ctguyg/item/ebc857 ...

  7. Linux Schedule Cron All In One

    Linux Schedule Cron All In One 定时任务 / 定时器 GitHub Actions Scheduled events Cron syntax has five field ...

  8. LeetCode Binary Search All In One

    LeetCode Binary Search All In One Binary Search 二分查找算法 https://leetcode-cn.com/problems/binary-searc ...

  9. Android vs iOS vs Web

    Android vs iOS vs Web UI view Android ViewGroup ImageView TextView iOS UIView ImageView TextView Web ...

  10. taro 如何展示多行文本 省略号

    taro 如何展示多行文本 省略号 webkit-box-orient: vertical; See the Pen Pure CSS multiline text with ellipsis by ...