1. 得到缩小后的灰度图像
- 1.1 函数内容:
/*************************************************************************
* 函数名称:Get_Use_Image
* 功能说明:把摄像头采集到原始图像,缩放到赛道识别所需大小
* 参数说明:无
* 函数返回:无
* 修改时间:2021年01月08日
* 备 注: 由于直接设置摄像头分辨率得到的图片是由188*120裁剪而来的,故进行缩小处理
* 实际所需大小为94*60
* image_col为实际图像的宽度,列,大小为94
* image_row为实际图像的高度,行,大小为60
*************************************************************************/
void Get_Use_Image(void)
{
int i,j;
for(i=0;i<image_row;i++)
for(j=0;j<image_col;j++)
{
Image_Use[i][j] = image[i*2][j*2+1];
}
}
- 1.2 变量声明:
uint8 image[MT9V032_H][MT9V032_W]; //图像数组
#define image_row 60 //图像高度(行)
#define image_col 94 //图像宽度(列)
uint8 Image_Use[image_row][image_col]; //用于储存缩小后的图像,实际应用的图像
2. 得到二值化后的图像
- 2.1 模式选择:
- 0:使用大津法阈值(GetOSTU)
- 1:使用平均阈值
- 2:sobel 算子改进型 手动阈值,同时输出改为提取边沿的图像(lq_sobel)
- 3:sobel 算子改进型 动态阈值,同时输出改为提取边沿的图像(lq_sobelAutoThreshold)
- 2.2 函数内容:
/*************************************************************************
* 函数名称:Get_Bin_Image
* 功能说明:图像二值化到Bin_Image[][]
* 参数说明:mode :
* 0:使用大津法阈值
* 1:使用平均阈值
* 2: sobel 算子改进型 手动阈值,同时输出改为提取边沿的图像
* 3:sobel 算子改进型 动态阈值,同时输出改为提取边沿的图像
* 函数返回:无
* 修改时间:2020年10月28日
* 备 注: Get_Bin_Image(0); //使用大津法二值化
*************************************************************************/
void Get_Bin_Image (unsigned char mode)
{
unsigned short i = 0, j = 0;
unsigned short Threshold = 0;
unsigned long tv = 0;
if (mode == 0)
{
Threshold = GetOSTU(Image_Use); //大津法阈值
}
if (mode == 1)
{
//累加
for (i = 0; i < image_row; i++)
{
for (j = 0; j < image_col; j++)
{
tv += Image_Use[i][j]; //累加
}
}
Threshold =(unsigned short)(tv / image_row / image_col); //求平均值,光线越暗越小,全黑约35,对着屏幕约160,一般情况下大约100
Threshold = Threshold + 20; //此处阈值设置,根据环境的光线来设定
}
else if (mode == 2)
{
Threshold = 80; //手动调节阈值
lq_sobel(Image_Use, Bin_Image, (unsigned char) Threshold);
return;
}
else if (mode == 3)
{
lq_sobelAutoThreshold(Image_Use, Bin_Image); //动态调节阈值
return;
}
/* 二值化 */
for (i = 0; i < image_row; i++)
{
for (j = 0; j < image_col; j++)
{
if (Image_Use[i][j] > Threshold) //数值越大,显示的内容越多,较浅的图像也能显示出来
Bin_Image[i][j] = WHITE_BIN;
else
Bin_Image[i][j] = BLACK_BIN;
}
}
}
- 2.3 变量声明:
#define image_row 60 //图像高度(行)
#define image_col 94 //图像宽度(列)
#define BLACK_BIN 0 //二值化黑色
#define WHITE_BIN 1 //二值化白色
uint8 Image_Use[image_row][image_col]; //用于储存缩小后的图像,实际应用的图像
uint8 Bin_Image[image_row][image_col]; //二值化图片
3. 过滤噪点
- 3.1 函数内容:
/*************************************************************************
* 函数名称:Bin_Image_Filter
* 功能说明:过滤噪点
* 参数说明:无
* 函数返回:无
* 修改时间:2021年01月08日
* 备 注:
*************************************************************************/
void Bin_Image_Filter (void)
{
int16 nr; //行
int16 nc; //列
for (nr = 1; nr < image_row - 1; nr++)
{
for (nc = 1; nc < image_col - 1; nc = nc + 1)
{
if ((Bin_Image[nr][nc] == 0)
&& (Bin_Image[nr - 1][nc] + Bin_Image[nr + 1][nc] + Bin_Image[nr][nc + 1] + Bin_Image[nr][nc - 1] > 2))
{
Bin_Image[nr][nc] = 1;
}
else if ((Bin_Image[nr][nc] == 1)
&& (Bin_Image[nr - 1][nc] + Bin_Image[nr + 1][nc] + Bin_Image[nr][nc + 1] + Bin_Image[nr][nc - 1] < 2))
{
Bin_Image[nr][nc] = 0;
}
}
}
}
- 3.2 变量声明:
#define image_row 60 //图像高度(行)
#define image_col 94 //图像宽度(列)
uint8 Image_Use[image_row][image_col]; //用于储存缩小后的图像,实际应用的图像
uint8 Bin_Image[image_row][image_col]; //二值化图片
4. 获得赛道边界
- 4.0 函数说明:
此函数可获得以下数据:
int16 Image_Side[2][image_row]; //边沿数据:第一行——左边界;第二行——右边界;下标——行,值——列
int16 DivLine; //有效行
int16 Road_Width[image_row]; //路宽
- 4.1 函数内容:
/*************************************************************************
* 函数名称:Image_Get_Side
* 功能说明:获得赛道边界
* 参数说明:无
* 函数返回:无
* 修改时间:2021年01月08日
* 备 注:
*************************************************************************/
void Image_Get_Side (void)
{
int16 x;
int16 y;
int16 start_col; //起始行的起始列,赛道可能完全在屏幕左半面或右半面
//如果起始行中点为不在赛道中点 往右寻找
for(x=start_col; x <= right_col; x++)
{
if(Bin_Image[start_row][x] == WHITE_BIN)
if(Bin_Image[start_row-1][x] == WHITE_BIN)
if(Bin_Image[start_row-2][x] == WHITE_BIN)
{
start_col=x;
break;
}
}
//如果起始行中点为不在赛道中点 往左寻找
for(x=start_col; x >= left_col; x--)
{
if(Bin_Image[start_row][x] == WHITE_BIN)
if(Bin_Image[start_row-1][x] == WHITE_BIN)
if(Bin_Image[start_row-2][x] == WHITE_BIN)
{
start_col=x;
break;
}
}
//寻找起始行右边界
for(x = start_col; x <= right_col; x++)
{
if(Bin_Image[start_row][x] == BLACK_BIN)
{
Image_Side[RIGHT][start_row] = x;
break;
}
}
if(x > right_col) //没有找到右边界,丢线
{
Image_Side[RIGHT][start_row] = LOST_RIGHT_SIDE ;
}
//寻找起始行左边界
for(x = start_col; x >= left_col; x--)
{
if(Bin_Image[start_row][x] == BLACK_BIN)
{
Image_Side[LEFT][start_row] = x;
break;
}
}
if(x < left_col) //没有找到左边界,丢线
{
Image_Side[LEFT][start_row] = LOST_LEFT_SIDE ;
}
//起始行宽度
Road_Width[start_row] = Image_Side[RIGHT][start_row] - Image_Side[LEFT][start_row];
//寻找其他行边界
for(y=start_row-1; y>=end_row; y--) //由近到远找
{
//左边界
x = Image_Side[LEFT][y+1] + 4; //从上一行左侧往右4个点开始寻找,如果这个值设置太大会影响远处找中线
while( (Bin_Image[y][x]==BLACK_BIN) && (x<=right_col) )
{
x += 4;
}
if(x>right_col) //找不到边界(只有两条边界相距太近时,才找不到)(找不到白色)(全都是黑色,才叫无效)
{
DivLine = y+1;
break;
}
for(; x>=left_col; x--)
{
if(Bin_Image[y][x] == BLACK_BIN)
{
Image_Side[LEFT][y] = x;
break;
}
}
if(x < left_col) //判断是否出了边界
{
Image_Side[LEFT][y] = LOST_LEFT_SIDE;
}
//右边界
x = Image_Side[RIGHT][y+1] - 4; //从上一行左侧往右4个点开始寻找
while( (Bin_Image[y][x]==BLACK_BIN) && (x>=left_col) )
{
x -= 4;
}
if(x < 0) //找不到边界
{
DivLine = y+1;
break;
}
for(;x <= right_col; x++)
{
if(Bin_Image[y][x] == BLACK_BIN)
{
Image_Side[RIGHT][y] = x;
break;
}
}
if(x > right_col)//判断是否出了边界
{
Image_Side[RIGHT][y] = LOST_RIGHT_SIDE;
}
//路宽
Road_Width[y] = Image_Side[RIGHT][y] - Image_Side[LEFT][y];
/*-------------满足以下情况时停止对这幅图片的处理并寻找有效行--------------*/
//如果满足 (左右边界靠得太近 或者 左侧边界太靠右 或者 右侧边界太靠左) 则跳出找线
if( (Road_Width[y] < 10) //此处的 10 可以根据需要来改
|| (Image_Side[LEFT][y] > image_col-5)
|| (Image_Side[RIGHT][y] < 4))
{
DivLine = y + 1;//确定该幅图像有效行,便于下面程序算斜率、截距
break;
}
else
DivLine=0; //否则就是直到最远处一行都是有效的
}
}
- 4.2 变量声明:
#define image_row 60 //图像高度(行)
#define image_col 94 //图像宽度(列)
#define BLACK_BIN 0 //二值化黑色
#define WHITE_BIN 1 //二值化白色
#define LEFT 0 //数组变量左
#define RIGHT 1 //数组变量右
#define LOST_LEFT_SIDE -1 //左边界丢失
#define LOST_RIGHT_SIDE image_col //右边界丢失
uint8 Image_Use[image_row][image_col]; //用于储存缩小后的图像,实际应用的图像
uint8 Bin_Image[image_row][image_col]; //二值化图片
uint8 left_col = 0; //最左边
uint8 right_col = image_col-1; //最右边
uint8 end_row = 0; //最远行
uint8 start_row = image_row-1; //最近行
int16 Image_Side[2][image_row]; //边沿
int16 DivLine; //有效行
int16 Road_Width[image_row]; //路宽
版权声明:本文为weixin_43964993原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。