C++ opencv 数字识别

#include "cv.h"
#include "highgui.h"
#include "cxcore.h"
#include <stdlib.h>
#include <stdio.h>
#define N 5//载入数字图片个数

char *testPic[] = {"test1.jpg"};
int thres = 115;    //二值化阀值

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;

char *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 = 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-获取全部轮廓
    CvSeq* seq;//储存图片轮廓信息
    if(flag == 0){
        cvFindContours(src, mem, &seq, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, cvPoint(0,0));
    }
    if(flag == 1){
        cvFindContours(src, mem, &seq, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE, cvPoint(0,0));
    }

    //释放图像空间
    cvReleaseImage(&src);

    //返回轮廓信息
    return seq;
}

//数字图片轮廓计算
void Init(void)
{
    IplImage *src0, *src;
    for(int i = 0; picture[i] != 0; i++){
        src0 = cvLoadImage(picture[i], 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)
{
    double tmp = 5,min = 5;
    int num = -1;
    for(int i = 0; i < N; 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 tem = 0;
    int newList[100] = {0};  //数字融合后的新序列
    for(int i = 0; i < count - 1; i++){
        for(int j = i + 1; j < count; 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(int i = 0; i < count; i++){
            printf("%d\t",numList[i][0]);
        }
    }

    //数字融合,可以自己改。。。。数字从左往右的顺序都在numList里面,[0]为数,[1]为坐标,自己可以根据数字间的距离判断是否为一个数
    if(count == 2){
        int width = 0;   //两数字间的距离
        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()
{
    Init();//初始化,在pic中储存所有图片轮廓
    IplImage* img = cvLoadImage(testPic[0], CV_LOAD_IMAGE_GRAYSCALE);

    int travel = 1;//如果为0,识别中间数字,如果为1,识别右边数字.其他数字,全部识别
    if(travel == 0){
        CvRect ins;
        ins.x = 170;
        ins.y = 140;
        ins.width = 300;
        ins.height = 200;
        cvSetImageROI(img, ins);
    }
    if(travel == 1){
        CvRect ins;
        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);
    contours = GetImageContour(img, 1);//获取轮廓信息
    contoursTemp = contours;

    //对轮廓进行循环
    int count=0;   //数字轮廓个数
    int numList[100][2];  //一幅图像中的数字序列  一维是数字,二维是数字所在横坐标
    for(; contoursTemp != 0; contoursTemp = contoursTemp->h_next){
        //如果符合数字轮廓长度条件 保留并画出
        if(contoursTemp->total > n_min && contoursTemp->total < n_max){
            int 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);

                //计算矩形顶点
                CvPoint pt1,pt2;
                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(int i = 0; i < contoursTemp->total; 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);
    for(int i = 0; i < count; i++){
        printf("%d(%d)\t", numList[i][0], numList[i][1]);
    }

    cvNamedWindow("image", 1);
    cvShowImage("image", imgColor);

    cvNamedWindow("contours");
    cvShowImage("contours", contoursImage);

    cvWaitKey(5000);//停顿5秒钟
    cvResetImageROI(imgColor);
    cvResetImageROI(img);
    cvReleaseImage(&img);
    cvReleaseImage(&contoursImage);
    cvReleaseImage(&imgColor);
    return 0;
}

由于代码是从网上下载下来的,所以整理了一下发布出来。可以运行。

配置环境:VS2013  opencv3.0.0

缺点:识别率不高

源码下载地址:http://download.csdn.net/detail/sz76211822/8986931

时间: 2024-10-10 22:06:25

C++ opencv 数字识别的相关文章

手写数字识别【QT+OpenCV】

[说明] 手写数字识别的实现方式很多. 本文尽量将其简化,以让大家能够快速了解怎样实现一个动起来的系统. [截图] [思路] 1.特征提取 将图像划分为5*5大小的区域,然后计算该区域内黑色(或白色)的像素点所占比例. 将需要测试的图像.用来分类的图像都进行特征提取. 2.计算当前的测试图像与用来分类的图像之间的欧氏距离. 3.找出欧式距离最小的值即为与当前测试图像最匹配的图像,即将该图像所代表的数字作为当前测试图像的结果. 4.为了处理上的方便,做了简化处理如下: 4.1仅仅选用10幅用来分类

Java基于opencv实现图像数字识别(一)

Java基于opencv实现图像数字识别(一) 最近分到了一个任务,要做数字识别,我分配到的任务是把数字一个个的分开:当时一脸懵逼,直接百度java如何分割图片中的数字,然后就百度到了用BufferedImage这个类进行操作:尝试着做了一下,做到灰度化,和二值化就做不下去了:然后几乎就没有啥java的资料了,最多的好像都是c++,惹不起.惹不起...... 我也想尝试着用c++做一下,百度到了c++基于opencv来做图像识别的:但是要下vs啊,十几个g呢,我内存这么小,配置这么麻烦,而且vs

Java基于opencv实现图像数字识别(二)—基本流程

Java基于opencv实现图像数字识别(二)-基本流程 做一个项目之前呢,我们应该有一个总体把握,或者是进度条:来一步步的督促着我们来完成这个项目,在我们正式开始前呢,我们先讨论下流程. 我做的主要是表格中数字的识别,但这个不是重点.重点是通过这个我们可以举一反三,来实现我们自己的业务. 图像的识别主要分为两步:图片预处理和图像识别:这两步都很重要 图像预处理: 1. 图像灰度化:二值化 2. 图像降噪,去除干扰线 3. 图像腐蚀.膨胀处理 4. 字符分割 5. 字符归一化 图像识别: 1.

使用Caffe进行手写数字识别执行流程解析

之前在 http://blog.csdn.net/fengbingchun/article/details/50987185 中仿照Caffe中的examples实现对手写数字进行识别,这里详细介绍下其执行流程并精简了实现代码,使用Caffe对MNIST数据集进行train的文章可以参考  http://blog.csdn.net/fengbingchun/article/details/68065338 : 1.   先注册所有层,执行layer_factory.hpp中类LayerRegis

手把手教你搭建caffe及手写数字识别(全程命令提示、纯小白教程)

手把手教你搭建caffe及手写数字识别 作者:七月在线课程助教团队,骁哲.小蔡.李伟.July时间:二零一六年十一月九日交流:深度学习实战交流Q群 472899334,有问题可以加此群共同交流.另探究实验背后原理,请参看此课程:11月深度学习班. 一.前言 在前面的教程中,我们搭建了tensorflow.torch,教程发布后,大家的问题少了非常多.但另一大框架caffe的问题则也不少,加之caffe也是11月深度学习班要讲的三大框架之一,因此,我们再把caffe的搭建完整走一遍,手把手且全程命

opencv 验证码 识别

示例图片 :   主要应用原理为:1 1.先识别出图片中每个像素的数量   例如 红色在200左右 2.将红色的像素单独提出来  这样起到去除噪点的作用 3.分割图片并保存 4.识别图片 具体代码如下: 1 # coding=utf-8 2 # !/usr/bin/python 3 """ 4 opencv 验证码识别 5 Created on: 2018/7/31 16:12 6 @author: 虫子慢慢爬 7 Email: 891915210[email protect

使用AI算法进行手写数字识别

人工智能 ??人工智能(Artificial Intelligence,简称AI)一词最初是在1956年Dartmouth学会上提出的,从那以后,研究者们发展了众多理论和原理,人工智能的概念也随之扩展.由于人工智能的研究是高度技术性和专业的,各分支领域都是深入且各不相通的,因而涉及范围极广 . 人工智能的核心问题包括建构能够跟人类似甚至超越人类的推理.知识.学习.交流.感知.使用工具和操控机械的能力等,当前人工智能已经有了初步成果,甚至在一些影像识别.语言分析.棋类游戏等等单方面的能力达到了超越

【转】机器学习教程 十四-利用tensorflow做手写数字识别

模式识别领域应用机器学习的场景非常多,手写识别就是其中一种,最简单的数字识别是一个多类分类问题,我们借这个多类分类问题来介绍一下google最新开源的tensorflow框架,后面深度学习的内容都会基于tensorflow来介绍和演示 请尊重原创,转载请注明来源网站www.shareditor.com以及原始链接地址 什么是tensorflow tensor意思是张量,flow是流. 张量原本是力学里的术语,表示弹性介质中各点应力状态.在数学中,张量表示的是一种广义的"数量",0阶张量

BP神经网络(手写数字识别)

1实验环境 实验环境:CPU [email protected],内存8G,windows10 64位操作系统 实现语言:python 实验数据:Mnist数据集 程序使用的数据库是mnist手写数字数据库,数据库有两个版本,一个是别人做好的.mat格式,训练数据有60000条,每条是一个784维的向量,是一张28*28图片按从上到下从左到右向量化后的结果,60000条数据是随机的.测试数据有10000条.另一个版本是图片版的,按0~9把训练集和测试集分为10个文件夹.这里选取.mat格式的数据