python-opencv系列的最后主要还是把opencv官方文档里面前面没有提到的内容消化一下。
在图像中寻找在其周围的所有区域中移动(少量)时具有最大变化的区域,这一句比较关键。
Harris Corner Detection(哈里斯角点检测)
原理参考了https://blog.csdn.net/newthinker_wei/article/details/45603583
和https://blog.csdn.net/linqianbi/article/details/78930239
这里的参数和上面稍有区别,注意一下。这个w是权重,这个目前不知道怎么设定。
如果不能对角化(关于方阵可以对角化的充要条件,大家自己翻一翻书,一共有两条),我记得好像总是可以化为(Jordan)约当标准型的,不过这里也没用到它。
二次型标准化还有一种拉格朗日配方法,这些大学的线性代数都学过。
怎么想出来的其实上面的红字已经解释了,这个转载的没有认真看原文,不过
B 提取的角点是像素级的。做一些图的补充,如果上面还没有理解,可以再看看:
非极大值抑制前面在canny算子的时候就提到过。
输入可以是uint8的,不过得是单通道的。得到的结果就是我们按照哈里斯角点检测计算出来的R。
红点比较难看到(瓷砖的角点),这是因为满足条件的像素太少了,一个像素的红点还是太难看到了,所以上面的例子做了一个局部最大值滤波,也就是膨胀处理,目的就是为了让红色区域可以看到。
这个就更容易看到了(这个膨胀其实可做可不做的),这个有些地方没有检测到,我们需要减小一下阈值试试。
这个阈值需要我们手动调整,看到阈值太小,这个有些边界点也给检测出来了,这个时候可以增大k。
有些没有检测到是因为blocksize上面取得都是2,太小了。
我觉得最好还是blocksize和ksize也就是sobel算子的大小一致比较好。
不过这样是无法精确定位的。因为我们得到的其实是很多团点,每一团点都不止一个点,而且每个点最多只能精确到一个像素单位,我们都是知道像素是一个矩形,要想继续精确定位的话,要借助函数:cv2.cornerSubPix()
这个函数用迭代的方法找到亚像素级别的角点的精确位置。所谓亚像素级别,可以理解为把图片像素resize(用插值的方法),然后现在放大之后的图片上的一个像素在原图上就相当于是一个像素中的某一个矩形,最小单位就不再局限于一个像素了。寻找精确亚像素角点位置是基于从中心q指向q邻域内的点p的向量,这个向量和p点的梯度方向垂直,这里定义了上面一个目标函数。其中DIp是q邻域内的某个点p的图像梯度。q得值要使上面的目标函数最小。通过让目标函数置为0,我们可以建立一系列方程,最终解出q的位置。不过一般我们还是用数值算法,而数值算法一般的方式就是迭代,我们也许先选一个初始点为q,然后计算邻域内点梯度,设一阶梯度为G,二阶梯度为b,那么q我们可以通过下列式子计算出来(为什么这么算就不知道了,这个算法应该是有数学收敛性证明的):
参数说明,image是单通道的,参考了https://blog.csdn.net/guduruyu/article/details/69537083
第二个参数也就是初始的q点位置了。第四个参数说的有问题,opencv官方说的是为了防止自相关矩阵出现可能的奇异现象才设置的这个参数,有点不懂,不过这个参数一般我们不需要动,给(-1,-1)就行。
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.001)
这个的意思应该就是最大迭代次数为100次,相邻两次迭代最大距离0.001,满足任意一个条件就可以停止了。这个函数的输出应该就是q点的位置了。
我对比了不加这句和加这句的:
还是明显可以看出来还是有膨胀的效果的,字体明显粗了。上面用了一个函数来测量连通区域的数据(虽然前面其实我们已经学过很多函数可以做这个事情):
这个统计可以选择输出的数据,一般我们都是默认就行,如果有需要,可以选择自己想要的。标签会把不同的连通区域标记为不同的值,0是背景,我们在前面分水岭那里见过。
这是我截取其中的一部分:这个还是可以看到明显的绿点的。我们上面其实没有体现亚像素,这是因为我们取整了,其实精度是可以达到亚像素的,只不过亚像素的话就没办法显示了,所以我们还是取整用像素级别显示了。这里还要提醒一点,关闭图片最好用键盘,这样一个python程序才是finish了,不然的话python程序其实并没有结束,即使关闭sublime,还是再运行,在任务管理器就会看到:
前面也说过现在有更先进的角点检测方法。
第四个参数给的其实就是经过角点计算出来的最大值的百分比。这个还可以指定角点个数的最大值,你可以给很大。例子:
但是有些角点就漏掉了,总之,调参基本也不可能一蹴而就。这个的结果如果想再精确的话,可以再进行亚像素处理。