本帖最后由 DEMOK 于 2014-9-18 18:59 编辑
我去年做过一届摄像头,其中对于摄像头阈值的确定方法不断变化,最终采用了直方图二值化,这种动态阈值的适应性很好,我们之后就没有再调过阈值了。
我们采用的岱默公司的OV7620摄像头,摄像头数据隔行采集完毕之后存放于数组Pix_Data1[40][320],这就是一帧图像。
需要定义的变量很多,看起来有点恐怖呃!不着急且听我慢慢道来。。。。。。
unsigned char Num[256]={0};
//该数组用来统计一幅图像每个灰度值的点数,注释:灰度值0-255,比如Num[68]=50就是灰度值是68的像素点有50个
unsigned char *p_Bz;//用于指示某行首地址的指针
int p1;//普通变量
unsigned char Thr=100;//随便给阈值一个初始值
unsigned int total;
float TotalWeight=0,ForeWeight = 0;
float TotalPixels = 0; //进行统计的点数和
float sb;
float fmax1=-1 ;
unsigned int BackNum=0;//当前阈值遍前景图象的点数
unsigned int ForeNum=0;/当前阈值遍后景图象的点数
float BackAvg;//后景的平均灰度值
float ForeAvg;// 前景的平均灰度值
1.统计所选行(二值化为了节约时间只选了几行,不过够用了)中的各灰度值的数目
for(i=13;i<23;i=i+2) // 这里选择第13-23 奇数行, 一行320 的像素点,
{
p_Bz=& ix_Data1[0][0] + i *320; // p_Bz 这个不用猜了,就是每一行的首地址
for (j = 0; j < 320; j+=2 ) // 为了节约时间也是两个像素统计一个
{
Num[*(p_Bz + j)]++; // (p_Bz + j )为每个像素的具体地址* (p_Bz + j )为灰度值
}
}
Num[256] 统计完毕哈哈!
2对Num[256]平滑滤波处理,基本思路是:
比如Num[0],Num[1],Num[2],Num[3],Num[4]灰度值0,1,2,3,4的像素点的个数
Num[2]=(Num[0]+Num[1]+Num[2]+Num[3]+Num[4])/5
然后每个点都是与他前后2个数一起平均作为最终值
上代码了!!!
for (i = 0;i<256;i++) // 从0 到第255 个灰度值之间的每一个数值
{
total = 0;
for(j = -2;j<3;j++) // 某灰度值对应的个数为改灰度值上下2 个(共5 个)的平均值
{
p1=i+j;
if(p1<0) // 越界处理
p1=0;
if(p1>255)
p1=255; // 越界处理
total+=Num[p1];
}
Num =total/5;
}
3.数学计算,有点复杂!!;P
for (i= 0; i< 256; i++)
{
TotalWeight += i * Num; // 质量矩,也就是每个灰度的值乘以其点数(归一化后为概率),TotalWeight为其总和
TotalPixels +=Num;
// ,256个灰度值对应的像素点的总和 ,total为图象总的点数,归一化后就是累积概率
}
4.假定将某灰度值作为阈值,小于该灰度值的称为前景,大于该灰度值的称为后景,从0-255一个个试探,计算假定灰度得出的值,比较大小,取最小的。
for (i= 0; i< 256; i++) //
{
ForeNum += Num; //ForePixNum为在当前阈值遍前景图象的点数
if (ForeNum == 0)//将0作为阈值虽然肯定不对但都要给机会嘛!!!;P
continue;
BackNum =(int) (TotalPixels - ForeNum); //BackPixNum为背景图象的点数
if (BackNum == 0)
break;
//BackPixNum为0表示全部都是前景图象,与ForePixNum=0情况类似,之后的遍历不可能使前景点数增加,所以此时可以退出循环
ForeWeight += i*Num; //前景图像质量矩
ForeAvg = (float)(ForeWeight/ForeNum);//
//前景对应灰度值*前景对应个数 /前景总个数 =前景平均灰度值
BackAvg = (float)(TotalWeight - ForeWeight)/BackNum;
//后景图像平均灰度 sb = (float)(ForeNum * BackNum * (ForeAvg- BackAvg) * (ForeAvg- BackAvg));
最后就是求一个x0(0~255)使得上述公式取得最大值,可以理解成方差最大时阈值上下的灰度值相对于阈值整体靠的更远,界限更加分明。差不多就是蓝布和赛道灰度值中间的数值。if (sb > fmax1) //////方差 { ///////取方差最大时候对应的灰度值为阈值fmax1 = sb;Thr = i; ///////for循环的作用就是取256个灰度值中方差最大时候对应的灰度值为阈值 } }
CCDGateVoltage=Thr;
//终于得到阈值了,好辛苦啊!!!!!!!!
有黄色标记的地方都是公式,无奈显示不了。直接上Word!!!!!!!
|