一、一张建筑照片引出的精度问题
拿一张建筑照片,想检测这栋楼歪没歪。
逻辑不复杂——找到建筑的垂直轮廓线,算算和铅垂方向的夹角,角度偏差超过阈值就判定为倾斜。但做起来会碰上一个让人头疼的问题:精度不够。
建筑倾斜检测有硬性的工程标准。住建部GB 50292-2015规定民用建筑的倾斜率警戒值在0.7%1.0%之间,换算成角度就是0.4°0.57°。检测系统必须能分辨不到0.5°的角度偏差才有实用价值。对一张1080p的照片来说,建筑轮廓线如果跨越500像素的高度,0.3°的倾斜只会导致顶端相对底端偏移大约2.6个像素。
2.6个像素。朴素的直线检测方法输出的端点坐标都是整数,2个像素的偏移和3个像素的偏移对应的角度差就是0.11°——这个量化误差直接吃掉了三分之一的检测余量。想检测0.3°的建筑倾斜?像素级精度根本不够用。
这就引出了"精度链"这个概念:从原始图像到最终角度数值,每一个环节都必须把精度损失控制在最小范围内,链条上任何一个环节粗糙了后面再怎么精确也补不回来。这条链有三个关键环节——线段检测方法的选择(不同算法对方向的估计精度差异巨大)、线段端点的定位精度(像素级还是亚像素级,这里差一个数量级)、从线段参数到角度的统计估计方法(怎么从一堆线段里提取出可靠的角度值)。
OpenCV里做线段检测的方案主要两套:Hough变换和LSD(Line Segment Detector)。做亚像素精化有cornerSubPix()。源码分散在hough.cpp(2523行)、lsd.cpp(1180行)和cornersubpi