智能系统专业实验(四):数字识别实验

  • 实验目的

1、了解模板匹配算法进行数字识别的基本原理,理解bmp 图像在存储器中的存储形式。

2、实现bmp格式图像中印刷体数字的识别。

  • 实验基本原理及步骤(或方案设计及理论计算)

1、基本原理

实验采用模板匹配中像素点重合的方法,将待测图像中的数字与模板库中的各个数字进行比对,认为模板库中与待测数字重合像素点最多的为数字识别结果。

注:当 bmp 图像读入DSP 实验板存储空间之后,imgbuf 指针指向其数据的首地址。

模板库的建立

将包含 0—9 十个数字的十张bmp 格式的图像(本模板库的图像均为白色背景黑色字体)读入,将其像素信息分别存入十个50 x 50的二维数组中。本实验中灰度图像的灰度值低于50的为有效像素点,其对应的二维数组中的数值定义为1,灰度值大于50 的认为是无效点,其对应的二维数组中的数值定义为0。

待检测图像中的数字分离

定义如下结构体:

struct{

int Left;

int Right;

}W[20];

struct{

int Up;

int Down;

}H[20];

如果输入图像包含n x m个数字,则需要将n x m个数字分离开之后,分别与模板库进行匹配并分别识别,将识别结果存入result[n x m]的数组中。

实验主要处理1 x m个数字的图像,先统计图像中每行每列有效像素点分别存入grayw[]和grayh[]中,然后逐行逐列扫描图像,通过W[].Left和W[].Right,H[].Up 和H[].Down 分别标记每个数字的左右上下可将数值分离。

模板的匹配与识别

依次识别每一位数字,将每一位数字的像素信息存入50´50的名为t 的二维数组中,有效像素点定为1,无效像素点定义0。将得到的分离后的数字的二维数组t 与各个模板进行匹配。由于模板和待检测数字中的有效像素点在数组中均表示为1,可通过对应点相加之后对2取余数再相加得到结果sum,比较待检测图像与十个模板得到的sum的值,sum 最小的表示待检测数字与其图像重合点最多,即认为待检测数字为该数字。

2、算法步骤

(1)模板库的建立,十个数字的十张bmp 格式的图像读入,并以二值形式分别存入十个50´50的二维数组中;

(2)通过分别标记每个数字的左右上下位置,将待检测图像中的

数字进行分离;

(3)统计待检测图像与十个模板得到的图像重合点数目,进行模

板的匹配与识别。

  • 实验结果分析及回答问题(或测试环境及测试结果)

模板

 

需要识别的图片

 

识别的结果

如上图结果所示,其是由识别出来的每一个数字的结果拼接得到。该算法进行识别之前必须对数字进行很好的分离,否则将会出现很大识别误差。

  • 实验代码
#include<stdio.h>
#include<cstring>
#include<math.h>
#include<windows.h>
#include <time.h>
#define imageW 288
#define imageH 36
int ImagePtr[10][1800];
int Height[10];int Width[10];
int bmpHeight, bmpWidth, biBitCount;
unsigned char *pBmpBuf;
RGBQUAD *pColorTable;
int image[10368];
int Print[10368];
int end[15];
int start[14][2]; 

