java opencv 数字识别_最简单的opencv数字识别+源码

这篇博客介绍了一个使用Java和OpenCV进行数字识别的简单应用。通过加载数字图片,进行二值化处理和轮廓提取,匹配数字轮廓并识别数字。代码包括预处理、轮廓匹配和数字排序等步骤。
摘要由CSDN通过智能技术生成

// NumberDemo.cpp : 定义控制台应用程序的入口点。

//

#include "stdafx.h"

#include

#include

#include

#define CV_VERSION_ID CVAUX_STR(CV_MAJOR_VERSION) CVAUX_STR(CV_MINOR_VERSION) CVAUX_STR(CV_SUBMINOR_VERSION)

#ifdef _DEBUG

#define cvLIB(name) "opencv_" name CV_VERSION_ID "d"

#else

#define cvLIB(name) "opencv_" name CV_VERSION_ID

#endif

#include

#include //创建界面的头文件

#pragma comment(lib,cvLIB("core"))

#pragma comment(lib, cvLIB("imgproc"))

#pragma comment(lib, cvLIB("highgui"))

using namespace cv;

using namespace std;

#define N 5 //载入数字图片个数

string testPic[] = {"test1.jpg","test2.jpg","test3.jpg","test4.jpg","test5.jpg","test6.jpg","test7.jpg","test8.jpg","test9.jpg","test10.jpg"};

int thres = 115; //二值化阀值

//int flag0 = 1; //准确标志 1为不符合,0为符合

int n_min = 80; //识别数字轮廓长度的下限 单位(像素)

int n_max = 400; //识别数字轮廓长度的上限

//数字轮廓的长度和宽度 单位(像素)

int n_width_min = 5,n_width_max = 40;

int n_height_min = 30,n_height_max = 50;

// 数组成员之间的距离小于一个阀值视为一个数

int n_width_n_min = 15,n_width_n_max = 40;

string picture[] = {"0.jpg","1.jpg","2.jpg","3.jpg","4.jpg"}; //数字图片集 这里储存白底黑子的数字图片 0 - 4;

CvSeq *pic[N]; //储存数字图片轮廓

CvSeq* GetImageContour(IplImage* srcIn,int flag = 0)

{

IplImage* src;

CvSeq* seq; //储存图片轮廓信息

int total = 0; //轮廓总数

int count = 0;

src = cvCreateImage(cvGetSize(srcIn),8,1);

//拷贝图像

cvCopy(srcIn,src);

//创建空间

CvMemStorage* mem = cvCreateMemStorage(0);

if(!mem)

{

printf("mem is NULL!");

}

//二值化图像

cvThreshold(src,src,thres,255,CV_THRESH_BINARY_INV);

//计算图像轮廓 0-只获取最外部轮廓 1-获取全部轮廓

if(flag == 0)

{

total = cvFindContours(src,mem,&seq,sizeof(CvContour),CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE,cvPoint(0,0));

}

if(flag == 1)

{

total = cvFindContours(src,mem,&seq,sizeof(CvContour),CV_RETR_CCOMP,CV_CHAIN_APPROX_NONE,cvPoint(0,0));

}

//printf("total = %d\n",total);

//释放图像空间

cvReleaseImage(&src);

//返回轮廓信息

return seq;

}

//数字图片轮廓计算

void Init(void)

{

IplImage *src0,*src;

int i;

for(i=0;i<5;i++)

{

src0 = cvLoadImage(picture[i].c_str(),CV_LOAD_IMAGE_GRAYSCALE);

if(!src0)

{

printf("Couldn't load %s\n",picture[i]);

exit(1);

}

src = cvCloneImage( src0 );

pic[i] = GetImageContour(src,0); //只获取最外部轮廓

}

}

int ReadNumber(CvSeq* contoursTemp)

{

int i;

double tmp = 5,min = 5;

int num = -1;

for(i=0;i

{

tmp = cvMatchShapes(contoursTemp,pic[i],1); //匹配

if(tmp < min)

{

min = tmp;

num = i;

}

}

return num;

}

void Paixu(int numList[100][2],int count) //将数字按横坐标从左往右排列

{

int i,j; //循环

int n=0; //融合后的数字个数

int tem;

int head = 0,tail = 1;

int width = 0; //两数字间的距离

int newList[100] = {0}; //数字融合后的新序列

for(i=0;i

{

for(j=i+1;j

{

if(numList[i][1] > numList[j][1])

{

//交换坐标

tem = numList[i][1];numList[i][1] = numList[j][1];numList[j][1] = tem;

//交换数字

tem = numList[i][0];numList[i][0] = numList[j][0];numList[j][0] = tem;

}

}

}

if(count == 0)

{

printf("no number!");

}

else

{

for(i=0;i

{

printf("%d\t",numList[i][0]);

}

}

//数字融合,可以自己改。。。。数字从左往右的顺序都在numList里面,[0]为数,[1]为坐标,自己可以根据数字间的距离判断是否为一个数

if(count == 2)

{

width = numList[1][1] - numList[0][1];

if((width < n_width_n_max) && (width > n_width_n_min))

{

tem = numList[0][0] * 10 + numList[1][0];

newList[0] = tem;

}

printf("the number is %d\t",newList[0]);

}

}

int main()

{

int travel = 1; //如果为0,识别中间数字,如果为1,识别右边数字.其他数字,全部识别

int i; //循环标志

int count=0; //数字轮廓个数

int num = -1; //识别一幅图像中的一个数字

int numList[100][2]; //一幅图像中的数字序列 一维是数字,二维是数字所在横坐标

CvPoint pt1,pt2;

CvRect ins;

Init(); //初始化,在pic中储存所有图片轮廓

//CvMemStorage* storage = cvCreateMemStorage(0);

IplImage* img = cvLoadImage(testPic[1].c_str(),CV_LOAD_IMAGE_GRAYSCALE);

if(travel == 0)

{

ins.x=170;

ins.y=140;

ins.width = 300;

ins.height = 200;

cvSetImageROI(img,ins);

}

if(travel == 1)

{

ins.x=470;

ins.y=140;

ins.width = 165;

ins.height = 200;

cvSetImageROI(img,ins);

}

IplImage* imgColor = cvCreateImage(cvGetSize(img),8,3);

IplImage* contoursImage = cvCreateImage(cvSize(img->width,img->height),8,1);

CvSeq* contours = 0 , *contoursTemp=0;

cvZero(contoursImage);

/*

//对图像进行二值化

cvThreshold(img,img,100,255,CV_THRESH_BINARY);

//img的备份

cvCvtColor(img,imgColor,CV_GRAY2BGR);

*/

/*

// 提取图像img的轮廓信息 contours指向第一个轮廓

int total = cvFindContours( img, storage, &contours, sizeof(CvContour),

CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE, cvPoint(0,0) );

*/

contours = GetImageContour(img,1); //获取轮廓信息

contoursTemp = contours ;

//对轮廓进行循环

for(; contoursTemp!=0 ; contoursTemp=contoursTemp->h_next)

{

//如果符合数字轮廓长度条件 保留并画出

if(contoursTemp->total > n_min && contoursTemp->total < n_max)

{

num = -1;

CvRect rect = cvBoundingRect(contoursTemp,1); //根据序列,返回轮廓外围矩形

//如果满座数字轮廓长宽

if( (rect.width >= n_width_min && rect.width <= n_width_max) && (rect.height >= n_height_min && rect.height <= n_height_max) )

{

//匹配该轮廓数字

num = ReadNumber(contoursTemp);

//计算矩形顶点

pt1.x = rect.x;

pt1.y = rect.y;

pt2.x = rect.x + rect.width;

pt2.y = rect.y + rect.height;

if(num >= 0)

{

numList[count][0] = num; //一维存数字

numList[count][1] = rect.x; //二维存数字横坐标

}

//在原图上绘制轮廓外矩形

cvRectangle(imgColor,pt1,pt2,CV_RGB(0,255,0),2);

//提取外轮廓 上的所以坐标点

for( i=0; itotal; i++)

{

CvPoint * pt = (CvPoint*)cvGetSeqElem(contoursTemp, i); // 读出第i个点。

cvSetReal2D(contoursImage , pt->y , pt->x , 255.0);

cvSet2D(imgColor,pt->y,pt->x,cvScalar(0,0,255,0));

}

count++; //数字轮廓+1

}

}

}

Paixu(numList,count); //将数字按横坐标从左往右的顺序排列

// printf("How number:%d\n",count); //输出数字字符个数

for(i=0;i

{

printf("%d(%d)\t",numList[i][0],numList[i][1]);

}

cvNamedWindow( "image", 1 );

cvShowImage( "image", imgColor );

cvNamedWindow( "contours");

cvShowImage("contours",contoursImage);

cvWaitKey(0);

cvResetImageROI(imgColor);

cvResetImageROI(img);

cvReleaseImage( &img );

cvReleaseImage(&contoursImage);

cvReleaseImage(&imgColor);

return 0;

}

图片包:opencvreadnumber

结果图:

014c7bd4023bf87366a3c73e45f9882a.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值