基于OpenCV简易的数字识别

思路:

识别的方法是获取一张测试图通过滤波,阈值分割前景与背景,边缘检测,查找轮廓,定位出数字,提取数字,由于提取的数字大小尺寸不一样且我们需要将图片的分割成5*5分块来计算欧氏距离,所以笔者统一将数字大小的尺寸规定为(250*250)然后通过计算获取的图片与样本图片进行欧氏距离计算,从而算出欧式距离最小该样本为其识别结果。

识别操作就是:

将提取的数字大小的尺寸重新定义其尺寸(250*250)后,将其分成5*5子块,则每一个子块占的像素点为:(250/5)*(250/5)= 2500个像素 然后计算每一个子块的所有像素值相加除于总的橡树点。例如计算某一个有2500个橡树的子块有1000个像素值为255 则该子块的所有的像素值相加为 255 * 1000 / 2500 为其分块的特征值。然后与样本的对应的分块进行欧式距离计算

\sqrt{(x-x0)*(x-x0))}  得到欧式距离 与所有样本计算欧式距离,则最小的欧式距离为其识别结果

#include <opencv2/opencv.hpp>
#include <iostream>
#include<sstream>
#define N 5

using namespace cv;
using namespace std;

Mat testImage;

float getDistance(float a[N*N], float b[N*N])
{
    int i;
    float distance = 0;
    for (i = 0; i < N*N; i++)
    {
        distance += (a[i] - b[i]) * (a[i] - b[i]);
    }
    return distance;
}
void getNumberFeature(Mat image, float a[N*N])
{    
    Mat temp = image.clone();

    cvtColor(temp, temp, COLOR_RGB2GRAY);
    blur(temp, temp, Size(3, 3));
    threshold(temp, temp, 0, 255, THRESH_OTSU);
    Canny(temp, temp, 3, 9, 3, true);

    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(temp, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE);

    vector<vector<Point>> contours_poly(contours.size());

    Mat temp_temp;
    //其实contours.size() == 1 因为单个数字不包括10
    for (int i = 0; i < contours.size(); i++)
    {
        approxPolyDP(contours[i], contours_poly[i], 3, false);
        Rect ROI;
        ROI = boundingRect(Mat(contours_poly[i]));
        temp_temp.create(Size(ROI.width,ROI.height),temp.type());
        temp(ROI).copyTo(temp_temp);
    }
    
    
    resize(temp_temp, temp_temp, Size(250, 250));
    imshow("temp_temp", temp_temp);

    int W, H;
    W = 250;
    H = 250;

    for (int i = 0; i < N*N; i++)
        a[i] = (float)0;

    for (int i = 0; i < W; i++)
        for (int j = 0; j < H; j++)
        {
            if (int(temp_temp.at<uchar>(j, i)) == 255)
            {
                //    printf("(%d,%d) = %d\n",j,i, (i / (W / 5) + j / (H / 5) * N) );
                //    if (i / (W / 5) + j / (H / 5) * N > 25)
                //    cout << "fail Erroe!" << endl;
                a[i / (W / N) + j / (H / N) * N]++;
            }
        }
    /******************************************/

    for (int i = 0; i < N*N; i++)
    {
        a[i] = a[i] / ((W / N) * (H / N));
    }
    

}
int getResultNumber()
{
    int i;
    float min;
    int Number;

    if (testImage.empty())
    {
        cout << "fail to read the test's Image!" << endl;
        return false;
    }

    float testFeature[N*N];;
    getNumberFeature(testImage, testFeature);

    Mat srcImage[9];
    float srcFeature[9][N*N];

    /*************************读取模板图*****************************/
    for (i = 0; i < 9; i++)
    {
        String filePath, fileName, allName;
        filePath = "D:/detectNumber";
        fileName = ".png";
        //  i+1  //
        allName = filePath + "/" + format("%d", i + 1) + fileName;
        srcImage[i] = imread(allName);
        if (srcImage[i].empty())
        {
            printf("fail to read the the %d testImage!", i);
            return false;
        }
    }
    /*****************************************************************/

    /*************************测试读取模板图是否成功*********************/
    //    for (int i = 0; i < 10; i++)
    //    {
    //        if (srcImage[i].empty())
    //        {
    //            printf("fail to read the %d testImage!", i);
    //            return false;
    //        }
    //    }
    /*****************************************************************/

    for (i = 0; i < 9; i++)
    {
        getNumberFeature(srcImage[i], srcFeature[i]);
    }

    float allDistanceValue[10] = { 0 };
    /*****************************匹配操作*****************************/
    for (i = 0; i < 9; i++)
    {
        allDistanceValue[i] = getDistance(testFeature, srcFeature[i]);
    }
    /******************************************************************/

    Number = 0;
    min = allDistanceValue[0];

    for (i = 0; i < 9; i++)
    {
        if (min > allDistanceValue[i])
        {
            min = allDistanceValue[i];
            Number = i;
        }
    }
    for (i = 0; i < 9; i++)
    {
        printf("Distance[%d] = %f\n", i + 1, allDistanceValue[i]);
    }
    return Number + 1;
}
// 数字转字符串操作
string IntToStrig(int number)
{
    ostringstream os;
    os << number;
    return os.str();
}

int main()
{

    testImage = imread("D:/detectNumber/test.png");
    int RusultNumber = getResultNumber();
    /********************************************************图上标注操作********************************************************/
    String Text;
    Text = "detect Number:" + IntToStrig(RusultNumber);

    Size TextSize;
    int fontFace = FONT_HERSHEY_SIMPLEX;
    double fontScale = 1;
    int thickness = 1;
    int LineType = LINE_4;
    TextSize = getTextSize(Text, fontFace, fontScale, thickness, int());
    putText(testImage, Text, Point(0, TextSize.height), fontFace, fontScale, Scalar(0, 0, 255), thickness, LineType, false);
    /**************************************************************************************************************************/
    imshow("数字识别操作", testImage);
    waitKey(0);
}

效果图:

存在的问题:

①.由于数字样本图片少,不同的数字图片有可能会出现识别错误.

 ②.局限性在于不能检测到"数字十"

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沉默羔羊_GUET

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值