前言
相机获取到一幅图像往往并不方便直接用于数据的测量,由于其客观存在的观测误差,我们便需要对其进行一定的预处理,来消除图像噪声,排除图像干扰区域,以便于检测到车辆,行人,车道线等检测目标。而车道线的检测,我们需要先建立车道线的参数模型,而后对其进行模型的拟合,Hough变换便是其中一种传统的方法。
图像预处理
图像由一个个离散的像素组成,例如8bit图像的像素值范围为0255(02^8)。由相机拍摄的一般都是彩色图像,一般是RGB三个通道的像素组成,即Red(红色),Green(绿色),Blue(蓝色),此即三原色。
由于图像数据中存在一些不必要的干扰信息,也称图像噪声,所以需要用到一些图像去噪的方法来保证图像不失真。图像滤波方法一般有线性平滑,非线性平滑,自适应平滑。
线性平滑滤波
均值滤波是线性平滑的一种比较简单的方法,首先定义一个边长为奇数的滑动窗口,也称滤波核。比如3×3均值滤波核,用它在图像上从左到右滑动,每滑动到一个位置就计算滤波核和图像各个对应位置像素值乘积之和,以此作为滤波核所处位置中心对应的像素值,这样就等效于把滤波核所处位置中心的像素值用滤波核内所有像素值的平均值替代。
当图像噪声由灰度级比较尖锐,比较大的变化组成,均值滤波便可以比较明显的压制住图像噪声,但它却是以图像模糊为代价换取噪声的减少,并且滤波核越大,图像噪声减少越明显。
非线性平滑滤波
中值滤波是非线性平滑的一种方法,它用像素点邻域灰度值的中值来代替像素点的灰度值,它可以有效的避免让图像变得模糊。
边缘增强
经过图像的灰度化处理和降噪处后,还需要进一步处理图像以便提取车道线像素点,这里用到的方法叫做边缘增强,图像中的边缘指的是像素灰度值变化梯度较大的地方,常用的边缘检测方法由有Prewitt算子,Sobel算子。
Prewitt算子是一种一阶差分算子,对图像像素灰度值进行一阶差分运算。一阶差分。它是两个方向的算子,需要计算两个方向上的梯度,计算方法与均值滤波,中值滤波方法类似。也就是用一个方向的Prewitt算子与图像的某个相同大小窗口中的像素值计算对应元素的乘积之和,以此得到一个方向的梯度。最后计算出总梯度和梯度方向。
具体计算过程如下:
x方向梯度:
▲
x
f
(
x
,
y
)
=
[
f
(
x
+
1
,
y
−
1
)
+
f
(
x
+
1
,
y
)
+
f
(
x
+
1
,
y
+
1
)
]
−
[
f
(
x
−
1
,
y
−
1
)
+
f
(
x
−
1.
y
)
+
f
(
x
−
1
,
y
+
1
)
]
▲_xf(x,y)=[f(x+1,y-1)+f(x+1,y)+f(x+1,y+1)]-[f(x-1,y-1)+f(x-1.y)+f(x-1,y+1)]
▲xf(x,y)=[f(x+1,y−1)+f(x+1,y)+f(x+1,y+1)]−[f(x−1,y−1)+f(x−1.y)+f(x−1,y+1)]
y方向梯度:
▲
y
f
(
x
,
y
)
=
[
f
(
x
−
1
,
y
+
1
)
+
f
(
x
,
y
+
1
)
+
f
(
x
+
1
,
y
+
1
)
]
−
[
f
(
x
−
1
,
y
−
1
)
+
f
(
x
,
y
−
1
)
+
f
(
x
+
1
,
y
−
1
)
]
▲_yf(x,y)=[f(x-1,y+1)+f(x,y+1)+f(x+1,y+1)]-[f(x-1,y-1)+f(x,y-1)+f(x+1,y-1)]
▲yf(x,y)=[f(x−1,y+1)+f(x,y+1)+f(x+1,y+1)]−[f(x−1,y−1)+f(x,y−1)+f(x+1,y−1)]
总梯度:
G
(
x
,
y
)
=
▲
x
f
2
+
▲
y
f
2
G(x,y)=\sqrt{▲_xf^2+▲_yf^2}
G(x,y)=▲xf2+▲yf2
梯度方向:
t
a
n
α
=
▲
y
f
(
x
,
y
)
▲
x
f
(
x
,
y
)
tanα=\frac{▲_yf(x,y)}{▲_xf(x,y)}
tanα=▲xf(x,y)▲yf(x,y)
sobel算子也是一种一阶差分算子,它是在Prewitt算子的基础上改进的
计算方法与Prewitt算子类似,他们都能进行边缘增强
//Sobel算法:
void sobel(unsigned char imageIn[MT9V03X_H][MT9V03X_W], unsigned char imageOut[MT9V03X_H][MT9V03X_W], unsigned char Threshold)
{
short KERNEL_SIZE = 3;//定义3×3滤波核 //
short xStart = KERNEL_SIZE / 2;
short xEnd = MT9V03X_W - KERNEL_SIZE / 2;
short yStart = KERNEL_SIZE / 2;
short yEnd = MT9V03X_H - KERNEL_SIZE / 2;
short i, j, k;
short temp[4];
for (i = yStart; i < yEnd; i++)
{
for (j = xStart; j < xEnd; j++)
{
temp[0] = -(short) imageIn[i - 1][j - 1] + (short) imageIn[i - 1][j + 1] //{{-1, 0, 1},
- (short) imageIn[i][j - 1] + (short) imageIn[i][j + 1] // {-1, 0, 1},
- (short) imageIn[i + 1][j - 1] + (short) imageIn[i + 1][j + 1]; // {-1, 0, 1}};
temp[1] = -(short) imageIn[i - 1][j - 1] + (short) imageIn[i + 1][j - 1] //{{-1, -1, -1},
- (short) imageIn[i - 1][j] + (short) imageIn[i + 1][j] // { 0, 0, 0},
- (short) imageIn[i - 1][j + 1] + (short) imageIn[i + 1][j + 1]; // { 1, 1, 1}};
temp[2] = -(short) imageIn[i - 1][j] + (short) imageIn[i][j - 1] // 0, -1, -1
- (short) imageIn[i][j + 1] + (short) imageIn[i + 1][j] // 1, 0, -1
- (short) imageIn[i - 1][j + 1] + (short) imageIn[i + 1][j - 1]; // 1, 1, 0
temp[3] = -(short) imageIn[i - 1][j] + (short) imageIn[i][j + 1] // -1, -1, 0
- (short) imageIn[i][j - 1] + (short) imageIn[i + 1][j] // -1, 0, 1
- (short) imageIn[i - 1][j - 1] + (short) imageIn[i + 1][j + 1]; // 0, 1, 1
temp[0] = abs(temp[0]);
temp[1] = abs(temp[1]);
temp[2] = abs(temp[2]);
temp[3] = abs(temp[3]);
for (k = 1; k < 4; k++)
{
if (temp[0] < temp[k])
{
temp[0] = temp[k];
}
}
}
}
}
以上