写在最前面:
想不到这么久的文章还有人看,现在回头看自己的代码,觉得写的实在拙劣,诸位后来者看个笑话即可,感谢!
声明:
由于学校代码不宜外泄,本文目的也只是记录生活、分享思路,故将除了变量申明部分保留了一部分外,所有组委会例程代码均被删除,在文中也有标记,剩下部分均为博主自己写出,应该不涉及保密。真有来学习的(不会真有人来吧)同学别看糊涂了。
正文:
博主参加的是北科21年的智能车校内赛,处理方法都是在提供的例程基础上添加的。例程使用的都是【区域生长】思想的搜索框架。基本上都是选用了【最大连通区域】进行主区域的搜索。
以下分享本次我对图像的处理代码,供大家参考学习。注意,每辆车的处理都不完全一样,请主要关注处理思路。而且在结束之后,我才找到一种更为稳定的补线思路。我将放在文末与各位分享。
#include "search.h"
/******** 变量声明 ********/
uint8 video_ori[MAX_VIDEO_LINE][MAX_VIDEO_POINT]; //图像原始数据,video_ori[m][n]代表图像的从下数第m行,从左数第n点,0为最黑,255为最白
//==============================图像数据================================//
Int16_point g_CenterPosition[MAX_POINT_NUM];//中心点数组,下标代表第几个,存储相应中心点的坐标值
Int16_point g_LeftEdge[MAX_POINT_NUM], g_RightEdge[MAX_POINT_NUM];//左、右边界点数组,下标代表第几个,存储相应边界点的坐标值
float g_LeftDown_x, g_LeftDown_y, g_LeftUp_x, g_LeftUp_y, g_RightDown_x, g_RightDown_y, g_RightUp_x, g_RightUp_y;//左下、左上、右下、右上拐点数据
int g_CenterNum;//中心点个数
int g_ImageLine,g_sum;
int g_Display,DirectionControlLine,DirectionControlWhole;//加权计算控制中心中的权值和项; 加权计算控制中心中的加权和项
int g_LeftEdgeNum, g_RightEdgeNum;//图像识别结束后为左、右边界点个数
//==============================图像处理用变量==========================//
uint16 g_Start[10], g_End[10], g_SEnum; //存放当前行各白块起始、结束位置的数组,下标为10意味着每行最多10个白块;白块计数器
uint8 g_SearchFlag=1;//区分当前是否在搜索第一行,值为1表明正在搜索第一行,否则为其余行
int g_Cover;//白块联通长度
uint8 g_CoverIndex[10],g_CoverNum;//;当前行与前一行左右边界对应白块有重合的白块数
int banma = 0;
//==============================新添的变量==============================//
int a = 0;
float b = 0;
double c = 0;
//======================================================================//
/********* search:处理数据即测试算法的函数 ********/
void search()
{
g_LeftEdgeNum=0; g_RightEdgeNum=0;
g_SearchFlag=1;
int i,line, white_width = 0;
/*int IMAGE_MIDDLE;
int j;*//*用于大津法*/
//=======================图像识别=========================//
//PS:此时我们的图像已经提取完毕 我们从底部开始,向上识别图像
//图像识别数据初始化
//大津法(效果不好,故暂时注释掉)
//int width = MAX_VIDEO_POINT;
//int height = MAX_VIDEO_LINE;
//int pixelCount[GrayScale] = { 0 }; //每个灰度值所占像素个数
//float pixelPro[GrayScale] = { 0 };//每个灰度值所占总像素比例
//int pixelSum = width * height; //总像素
//uint8 * data = video_ori[MAX_VIDEO_LINE]; //指向像素数据的指针
// //统计灰度级中每个像素在整幅图像中的个数
//for (i = 0; i < height; i++)
//{
// for (j = 0; j < width; j++)
// {
// pixelCount[(int)video_ori[i][j]]++; //将像素值作为计数数组的下标
// }
//}
计算灰度集中每个像素在整幅图像中的比例
//for (i = 0; i < GrayScale; i++)
//{
// pixelPro[i] = (float)pixelCount[i] / pixelSum;
//}
遍历灰度级[0,255]
//float wf, wb, uftmp, ubtmp, uf, ub, u, deltaTmp, deltaMax = 0;
//for (i = 0; i < GrayScale; i++) // i作为阈值
//{
// wf = wb = uftmp = ubtmp = uf = ub = u = deltaTmp = 0;
// for (j = 0; j < GrayScale; j++)
// {
// if (j <= i) //背景部分
// {
// wb += pixelPro[j];//背景像素点占整个图像的比例
// ubtmp += j * pixelPro[j];
// }
// else //前景部分
// {
// wf += pixelPro[j];//前景像素点占整个图像的比例
// uftmp += j * pixelPro[j];
// }
// }
// ub = ubtmp / wb;//背景平均灰度μ0
// uf = uftmp / wf;//前景平均灰度μ1
// deltaTmp = (float)(wb * wf * (ub - uf)*(ub-uf)); //类间方差公式 g = w1 * w2 * (u1 - u2) ^ 2
// if (deltaTmp > deltaMax)
// {
// deltaMax = deltaTmp;
// IMAGE_MIDDLE = i;
// }
//}
//
g_CenterNum = 0;
g_LeftEdgeNum = 0;
g_RightEdgeNum = 0;
g_SearchFlag=1;
int banmajishu = 0;
//注意,此处删除了寻找画面白块部分!!!!!!!
//下面开始正式补线
int r_down_flag = 0;//右下拐点标志
int r_up_flag = 0;//右上拐点标志
int l_down_flag = 0;//左下拐点标志
int l_up_flag = 0;//左上拐点标志
int l_xie_crossroad_jin = 0;//近左斜标志
int r_xie_crossroad_jin = 0;//近右斜标志
int straightway = 0;//直道标志
int before_crossroad = 0;//正十字前标志
int ing_crossroad = 0;//正十字中标志
int l_xie_crossroad_yuan = 0;//远左斜标志
int r_xie_crossroad_yuan = 0;//远右斜标志
int ing_crossroad_pd = 0;//正十字中与弯道离奇拐点、远斜十字判别标志
for (i = 0; i < 20; i++)
{
if (video_ori[i][0] > IMAGE_MIDDLE && video_ori[i][161] > IMAGE_MIDDLE)
{
ing_crossroad_pd++;
}
}
for (i = 5; i < 50; i++)//判断上面拐点类型
{
if (g_RightEdge[i].y - g_RightEdge[i + 1].y < 5 && g_RightEdge[i-1].y - g_RightEdge[i].y > 5 && g_RightEdge[i - 2].y - g_RightEdge[i].y > 10 && g_LeftEdge[i - 10].y < 20)
{
r_up_flag = 1;
g_RightUp_x = i;
g_RightUp_y = g_RightEdge[i].y;
//break;
/*printf("%d\n",2);*/
}
if (g_LeftEdge[i+1].y - g_LeftEdge[i].y < 5 && g_LeftEdge[i].y - g_LeftEdge[i - 1].y > 5 && g_LeftEdge[i].y - g_LeftEdge[i - 2].y > 10 && g_RightEdge[i - 10].y > 140)
{
l_up_flag = 1;
g_LeftUp_x = i;
g_LeftUp_y = g_LeftEdge[i].y;
//break;
/*printf("%d\n",4);*/
}
}
for (i = 7; i < 40; i++)//判断下面拐点类型
{
if (g_RightEdge[i+1].y - g_RightEdge[i].y > 5 && g_RightEdge[i+2].y - g_RightEdge[i].y > 10 && g_RightEdge[i-1].y - g_RightEdge[i].y < 5 && g_RightEdge[i - 4].y - g_RightEdge[i].y >= 0)
{
r_down_flag = 1;
g_RightDown_x = i;
g_RightDown_y = g_RightEdge[i].y;
//break;
/*printf("%d\n",1);*/
}
if (g_LeftEdge[i].y - g_LeftEdge[i + 1].y > 5 && g_LeftEdge[i].y - g_LeftEdge[i + 2].y > 10 && g_LeftEdge[i].y - g_LeftEdge[i - 1].y < 5 && g_LeftEdge[i].y - g_LeftEdge[i - 4].y >= 0)
{
l_down_flag = 1;
g_LeftDown_x = i;
g_LeftDown_y = g_LeftEdge[i].y;
/*if (g_LeftDown_y > 81)
{
l_down_flag = 0;
}*/
}
}
if (r_down_flag == 1 && r_up_flag == 1 && l_down_flag == 0 && l_up_flag == 0)
{
l_xie_crossroad_jin = 1;
}
else if (r_down_flag == 0 && r_up_flag == 0 && l_down_flag == 1 && l_up_flag == 1)
{
r_xie_crossroad_jin = 1;
}
else if (r_down_flag == 1 && r_up_flag == 1 && l_down_flag == 1 && l_up_flag == 1)
{
before_crossroad = 1;
}
else if (r_down_flag == 0 && r_up_flag == 1 && l_down_flag == 0 && l_up_flag == 1 && ing_crossroad_pd > 10)
{
ing_crossroad = 1;
}
else
{
r_down_flag = 0, r_up_flag = 0, l_down_flag = 0, l_up_flag = 0;
}
if (r_down_flag == 0 && r_up_flag == 0 && l_down_flag == 0 && l_up_flag == 0 && l_xie_crossroad_jin == 0 && r_xie_crossroad_jin == 0)//远斜十字拐点判别
{
for (i = 0; i < 55; i++)
{
if (g_LeftEdge[i + 1].y == 0 && g_RightEdge[i - 1].y > g_RightEdge[i + 1].y && g_RightEdge[i + 2].y > g_RightEdge[i + 1].y && g_RightEdge[i + 1].y < 155 && g_RightEdge[i - 1].y < 155 && g_RightEdge[i + 2].y < 155)
{
r_down_flag = 1;
g_RightDown_x = i + 1;
g_RightDown_y = g_RightEdge[i + 1].y;
}
if (g_LeftEdge[i].y == 0 && g_LeftEdge[i + 1].y == 0 && g_LeftEdge[i + 2].y != 0 && g_LeftEdge[i + 3].y != 0 && g_LeftEdge[i + 2].y > 10)
{
r_up_flag = 1;
g_RightUp_x = i + 2;
g_RightUp_y = g_LeftEdge[i + 2].y;
}
if (g_RightEdge[i + 1].y == 161 && g_LeftEdge[i - 1].y < g_LeftEdge[i + 1].y && g_LeftEdge[i + 2].y < g_LeftEdge[i + 1].y && g_LeftEdge[i + 1].y > 5 && g_LeftEdge[i -1].y > 5 && g_LeftEdge[i + 2].y > 5)
{
l_down_flag = 1;
g_LeftDown_x = i + 1;
g_LeftDown_y = g_LeftEdge[i + 1].y;
}
if (g_RightEdge[i].y == 161 && g_RightEdge[i + 1].y == 161 && g_RightEdge[i + 2].y != 161 && g_RightEdge[i + 3].y != 161 && g_RightEdge[i + 2].y < 151)
{
l_up_flag = 1;
g_LeftUp_x = i + 2;
g_LeftUp_y = g_RightEdge[i + 2].y;
}
}
}
int x_d = 0, x_u = 0;
int r_turn_pd = 0;
int l_turn_pd = 0;
int r_near_turn = 0;//右近弯标志
int r_far_turn = 0;//右远弯标志
int l_near_turn = 0;//左近弯标志
int l_far_turn = 0;//左远弯标志
int r_turn_fuzhu = 0;
int l_turn_fuzhu = 0;
for (i = 0; i < 60; i++)
{
if (g_LeftEdge[i].y == 0 && g_RightEdge[i].y < 161 && g_RightEdge[i].y < g_RightEdge[i - 1].y)
{
l_turn_pd++;
}
if (g_RightEdge[i].y == 161 && g_LeftEdge[i].y > 0 && g_LeftEdge[i].y > g_LeftEdge[i - 1].y)
{
r_turn_pd++;
}
if (g_LeftEdge[i].y == 0)
{
l_turn_fuzhu++;
}
if (g_RightEdge[i].y == 161)
{
r_turn_fuzhu++;
}
}
if (l_turn_pd > 30 && video_ori[l_turn_pd][100]< IMAGE_MIDDLE/*&& r_turn_fuzhu < 10*/)
{
l_near_turn = 1;
}
if (l_turn_pd > 10 && l_turn_pd < 30 && l_turn_fuzhu-l_turn_pd<8)
{
l_far_turn = 1;
}
if (r_turn_pd > 30 && video_ori[r_turn_pd][60] < IMAGE_MIDDLE/*&& l_turn_fuzhu < 10*/)
{
r_near_turn = 1;
}
if (r_turn_pd > 10 && r_turn_pd < 30 && r_turn_fuzhu-r_turn_pd<8)
{
r_far_turn = 1;
}
if (l_far_turn == 1 && r_far_turn == 1)
{
l_far_turn = 0;
r_far_turn = 0;
}
if (l_far_turn == 1)
{
for (i = 20; i < 55; i++)
{
if (g_LeftEdge[i].y == 0 && g_LeftEdge[i - 1].y > 0)
{
x_d = i;
}
if (g_LeftEdge[i].y == 0 && g_LeftEdge[i + 1].y > 0)
{
x_u = i;
}
}
}
if (r_far_turn == 1)
{
for (i = 25; i < 55; i++)
{
if (g_RightEdge[i].y == 161 && g_RightEdge[i - 1].y < 161)
{
x_d = i;
}
if (g_RightEdge[i].y == 161 && g_RightEdge[i + 1].y < 161)
{
x_u = i;
}
}
/*for (i = x_d; i < 55; i++)
{
if (g_RightEdge[i].y == 161 && g_RightEdge[i + 1].y < 161)
{
x_u = i;
}
}*/
}
if (x_d == 0 && x_u == 0)
{
l_far_turn = 0;
r_far_turn = 0;
}
if (r_down_flag == 0 && r_up_flag == 0 && l_down_flag == 0 && l_up_flag == 0)
{
straightway = 1;
}
else if (r_down_flag == 1 && r_up_flag == 1 && l_down_flag == 0 && l_up_flag == 0 && l_xie_crossroad_jin == 0)
{
l_xie_crossroad_yuan = 1;
}
else if (r_down_flag == 0 && r_up_flag == 0 && l_down_flag == 1 && l_up_flag == 1 && r_xie_crossroad_jin == 0)
{
r_xie_crossroad_yuan = 1;
}
if (l_near_turn == 1 && l_xie_crossroad_jin == 1)
{
l_xie_crossroad_jin = 0;
}
if (r_near_turn == 1 && r_xie_crossroad_jin == 1)
{
r_xie_crossroad_jin = 0;
}
int l_ku = 0;
int r_ku = 0;
int l_ku_qian = 0;
int l_ku_zhong = 0;
int l_ku_hou = 0;
int r_ku_qian = 0;
int r_ku_zhong = 0;
int r_ku_hou = 0;
if (banma == 1)
{
l_down_flag = 0;
l_up_flag = 0;
r_down_flag = 0;
r_up_flag = 0;
int r_ku_pd = 0;
int l_ku_pd = 0;
for (i = 0; i < 60; i++)
{
if (g_LeftEdge[i].y == 0)
{
l_ku_pd++;
}
if (g_RightEdge[i].y == 161)
{
r_ku_pd++;
}
}
if (l_ku_pd > r_ku_pd)
{
l_ku = 1;
}
else
{
r_ku = 1;
}
if (l_ku == 1)
{
for (i = 0; i < 30; i++)
{
if (g_LeftEdge[i - 1].y < g_LeftEdge[i + 1].y && g_LeftEdge[i + 2].y < g_LeftEdge[i + 1].y)
{
l_down_flag = 1;
g_LeftDown_x = i + 1;
g_LeftDown_y = g_LeftEdge[i + 1].y;
}
}
for (i = 55; i > 35; i--)
{
if (g_LeftEdge[i + 1].y - g_LeftEdge[i].y < 5 && g_LeftEdge[i].y - g_LeftEdge[i - 1].y > 5)
{
l_up_flag = 1;
g_LeftUp_x = i;
g_LeftUp_y = g_LeftEdge[i].y;
}
}
if (l_down_flag == 1 && l_up_flag == 1&&g_LeftDown_y<g_LeftUp_y)
{
l_ku_qian = 1;
}
if (l_ku_qian == 0 && l_up_flag == 1)
{
l_ku_zhong = 1;
}
}
else if (r_ku == 1)
{
for (i = 0; i < 30; i++)
{
if (g_RightEdge[i - 1].y > g_RightEdge[i + 1].y && g_RightEdge[i + 2].y > g_RightEdge[i + 1].y)
{
r_down_flag = 1;
g_RightDown_x = i + 1;
g_RightDown_y = g_RightEdge[i + 1].y;
}
}
for (i = 55; i > 38; i--)
{
if (g_RightEdge[i].y - g_RightEdge[i+1].y < 3 && g_RightEdge[i-1].y - g_RightEdge[i].y > 3)
{
r_up_flag = 1;
g_RightUp_x = i;
g_RightUp_y = g_RightEdge[i].y;
}
}
if (r_down_flag == 1 && r_up_flag == 1&&g_RightUp_y<g_RightDown_y)
{
r_ku_qian = 1;
}
if (r_ku_qian == 0 && r_up_flag == 1)
{
r_ku_zhong = 1;
}
}
r_near_turn = 0;
l_near_turn = 0;
r_far_turn = 0;
l_far_turn = 0;
r_xie_crossroad_yuan = 0;
l_xie_crossroad_yuan = 0;
}
float b_r, k_r, b_l, k_l;//补线斜率和截距
if (banma == 1)
{
g_CenterNum = g_RightEdgeNum;
DEBUG_VAR(g_CenterNum, d)
for (i = 0; i < g_RightEdgeNum; i++)
{
g_CenterPosition[i].x = g_RightEdge[i].x;
g_CenterPosition[i].y = 81;
}
}
else if (before_crossroad == 1)//正十字前中心求取
{
k_r = (g_RightUp_y - g_RightDown_y) / (g_RightUp_x - g_RightDown_x);
b_r = g_RightDown_y - k_r * g_RightDown_x;
for (i = g_RightDown_x; i < g_RightUp_x + 1; i++)
{
g_RightEdge[i].y = k_r * g_RightEdge[i].x + b_r;
}
k_l = (g_LeftUp_y - g_LeftDown_y) / (g_LeftUp_x - g_LeftDown_x);
b_l = g_LeftDown_y - k_l * g_LeftDown_x;
for (i = g_LeftDown_x; i < g_LeftUp_x + 1; i++)
{
g_LeftEdge[i].y = k_l * g_LeftEdge[i].x + b_l;
}
g_CenterNum = g_RightEdgeNum;
DEBUG_VAR(g_CenterNum, d)
for (i = 0; i < g_RightEdgeNum; i++)
{
g_CenterPosition[i].x = g_RightEdge[i].x;
g_CenterPosition[i].y = (g_RightEdge[i].y + g_LeftEdge[i].y) / 2;
}
}
else if (ing_crossroad == 1)//正十字中中心求取
{
k_r = (g_RightUp_y - 161) / g_RightUp_x;
b_r = 161;
for (i = 0; i < g_RightUp_x + 1; i++)
{
g_RightEdge[i].y = k_r * g_RightEdge[i].x +b_r;
}
k_l = g_LeftUp_y / g_LeftUp_x ;
b_l = 0;
for (i = 0; i < g_LeftUp_x + 1; i++)
{
g_LeftEdge[i].y = k_l * g_LeftEdge[i].x;
}
g_CenterNum = g_RightEdgeNum;
DEBUG_VAR(g_CenterNum, d)
for (i = 0; i < g_RightEdgeNum; i++)
{
g_CenterPosition[i].x = g_RightEdge[i].x;
g_CenterPosition[i].y = (g_RightEdge[i].y + g_LeftEdge[i].y) / 2;
}
}
else if (l_xie_crossroad_jin == 1)//近左斜十字中心求取
{
k_r = (g_RightUp_y - g_RightDown_y) / (g_RightUp_x - g_RightDown_x);
b_r = g_RightDown_y - k_r * g_RightDown_x;
for (i = g_RightDown_x; i < g_RightUp_x + 1; i++)
{
g_RightEdge[i].y = k_r * g_RightEdge[i].x + b_r;
}
int left_create = g_RightUp_x;
k_l = -k_r;
b_l = g_LeftEdge[left_create].y - k_l * g_RightUp_x;
for (i = left_create; i >= 0; i--)
{
g_LeftEdge[i].y = k_l * g_LeftEdge[i].x + b_l;
}
g_CenterNum = g_RightEdgeNum;
DEBUG_VAR(g_CenterNum, d)
for (i = 0; i < g_RightEdgeNum; i++)
{
g_CenterPosition[i].x = g_RightEdge[i].x;
g_CenterPosition[i].y = (g_RightEdge[i].y + g_LeftEdge[i].y) / 2;
}
}
else if (r_xie_crossroad_jin == 1)//近右斜十字中心求取
{
k_l = (g_LeftUp_y - g_LeftDown_y) / (g_LeftUp_x - g_LeftDown_x);
b_l = g_LeftDown_y - k_l * g_LeftDown_x;
for (i = g_LeftDown_x; i < g_LeftUp_x + 1; i++)
{
g_LeftEdge[i].y = k_l * g_LeftEdge[i].x + b_l;
}
int right_create = g_LeftUp_x;
k_r = -k_l;
b_r = g_RightEdge[right_create].y - k_r * g_LeftUp_x;
for (i = right_create; i >= 0; i--)
{
g_RightEdge[i].y = k_r * g_RightEdge[i].x + b_r;
}
g_CenterNum = g_RightEdgeNum;
DEBUG_VAR(g_CenterNum, d)
for (i = 0; i < g_RightEdgeNum; i++)
{
g_CenterPosition[i].x = g_RightEdge[i].x;
g_CenterPosition[i].y = (g_RightEdge[i].y + g_LeftEdge[i].y) / 2;
}
}
else if (l_xie_crossroad_yuan == 1)//远左斜十字中心求取
{
k_r = (g_RightUp_y - g_RightDown_y) / (g_RightUp_x - g_RightDown_x);
b_r = g_RightDown_y - k_r * g_RightDown_x;
for (i = g_RightDown_x; i < g_RightUp_x + 1; i++)
{
g_RightEdge[i].y = k_r * g_RightEdge[i].x + b_r;
}
g_RightEdgeNum = g_RightUp_x;
g_LeftEdgeNum = g_RightUp_x;
g_CenterNum = g_RightEdgeNum;
DEBUG_VAR(g_CenterNum, d)
for (i = 0; i < g_RightEdgeNum; i++)
{
g_CenterPosition[i].x = g_RightEdge[i].x;
g_CenterPosition[i].y = k_r * g_RightEdge[i].x + b_r / 2;
}
}
else if (r_xie_crossroad_yuan == 1)//远右斜十字中心求取
{
k_l = (g_LeftUp_y - g_LeftDown_y) / (g_LeftUp_x - g_LeftDown_x);
b_l = g_LeftDown_y - k_l * g_LeftDown_x;
for (i = g_LeftDown_x; i < g_LeftUp_x + 1; i++)
{
g_LeftEdge[i].y = k_l * g_LeftEdge[i].x + b_l;
}
g_RightEdgeNum = g_LeftUp_x;
g_LeftEdgeNum = g_LeftUp_x;
g_CenterNum = g_RightEdgeNum;
DEBUG_VAR(g_CenterNum, d)
for (i = 0; i < g_RightEdgeNum; i++)
{
g_CenterPosition[i].x = g_LeftEdge[i].x;
g_CenterPosition[i].y = k_l * g_LeftEdge[i].x + (161 - b_l) / 2;
}
}
else if (l_near_turn == 1)//左近弯中心求取
{
int left_pinyi = g_RightEdge[0].y;
for (i = 0; i <= l_turn_pd; i++)
{
g_LeftEdge[i].y = g_RightEdge[i].y - left_pinyi - 2 * i;
}
g_CenterNum = g_RightEdgeNum;
DEBUG_VAR(g_CenterNum, d)
for (i = 0; i < g_RightEdgeNum; i++)
{
g_CenterPosition[i].x = g_RightEdge[i].x;
g_CenterPosition[i].y = (g_RightEdge[i].y + g_LeftEdge[i].y) / 2;
}
}
else if (r_near_turn == 1)//右近弯中心求取
{
int right_pinyi = 161 - g_LeftEdge[0].y;
for (i = 0; i <= r_turn_pd; i++)
{
g_RightEdge[i].y = g_LeftEdge[i].y + right_pinyi + 2 * i;
}
g_CenterNum = g_RightEdgeNum;
DEBUG_VAR(g_CenterNum, d)
for (i = 0; i < g_RightEdgeNum; i++)
{
g_CenterPosition[i].x = g_RightEdge[i].x;
g_CenterPosition[i].y = (g_RightEdge[i].y + g_LeftEdge[i].y) / 2;
}
}
else if (l_far_turn == 1)
{
g_CenterNum = g_RightEdgeNum;
g_LeftEdgeNum = x_d;
DEBUG_VAR(g_CenterNum, d)
for (i = 0; i <= x_d; i++)
{
g_CenterPosition[i].x = g_RightEdge[i].x;
g_CenterPosition[i].y = (g_RightEdge[i].y + g_LeftEdge[i].y) / 2;
}
k_l = -2 * g_CenterPosition[x_d].y / (x_u - x_d);
b_l = -k_l * (x_d + x_u) / 2;
for (i = x_d; i <= g_RightEdgeNum/*(x_d + x_u) / 2*/; i++)
{
g_CenterPosition[i].x = i;
g_CenterPosition[i].y = k_l * i + b_l;
}
}
else if (r_far_turn == 1)
{
g_CenterNum = g_LeftEdgeNum;
g_RightEdgeNum = x_d;
DEBUG_VAR(g_CenterNum, d)
for (i = 0; i <= x_d; i++)
{
g_CenterPosition[i].x = g_RightEdge[i].x;
g_CenterPosition[i].y = (g_RightEdge[i].y + g_LeftEdge[i].y) / 2;
}
k_r = 2 * (161 - g_CenterPosition[x_d].y) / (x_u - x_d);
b_r = 161 - k_r * (x_d + x_u) / 2;
for (i = x_d; i <= g_RightEdgeNum/*(x_d + x_u) / 2*/; i++)
{
g_CenterPosition[i].x = i;
g_CenterPosition[i].y = k_r * i + b_r;
}
}
//else if (l_ku_qian == 1)
//{
// g_CenterNum = g_LeftUp_x;
// g_RightEdgeNum = g_LeftUp_x;
// g_LeftEdgeNum = g_LeftDown_x;
// DEBUG_VAR(g_CenterNum, d)
// int start = g_LeftDown_x;
// int end_x = (g_LeftDown_x + g_LeftUp_x) / 2;
// int end_y = (g_LeftDown_y + g_LeftUp_y) / 2;
// k_l = (g_RightEdge[start].y - g_LeftUp_y) / (start - g_LeftUp_x);
// b_l = g_LeftUp_y - k_l * g_LeftUp_x;
// for (i = start; i < g_LeftUp_x+1; i++)
// {
// g_RightEdge[i].y = k_l * i + b_l;
// }
// for (i = 0; i < start; i++)
// {
// g_CenterPosition[i].x = i;
// g_CenterPosition[i].y = (g_RightEdge[i].y + g_LeftEdge[i].y) / 2;
// }
// for (i = start; i < g_LeftUp_x; i++)
// {
// g_CenterPosition[i].x = i;
// g_CenterPosition[i].y = (k_l-1) * i + b_l + 81 - g_RightEdge[start].y;
// }
// /*for (i = end_x; i < g_LeftUp_x; i++)
// {
// g_CenterPosition[i].x = i;
// g_CenterPosition[i].y = -i + b_l + 81 - g_RightEdge[start].y;
// }*/
// }
//else if (r_ku_qian == 1)
//{
// g_CenterNum = g_RightUp_x;
// g_RightEdgeNum = g_RightDown_x;
// g_LeftEdgeNum = g_RightUp_x;
// DEBUG_VAR(g_CenterNum, d)
// int start = g_RightDown_x;
// //int end_x = (g_LeftDown_x + g_LeftUp_x) / 2;
// //int end_y = (g_LeftDown_y + g_LeftUp_y) / 2;
// k_r = (g_LeftEdge[start].y - g_RightUp_y) / (start - g_RightUp_x);
// b_r = g_RightUp_y - k_r * g_RightUp_x;
// for (i = start; i < g_RightUp_x + 1; i++)
// {
// g_LeftEdge[i].y = k_r * i + b_r;
// }
// for (i = 0; i < start; i++)
// {
// g_CenterPosition[i].x = i;
// g_CenterPosition[i].y = (g_RightEdge[i].y + g_LeftEdge[i].y) / 2;
// }
// for (i = start; i < g_RightUp_x; i++)
// {
// g_CenterPosition[i].x = i;
// g_CenterPosition[i].y = (k_r + 1) * i + b_r + 81 - g_LeftEdge[start].y;
// }
//}
//else if (l_ku_zhong == 1)
//{
// g_CenterNum = g_LeftUp_x;
// g_RightEdgeNum = g_LeftUp_x;
// g_LeftEdgeNum = g_LeftUp_x;
// DEBUG_VAR(g_CenterNum, d)
// k_l = (161 - g_LeftUp_y) / (-g_LeftUp_x);
// b_l = 161;
// for (i = 0; i < g_LeftUp_x; i++)
// {
// g_RightEdge[i].y = k_l * i + b_l;
// g_LeftEdge[i].y = k_l * i;
// }
// for (i = 0; i < g_LeftUp_x; i++)
// {
// g_CenterPosition[i].x = g_RightEdge[i].x;
// g_CenterPosition[i].y = (g_RightEdge[i].y + g_LeftEdge[i].y) / 2;
// }
//}
//else if (r_ku_zhong == 1)
//{
// g_CenterNum = g_RightUp_x;
// g_RightEdgeNum = g_RightUp_x;
// g_LeftEdgeNum = g_RightUp_x;
// DEBUG_VAR(g_CenterNum, d)
// k_r = g_RightUp_y / g_RightUp_x;
// for (i = 0; i < g_RightUp_x; i++)
// {
// g_LeftEdge[i].y = k_r * i;
// g_RightEdge[i].y = k_r * i + 161;
// }
// for (i = 0; i < g_RightUp_x; i++)
// {
// g_CenterPosition[i].x = g_RightEdge[i].x;
// g_CenterPosition[i].y = (g_RightEdge[i].y + g_LeftEdge[i].y) / 2;
// }
//}
else
{
g_CenterNum = g_RightEdgeNum;
DEBUG_VAR(g_CenterNum, d)
for (i = 0; i < g_RightEdgeNum; i++)
{
g_CenterPosition[i].x = g_RightEdge[i].x;
g_CenterPosition[i].y = (g_RightEdge[i].y + g_LeftEdge[i].y) / 2;
}
}
/*g_CenterNum = g_RightEdgeNum;
DEBUG_VAR(g_CenterNum, d)
for (i = 0; i < g_RightEdgeNum; i ++)
{
g_CenterPosition[i].x = g_RightEdge[i].x;
g_CenterPosition[i].y = (g_RightEdge[i].y + g_LeftEdge[i].y) / 2;
}*/
}
代码较长,而且图像处理是一个工程文件,这里给出的是search.c文件中内容,即主要的图像处理文件。通过以上代码可以较好地处理包括正十字、斜十字、左右弯道,可以勉强处理车库问题,但由于难以稳定,在上文给出的代码中就被我注释掉了。下面给出处理效果图:
处理思路:
1、正十字:不论是十字前还是十字中,都需要寻找拐点。
(1)找到四个拐点则为正十字中,左右两边分别用上下拐点拟合直线来补出缺线;
(2)找到上面两个拐点则为正十字中,左右分别用上拐点与(0,0)、(0,161)拟合直线来补出缺线。
2、斜十字:
(1)若只找到右边两个拐点,则为左斜十字中(两拐点离车近)。
(2)而左斜十字前,即两“拐点”离车远的情况则不同。在四个拐点都没找到且不为左右斜十字中时,重新扫线二次找拐点(换了要求)。找到右边两个拐点先补出直线,方法与上面类似。再为左边拟合一个镜像的直线,最后再求取中线得出。
(3)右斜十字的方法同上。
3、弯道:
(1)近弯:若判断为左近弯,那么右边边界不变,通过右边界平移出一个y值为负的左边界,之后两者求中值即可。右近弯方法同上。
(2)远弯:判断为左远弯后,扫线找出一个x_d值,在此之下依旧相加除以二,在此之上的中心线拟合为直线。
4、入库
通过找寻斑马线,找到斑马线后找拐点来补线。建议通过控制开环入库,简单好用。
更优处理
自己的思路是无论直道、弯道、还是正、斜十字和车库,都是识别出道路类型后,最后进行处理。但这样多重的识别势必需要不同的辨识点来分辨,最常用的就是拐点。道路类型一多,很容易造成“串道”,比如十字成了弯道、车库成了弯道等等。
为什么会这样呢?是因为采用的中心求取思路非常简单粗糙,因为之前在边沿搜索的时候并没有区分两边,而是直接把一个白块的start认为是左边,end认为是右边 故中心数将与左右边的数相等,而中心位置直接由左右边相加除2所得。
另一种思路,在小车处于直道正中央时,处理这时的图像,此时左右边界线与理想中心线距离时相等的,记录每一行这种边界线与理想中心线之间的距离组成一个数组,姑且称这些距离为视距。这样在处理直道和弯道时可以不用辨识,使用同一种处理方法。直道不必多说,找每一行距离左边界线或者右边界线视距的点,即为中心点;弯道也是类似,但我自己也不清楚了。给出下图,看看有没有天才自己悟出来,哈哈哈哈