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}}}" />
然后重新进行区域生长和建立最小外接矩形,若得到的区域仍未满足密度阈值,则减小区域半径