【实验项目名称】
手写数字特征提取方法与实现
【实验目的】
通过手写数字特征的提取,了解数字的特征提取方法,掌握特征匹配准则。
【实验原理】
读取标准化后的数字0~9,二值化,对每个数字进行等分区域分割,统计 每个区域内的黑色像素点的个数,即为特征初值。采用欧式距离的模板匹配 法判断数字。
【实验要求】
给定数字0-9的原始样本集合,每个数字都有10个大小为240*240的样本 图像。要求如下:
1、 将上述图像切分成标准图像库,存储为文件。
2、 对每个数字进行等分区间分割(分割区间至少大于等于10*10)
3、 给出统计结果:每个区域内的黑色像素点个数值以及占总量的百分 比,显示出计算结果。
4、 采用欧氏距离模板匹配法,给出识别结果。
5、 从统计意义上,给出每个数字的识别率。
具体步骤如下
使用vc++6.0以及opencv1.0实现,opencv需要提前进行环境配置。
// NumberReg.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include "cv.h"
#include "highgui.h"
#include "string.h"
#include "malloc.h"
#include "stdio.h"
#include<stdlib.h>
#define M 14
#define N 14
#pragma comment(lib,"cv.lib")
#pragma comment(lib,"cxcore.lib")
#pragma comment(lib,"highgui.lib")
#pragma comment(lib,"cvaux.lib")
#pragma comment(lib,"cvcam.lib")
char* StandardStr(IplImage *img)//获取分块后的01字符串
{
int wp=img->widthStep;
char *str=(char *)malloc(M*N+1);//动态建立字符串。
uchar *data=(uchar *)img->imageData;
int count=0;//计数
for(int i=0;i<M;i++)
{
for(int j=0;j<N;j++)
{
if(data[2*i*wp+2*j]>127)
{
count++;
}
if(data[(2*i+1)*wp+2*j]>127)
{
count++;
}
if(data[2*i*wp+(2*j+1)]>127)
{
count++;
}
if(data[(2*i+1)*wp+(2*j+1)]>127)
{
count++;
}
if(count>1)//块里面像素值大于127的个数大于一半
{
str[i*M+j]='1';
}
else//块里面像素值大于127的个数小于一半
{
str[i*M+j]='0';
}
count=0;
}
}
str[M*N]='\0';//字符串结尾
return str;
}
void WriteStr(char* str,char *filename,FILE *fp,char *i,char *j)
{
remove(filename);
//FILE *fp;
if(fp==NULL)
{
puts("Fail to open file!");
}
else
{
char *str1=(char *)malloc(strlen(str)+3);
strcpy(str1,i);
strcat(str1,j);
strcat(str1,str);
fprintf(fp,"%s\n",str1);
}
}
void train(int row)//获得要测试的数据
{
remove("C:\\Users\\曹人\\Desktop\\train.txt");
IplImage *img=0;
FILE *fp;
fp=fopen("C:\\Users\\曹人\\Desktop\\train.txt","a+");
//地址
for(int i=0;i<10;i++)
{
for(int j=0;j<10;j++)
{ //获取数字0-9各10张图片
char *address=(char *)malloc(sizeof("C:\\Users\\曹人\\Desktop\\手写数字数据集\\train-images\\")+10);
char *a=(char *)malloc(1),*b=(char *)malloc(2);
itoa(i,a,10);
itoa(j+10*row,b,10);//取训练集当中的10开始的数字
strcpy(address, "C:\\Users\\曹人\\Desktop\\手写数字数据集\\train-images\\");
strcat(address,a);
strcat(address,"_");
strcat(address,b);
strcat(address,".bmp");
img=cvLoadImage(address,0);
WriteStr(StandardStr(img),"C:\\Users\\曹人\\Desktop\\train.txt",fp,a,b);
free(address);
}
}
fclose(fp);
}
void test()//获取标准化后数据
{
IplImage *img=0;
FILE *fp;
remove("C:\\Users\\曹人\\Desktop\\test.txt");
fp=fopen("C:\\Users\\曹人\\Desktop\\test.txt","a+");
//地址
for(int i=0;i<10;i++)
{
for(int j=10;j<100;j++)
{ //获取数字0-9各10张图片
char *address=(char *)malloc(sizeof("C:\\Users\\曹人\\Desktop\\手写数字数据集\\test-images\\")+10);
char *a=(char *)malloc(1),*b=(char *)malloc(2);
itoa(i,a,10);
itoa(j,b,10);
strcpy(address, "C:\\Users\\曹人\\Desktop\\手写数字数据集\\test-images\\");
strcat(address,a);
strcat(address,"_");
strcat(address,b);
strcat(address,".bmp");
img=cvLoadImage(address,0);
WriteStr(StandardStr(img),"C:\\Users\\曹人\\Desktop\\test.txt",fp,a,b);
free(address);
}
}
fclose(fp);
}
char* ReadStr(FILE *fp,int i,int n)
{
//FILE*fp;
int CurrentIndex=0;
char *StrLine=(char *)malloc(n);
//fp = fopen(filename,"r+");
fseek(fp,0,SEEK_SET);//指针调到最开始。
if(fp == NULL) //判断文件是否存在及可读
{
printf("error!");
return NULL;
}
while (!feof(fp))
{
if (CurrentIndex==i)
{
fgets(StrLine,n,fp); //读取一行
printf("%s", StrLine); //输出
return StrLine;
}
fgets(StrLine,n,fp); //读取一行,并定位到下一行
CurrentIndex++;
}
return NULL;
}
void ShowImage(char *str)
{
IplImage *img=cvLoadImage("C:\\Users\\曹人\\Desktop\\show.bmp",0);//存储结果的照片
int wp=img->widthStep;
uchar *data=(uchar *)img->imageData;
int Inum=2;
for(int i=0;i<M;i++)
{
for(int j=0;j<N;j++)
{
data[2*i*wp+2*j]=(str[Inum]-'0')*255;//依次一个小块
data[(2*i+1)*wp+2*j]=(str[Inum]-'0')*255;
data[2*i*wp+(2*j+1)]=(str[Inum]-'0')*255;
data[(2*i+1)*wp+(2*j+1)]=(str[Inum]-'0')*255;
Inum++;
}
}
/*for(int i=0;i<img->width;i++)
{
for(int j=0;j<img->height;j++)
{
if(data1[i*wp+j]>0)
{
data1[i*wp+j]=255;
}
printf("%d",data1[i*wp+j]/255);
}
printf("\n");
}*/
cvNamedWindow("First", 0);
cvShowImage("First", img);
cvWaitKey(0);
}
double Odistance(char *num,char *rightNum)//求欧氏距离
{
int Sq=0;
for(int i=3;rightNum[i]!='\n';i++)
{
int a=num[i-1]-'0';//需要被识别的数字。
//int a=num[i]-'0';
int b=rightNum[i]-'0';
Sq+=(a-b)*(a-b);
}
return sqrt(Sq);
}
bool JudgeImage(char *Number,FILE *fp,int n)//遍历每一个测试集的图片。
{
double minDistance=100000.0;//记录最短欧氏距离。
char rightNumber;//识别出的数字
char location;//识别出的数字的位置。
char *StrLine=(char *)malloc(n);
fseek(fp,0,SEEK_SET);//指针调到最开始。
if(fp == NULL) //判断文件是否存在及可读
{
printf("error!");
return NULL;
}
while (!feof(fp))
{
fgets(StrLine,n,fp); //读取一行,并定位到下一行
double temp=Odistance(Number,StrLine);
if(minDistance>temp)//当找到一个更接近的就更换原来的数。
{
rightNumber=StrLine[0];
location=StrLine[1];
minDistance=temp;
}
}
if(rightNumber==Number[0])
{
printf("第几行%c\n",rightNumber);
printf("第几列%c\n",location);
return true;
}
printf("识别错误,识别的是%c,第%c个\n",rightNumber,location);
return false;
}
int main(int argc, char* argv[])
{
/*IplImage *img=0;
//地址
for(int i=0;i<10;i++)
{
for(int j=0;j<10;j++)
{ //获取数字0-9各10张图片
char *address=(char *)malloc(sizeof("C:\\桌面\\手写数字数据集\\train-images\\")+10);
char *a=(char *)malloc(1),*b=(char *)malloc(1);
itoa(i,a,10);
itoa(j,b,10);
strcpy(address, "C:\\桌面\\手写数字数据集\\train-images\\");
strcat(address,a);
strcat(address,"_");
strcat(address,b);
strcat(address,".bmp");
img=cvLoadImage(address,0);
WriteStr(StandardStr(img,14,14),"C:\\桌面\\train.txt",a,b);
free(address);
}
}*/
int row=0;
train(row);//训练集。
test();
/*FILE *fp;
fp=fopen("C:\\Users\\曹人\\Desktop\\test.txt","r");
ShowImage(ReadStr(fp,48,200));//展现需要的图片。
fclose(fp);*/
FILE *fpTrain;
FILE *fpTest;
fpTrain=fopen("C:\\Users\\曹人\\Desktop\\train.txt","r");
fpTest=fopen("C:\\Users\\曹人\\Desktop\\test.txt","r");
int Tnum=0;
int i=0;
int Dinum[11]={0};
for(i=0;i<100;i++)
{
//ShowImage(ReadStr(fpTest,i,201));//展现压缩后的的图片。
if(JudgeImage(ReadStr(fpTrain,i,202),fpTest,201))
{
Dinum[i/10]++;
Tnum++;
}
}
for(i=0;i<10;i++)
{
printf("数字%d的正确率为%d%%\n",i,Dinum[i]*10);
}
printf("\n\n");
printf("总的正确率%d%%",Tnum);
//printf("%d",JudgeImage(ReadStr(fpTrain,99,201),fpTest,200));
fclose(fpTrain);
fclose(fpTest);
/*for(int i=0;i<img->width;i++)
{
for(int j=0;j<img->height;j++)
{
if(data1[i*wp+j]>0)
{
data1[i*wp+j]=255;
}
printf("%d",data1[i*wp+j]/255);
}
printf("\n");
}*/
//cvNamedWindow("First", 0);
//cvShowImage("First", img);
//cvWaitKey(0);
return 0;
}
注意文件存放的位置
附件如下链接:
https://pan.baidu.com/s/1W4CIVKlptYX00rqbx46xFA
提取码:kzcp