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區域

 

再改進吧。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM