android led数字识别,opencv 学习之 液晶数字识别

算法采用纵向及横向扫描方式,对清晰图片进行了实验,效果较好。

算法未检测小数点,感兴趣的同学可以Y方向腐蚀检测小数点,按照X坐标排序即可。

当然,数字及字符识别,SVM、K近邻、神经网络等等这些才是正道,平常用得比较多的算法。

源图如下:

0818b9ca8b590ca3270a3433284dd417.png

代码如下:

//DATE : 20160729

//CODE FOR LIDAN NUMBER RECG

#include "highgui.h"

#include "cv.h"

using namespace std;

using namespace cv;

void detect(IplImage * img, char * strnum, CvRect rc);

int list[10][2] = {0};//1列坐标,2列字符数值

int l = 0;//字符个数

int main()

{

IplImage * src_img = cvLoadImage("plate1.jpg");

if(!src_img)

{

printf("src_img could not be load\n");

return -1;

}

//cvShowImage("src", src_img);//src img

IplImage * gray_img = cvCreateImage(cvGetSize(src_img), src_img->depth, 1);

cvCvtColor(src_img, gray_img, CV_BGR2GRAY);

cvShowImage("gray", gray_img);//gray img

IplImage * adp_img = cvCreateImage(cvGetSize(src_img), src_img->depth, 1);

int threshold_type = CV_THRESH_BINARY_INV;

int adaptive_method = CV_ADAPTIVE_THRESH_GAUSSIAN_C; //CV_ADAPTIVE_THRESH_MEAN_C

int block_size = 7;

double offset = 5;

//cvAdaptiveThreshold(gray_img, adp_img, 255, adaptive_method, threshold_type, block_size, offset);

cvThreshold(gray_img, adp_img, 80, 255.0, CV_THRESH_BINARY);

cvShowImage("adp", adp_img);

IplImage * xtx_img = cvCreateImage(cvGetSize(adp_img), adp_img->depth, adp_img->nChannels);

cvCopy(adp_img, xtx_img);

IplConvKernel * kernal;

//自定义 1x3 的核进行 x 方向的膨胀腐蚀

kernal = cvCreateStructuringElementEx(1, 3, 0, 1, CV_SHAPE_RECT);

cvDilate(xtx_img, xtx_img, kernal, 3);

cvErode(xtx_img, xtx_img, kernal, 3); //y 腐蚀去除碎片

//自定义 3x1 的核进行 y 方向的膨胀腐蚀

kernal = cvCreateStructuringElementEx(3, 1, 1, 0, CV_SHAPE_RECT);

cvDilate(xtx_img, xtx_img, kernal, 3); //x 膨胀回复形态

cvErode(xtx_img, xtx_img, kernal, 3); //x 腐蚀去除碎片

cvShowImage("xtx", xtx_img);

IplImage * temp_img = cvCreateImage(cvGetSize(xtx_img), xtx_img->depth, adp_img->nChannels);

cvCopy(xtx_img, temp_img);

cvShowImage("temp", temp_img);

CvSeq * contours = NULL;

CvMemStorage * storage = cvCreateMemStorage(0);

int count = cvFindContours(xtx_img, storage, &contours, sizeof(CvContour), CV_RETR_EXTERNAL);

printf("The count is :%d\n", count);

int idx = 0;

char szName[56] = {0};

int tempcount = 0;

CvSeq * c=contours;

for( ; c!=NULL; c=c->h_next)

{

CvRect rc = cvBoundingRect(c, 0);

double tmparea = fabs(cvContourArea(c));

if(tmparea > ((src_img->height*src_img->width)/4))

{

cvSeqRemove(c,0); //删除面积大于设定值的轮廓,1/4

continue;

}

if(tmparea < ((src_img->height*src_img->width)/100))

{

cvSeqRemove(c,0); //删除面积小于设定值的轮廓,1/20

continue;

}

//cvDrawRect(src_img, cvPoint(rc.x, rc.y), cvPoint(rc.x+rc.width, rc.y+rc.height), CV_RGB(255, 0, 0));

IplImage * sub_img = cvCreateImage(cvSize(rc.width, rc.height), xtx_img->depth, adp_img->nChannels);

cvSetImageROI(temp_img, rc);

cvCopyImage(temp_img, sub_img);

cvResetImageROI(temp_img);

sprintf(szName, "win_%d", idx++);

detect(sub_img, szName, rc);//DETECT NUMBER

cvShowImage(szName, sub_img);

cvReleaseImage(&sub_img);

}

printf("\n字符识别结果为:");

for(int i=0; i

{

for(int j=0; i+j

{

if(list[j][0] > list[j + 1][0])

{

//坐标排序

int temp = list[j][0];

list[j][0] = list[j + 1][0];

list[j + 1][0] = temp;

//数值随之变化

temp = list[j][1];

list[j][1] = list[j+1][1];

list[j+1][1] = temp;

}

}

}

for(int i=0; i

{

printf("%d ", list[i][1]);

}

cvShowImage("src", src_img);//src img

cvWaitKey(0);

return 1;

}

void detect(IplImage * img, char * strnum, CvRect rc)

{

printf("\n模块 %s\n", strnum);

//printf("高度 %d\n", img->height);

//printf("宽度 %d\n", img->width);

list[l][0] = rc.x;//第l个字符横坐标

//if the height is more two longer than width,number is 1

if((img->height/img->width)>2)

{

list[l][1] = 1;

printf("字符是 1.\n");

}

else

{

int ld[3] = {0};

CvScalar pix;

int i = img->width/2;

int j = img->height/3;

int k = img->height*2/3;

//竖向扫描

for(int m=0; m<3; m++)

{

for(int n=m*j; n

{

pix = cvGet2D(img, n, i);

if(pix.val[0]==255)

{

ld[0]++;

break;

}

}

}

printf("竖向 %d\n", ld[0]);

//横向扫描

for(int m=0; m<2; m++)

{

for(int n=m*i; n

{

//横向1/3扫描

pix = cvGet2D(img, j, n);

if(pix.val[0]==255)

{

ld[1]++;

break;

}

}

}

printf("横向1 %d\n", ld[1]);

//横向扫描

for(int m=0; m<2; m++)

{

for(int n=m*i; n

{

//横向2/3扫描

pix = cvGet2D(img, k, n);

if(pix.val[0]==255)

{

ld[2]++;

break;

}

}

}

printf("横向2 %d\n", ld[2]);

if((ld[0]==2)&&(ld[1]==2)&&(ld[2]==2))

{

printf("字符是 0\n");

list[l][1] = 0;

}

else if((ld[0]==1)&&(ld[1]==2)&&(ld[2]==1))

{

printf("字符是 4\n");

list[l][1] = 4;

}

else if((ld[0]==3)&&(ld[1]==1)&&(ld[2]==2))

{

printf("字符是 6\n");

list[l][1] = 6;

}

else if((ld[0]==1)&&(ld[1]==1)&&(ld[2]==1))

{

printf("字符是 7\n");

list[l][1] = 7;

}

else if((ld[0]==3)&&(ld[1]==2)&&(ld[2]==2))

{

printf("字符是 8\n");

list[l][1] = 8;

}

else if((ld[0]==3)&&(ld[1]==2)&&(ld[2]==1))

{

printf("字符是 9\n");

list[l][1] = 9;

}

else if((ld[0]==3)&&(ld[1]==1)&&(ld[2]==1))

{

int l1=0, l2=0;

//横向扫描

int k = img->height/3;

for(int i=0; iwidth/2; i++)

{

//横向2/3扫描

pix = cvGet2D(img, k, i);

if(pix.val[0]==255)

{

l1++;

break;

}

}

//横向扫描

k = img->height*2/3;

for(int i=0; iwidth/2; i++)

{

//横向2/3扫描

pix = cvGet2D(img, k, i);

if(pix.val[0]==255)

{

l2++;

break;

}

}

if((l1==0)&&(l2==0))

{

printf("字符是 3\n");

list[l][1] = 3;

}

else if((l1==0)&&(l2==1))

{

printf("字符是 2\n");

list[l][1] = 2;

}

else if((l1==1)&&(l2==0))

{

printf("字符是 5\n");

list[l][1] = 5;

}

}

else printf("识别失败\n");

}

l++;

}

效果如下:

1、二值化后形态学处理

0818b9ca8b590ca3270a3433284dd417.png

2、字符识别并排序

0818b9ca8b590ca3270a3433284dd417.png  

0818b9ca8b590ca3270a3433284dd417.png  

0818b9ca8b590ca3270a3433284dd417.png  

0818b9ca8b590ca3270a3433284dd417.png

代码中有位置排序,可以自己看看。

代码基于OpenCV1,C语言编写,实验版本。目前OpenCV2已成为主流,毕竟功能完善了很多,也省去了管理空间的麻烦,得好好学学C++。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值