花了两个星期的时间,终于把一个简单的模式识别程序移植到开发板上了。程序是现成的,以前用VC实现的。在移植过程中,中间走了一些弯路,花费了不少时间。
程序很简单,用模板匹配法实现数字5和非5的识别,最终显示出来。关于特征值的选取,我一开始把图像分成了5*5个区域,用每个区域的像素值当做特征值。原来VC上,就是这么分的,连阈值我都是直接照搬原程序。实验的时候发现,即使同一个数字,每次从摄像头读取后的像素值差别比较大,毕竟不是读BMP图片。最后改用比值做特征值,分成3*4个区域,区域分的太多反而会受误差影响较大。重新训练选取阈值,最后的结果差强人意,可以大致区分出5和其他数字,但有时也会失败。
程序过程如下:
1. 初始化。从摄像头中读图并二值化存入对应数组。由于摄像头的数据直接放在DDR2中,所以从摄像头读数就是从DDR2对应的地址读数。
2. 把二值化的图像显示出来。就是把二值化的图像数据放到DDR2中。
3. 对图像进行边界扫描。这是为了下一步标准化做准备。上边界确定方法如下:
//从上往下扫描,找到上边界
tmp=(Uint8 *)sample;
for (i=10;i //边界有黑线,i不从0开始
{
count=0;
//列
for (j=0;j
{
// 指向图像第i行,第j个象素的指针
tmp = (Uint8 *)sample + lLineBytes * i + j;
//获得该点的灰度值
//gray = *(lpSrc);
//看是否为黑点
if (*tmp == 0)
{
count++;
//若黑点数>10,把此行作为字符大致的最高点
}
//如果该点不是黑点,继续循环
}
if(count>10)
{
top=i;
break;
}
}
很简单,就是从上往下一行一行统计黑像素个数,当首先超过阈值时(我取10),记录位置,作为上边界。其他边界以此类推。
4. 标准化。把读到的图像尺寸标准化。代码如下:
height=rect.bottom-rect.top;
width=rect.right-rect.left;
lLineBytes=150;
//分配空间存标准化后的图像
dest=malloc(150*200);
memset(dest,0xff,150*200);
//计算缩放因子
//横坐标方向的缩放因子
wscale=(double)tarWidth/width;
//纵坐标方向的缩放因子
hscale=(double)tarHeight/height;
for(i=0 ;i<200 ;i++)
{
for(j=0 ;j<150 ;j++)
{
//计算映射坐标
i_src=top +(Uint32)(i /hscale);
j_src=left +(Uint32)(j /wscale);
//将相对应的象素点进行映射操作
src=sample + lLineBytes * i_src + j_src;
dest = transample + 150 * i + j;
*dest=*src;
}
}
就是把原来图像的像素映射到标准大小的框框中。我这里标准化大小为:150*200。
5. 计算标准化后图像的黑 {MOD}像素总个数。
6. 计算3*4个区域中每个区域的黑 {MOD}像素个数,算出特征值。
7. 与模板比较,显示结果。
我的模板是事先存好的,保存了3*4个特征值,比较的时候从文件中读取即可。这样不用每次都从摄像头中读模板。
遇到问题:
1. 我没有用DSP/BIOS所以开始的时候在CMD文件中遇到了麻烦,编译总是过不去,提示我文件太大,放不到L2 Cache中,L2 Cache有128K大小,我这么小的程序居然会超,我怎么也想不明白。.我发现cinit 、.far和. text占用空间较大。.cinit则用来存放全局变量的初始值 .far 好像也是存放初始值的。.text是代码大小。最后没办法,全都放到了DDR中。这才能够编译通过。
2. 开始我从屏幕上取的窗口大小为200*240的,就是摄像头存放在DDR中数据大小,后来发现读的图像不正确,改为320*240后,问题解决,应该是VPFE的设置有问题。