zoukankan      html  css  js  c++  java
  • OpenCV——识别手写体数字

    这个是树莓派上运行的, opencv3

    opencv提供了一张手写数字图片给我们,如下图所示,可以作为识别手写数字的样本库。

    0到9共十个数字,每个数字有五行,一行100个数字。首先要把这5000个数字截取出来。

    图片大小为1000*2000,则每个数字块大小为20*20。

    1.截取样本并存储

    以下代码为截取以上数字并将其存储在矩阵中的过程

    训练的数据,一般都会是两个矩阵,一个矩阵存放着数据图像,另一个矩阵存放数据图像对应的数字

     Mat src = imread("sample.png");
        Mat grayImage;
        cvtColor(src, grayImage, CV_BGR2GRAY);
        threshold(grayImage, grayImage, 48, 255, CV_THRESH_BINARY);
        int p = 20;                                         //一个数字大小为20*20
        int m = grayImage.rows / p;          //横行的数字个数m
        int n  = grayImage.cols / p;            //纵列的数字个数n 
        Mat data, labels;                              //data存放样本数据,label为data样本所对应的数字
    
        for( int i = 0; i < n; i++){
            int y = i * p;                                   //纵列第i个数字开始的位置
            for(int j = 0; j < m; j++){
                int x = j * p;                               //横行第i个数字开始的位置
                Mat dst;
                grayImage(Range(x,x + p), Range(y, y + p)).copyTo(dst);
                
                data.push_back(dst.reshape(0,1));         //将20*20大小矩阵变为1*400 向量
                labels.push_back( j / 5);                           //对应数据向量存储的数字
            }
        }
    
        data.convertTo(data, CV_32F);                       //改变像素的数据类型为浮点型
        Mat trainData, trainLabels; 
        trainData = data(Range(0, 5000), Range::all()); 
        trainLabels = labels(Range(0, 5000), Range::all());


    2.处理待识别数字的图像

    //处理代检测图像
        Mat Image, dst;
        Image = imread("6.png");
        cvtColor(Image, Image, COLOR_BGR2GRAY);
        threshold(Image, Image, 48, 255, CV_THRESH_BINARY_INV);
        imshow("Image", Image);
        Image.copyTo(dst);
        vector< vector<Point> > contours;
        vector<Vec4i> hierarchy; 
        findContours(Image,contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
        vector<Point> point = contours[0];
        Rect rect = boundingRect(point);
        int x = rect.x, y = rect.y;
        int h=rect.height, w = rect.width;
       Mat now = dst(Range(x, x+h-1), Range(y, y+w-1));
        //dst(rect).copyTo(now);
        resize(now,now,Size(20,20));


    3.使用knn算法进行识别,要将识别的图像也进行像训练样本一样的处理

    我在运行程序时,一直有如下的错误,换了好几种处理图片的方式,仍然没有用 

    Mat_<float>  nums;
        nums  = now.reshape(0,1);
        nums.convertTo(nums, CV_32F);
        imshow("待测图像", now);
       /* Mat mm;
         mm.push_back(now.reshape(0,1));
         mm.convertTo(mm,CV_32F);
         Mat nums = mm(Range(0,1),Range::all());
         /*float imagedata[20*20];
         for(int i =0; i < 20; i++){
           for(int j=0;j<20;j++){
                          imagedata[ i *20 +j] = now.data[i *20+j];
             }
       }  
       Mat nums(1,20*20, CV_32F, imagedata);*/

    最后查看源代码才发现不是其他参数的问题:

    ///  错误 knn->findNearest(nums, 1, Mat());
    
    Mat temp;
    knn->findNearest(nums, 1, temp);
    //要传入一个具体的Mat类型

    最后的识别代码为

    //创建knn分类器
        Ptr<ml::KNearest>  knn = (ml::KNearest::create()); 
        knn->setIsClassifier(true);
        Ptr<ml::TrainData> tData = ml::TrainData::create(trainData,ml::ROW_SAMPLE, trainLabels);
        knn->train(tData);
        Mat temp;
        float result = knn->findNearest(nums, 1, temp);
        
        cout << result<<endl;

    检查了好多遍,也只是不能识别出所有

    程序缺陷:待检测的图像处理问题。不能截取出合适的roi区域

    再改进吧。

  • 相关阅读:
    LIKE语句也可以这样写
    a链接触发javascript函数导致innerHTML里的图片无法加载
    引用类型真屌
    网站建设心得
    SPAN
    Go! 环境配置和入门
    linux内核编译
    面试题
    KCMT开源控件之方便简洁的分页控件
    c#中out、ref和params的用法与区别
  • 原文地址:https://www.cnblogs.com/farewell-farewell/p/5911050.html
Copyright © 2011-2022 走看看