基于C+OpenCV4.0的LSD算法实现

LSD的基本实现流程是计算出图像的梯度和场方向,然后对梯度进行排序,然后从大到小进行区域增长,之后对增长得到的区域求最小外接矩形,如果矩形不满足,则。。。

笔者对图像进行了高斯降采样,主要是加快计算速度

高斯降采样:

梯度与Level-Line场方向:

求梯度的公式一般使用这三个公式

<img src="http://latex.codecogs.com/gif.latex?\frac{\partial f(x,y)}{\partial x}  = f(x+1,y) - f(x,y) = gx" />

<img src="http://latex.codecogs.com/gif.latex?\frac{\partial f(x,y)}{\partial y}  = f(x,y+1) - f(x,y) = gy" />

<img src="http://latex.codecogs.com/gif.latex?M(x,y)=\sqrt{(gx)^{2}+(gy)^{2}}" />

笔者使用的是LSD的公式

<img src="http://latex.codecogs.com/gif.latex?gx = f(x+1,y)-f(x,y)+f(x+1,y+1)-f(x,y+1)" />

<img src="http://latex.codecogs.com/gif.latex?gy = f(x,y+1)-f(x,y)+f(x+1,y+1)-f(x+1,y)" />

<img src="http://latex.codecogs.com/gif.latex?M(x,y)=\sqrt{(gx)^{2}+(gy)^{2}}" />

将1x2窗口变成了2x2窗口

 人为设定角度阈值(degreeThreshold),记为degThre,通过下面公式计算出梯度阈值(gradientThreshold),记为gradThre

<img src="http://latex.codecogs.com/gif.latex?gradThre=2/sin(degThre)" />

如果该点梯度小于阈值,则加入usedMap,这步主要将边角和某些凹凸区域给去掉了,然后用gx和gy计算出每点的梯度方向,即level-line场方向,每个点的值记为degree(简记为deg)

<img src="http://latex.codecogs.com/gif.latex?degree= atan2(gx,-gy)" />

区域生长RegionGrower:

 对所有剩下的像素进行快排,然后从梯度最大的像素开始增长,增长的方式是在usedMap为空的像素中增长,方法是比较当前像素与周围8个像素的deg差,如果小于阈值degThre则加入区域Region,然后将最后比较并加入的像素作为下次比较的基准像素(动画中为浅蓝色),通过动画和代码可知,新增长点有滞后性,所以在区域两个端点切换的时候,基准像素在端点的另一侧,所以能够保证两端的角度差较小,若最后生长得到的直线弧度较大,后面有算法进行修正,如果得到的区域所含像素过少,则舍去该区域

最小外接矩形RectangleConvert:

遍历所有像素,找到四个方向上最边界上的像素,然后得到他们的外接矩形

 精炼Rifiner

这步主要是解决前面所说的弧度过大问题,因为可能在增长的时候一侧增长完,则基准像素一直在一端,则无法控制弧度,最终导致弧度过大,使用下式计算出den,若大于阈值则进行精炼

<img src="http://latex.codecogs.com/gif.latex?den=\frac{num}{\sqrt{(x1-x2)^{2}+(y1-y2)^{2}} * width}" />

首先计算出新的degThre

<img src="http://latex.codecogs.com/gif.latex?\\ difSum=\sum_{1}^{n}(curDeg-cenDeg)\\ squSum=\sum_{1}^{n}(curDeg-cenDeg)^{2}\\ meanDif=difSum/num\\ degThre=2*\sqrt{\frac{squSum-2*meanDif*difSum}{num}+meanDif^{2}}}" />

然后重新进行区域生长和建立最小外接矩形,若得到的区域仍未满足密度阈值,则减小区域半径

猜你喜欢

转载自www.cnblogs.com/Pyrokine/p/10384930.html