OpenCV数字识别

  熟悉OpenCV的朋友都知道OpenCV可以用来识别很多东西,今天我们就以基本的数字识别来探索OpenCV的识别之路。

大致的步骤如下:

(1)首先要加载一幅含有数字的图片,并对它进行二值化。

(2)寻找数字的大致轮廓。

(3)对找到的数字轮廓按照输入图片的顺序进行排序。

(4)根据上一步找到的顺序对数字轮廓进行分割,将单个数字轮廓提取出来。

(5)模板匹配

1、图片二值化处理

输入一幅图片并进行二值化处理,方便下一步找到轮廓。

Mat srcImage=imread("E://pictured//photo.jpg");

imshow(''原图",srcImage);

Mat grayImage,binImage;

cvtColor(srcImage,grayImage,COLOR_BGR2GRAY);

threshold(grayImage,binImage,100,255,CV_THRESH_BINARY_INV);//这个CV_THRESH_BINARY_INV参数的选择是根据输入图片的数字颜色和背景颜色决定的。

2、寻找数字的轮廓

    Mat conImage = Mat::zeros(binImage.size(), binImage.type());//寻找轮廓,必须指定为寻找外部轮廓。目的是为了限定一个数字只有一个轮廓。

    vector> contours;

    vector hierarchy;

    findContours(binImage, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);//指定CV_RETR_EXTERNAL寻找数字的外轮廓

    drawContours(conImage, contours, -1, 255);//绘制轮廓

3、对找到的轮廓进行排序

(1)定义一个新的Rect类,存放轮廓的外接矩形方便接下来的排序

class Rect

 {

  public:  

            Rect(){}  

            ~Rect(){}  

            Rect(Rect &temp):Rc(temp){}    //比较矩形左上角的横坐标,以便排序  

            bool operator<(Rect &rect)  

         {    

          if (this->Rc.x < rect.Rc.x)     

         {      

            return true;  

         }     

         else      

      {     

            return false;        

      }  

    }    //重载赋值运算符  

     Rect operator=(Rect &rect)  

   {      

      this->Rc = rect.Rc;      

      return *this;  

  }    //获取矩形  

   Rect getRect()  

  {    

     return Rc;  

  }

  private:    Rect Rc;//存放矩形

};

(2)冒泡排序法

   for (int  i = 0; i < sort_rect.size(); i++)  //对矩形进行排序找到数字的排列顺序

 {      

       for (int j = i + 1; j < sort_rect.size(); j++)      

   {          

       if (sort_rect[j] < sort_rect[i])         

      {          

            Rect temp = sort_rect[j];    

            sort_rect[j] = sort_rect[i];     

            sort_rect[i] = temp;     

       }  

    }  

 }

4、初始化数字模板

   for (int i = 0; i < 10; i++)  

 {        

     Mat ROI = conImage(sort_rect[i].getRect());    

     Mat dstROI;      

     resize(ROI, dstROI, Size(40, 50),0, 0, INTER_NEAREST);     

     char name[64];     

     sprintf(name, "E;//pictured//%d.jpg", i);       dstROI);  

     imwrite(name, dstROI);  

 }

5、数字分割  

   vector myROI;   //按顺序取出和分割数字    

   for (int i = 0; i < sort_rect.size(); i++)  

  {        

    Mat ROI;     

    ROI = conImage(sort_rect[i].getRect());    

    Mat dstROI = Mat::zeros(myTemplate[0].size(),myTemplate[0].type());        

    resize(ROI, dstROI, myTemplate[0].size(), 0, 0, INTER_NEAREST);        

    myROI.push_back(dstROI); 

   }

6、模板匹配

(1)首先进行比较,使用adsdiff计算模板和待识别数字的差值,差值最小的即为最匹配的数字,

int getPiexSum(Mat &image)//求图片的像素和

{  

     int sum = 0; 

    for (int i = 0; i < image.cols; i++) 

   {     

        for (int j = 0; j < image.rows; j++)    

       {         

          sum += image.at(j, i);     

       } 

   }  

        return sum;

}

(2)匹配结果并输出   

vector seq;//顺序存放识别结果    

for (int i = 0; i < myROI.size(); i++)  

 {        

   Mat subImage;      

   int sum = 0;      

   int min = 100000;      

   int min_seq = 0;//记录最小的和对应的数字      

 for (int j = 0; j < 10; j++)  

     {                     

        absdiff(myROI[i], myTemplate[j], subImage);   //计算两个图片的差值    

        sum = getPiexSum(subImage);      

       if (sum < min)         

     {            

        min = sum;          

        min_seq = j;      

     }         

       sum = 0;     

   }        

       seq.push_back(min_seq); 

   }     //输出结果 

     cout << "识别结果为:";  

    for (int i = 0; i < seq.size(); i++) 

    {        

       cout << seq[i]; 

   }    

       cout << endl;
 

  存在的问题与不足:发现有很多影响准确率的因素,例如数字颜色与背景颜色,要识别的字体的大小与控制台输出字体大小的差异。


 


 

 


 

 

 

 

 
 

 

 

你可能感兴趣的:(OpenCV数字识别)