这篇博客是我去年的一个作业题,觉得还有点意思,和大家分享下。
- 1.全方位图简述
图3-1左图所示,是一种全方位视觉相机,主要由反射镜面和单孔摄像机组成,周围光线经过反射镜反射后进入摄像头,经过摄像镜头折射成像,利用镜面反射原理,扩大视觉系统的视野。这种全向视觉系统成像十分迅速,一次成像可以提供360度的环境信息,图3-1右图为相机获得的图像。这种相机可以很好的应用于移动机器人视觉导航系统,具有十分重要的应用前景。
本文针对右图的全方位图像,将全方位图像展开为普通图像,并提取其中走廊环境中的竖直线。
- 2 中心提取
要想将全方位图像准确的转化为普通图像,首先需要获得目标区域的中心,将其作为极坐标的原点,针对本题,黑色环的内部图像即为我们的目标区域,区域中心的提取过程如下:
灰度化
将原全方位图变为灰度图,加快处理速度,方便后续操作,结果如图3-3 (a) 所示。
二值化
利用自己编写的函数Mat myBinary(const Mat &src, int min, int max),将灰度图变为二值图,选取阈值范围为80-210,将灰度值在80到210之间的像素灰度值变为255,其他变为0,结果如图3-3 (b)所示。
(a)灰度图 (b)二值图
图3-2 全方位图像处理
寻找轮廓
利用opencv库中的 findContours( ) 函数,从二值图中寻找到的轮廓线如图3-3(a) 所示。
最小包围圆
遍历图3-3(a) 中的所有轮廓线,使用opencv库中的minEnclosingCircle函数Void minEnclosingCircle ( InputArray points, CV_OUT Point2f& center, CV_OUT float& radius );获得每个轮廓的最小包围圆,从原全方位图中容易得到,我们感兴趣的目标区域最小包围圆的半径小于原全方位图图像高的二分之一,大于原全方位图高的三分之一;遍历所有轮廓的最小包围圆,根据半径筛选,最终得到我们感兴趣区域外围轮廓的最小包围圆如图3-3 (b)所示的红色圆。
具体信息为:圆心坐标(164.08,106.10);半径 114.204。根据圆心的坐标,可以在全方位图中建立极坐标系,将全方位图展开成普通图像。
图3-3 寻找目标区域中心
- 3.3 极坐标变换
由于全方位视觉系统获得的视频或图像包含水平360 度的环境信息,成像存在扭曲,不符合人眼视觉观察习惯,在实际应用中,经常需要把全方位图展开成柱面全景图[2]。
全方位图展开原理示意图如图3-4所示,主要利用极坐标变换原理来展开。要实现极坐标变换,关键是找到展开图中的点与极坐标图中对应点的变换关系。如图3-4所示,假设极坐标中的一点P(m, n) ,在展开图中对应的点为P’( i , j) ,展开图上的每一列对应为圆图上的每条半径,展开图的高为R,展开图的宽近似为半径为R的弧长。
图3-4 全方位展开示意图
根据图3-4中的几何关系,可以列出啊一下关系式:
点P在全方位图图像坐标中坐标为:
其中centerX , centerY 为极坐标系的原点在全方位图图像坐标系中的想行列坐标。
根据公式3-1,和3-2,可以找到展开图中任意一点P’ ( i, j)在全方位图中对应的点P(m, n),从而编写极坐标变化算法为:
Mat myPolarToLiner(Mat & src, int center_x, int center_y, int radius)
{
Mat img_polar = cv::Mat::zeros((int)radius, (int)2 * radius*PI, CV_8UC1);
for (int j = 0; j < img_polar.cols; j++)
{
double delta = 1.0* j / (radius);
for (int i = 0; i < img_polar.rows; i++)
{
double src_x, src_y;
src_x = i*cos(delta);
src_y = i*sin(delta);
int src_row = center_y - src_y; //
int src_col = center_x + src_x;
if ((src_row < 0) | (src_row > src.rows - 1))
img_polar.at<uchar>(i, j) = 255;
else if ((src_col < 0) | (src_col > src.cols - 1))
img_polar.at<uchar>(i, j) = 255;
else
img_polar.at<uchar>(i, j) = src.at<uchar>(src_row, src_col);
}
}
return img_polar;
}
输入全方位图,极坐标系的原点以及极半径,即可得到一副高为R,宽为2πR的展开图。
图3-5为全方位图灰度化以后展开的图像,因为是以逆时针方向旋转展开的,所以图像中的人物是倒立的,为了便于观察,将其旋转180度后得到的图像如图3-6所示。
图3-6 展开图翻转180度
- 3.4 霍夫变换提取直线
物体特征提取中直线提取在机器视觉领域非常关键,当前对直线的检测方法大多基于Hough提出的 Hough变换算法,cuda等改进了此方法,将极坐标的参数方程引入 Hough变换,解决了在斜率无穷大情况下的参数转换,Hough变换实现了从图像空间到参数空间的映射关系,噪声图像稳定性和稳健性良好。
假设一条直线在直角坐标系下用一般方程y=ax+b表示, 霍夫变换的主要思想是将该方程的参数和变量交换,即用x,y作为已知量a,b作为变量坐标,也就有直线y=ax+b上任意一点在参数坐标系下的坐标都为(a,b)。
因此可以先将图片进行边缘检测,然后对图像上每一个非零像素点,在参数坐标下变换为一条直线,那么在直角坐标下属于同一条直线的点便在参数空间形成多条直线并内交于一点。从而可用该原理进行直线检测。
为了计算方便,1972年,Duda 和 Hart 将极坐标引入 Hough 变换,采用直线的极坐标方程:
式(3-3)称为标准 Hough 变换。其中,ρ 为从图像空间的原点到该空间内直线的距离(即原点到直线的垂直线的长度),θ 为直线法线与x 轴的夹角(即原点到直线的垂直线与 x 轴方向的夹角),如图3-8所示。根据方程(3-3),原图像空间中的点对应新参数空间中的一条正弦曲线,即原来的点-直线对偶性变成了现在的点-正弦曲线对偶性。检测在图像空间中共线的点需要在新参数空间里检测正弦曲线的交点。具体就是让 θ 取遍θ 轴上所有可能的值,并根据式(3.6)算出所对应的 ρ ,若在 x- y 平面上有三个共线点,则它们变换到 ρ-θ 平面上为有一公共交点的三条曲线[5]。
图3-8 标准hough变换
首先利用Canny算子提取图像边缘,结果如图3-9所示:
图3-9 Canny边缘提取
使用HoughLines( )函数寻找直线,选择角度theta小于1.1度或者大于178.9度的直线,得到结果如图3-10所示。
图3-10 Hough变换寻找直线
从图3-9可以看出,利用Hough变换可以找到在一条直线上的点,但是无法区分直线上的点是属于墙壁还是属于地面。通过查阅论文,我们发现概率Hough变换可以解决上述问题。
概率Hough变换在 Hough变换基础上,对边界点进行随机采样,在直线到原点距离ρ和直线角度θ(0~π)形成的累加器空间进行投票,达到阈值即认为有直线,该方法不像 Hough变换对全部边 界 点 进 行 检 索,仅 部 分 抽样,大大减少了计算时间和计算量。
利用OpenCV中的概率Hough变换函数HoughLinesP( )可以得到更好的效果,并且获得墙壁上直线的起点与终点,通过直线的斜率筛选,得到墙壁的直线如图3-11所示。
图3-11 概率Hough变换得到的直线