后车规定采用红外摄像头追踪前车红外灯板(两个横置红外光源,左边一个,右边一个),本文旨在为基础识别提供思路和介绍,用于个人复盘,代码仅供参考,参考逐飞和龙邱思路,可关注两家微信公众号。
偏差的计算
采用获取图像中所有白色像素点平均坐标的方法。具体来说,先统计出这些白色像素的平均坐标值,然后将该平均坐标的 x 轴数值与图像中点的 x 轴坐标值进行差值运算,所得结果即为后车相对于前车的横向偏差。
距离的计算
对于后车与前车之间距离的计算,借助图像中所有白色像素点的方差来实现。实际情况中,车辆间距的变化会直接影响到前车 LED 灯光斑在图像中的呈现效果。当两车距离较远时,光斑在图像中显示较小,同时两个光斑之间的间距也更近,这种情况下图像中白色像素点的分布更为集中,进而导致方差较小;反之同理。通过对白色像素点方差的计算与分析,能够有效获取两车之间的距离信息。
分析左边光源,得出左上角和右下角坐标;分析右边光源,得出左下角和右上角坐标。取平均得左右光源中心位置。。。。。
备注:采用逐飞mt9v03x库,和龙邱神眼摄像头,
#define LIMIT 0
uint8_t threshold_value =80; //黑白区分阈值
uint8_t image_deal[MT9V03X_H][MT9V03X_W]; //MT9V03X摄像头读取图像范围
uint8_t point1[2][2], point2[2][2], centre[2][2]; //存储光源1,2和图像中心坐标值
uint8_t point1_flag = 0;
// 0: 未发现第一个点的左上角
// 1: 发现第一个点的左上角
// 2: 发下第一个点的右下角
uint8_t point2_flag = 0;
// 0: 未发现第二个点的左下角
// 1: 发现第二个点的左下角
// 2: 发下第二个点的右上角
extern uint8_t protect_flag; //保护标志,1为开启保护,0为关闭保护
uint8_t Deal_succeed_count = 0; //对正确处理图像计数 当正确处理图像超100次时退出该状态
void Image_process_calculate(float *x_error,float *y_reeor)
{
Image_filter(threshold_value);
uint8_t Y =0,X=0;
float value1 = 0,value2 = 0;
if( (point1_flag == 0 && point2_flag == 1) ||
(point1_flag == 0 && point2_flag == 0) ||
(point1_flag == 1 && point2_flag == 0)) //寻找点1的左上角和点2的左下角
{ for(Y =0;Y< MT9V03X_H ;Y++)
{ for(X = 0;X< MT9V03X_W ;X++)
{ if(point1_flag == 0)//寻找第一个点的左上角
{
value1 = Image_process_deal_point1(X,Y);
if(value1 > LIMIT ){ point1[0][0] = X; point1[0][1] = Y; point1_flag = 1;}
}
if(point2_flag == 0)//寻找第二个点的左下角
{
value2 = Image_process_deal_point2(X,Y);
if(value2 > LIMIT )
{
point2[0][0] = X; point2[0][1] = MT9V03X_H - Y - 1; point2_flag = 1;
}
}
if(point1_flag == 1 && point2_flag == 1) break;
}
if(point1_flag == 1 && point2_flag == 1) break;
}
}
if( (point1_flag == 1 && point2_flag == 1) ||
(point1_flag == 1 && point2_flag == 2) ||
(point1_flag == 2 && point2_flag == 1))//寻找点1的右下角和点2的右上角
{
for(Y = ( point2[0][1] + point1[0][1])/2 ; Y< MT9V03X_H ; Y++)
{
for( X = MT9V03X_W-1; X>0 ;X-- )
{
if(point1_flag == 1)
{ value1 = Image_process_deal_point1_right(X,Y);
if(value1 > LIMIT ){
point1[1][0] = X;
point1[1][1] = ( point2[0][1] + point1[0][1]) - Y;
point1_flag = 2;}
}
if(point2_flag == 1)
{
value2 = Image_process_deal_point2_right(X,Y);
if(value2 > LIMIT ){ point2[1][0] = X;
point2[1][1] = Y; point2_flag = 2; }
}
if(point1_flag == 2 && point2_flag == 2) break;
}
if(point1_flag == 2 && point2_flag == 2) break;
}
}
if(point1_flag == 2 && point2_flag == 2)
{
Square_centre(point1,¢re[0][0],¢re[0][1]);
Square_centre(point2,¢re[1][0],¢re[1][1]);
*y_reeor = centre[1][1] - centre[0][1];
*x_error = (centre[0][0] + centre[1][0])/2.0;
point1_flag = 0;
point2_flag = 0;
Deal_succeed_count ++;
if(Deal_succeed_count > 100)
{
if(protect_flag == 1)//退出保护状态
{
protect_flag = 0;
}
Deal_succeed_count = 0;
}
}else
{
protect_flag = 1;
}
//图像识别保护 若经过上述两个过程后
//point1_flag和 point2_flag 两个都不为2则证明图像丢失这时开启保护位
}
// function : 传入图像的两个对角坐标(x1,y1) (x2,y2),计算中心点坐标(centre_x,centre_y)
// parameter: 两个对角坐标(x1,y1) (x2,y2) 中心点坐标(centre_x,centre_y)指针
// return : NULL
void Square_centre(uint8_t point[2][2],uint8_t * center_x,uint8_t*centre_y)
{
*center_x = (point[0][0]*1.0 + point[1][0]*1.0)/2;
*centre_y = (point[0][1]*1.0 + point[1][1]*1.0)/2;
}
// function : 取绝对值
// parameter: value值
// return : value的绝对值
float absolute(float value)
{
if(value <0)
{
value = -value;
}
return value;
}
// function : 从图像左上到右下寻找第一个亮点的左上角
// parameter:
// return :
// ----------------
// | -> ** |
// | ** |
// | |
// | |
// ----------------
float Image_process_deal_point1(uint8_t x,uint8_t y)
{
float value = 0;
if (x < MT9V03X_W - 1)//防止数组越界
{
value = ( image_deal[y][x+1]*1.0 - image_deal[y][x])/
( image_deal[y][x+1]*1.0 + image_deal[y][x]);
} //计算相邻两个点的差比和
value = absolute(value);//取绝对值保障都是正数
return value;
}
// function : 从图像左下到右上寻找第二个亮点的左下角
// parameter:
// return :
// ---------------
// | |
// | ** |
// | ** |
// | -> |
// ---------------
float Image_process_deal_point2(uint8_t x,uint8_t y)
{
float value = 0;
y = MT9V03X_H - y - 1;
if (x < MT9V03X_W - 1)//防止数组越界
{
value = ( image_deal[y][x+1]*1.0 - image_deal[y][x])/
( image_deal[y][x+1]*1.0 + image_deal[y][x]);
} //计算相邻两个点的差比和
value = absolute(value);//取绝对值保障都是正数
return value;
}
// function : 从图像左上到右下寻找第一个亮点的右下角
// parameter:
// return :
// ----------------
// | ** |
// | ** <-|
// | |
// | |
// ----------------
float Image_process_deal_point1_right(uint8_t x,uint8_t y)
{
float value = 0;
y = ( point2[0][1] + point1[0][1]) - y;
if (x > 0)//防止数组越界
{
value = ( image_deal[y][x-1]*1.0 - image_deal[y][x])/
( image_deal[y][x-1]*1.0 + image_deal[y][x]);
} //计算相邻两个点的差比和
value = absolute(value);//取绝对值保障都是正数
return value;
}
// function : 从图像左下到右上寻找第二个亮点的右上角
// parameter:
// return :
// ---------------
// | |
// | |
// | ** <-|
// | ** |
// ---------------
float Image_process_deal_point2_right(uint8_t x,uint8_t y)
{
float value = 0;
if (x > 0)//防止数组越界
{
value = ( image_deal[y][x-1]*1.0 - image_deal[y][x])/
( image_deal[y][x-1]*1.0 + image_deal[y][x]);
} //计算相邻两个点的差比和
value = absolute(value);//取绝对值保障都是正数
return value;
}
// function : 将图像预处理,将外界小光斑滤掉(小于阈值的点的灰度值赋1)
// parameter: threshold 阈值
// return :
void Image_filter(uint8_t threshold)
{
for (uint8_t y = 0; y < MT9V03X_H; y++)
{
for (uint8_t x = 0; x < MT9V03X_W; x++)
{
if (mt9v03x_image[y][x] >= threshold)
image_deal[y][x] = mt9v03x_image[y][x] ;
else
image_deal[y][x] = 1;
}
}
}
float cauclate_variance(float average,float num)
{
float out = 0;
out = (num - average)*(num - average);
return out;
}
// function : 将图像预处理,计算图片中所有白色光斑的横坐标的均值和方差
// parameter: threshold 阈值 Image_x_average 横坐标的均值 variance 横坐标的方差
// return :
void LQ_Deal_Image(float *Image_x_average, float *variance,uint8_t threshold)
{
uint16_t point_x_record[800] = {0}; //存储所有白色光斑点的横向坐标
uint16_t i = 0,j = 0,point_count = 0;
float x_sum = 0,variance_sum = 0;
for(i= 0 ;i < MT9V03X_H;i++)
{
for(j= 0 ;j < MT9V03X_W;j++)
{
if (mt9v03x_image[i][j] >= threshold )
{
x_sum += j;
point_x_record[point_count] = j;
point_count ++;
if(point_count >= 800)
{
ips200_show_string(100,120,"ERROR");
}
}
}
}
if(point_count != 0) //图像中残存的有亮点
{
if( protect_flag == 1) //保护状态机
{
Deal_succeed_count ++;
if(Deal_succeed_count > 50)
{
Deal_succeed_count =0;
protect_flag = 0;
}
}
*Image_x_average= x_sum/point_count;
for (uint8_t k = 0 ;k < point_count;k++)
{
variance_sum += cauclate_variance(*Image_x_average,point_x_record[k]);
}
*variance = variance_sum/ point_count;
}else if(point_count == 0) //图像光电丢失
{
*variance = 0;
*Image_x_average = 0;
protect_flag = 1; //开启保护
}
}
860

被折叠的 条评论
为什么被折叠?