void fun(){
	end[0]=0;
	int i,j,k,q;
	//寻找起始点ox,oy,每个数字的终点end
	for(k=0;k<14;k++){		
		//寻找数字k的起点ox
		for(i=end[k];i<288;i++){
			for(j=0;j<36;j++){
				if (image[i+j*288]==0){
					start[k][0]=i;
					j=36;
					i=288;
				}
			}
		}
		//寻找数字k的起点oy
		for(j=0;j<36;j++){
			for(i=end[k];i<288;i++){
				if(image[i+j*288]==0){
					start[k][1]=j;
					j=36;
					i=288;
				}
			}
		}
		//寻找数字k的终点end
		for(i=start[k][0];i<288;i++){
			j=0;
			while(image[i+j*288]==255&&j<36){
				j++;
			}
			if(j==36){
				end[k+1]=i;
				i=288;
			}					
		}	
	}
	
	//匹配	
	int sum=0;
	int Lsum=0;
	int res;
	int m;
	int n;
	for(k=0;k<14;k++){
		Lsum=0;
		for(q=0;q<10;q++){
			sum=0;
			for(i=start[k][0];i<end[k+1];i++){
				for(j=start[k][1];j<36;j++){
					m=i-start[k][0];
					n=j-start[k][1]+19;
					int w = end[k+1] - start[k][0];
					if(image[i+j*288]==ImagePtr[q][n * 40 + m]){
						sum+=1;
					}
				}
			}
			if(Lsum<sum){
				Lsum=sum;
				res=q;
			}
		}
		for(i=k*20;i<(k+1)*20;i++){
			for(j=0;j<36;j++){
				m=i-k*20;
				n=j+9;
				Print[i+j*288]=ImagePtr[res][m+n*40];
			}	
		}
	}
	for(i=(k+1)*20;i<288;i++){
		for(j=0;j<36;j++){
			Print[i+j*288]=255;
		}
	}
}

void read_temp(){
	for (int photonum = 0;photonum < 10;photonum++){
		const char src0[] = "0.bmp";
		const char src1[] = "1.bmp";
		const char src2[] = "2.bmp";
		const char src3[] = "3.bmp";
		const char src4[] = "4.bmp";
		const char src5[] = "5.bmp";
		const char src6[] = "6.bmp";
		const char src7[] = "7.bmp";
		const char src8[] = "8.bmp";
		const char src9[] = "9.bmp";
				
		FILE *fp = fopen(src9, "rb");	
		if (photonum == 0) fp = fopen(src0, "rb");
		else if (photonum == 1) fp = fopen(src1, "rb");
		else if (photonum == 2) fp = fopen(src2, "rb");
		else if (photonum == 3) fp = fopen(src3, "rb");
		else if (photonum == 4) fp = fopen(src4, "rb");
		else if (photonum == 5) fp = fopen(src5, "rb");
		else if (photonum == 6) fp = fopen(src6, "rb");
		else if (photonum == 7) fp = fopen(src7, "rb");
		else if (photonum == 8) fp = fopen(src8, "rb");
//		else if (photonum == 9) fp = fopen(src9, "rb");		

		if (fp == 0){printf("false\n");}
		fseek(fp, sizeof(BITMAPFILEHEADER), 0);
		BITMAPINFOHEADER head;
		fread(&head, 40, 1, fp);
		bmpHeight = head.biHeight;
		bmpWidth = head.biWidth;
		biBitCount = head.biBitCount;
		fseek(fp, sizeof(RGBQUAD), 1);
		int LineByte = (bmpWidth*biBitCount / 8 + 3) / 4 * 4;
		pBmpBuf = new unsigned char[LineByte*bmpHeight];
		fread(pBmpBuf, LineByte*bmpHeight, 1, fp);
		fclose(fp);
	
		int rgbMap[bmpHeight * bmpWidth][3];
		for (int i = 0; i < bmpHeight;i++){ //取位图 rgb 三通道数据
			for (int j = 0; j < bmpWidth;j++){
				unsigned char *tmp;
				tmp = pBmpBuf + i * LineByte + j * 3;
				rgbMap[i * bmpWidth + j][0] = int(*(tmp));
				rgbMap[i * bmpWidth + j][1] = int(*(tmp+1));
				rgbMap[i * bmpWidth + j][2] = int(*(tmp+2));
			}
		}
		for (int i = 0; i < bmpHeight * bmpWidth;i++){
			ImagePtr[photonum][i] = rgbMap[i][0]*0.299 + rgbMap[i][1]*0.587 + rgbMap[i][2]*0.114;
		}
		Height[photonum] = bmpHeight;
		Width[photonum]	= bmpWidth;
		
	}
}



