智能车摄像头算法——寻线
寻线
1.灰度图像二值化
如果使用的是小钻风摄像(二值化摄像头),就不用再进行软件二值化。
使用灰度摄像头,就需要这步。
以下展示常用的大津法
(1)首先获得分割的阈值
uint8 otsuThreshold(uint8 *GrayImage,uint32 ImageSize)
{
int T; //T为动态阈值
uint8 threshold = 0; //最佳阈值
uint32 N0 = 0,N1 = ImageSize; //图像中像素小于阈值T的像素个数记作N0,像素大于阈值T的像素个数记作N1
float w0,w1; //w0为前景像素点占整幅图像的比例 w0 = N0/ImageSize (ImageSize为图像大小)
//w1为前景像素点占整幅图像的比例 w1 = N1/ImageSize (ImageSize为图像大小)
uint32 u0den = 0,u1den = 0; //图像中像素小于阈值T的像素加权和记作u0den
//图像中像素大于阈值T的像素加权和记作u1den
float u0,u1; //u0为前景像素点平均灰度 u0 = u0den/N0
//u1为前景像素点平均灰度 u1 = u1den/N1
float deltaTmp; //类间方差 计算公式 w0*w1*(u0-u1)^2
//类间方差最大的阈值T为所求最佳阈值
uint32 itemp,*pPixelCount = pixelCount;
float deltaMax = 0;
//获取灰度图像直方图
_Getting_GrayHistogram(pPixelCount,GrayImage,ImageSize);
//计算动态阈值
for (T = 0;T < 255;T ++)
{
itemp = *(pPixelCount + T);
u1den += T * itemp;
}
for (T = 0; T < 255; T++)
{
itemp = *(pPixelCount + T);
N0 += itemp;
N1 -= itemp;
if (N0 == 0 || N1 == 0)
continue ;
itemp = itemp * T;
u0den += itemp;
u1den -= itemp;
w0 = (float)N0 / (float)ImageSize;
w1 = (float)N1 / (float)ImageSize;
u0 = (float)u0den / (float)N0;
u1 = (float)u1den / (float)N1;
deltaTmp = w0*w1*(u0-u1)*(u0-u1);
if (deltaTmp > deltaMax)
{
deltaMax = deltaTmp;
threshold = T;
}
}
if(deltaMax < 80)
{
if(threshold >= 50)
threshold = 10;
else if(threshold < 50)
threshold = 100;
}
return threshold;
}
(2)再进行二值化(white=255 black =0)
//***********************************************//
//函数名称: image_Gray2Binary //
//函数版本: V1.0 //
//函数说明: 灰度图片转化为二值化图片 //
//函数输入: BinImage : 二值化图像指针 //
// GrayImage : 灰度图像指针 //
// ImageSize : 输入图像尺寸(长度*宽度) //
// threshold : 图像转化阈值 //
//函数输出: BinImage : 二值化图像指针 //
//***********************************************//
void image_Gray2Binary(uint8 *Binimg,uint8 *GrayImage,uint32 ImageSize,uint8 threshold)
{
uint32 z;
uint32 temp,temp_1 = white,temp_2 = black;
for (z = 0;z < ImageSize;z++)
{
temp=*(GrayImage + z);
if (temp >= threshold)
*(Binimg + z) = temp_1;
else
*(Binimg + z) = temp_2;
}
}
使用:
//mt9v03x_image是灰度图像数组
pixel=otsuThreshold(&mt9v03x_image[0][0],MT9V03X_W*MT9V03X_H);
//img是二值化后得到的图像
image_Gray2Binary(&img[0][0],&mt9v03x_image[0][0],MT9V03X_W*MT9V03X_H,pixel);//img二值化图像
当然还有很多算法,例如基于sobel算子,动态阈值法等等。有需要可以评论邮箱,我发你。但是我觉得只要能把图像大体的边界信息保留下来,就可以了。并且有部分算法运算量很大,智能车比赛有些指定的单片机运用这些算法会把图像卡成PPT。
2.找边线
找边线可以就用最简单的逻辑,从中间向两边搜黑点。从距离车头较近的行开始从中间向两边搜线。
以下代码思路稍微有点变化:
左边线默认:1 右边线默认:(图像宽度-1)
从车头最近的一行开始,把这行图像单独拿出来,作为一个参考。之后的行,搜左边线时,从前一个搜的左边线的横坐标加一个值向左搜;搜右边线时,从前一个搜的右边线的横坐标减一个值向右搜。这个过程完成,就得到了一幅图像的边界数组。
/*-----------------------------------------------------------------!
* @brief 获取边线
*
* @param imageInput : 二值图像信息
* @param imageOut : 边线数组
*
* @return 是否丢线
*
* @note 思路:从距离车头较近的行开始从中间向两边搜线
---------------------------------------------------------------------- */
uint8_t ImageGetSide(uint8_t imageInput[OV7725_UART_H][OV7725_UART_W], uint8_t imageOut[OV7725_UART_H][2])
{
uint8_t i = 0, j = 0,k=0;
for(i = OV7725_UART_H-1; i > 0; i--)
{
imageOut[i][left] = 1;
imageOut[i][right] = OV7725_UART_W-1;
}
// 用距离小车比较近的行 判断是否丢线
for(i = OV7725_UART_W/2; i > 1; i--)
{
if(!imageInput[OV7725_UART_H-1][i])
{
imageOut[OV7725_UART_H-1][left] = i;
break;
}
}
for(i = OV7725_UART_W/2+1; i < OV7725_UART_W-1; i++)
{
if(!imageInput[OV7725_UART_H-1][i])
{
imageOut[OV7725_UART_H-1][right] = i;
break;
}
}
//-------------------------------------------------------------
// 遍历每行
for(i = OV7725_UART_H-2; i > 0; i--)
{
// 向左搜线
for(j = imageOut[i+1][left] + 10; j > 0; j--)
{
if(!imageInput[i][j])
{
imageOut[i][left] = j;
break;
}
}
if(imageOut[i][left] > OV7725_UART_W/2)
{
imageOut[i][left]=OV7725_UART_W/2;
for(k=i;k>0;k--)
{
imageOut[k][left]=OV7725_UART_W/2;
}
break;
}
}
//遍历每一行
for(i = OV7725_UART_H-2; i > 0; i--)
{
//向右搜线
for(j = imageOut[i+1][right] - 10; j < OV7725_UART_W-1; j++)
{
if(!imageInput[i][j])
{
imageOut[i][right] = j;
break;
}
}
if(imageOut[i][right] < OV7725_UART_W/2)
{
imageOut[i][right]=OV7725_UART_W/2;
for(k=i;k>0;k--)
{
imageOut[k][right]=OV7725_UART_W/2;
}
break;
}
}
3.获得中线
一般情况:
中线 =(左边线+右边线)/2
特殊情况:
中线 = 左边线+N 或者
中线 = 右边线-N
这个特殊处理根据实际情况自己处理就行了。比如说,在左转弯的时候弧度太大,导致左边线全部丢线,这个时候就可以令中线 = 右边线 – N。当然还是要根据自己摄像头采集到的图像特征来灵活运用