harris角点检测算法步骤,harris角点检测python实现
接下来,前面的基于生长的棋盘格角点检测方法——(2)详细的代码讲解(第一部分),我们来看看第二个重要的函数chessboardsFromCorners。
该函数的目的是用上一步中找到的角点恢复棋盘结构。首先初始化一个3x3的角矩阵,也就是一个2x2的棋盘,这是一个棋盘的最小单位。然后利用定义的棋盘能量函数从四条外边缘开始生长棋盘,将能量最低的方向(最有可能是棋盘)作为新的棋盘,以此类推,最终得到优化的棋盘阵列。
该功能的主要结构:
chess boards=chesboardsfromcorners(角);棋盘=init棋盘(角,I);energy=chessboardEnergy(棋盘,拐角)proposal { j }=棋盘(棋盘,拐角,j);pred=predictCorners(p1,p2,P3)idx=assignClosestCorners(cand,pred);init circuit board将一个3x3的棋盘初始化为0,选取具有V1和V2两个主梯度方向的idx角点,并将该角点作为棋盘的初始中心。如下图
然后以这个角点为中心,根据两个主要的梯度方向寻找最近邻角点。
方向邻居函数[neighbor _ idx,min _ dist]=方向邻居(idx,v,棋盘,角),其中v是归一化的方向向量。此函数计算当前点和所有其他点之间的距离向量dir,以及其他点在该点主方向上的投影距离dist。
dir=corners.p(未使用,)- ones(长度(未使用),1)*corners.p(idx,);dist=(dir(:1)*v(1) dir(:2)* v(2);参考下图,看看一些重要参数的物理意义:
Dist*v表示其他点在该点的梯度向量方向上的投影向量。
Dist_edge表示从其他点到该点的梯度向量V方向的垂直距离。
dist _ point(dist _ point 0)=INF;表示其他点与该点方向的夹角大于90度,当该点乘以负数时,视为无穷大。
Dist_edge是对应点到棋盘中心点边缘的垂直距离。
距离是投影距离。考虑到我们要找到V方向对应的最近点,我们放大了dist_edge的值。代码被放大了5倍,如下:
[min_dist,min_idx]=min(距离点5 *距离边缘);neighbor_idx=未使用(min _ idx);寻找米字形的三个正方形(上、下、左、右、左上、左下、右上、右下)中所有点的最近邻。代码如下所示
% find left/right/top/bottom neighbors[棋盘(2,3),dist 1(1)]=directional neighbor(idx,v1,棋盘,拐角);[棋盘(2,1),dist 1(2)]=directional neighbor(idx,-v1,棋盘,拐角);[棋盘(3,2),dist 2(1)]=directional neighbor(idx,v2,棋盘,拐角);[棋盘(1,2),dist 2(2)]=directional neighbor(idx,-v2,棋盘,拐角);% find左上/右上/左下/右下邻居[棋盘(1,1),dist2(3)]=directionalNeighbor(棋盘(2,1),-v2,棋盘,角);[棋盘(3,1),dist2(4)]=directionalNeighbor(棋盘(2,1),v2,棋盘,角);[棋盘(1,3),dist2(5)]=directionalNeighbor(棋盘(2,3),-v2,棋盘,角);[棋盘(3,3),dist2(6)]=directionalNeighbor(棋盘(2,3),v2,棋盘,角);我们来验证一下找到的棋盘是否符合自定义棋盘标准。这里有个概念叫标准差率。标准差率=标准差/期望值。
这里的阈值0.3应该是经过多次实验后慎重选择的。如果选择偏置,棋盘的约束条件会降低,容易出现假棋盘;如果选择过小,约束条件过严,生成的棋盘格数就会少。代码如下所示
如果有(isinf(dist1)) 任何(isinf(dist2)) .STD(dist 1)/mean(dist 1)0.3 STD(dist 2)/mean(dist 2)0.3棋盘=[];返回;然后end进一步验证生成的所谓33初始化棋盘,确保其不为空,且棋盘能量值大于0。下面是一个非常重要的计算板能量的函数。
ChessboardEnergy棋盘总能量定义:
其中第一项E_corners是当前棋盘的总角数的负值,表达式和编码如下:
E_corners=-size(棋盘,1)*size(棋盘,2);E_structure描述了两个相邻角点和预测角点的匹配程度。计算棋盘每行每列相邻三个角的结构能量,取最大值。表达式是:
代码如下所示
%遍历行对于j=1:size(棋盘,1)对于k=1:size(棋盘,2)-2 x=corners.p(棋盘(j,k:k 2),);E_structure=max(E_structure,norm(x(1,)x(3,)-2*x(2,)/norm(x(1,)-x(3,));endend %遍历列对于j=1:size(棋盘,2)对于k=1:size(棋盘,1)-2 x=角. p(棋盘(k:k ^ 2,j),);E_structure=max(E_structure,norm(x(1,)x(3,)-2*x(2,)/norm(x(1,)-x(3,));恩登的最终棋盘能量是
E=E_corners 1*size(棋盘,1)*size(棋盘,2)* E _ structure;因此,总能量E应大于0,即每相邻三点的E_structure的最大值应小于1。
下面我画了一个图来解释E_structure的含义,棋盘结构的能量约束。如下图:
-上图中,上半部分是理想棋盘(为方便起见称之为case1),下半部分是扭曲棋盘(为方便起见称之为case2)。P1,p2,p3是获得的棋盘中三个相邻角的坐标。对应于代码中的x(1,),x(2,),x(3,),
-结构能量分子范数(x(1,)x(3,)-2*x(2,)其中x(1,)-2*x(2,)可以单独写成[x (1,)-x (2,)
-结构能量分母范数(x(1,)-x(3,)),也就是范数(p1-p3)。
-情形1:结构能量分子[p1-p2]和[p3-p2]大小相等,方向相反,其和的2范数结果为0,所以结构能量也为0。
-案例2: p4是P1、P2和P3组成的平行四边形的第4个顶点,是虚构的,没有出现在棋盘上,仅用于分析。结构能量分子[p1-p2] [p3-p2]对应于图中的向量v2,结构能量分母p1-p3对应于图中的向量v1。在E_structure的最大值为1的情况下,向量V1和V2的两个范数相等。这样,平行四边形p1、p2、p3和p4实际上被升级为矩形。这是结构约束中的畸变极限,E_structure的中值为1。
至此,棋盘格(大小2x2棋盘格,即3x3角点)的初始化种子已经完成。
如果growth棋盘顺利通过之前的系列测试,下一步将升级打怪模式,进入棋盘成长阶段。棋盘每次生长都是从上下左右四个方向整行或整列生长。计算生长后新棋盘格的能量,选择能量最小的生长方向作为新棋盘格。首先,您需要预测现有棋盘周围可能的拐角位置:
predictCorners的思路很直观,就是根据三个相邻角的角度差和长度差的增量来预测下一个相邻角的位置,然后打个折,在代码中是75%。这个参数的选择也应该是多次实验的结果。我做过实验,对畸变大的图像比较敏感。
pred=p3 0.75 * s3 *个(1,2)。*[cos(a3)sin(a3)];我给你举个例子。如下图,蓝色是原来棋盘的角。我们预测延伸到棋盘右侧最外边缘的三个点。结果就是下图中的绿点。红点是检测到的其余角点。下一步是根据预测点的位置找到离预测点最近的角点。
AssignClosestCorners寻找最接近pred的角点,使用贪婪算法寻找最近的角点。代码如下所示
对于i=1:size(pred,1) [row,col]=find(D==min(D(:)),1, first );idx(col)=row;D(row,)=infd(:col)=INF;End分别从四个方向生长棋盘,并生成四个新的棋盘方案。如果能量最小的棋盘格的能量值小于扩展前的棋盘格,说明生长成功,用这个新的棋盘格代替原来的棋盘格。继续增长直到跳棋的能量四方不再减少。代码如下:
% compute proposals and energies for j=1:4 proposals { j }=grow棋盘(棋盘,角,j);p _ energy(j)=chesboardenergy(proposal { j },corners);end% find best proposal[min_val,min _ idx]=min(p _ energy);%接受最佳建议,如果能量减少f p_energy(min_idx)energy棋盘=建议{ min _ idx };下面,检查新生成的棋盘是否与原棋盘重复。如果有重复的地方,用重叠标记出来。第一列表示重复的棋盘号,第二列表示对应的能量值。代码如下所示
%检查新棋盘建议是否与现有棋盘重叠overlap=(长度(棋盘),2);对于j=1:length(棋盘)对于k=1:length(棋盘{j}(:))如果有(棋盘{ j }(k)==棋盘(:))overlap(j,1)=1;overlap(j,2)=chesboardenergy(chesboards { j },corners);打破;End end end新棋盘的能量小于现有棋盘的能量,删除重复棋盘,用能量更小的棋盘替换。
%添加棋盘(并在必要时替换重叠部分)if ~any(overlap(:1)) chessboards{end 1}=棋盘;else idx=find(overlap(:1)==1);if ~any(overlap(idx,2)=chesboardenergy(棋盘,角))chess boards(idx)=[];棋盘{end 1}=棋盘;最终由END生成的棋盘结果如下:
上面的棋盘主要是用来展示在自然环境下的抗干扰效果。下面是鱼眼镜头下图像畸变较大时的一些棋盘格检测结果。从结果来看,效果很好,如下图所示:
但是这种方法也有其缺点,因为受到棋盘的限制,所以当棋盘被部分遮挡时,检测结果并不理想。如下图。
该算法找到的棋盘是其约束下的最佳结果。但上图左下方的棋盘因为次优而被忽略。这在鱼眼镜头的标定中是非常不利的。鱼眼镜头越靠近边缘,畸变越大,越难被检测到,但计算标定参数更重要。以后我会介绍其他的棋盘格角点检测方法,可以解决这个问题。
1参考文献,geiger a,moosmann f,car,等.利用单次拍摄进行自动摄像机和距离传感器校准[c]//机器人与自动化(ICRA),2012年IEEE国际会议论文集。IEEE,2012: 3936-3943。
2、http://www.cvlibs.net/software/libcbdetect/
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。