飞思卡尔杯全国大学生智能车大赛摄像头组图像处理程序
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
#include "Includes.h"
#define LINEWITH 8 //摄像头垂直照射黑线时,和线宽度,用于判断是交叉线还是终点线
#define MINLINEWITH 4 //处理摄像头的黑线的最小线宽,如果线宽小于这个最小值的话,认为看不见了
#define ALLWHITE 200 //本条线上全白时赋值
#define NOISE 1 //噪点系数,某一个点旁NOISE个点不全与这个点值相同,则认为这个点为噪点
#define BODER 100 //边界,采用两点预判使得边界百分比,如果超过的话按平均值判断
#define UN 24 //判别线宽异常的系数,在判断图片性质使用到,黑点占三倍线宽的百分比
#define FINWITH 9 //终点线白线宽度
#define MINWITH 5 //终点线白线最小宽度
#define SENSE 6 //脚下可判别图片性质区域占整幅图行数的十分之几
#define PREVIEW 15 //以前一帧脚下线做预判时,向左和向右搜索的范围,用来防止丢线
/************************************************************************/
/***********************裁代码时的宏定义*********************************/
/************************************************************************/
#define SNS_R 30 //敏感行计数,代替原来的 ROW_VALUE * SENSE / 10
#define BDR_V 80 //边界值,代替COLUMN_VALUE * BODER / 100
#define UN_V 8 //非正常界限,代替UN * LINEWITH * 4 / 100
#define JLW_V 16 //在判别终点线时线宽值,代替LINEWITH * 4 / 2
#define THRESHOLD 45
#define BLACK 0
#define WHITE 1
unsigned int Line_Center[ROW_VALUE];
unsigned char FinishLine = 0;
unsigned char LastPoint;
unsigned char LossLine = 1;
//------------------------------//
//----------二值化程序----------//
//------------------------------//
void Image_binaryzation(void)
{
unsigned char *p_Image;
unsigned char *q_Image;
q_Image=&uca_Buffer1[0][0];
for(p_Image=&uca_Buffer[0][0];p_Image<=&uca_Buffer[ROW_VALUE-1][COLUMN_VALUE-1];p_Image++)
{if(*p_Image<THRESHOLD) *(q_Image++)=BLACK;
else
*(q_Image++)=WHITE;
}
}
//------------------------------//
//----------黑线的提取----------//
//------------------------------//
void black_extract() //黑线提取程序
{
/*********************************************************************************************************************/
//一、变量声明
uchar i = 0; //标记相应处理行,与ROW_VALUE配合使用
uchar j = 0; //标记当前处理的行的相应点,与COLUMN_VALUE配合使用
uchar k = 0;
char xx = 0; //标记j的起始值
char yy = 0; //标记j的结束值
uchar same = 0; //噪声判断的标志,通过&&或者||来确定其值
uint l = 0; //找到黑线的标志位
uchar n1 = 0; //辅助计数
uint Sum = 0; //个黑点下脚标的累加和
uint Sum1 = 0; //辅助求和
uint Sum2 = 0; //
uint
Sum3 = 0; //
uchar flag = 0; //重叠标志位
uchar IsFin = 0; //本条线终点线标志位
uchar u =0; //辅助判别图片性质,计数边界
uchar discover = 0; //发现白点标志,在判断终点线时用到
unsigned int temp = 0; //备用,临时存储空间
int temp1 = 0; //备用,临时存储空间
int temp2 = 0;
uint Aver = ALLWHITE; //初始化时,没有对任何信息做计算,认为什么黑色点都没看见
uchar AllwhiteCounter = 0;
FinishLine = 0;
LastPoint = 0; //路的尽头默认为最远处
/********************************************************************************************************************/
//二、处理部分
//先处理从底下数的第一行信息和第二行信息
//这两行的处理至关重要,是剩余行处理的基础
//如果这两行处理不好,其余行的处理计算里那个就会增大,
//而其如果影响了图片最下几行的制的正确性的话,可能会有难以控制的结果
/***************************************************************************************************************/
//二、1.1 第一行处理部分
//在第一行上从左向右判断,找到黑点,第一行不判断图片性质,只判断脚下点位置,其余行作参考建议,如果出错,设计思想中
//会增加其余行计算量,因该不会导致小车转向失灵 ( 待议!!!!!)
/////////////////////////////////////////////////////////////////////////
xx = (int) Line_Center[ROW_VALUE - 1] - PREVIEW ; //设定第一行的搜索范围
if (xx < 0) //在前一帧的第一行的左右PREVIEW
xx = 0; //范围搜索
yy = Line_Center[ROW_VALUE - 1] + PREVIEW; //但不能超过数组的边界
if (yy > COLUMN_VALUE) //
yy = COLUMN_VALUE; //
//////////////////////////////////////////////////////////////////////////
for (j = xx; j < yy; j++)
{
if ((l != 0)&&(uca_Buffer1[ROW_VALUE - 1][j] == 1)) //在黑点区域如果出现白点,判断是否到了边缘
{ //或者这个白点仅仅是个噪声而已,判断其右的点来确定
same = 1; //
same = same && uca_Buffer1[ROW_VALUE - 1][j + 1]; //削减代码后的降噪1处
if (same == 1) //
{ //如果的确到了黑线的边缘,即白线上
Sum = Sum + j - 1; //把上一个不是白点的下脚标加在Sum
break; //上,之后跳出循环,节约资源,也防止
} //将来会误判
}
//
/****************************************
*************************/
if ((l != 0)&&(j == (yy - 1))) //这里很关键
Sum = Sum + j; //如果循环检测即将结束还没找到结束点,即将检测的最后一点为结束点
/*****************************************************************/
if ((l == 0)&&(uca_Buffer1[ROW_VALUE - 1][j] == 0)) //
{ //这一块是判断黑点的起始位置的
same = 0; //寻找值为1的点
same = same || uca_Buffer1[ROW_VALUE - 1][j + 1]; //削减代码后的降噪2处
if (same == 0) //
{ //如果是黑线起点
Sum = j; //记下起始位置
l = 1; //L为找到黑线的标志位
} //
}
}
if (l != 0)
Aver = Sum >> 1;
else
{
Aver = ALLWHITE; //补丁,如果全白给Aver赋全白
//如果第一行的值为全白,则不进行Line_Center存储,
LossLine = 1; //将丢线标志位置一,提示控制程序按上一次不丢线
return; //的情况转弯
//直接返回,函数不修改路线值
}
//累加和与计数都清零
Sum = 0; //
l = 0; //
Line_Center[ROW_VALUE - 1] = Aver; //
Aver = ALLWHITE;
//二、1.2 第二行处理部分
//在第二行上从右向左判断,找到黑点,第二行不判断图片性质,只判断脚下点位置,其余行作参考建议,如果出错,设计思想中
//会增加其余行计算量,因该不会导致小车转向失灵 ( 待议!!!!!)
//////////////////////////////////////////////////////////////////////////////////////////////
if (Line_Center[ROW_VALUE - 2] != ALLWHITE) //如果上次倒数第二行不是白的
{ //就按上一帧的倒数第二行判断
xx = COLUMN_VALUE - (int)Line_Center[ROW_VALUE - 2] - PREVIEW;
if (xx < 1)
xx =1;
yy = COLUMN_VALUE - Line_Center[ROW_VALUE - 2] + PREVIEW - 1;
if (yy > COLUMN_VALUE)
yy = COLUMN_VALUE;
}
else //否则按上一帧的最后一行判断
{
xx = COLUMN_VALUE - (int)Line_Center[ROW_VALUE - 1] - PREVIEW;
if (xx < 1)
xx =1;
yy = COLUMN_VALUE - Line_Center[ROW_VALUE - 1] + PREVIEW - 1;
if (yy > COLUMN_VALUE)
yy = COLUMN_VALUE;
}
////////////////////////////////////////////////////////////////////////////////////////////////
for (j = xx; j <= yy; j++)
{
if ((l != 0)&&(uca_Buffer1[ROW_VALUE
- 2][COLUMN_VALUE - j] == 1))
//在黑点区域如果出现白点,判断是否到了边缘
{ //或者这个白点仅仅是个噪声而已,判断其右的点来确定
same = 1; //
same = same && uca_Buffer1[ROW_VALUE - 2][COLUMN_VALUE - j - 1]; //削减代码后的降噪3处
if (same == 1)
{
Sum = Sum + COLUMN_VALUE - j;
break;
}
}
/*************************************************************************/
if((l != 0)&&(j == (yy - 1)))
Sum = Sum + COLUMN_VALUE - j;
/*************************************************************************/
//判断起始点
/***********************************************************************************************************/
if ((l == 0)&&(uca_Buffer1[ROW_VALUE - 2][COLUMN_VALUE - j] == 0)) //j为零时相当于判断了四个点,其他的是判断了三个点
{ //这一块是判断黑点的起始位置的
same = 0; //寻找值为1的点 //
same = same || uca_Buffer1[ROW_VALUE - 2][COLUMN_VALUE - j - 1]; //削减代码后的降噪4
if (same == 0) //
{ //
Sum = COLUMN_VALUE - j; //
l = 1; //
} //
} // //
/*************************************************************************************************************/
}
if(l != 0)
Aver = Sum >> 1;
else Aver = ALLWHITE; //补丁,如果全白给Aver赋全白
//累加和与计数都清零
Sum = 0; //
l = 0; //
Line_Center[ROW_VALUE - 2] = Aver; //
Aver = ALLWHITE; //
/*****************************************************************************************************************/
//二、2 其他行处理部分
//包括预判断,行处理,推按性质处理
for (i = 2; i < ROW_VALUE; i++)
{
/*************************************************************************************************************/
//二、2.1 预判断
if ((Line_Center[ROW_VALUE - i] == ALLWHITE) || (Line_Center[ROW_VALUE - i + 1] == ALLWHITE)) //以前的两行中有全白的
temp = ((Line_Center[ROW_VALUE - i] == ALLWHITE) ? Line_Center[ROW_VALUE - i + 1] : Line_Center[ROW_VALUE - i]);
//区行中不为全白的行最为预判
//这两行不可能同时为全白,否则就
//被视为路的尽头而结束程序,或认为丢线
else
{
temp2 = (int) Line_Center[ROW_VALUE - i] + (int) Line_Center[ROW_VALUE - i] - (int) Line_Cent
er[ROW_VALUE - i + 1];
if ((temp2 >= BDR_V) || (temp2 < (COLUMN_VALUE - BDR_V))) //原值为(COLUMN_VALUE * BODER / 100)
temp = (Line_Center[ROW_VALUE - i] + Line_Center[ROW_VALUE - i + 1]) >> 1; //
else temp = temp2;
}
/**************************************************************************************************************/
//二、2.2.1
//向左寻找
Sum2 = 0;
for (j = 0; j < LINEWITH; j++)
{ //
if ((n1 != 0)&&(uca_Buffer1[ROW_VALUE - i -1][temp - j] == 1)) //
{ //
same = 1;
if ((temp - j - 1) >= 0)
same = same && uca_Buffer1[ROW_VALUE - i -1][temp - j - 1]; //削减代码后的降噪5处
if (same == 1)
{
Sum1 = Sum1 + temp - j + 1;
break;
}
}
/*********************************************************/
if ((n1 != 0)&&(j == (LINEWITH - 1)))
Sum1 = Sum1 + temp - j;
/*********************************************************/
if ((n1 == 0)&&(uca_Buffer1[ROW_VALUE - i -1][temp - j] == 0))
{
same = 0;
same = same || uca_Buffer1[ROW_VALUE - i -1][temp - j - 1];//削减代码后的降噪6处
if (same == 0) //
{ //
Sum1 = temp - j;
Sum2 = Sum1;
if (j == 0)
flag = 1;
n1 = 1;
j = 0; // 如果在左侧找到黑点,就从此向左标定线宽
} //
} //
} //
Sum = Sum1; //
l = n1; //
Sum1 = 0; //
n1 = 0; //
/**************************************************************************************************************/
//二、2.2.2
//向右寻找
Sum3 = 0;
for (j = 0; j < LINEWITH; j++) //
{
if ((n1 != 0)&&(uca_Buffer1[ROW_VALUE - i -1][temp + j] == 1)) //
{ //
same = 1;
if ((temp + j + 1) <COLUMN_VALUE)
same = same && uca_Buffer1[ROW_VALUE - i -1][temp + j + 1]; //削减代码后的降噪7处
if (same == 1)
{
Sum1 = Sum1 + temp + j - 1;
break;
}
}
/*********************************************************/
if ((n1 != 0)&
&(j == (LINEWITH - 1)))
Sum1 = Sum1 + temp + j;
/*********************************************************/ //
if ((n1 == 0)&&(uca_Buffer1[ROW_VALUE - i -1][temp + j] == 0)) //
{ //
same = 0; //
same = same || uca_Buffer1[ROW_VALUE - i -1][temp + j + 1];//削减代码后的降噪8处
if (same == 0) //
{
//
Sum1 = temp + j;
Sum3 = Sum1;
n1 = 1;
if (j != 0) //判断重叠
flag = 0; //
j = 0; // 如果在右侧找到黑点,就从此向右标定线宽
} //
} //
} //
if ((l && n1) == 1)
Sum = Sum + Sum1 - Sum2 - Sum3;
else
Sum = Sum + Sum1;
l = l || n1;
if (l != 0) //
Aver = Sum >> 1;
else
{
Aver = ALLWHITE; //补丁,如果全白给Aver赋全白
AllwhiteCounter++; // 如果出现全白,全白计数相加
if (AllwhiteCounter == 2) //如果出现两行全白则进一步判断
{ // 如果两行全白连续,
if ((Line_Center[ROW_VALUE - i] == ALLWHITE)&&(Line_Center[ROW_VALUE - i + 1] != ALLWHITE))
{ //且这两行的前一行不为白,则认为
LastPoint = ROW_VALUE - i + 1; //路的尽头是但前行的前两行
for ( ; i < ROW_VALUE - 1; i++) //给剩余行赋全白,留下最后一行
{
Line_Center[ROW_VALUE - i - 1] = ALLWHITE;
} //退出for循环时,i为 ROW_VALUE - 1
}
else //如果不满足要求,计数回一个值
AllwhiteCounter = 1;
}
}
Line_Center[ROW_VALUE - i - 1] = Aver;
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
if (i == (ROW_VALUE - 1)) //LastPoint强化程序,防止最后一行白而前一行黑
{ //
if ((LastPoint == 0)&&(Line_Center[0] == ALLWHITE)) //如果所有行的位置都判定完后
for (k = 1; k < ROW_VALUE; k++) //发现Lastpoint仍为零
,检测从上
{ //往下数部位全白的行,把那一行返给LastPoint
if (Line_Center[k] != ALLWHITE) //
LastPoint = k; //
} //
} //
/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
Sum = 0;
l = 0;
Sum1 = 0;
n1 = 0;
flag = 0;
/*********
*************************************************************************************************/
//
//二、3 判断图片性质
if (i < SNS_R) //原来值为(ROW_VALUE * SENSE / 10)
{
temp = Line_Center[ROW_VALUE - i - 1];
u = JLW_V;
for (j = 0; j < u; j++) //向右
{
if (uca_Buffer1[ROW_VALUE - i -1][temp + j] == 0)
n1++;
}
for (j = 1; j < u; j++) //向左
{
if (uca_Buffer1[ROW_VALUE - i -1][temp - j] == 0)
n1++;
}
if (n1 >= UN_V) //如果有异常情况 // 原值为UN * LINEWITH * 4 / 100
{
/*********************************************************************************************************/
//向右找白色间隔,并判断间隔是否合格
n1 = 0;
discover = 0;
for (j = 0; j < FINWITH + 5; j++)
{
if ((discover == 1)&&(uca_Buffer1[ROW_VALUE - i -1][temp1 + j] == 0))
{
same = 0; //
same = same || uca_Buffer1[ROW_VALUE - i -1][temp1 + j + 1];//削减代码后的降噪9处
if (same == 0)
{
n1 = j;
break;
}
}
if ((discover == 1)&&(j == (FINWITH + 4)))
n1 = FINWITH + 5;
if ((discover == 0)&&(uca_Buffer1[ROW_VALUE - i -1][temp + j] == 1))
{
same = 1; //
same = same && uca_Buffer1[ROW_VALUE - i -1][temp + j + 1]; //削减代码后的降噪10处
if (same == 1) //!!!关键!!!
{ //
discover = 1; //
temp1 = temp + j; //
j = 0; //
}
}
}
if ((n1 >= MINWITH)&&(n1 <= FINWITH))
{
k = temp1 + n1 / 2;
if ((uca_Buffer1[ROW_VALUE - i][k] == 1)&&(uca_Buffer1[ROW_VALUE - i - 2][k] == 1))
IsFin = 1; //初步判断是终点线
else
IsFin = 0;
}
k = 0;
/*******************************************************************************************************/
//向左找白色间
隔,并判断间隔是否合格
n1 = 0;
discover = 0;
for (j = 0; j < FINWITH + 5; j++)
{
if ((discover == 1)&&(uca_Buffer1[ROW_VALUE - i -1][temp1 - j] == 0))
{
same = 0; //
same = same || uca_Buffer1[ROW_VALUE- i -1][temp1 - j - 1];//削减代码后的降噪11处
if (same == 0)
{
n1 = j;
break;
}
}
if ((discover == 1)&&(j == (FINWITH + 5)))
n1 = FINWITH + 5;
if ((discover == 0)&&(uca_Buffer1[ROW_VALUE - i -1][temp - j] == 1))
{
same = 1; //
same = same && uca_Buffer1[ROW_VALUE - i -1][temp - j - 1]; //削减代码前的降噪12处
if (same == 1) //
{ //
n1 = temp - j; //
discover = 1; //
temp1
= temp - j; //
j = 0; //
}
}
}
if ((n1 >= MINWITH)&&(n1 <= FINWITH))
{
k = temp1 - n1 / 2;
if ((uca_Buffer1[ROW_VALUE - i][k] == 1)&&(uca_Buffer1[ROW_VALUE - i - 2][k] == 1))
IsFin = IsFin && 1; // 最终判断是否为终点线
else
IsFin = 0;
}
else IsFin = 0;
/**************************************************************************************************/
//图片性质写入
if (uca_Buffer1[ROW_VALUE - i -1][temp] != 1)
FinishLine = FinishLine || IsFin;
IsFin = 0;
}
}
n1 = 0; //n清零
}
//黑线的中值滤波程序!
// if(PT1AD0_PT1AD00 == 1)
// {
// for(i=1;i<ROW_VALUE-1;i++)
// {
// temp=get_mid(Line_Center[i-1],Line_Center[i],Line_Center[i+1]);
// Line_Center[i]=temp;
// }
// }
}
//-----------------------------------------//
//--------脚下两条线初始化程序-------------//
//-----------------------------------------//
void InitFirLine() //小车启动的时,前两行的初始化,用于第一帧的前两行预判断
{
uchar j = 0; //标记当前处理的行的相应点,与COLUMN_VALUE配合使用
uchar k = 0; //标记当前处理的噪点情况,与NOISE配合使用
uchar same = 0; //噪声判断的标志,通过&&或者||来确定其值
uint l = 0; //计数当前找到了多少个有效的黑点
uchar n1 = 0; //辅助计数
uint Sum = 0; //个黑点下脚标的累加和
uint Aver = ALLWHITE; //初始化时,没有对任何信息做计算,认为什么黑色点都没看见
LossLine = 0; //丢线初始化默认为没丢线
//////////从左到右检测第一行
///////////////
for (j = 0; j < COLUMN_VALUE; j++)
{
/**********************
************************************************************************************/
if ((l != 0)&&(uca_Buffer1[ROW_VALUE - 1][j] == 0)) //找到黑点区域后正常对各点的下脚标进行累加并计数
{ //
Sum = Sum + j; //
l++; //
} //
/**********************************************************************************************************/
if ((l != 0)&&(uca_Buffer1[ROW_VALUE - 1][j] == 1)) //在黑点区域如果出现白点,判断是否到了边缘
{ //或者这个白点仅仅是个噪声而已,判断其右的点来确定
same = 1; //
for(k = 0; k < NOISE; k++) //
{ //
same = same && uca_Buffer1[ROW_VALUE - 1][j + k + 1]; //
} //
if (same == 0) //如果
是噪声,把它按黑点累加并计数
{ //
Sum = Sum + j; //
l++; //
} //
else //如果不是噪声,的确到了边缘
{ //求出平均下脚标,并把下脚标值赋给处理结果
//
break; //跳出FOR循环,节约资源
} //
}
/***********************************************************************************************************/
if ((l == 0)&&(uca_Buffer1[ROW_VALUE - 1][j] == 0)) //
{ //这一块是判断黑点的起始位置的
same = 0; //寻找值为1的点
for (k = 0; k < NOISE; k++) //
{ //
same = same || uca_Buffer1[ROW_VALUE - 1][j + k + 1]; //
} //
if (same == 0) //
{ //
Sum = Sum + j; //
l++; //
} //
} // //
/*************************************************************************************************************/
}
if (l != 0)
Aver = Sum / l;
else Aver = ALLWHITE; //补丁,如果全白给Aver赋全白
//累加和与计数都清零
Sum = 0; //
l = 0; //
Line_Center[ROW_VALUE - 1] = Aver; //
Aver = ALLWHITE;
//////////从右往左检测第二行
///////////////
for (j = 1; j <
= COLUMN_VALUE; j++)
{
/**********************************************************************************************************/
if ((l != 0)&&(uca_Buffer1[ROW_VALUE - 2][COLUMN_VALUE - j] == 0)) //找到黑点区域后正常对各点的下脚标进行累加并计数
{ //
Sum = Sum + COLUMN_VALUE - j; //
l++; //
} //
/**********************************************************************************************************/
if ((l != 0)&&(uca_Buffer1[ROW_VALUE - 2][COLUMN_VALUE - j] == 1)) //在黑点区域如果出现白点,判断是否到了边缘
{ //或者这个白点仅仅是个噪声而已,判断其右的点来确定
same = 1; //
for(k = 0; k < NOISE; k++) //
{ //
same = same && uca_Buffer1[ROW_VALUE - 2][COLUMN_VALUE - j - k - 1]; //
} //
if (same == 0) //
如果是噪声,把它按黑点累加并计数
{ //
Sum = Sum + COLUMN_VALUE - j; //
l++; //
} //
else //如果不是噪声,的确到了边缘
{ //求出平均下脚标,并把下脚标值赋给处理结果
break; //跳出FOR循环,节约资源
} //
}
//
//判断起始点
/***********************************************************************************************************/
if ((l == 0)&&(uca_Buffer1[ROW_VALUE - 2][COLUMN_VALUE - j] == 0)) //j为零时相当于判断了四个点,其他的是判断了三个点
{ //这一块是判断黑点的起始位置的
same = 0; //寻找值为1的点
for (k = 0; k < NOISE; k++) //
{ //
same = same || uca_Buffer1[ROW_VALUE - 2][COLUMN_VALUE - j - k - 1]; //
} //
if (same == 0) //
{ //
Sum = Sum + COLUMN_VALUE - j; //
l++; //
} //
} // //
/*************************************************************************************************************/
}
if(l != 0)
Aver = Sum / l;
else Aver = ALLWHITE; //补丁,如果全白给Aver赋全白
//累加
和与计数都清零
Sum = 0; //
l = 0; //
Line_Center[ROW_VALUE - 2] = Aver; //
Aver = ALLWHITE; //
/****************************************************************************************************************/
if ((Line_Center[ROW_VALUE - 1] != ALLWHITE)&&(Line_Center[ROW_VALUE - 2] != ALLWHITE))
LossLine = 0; //如果脚下两条线均部位全白则找到线,即没有丢失线
else LossLine = 1; //否则认为丢失,控制程序在车启动时可以循环使用此程序,
//即等待LossLine得知变为0时再启动。
}