原创:CCD摄像头的采集电路、动态阈值图像处理算法
0赞
发表于 2012/1/9 21:12:03
阅读(8677)
今天刚考完操作系统,我把基于S12X的CCD摄像头的电路和原创代码上传,记得顶啊
一、先上电路图:
1、12V升压电路
2、视频分离电路:
3、片外AD电路:
先介绍下上述电路的原理:
1、采用的是CCD摄像头,所以需要12V的升压电路,采用的升压模块是LM2731。
2、视频信号输出后,经过LM1881N分离出行和场信号,这两个信号用于S12X的中断,采集视频信号。
3、片外AD TLC5510,输出8位的信号值,直接连接S12X的PA口就可以了。
二、代码
原创:可调节动态阈值搜索的区域,以及对比度
采用动态阈值对图像进行二值化处理,得到二值化的图像数组后,下面的赛道识别处理方式和智能车的运动控制就看你自己了。
#define IMAGE_ROW 40 //本系统采集40行和100列图像
#define IMAGE_COLUMN 100
unsined char photo[IMAGE_ROW ][IMAGE_COLUMN] // 本数组用于存放二值化后的图像
//此算法在不丢失黑线的状况下有效,至少保证哪怕是一行中的一侧有黑线
//此算法可调选窗口阈值的范围,以及图像的对比度
void Dynamic_01(unsigned char start,unsigned char end,unsigned char contrast)
{
unsigned char i,j;
unsigned char a,b,c;
unsigned char num,temp,max,min;
unsigned char max_temp,min_temp;
unsigned char Max_num[],Min_num[];
unsigned char hang_end,hang_start;
unsigned char total_max,total_min;
unsigned char contr;
total_max=0;
total_min=0;
contr=contrst;
hang_end=end;
hang_start=start;
for(i=hang_start;i<hang_end;i++) //取视采集到的图像的某几行(连续行)
{
for(j=0;j<IMAGE_COLUMN;j=j+3) //对相邻的三个点取平均,找出最小的和最大的,构成窗口阈值
{
num=j;
a=Buffer[15][num];
num=num+1;
b=Buffer[15][num];
num=num+2;
c=Buffer[15][num];
min_temp=(a+b+c)/3;
if(min>max)
{
temp=min_temp;
min_temp=max_temp;
max_temp=temp;
}
}
Max_num[i]=max_temp;
Min_num[i]=min_temp;
}
for(i=hang_start;i<hang_end;i++)
{
total_max=total_max+Max_num[i];
total_min=total_min+Min_num[i];
}
max=total_max/(hang_end-hang_start)*(1-contr/100) // white 对比度可调
min=total_min/(hang_end-hang_start)*(1+contr/100) // black
//通过以上的运算,我们成功获得了窗口阈值,接下来我们便可以进行二值化处理
for(i=0;i<IMAGE_ROW;i++) //行
{
for(j=0; j<IMAGE_COLUMN; j++) //列
{
if(Buffer[i][j]>=max) photo[i][j]=1;
if(Buffer[i][j]<=min) photo[i][j]=0;
}
}
{
unsigned char i,j;
unsigned char a,b,c;
unsigned char num,temp,max,min;
unsigned char max_temp,min_temp;
unsigned char Max_num[],Min_num[];
unsigned char hang_end,hang_start;
unsigned char total_max,total_min;
unsigned char contr;
total_max=0;
total_min=0;
contr=contrst;
hang_end=end;
hang_start=start;
for(i=hang_start;i<hang_end;i++) //取视采集到的图像的某几行(连续行)
{
for(j=0;j<IMAGE_COLUMN;j=j+3) //对相邻的三个点取平均,找出最小的和最大的,构成窗口阈值
{
num=j;
a=Buffer[15][num];
num=num+1;
b=Buffer[15][num];
num=num+2;
c=Buffer[15][num];
min_temp=(a+b+c)/3;
if(min>max)
{
temp=min_temp;
min_temp=max_temp;
max_temp=temp;
}
}
Max_num[i]=max_temp;
Min_num[i]=min_temp;
}
for(i=hang_start;i<hang_end;i++)
{
total_max=total_max+Max_num[i];
total_min=total_min+Min_num[i];
}
max=total_max/(hang_end-hang_start)*(1-contr/100) // white 对比度可调
min=total_min/(hang_end-hang_start)*(1+contr/100) // black
//通过以上的运算,我们成功获得了窗口阈值,接下来我们便可以进行二值化处理
for(i=0;i<IMAGE_ROW;i++) //行
{
for(j=0; j<IMAGE_COLUMN; j++) //列
{
if(Buffer[i][j]>=max) photo[i][j]=1;
if(Buffer[i][j]<=min) photo[i][j]=0;
}
}
以下是摘抄别人的行场中断的代码
很简单的中断处理方法
不作解释
自己研究和改进
#pragma CODE_SEG __NEAR_SEG NON_BANKED
#pragma TRAP_PROC
void Port1_interrupt(void)
{
//测试行场信号是否接对
if(chang_count++>=50)
{
PORTB_PB0 = ~PORTB_PB0;
chang_count =0;
}
TFLG1_C1F=1; // 清场中断标志
heixian =0; //从置 行里面的信息
jiange_m=0; //行数清零
//交换图像采集和处理缓存
puca_BufferSample=puca_BufferProcess;
puca_BufferProcess=puca_BufferTemp;
puca_BufferTemp=puca_BufferSample;
TFLG1_C0F=1; // 清行中断标志 --注意这个是必须的。切记!!!!
TIE_C0I =1;// 行中断
}
#pragma TRAP_PROC
void Port1_interrupt(void)
{
//测试行场信号是否接对
if(chang_count++>=50)
{
PORTB_PB0 = ~PORTB_PB0;
chang_count =0;
}
TFLG1_C1F=1; // 清场中断标志
heixian =0; //从置 行里面的信息
jiange_m=0; //行数清零
//交换图像采集和处理缓存
puca_BufferSample=puca_BufferProcess;
puca_BufferProcess=puca_BufferTemp;
puca_BufferTemp=puca_BufferSample;
TFLG1_C0F=1; // 清行中断标志 --注意这个是必须的。切记!!!!
TIE_C0I =1;// 行中断
}
/*
*****************************行中断*********************************************************************
*
************************* *******************************************************************************
*/
*****************************行中断*********************************************************************
*
************************* *******************************************************************************
*/
unsigned char hang_i=0; //行中断里面用的记录每行点的个数的变量
#define JIANGE_HANG 3 //这个数据必须大于3 当然也不能太大
void delay_hang(unsigned char tt) {
#define JIANGE_HANG 3 //这个数据必须大于3 当然也不能太大
void delay_hang(unsigned char tt) {
while(tt-->0) {
asm{
nop;
}
}
}
asm{
nop;
}
}
}
unsigned char *H_puTemp= NULL;
#pragma CODE_SEG __NEAR_SEG NON_BANKED
#pragma TRAP_PROC
void Port0_interrupt(void)
{
TFLG1_C0F=1; // 清中断标志
if(jiange_m>JIANGE_HANG) //if JIANGE_HANG ==3 每隔5行采集一次。 if 4 每隔6行
{
jiange_m = 0;
//----------------ver------ 2.0 ---------------核心代码--------------------------------
if(heixian<IMAGE_ROW - IMAGE_ROW_DIS)
{
delay_hang(20); //延时来过滤行消隐区
H_puTemp =puca_BufferSample+heixian*IMAGE_COLUMN;
for(hang_i=0;hang_i<IMAGE_COLUMN;hang_i++) //一共100个点,计满就算是完成一行的采集了
{
*(H_puTemp+hang_i)=PORTA;
}
heixian ++; //记录黑线的数目
if(heixian ==(IMAGE_ROW - IMAGE_ROW_DIS)) //一共采集33行图像
{
g_car_show_yn = 1; //可以显示,可以处理这场数据了
}
}
}
jiange_m++;
{
jiange_m = 0;
//----------------ver------ 2.0 ---------------核心代码--------------------------------
if(heixian<IMAGE_ROW - IMAGE_ROW_DIS)
{
delay_hang(20); //延时来过滤行消隐区
H_puTemp =puca_BufferSample+heixian*IMAGE_COLUMN;
for(hang_i=0;hang_i<IMAGE_COLUMN;hang_i++) //一共100个点,计满就算是完成一行的采集了
{
*(H_puTemp+hang_i)=PORTA;
}
heixian ++; //记录黑线的数目
if(heixian ==(IMAGE_ROW - IMAGE_ROW_DIS)) //一共采集33行图像
{
g_car_show_yn = 1; //可以显示,可以处理这场数据了
}
}
}
jiange_m++;
TFLG1_C0F=1; // 清中断标志
} //end inter
} //end inter