int main(){
	read_temp();
	
	const char src[] = "test.bmp";
	FILE *fp = fopen(src, "rb");	
	if (fp == 0){
		printf("false\n");
		return 0;
	}
	fseek(fp, sizeof(BITMAPFILEHEADER), 0);
	
	BITMAPINFOHEADER head;
	fread(&head, 40, 1, fp);
	bmpHeight = head.biHeight;
	bmpWidth = head.biWidth;
	biBitCount = head.biBitCount;
	fseek(fp, sizeof(RGBQUAD), 1);
	int LineByte = (bmpWidth*biBitCount / 8 + 3) / 4 * 4;
	pBmpBuf = new unsigned char[LineByte*bmpHeight];
	fread(pBmpBuf, LineByte*bmpHeight, 1, fp);
	fclose(fp);

	int rgbMap[bmpHeight * bmpWidth][3];
	for (int i = 0; i < bmpHeight;i++){ //取位图 rgb 三通道数据
		for (int j = 0; j < bmpWidth;j++){
			unsigned char *tmp;
			tmp = pBmpBuf + i * LineByte + j * 3;
			rgbMap[i * bmpWidth + j][0] = int(*(tmp));
			rgbMap[i * bmpWidth + j][1] = int(*(tmp+1));
			rgbMap[i * bmpWidth + j][2] = int(*(tmp+2));
		}
	}
	
	for (int i = 0; i < bmpHeight * bmpWidth;i++){
		image[i] = rgbMap[i][0]*0.299 + rgbMap[i][1]*0.587 + rgbMap[i][2]*0.114;
	}	

	const char dst[] = "segResultTest.bmp";
	FILE *fp1 = fopen(dst, "wb");
	if (fp1 == 0){
		printf("false\n");
		return 0;
	}
	
	int LineByte1 = (bmpWidth * 8 / 8 + 3) / 4 * 4;
	//修改文件头,其中有两项需要修改,分别为 bfSize 和 bfOffBits
	BITMAPFILEHEADER bfhead;
	bfhead.bfType = 0x4D42;
	bfhead.bfSize = 14 + 40 + 256 * sizeof(RGBQUAD)+LineByte1*bmpHeight;
	bfhead.bfReserved1 = 0;
	bfhead.bfReserved2 = 0;
	bfhead.bfOffBits = 14 + 40 + 256 * sizeof(RGBQUAD);//修改偏移字节数
	fwrite(&bfhead, 14, 1, fp1); //将修改后的文件头存入 fp1;
	BITMAPINFOHEADER head1;
	head1.biBitCount = 8; //将每像素的位数改为 8
	head1.biClrImportant = 0;
	head1.biCompression = 0;
	head1.biClrUsed = 0;
	head1.biHeight = bmpHeight;
	head1.biWidth = bmpWidth;
	head1.biPlanes = 1;
	head1.biSize = 40;
	head1.biSizeImage = LineByte1*bmpHeight;//修改位图数据的大小
	head1.biXPelsPerMeter = 0;
	head1.biYPelsPerMeter = 0;
	fwrite(&head1, 40, 1, fp1); //将修改后的信息头存入 fp1;
	pColorTable = new RGBQUAD[256];
	for (int i = 0; i < 256; i++){	
		pColorTable[i].rgbRed = i;
		pColorTable[i].rgbGreen = i;
		pColorTable[i].rgbBlue = i; //是颜色表里的 B、G、R 分量都相等,且等于索引值
	}
	fwrite(pColorTable, sizeof(RGBQUAD), 256, fp1); //将颜色表写入 fp1
	//写位图数据
	unsigned char *newBmp;
	newBmp = new unsigned char[LineByte1*bmpHeight];
	
	fun();
	
	for (int i = 0; i < bmpHeight; i++){
		for (int j = 0; j < bmpWidth; j++){
			unsigned char *pb;
			pb = newBmp + i * LineByte1 + j;
			*pb = Print[i * bmpWidth + j];
		}
	}

	fwrite(newBmp, LineByte1*bmpHeight, 1, fp1);
	fclose(fp1);
	system("pause");
	return 0;
}

 

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值