zoukankan      html  css  js  c++  java
  • C++ opencv 识别数字编号

    利用opencv的KNN识别数字,可以用在很多编码扫描上。第一次写c++ 边试边写的 很糙

    结果:

      

    效果还可以 但是对裁剪的准确性要求较高。

    需要配置好opencv的环境

    step 1 :切分训练数据

    int split_data()
    {
        Mat src, dst;
        src = imread("D:/Works/KNN-letters/my.png");
        if (src.empty())
        {
            std::cout << "can not load image 
    " << std::endl;
            return -1;
        }
        imshow("input", src);
        dst = src.clone();
        cvtColor(src, src, COLOR_BGR2GRAY);
        Mat bin = src.clone();
        Mat ROI = src(Rect(0, 0, src.size().width, src.size().height));
        blur(ROI, ROI, Size(5, 5));
        imshow("blur", ROI);
        threshold(ROI, ROI, 220, 255, THRESH_BINARY);
        Canny(ROI, ROI, 20, 80, 3, false);
    
        std::vector<std::vector<Point>> contours;
        std::vector<Vec4i>hierarchy;
        imshow("ROI", ROI);
    
        findContours(ROI, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
        std::cout << contours.size() << std::endl;
        RNG rng(0);
    
        std::vector<RotatedRect> minRects(contours.size());
        std::vector<float> height, width;
        for (int i = 0; i < contours.size(); i++)
        {
            Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
            Rect rect = boundingRect(contours[i]);
            height.push_back(rect.height);
            width.push_back(rect.width);
        }
        //获取字符外接矩形宽高的最大值
        std::vector<float>::iterator h = std::max_element(std::begin(height), std::end(height));
        std::vector<float>::iterator w = std::max_element(std::begin(width), std::end(width));
        //获得轮廓的外接矩形
        std::vector<Rect>rects;
        //将轮廓外接矩形按纵坐标排序
        std::vector<float>sequence;
    
        for (int i = 0; i < contours.size(); i++)
        {
            Scalar color = Scalar(0, rng.uniform(0, 255), rng.uniform(0, 255));
            Rect rect = boundingRect(contours[i]);
            Rect reRect = Rect(Point(rect.x + rect.width / 2.0 - *w / 2.0, rect.y + rect.height / 2.0 - *h / 2.0 ), Point(rect.x + rect.width / 2.0 + *w / 2.0, rect.y + rect.height / 2.0 + *h / 2.0));
            rectangle(dst, reRect, color, 2);
            rects.push_back(reRect);
            sequence.push_back(reRect.y);
        }
        //按纵坐标排序
        sort(sequence.begin(), sequence.end());
        
        threshold(bin, bin, 0, 255, THRESH_BINARY | THRESH_OTSU);
        std::cout << rects.size() << std::endl; 
        int n = 0;
        for (int i = 0; i < rects.size(); i++)
        {
            for (int j = 0; j < 10; j++)
            {
                std::string outPath = "D:/Works/KNN-letters/letters3/";
                char label = '0';
                char temp[256];
                if ((rects[i].y > sequence[j * 6] - *h / 2.0) && (rects[i].y < sequence[j * 6] + *h / 2.0))
                {
                    label = label + j;
                    sprintf_s(temp, "%d", n);
                    outPath = outPath + label + "/" + temp + ".jpg";
                    std::cout << outPath << std::endl;
                    //imwrite(outPath, bin(rects[i]));
                    n++;
                }
            }
        }
        imshow("output", dst);
        waitKey();
    
        waitKey();
        return 0;
    }

    注意分类文件夹寻妖自己创建

       

    step 2 训练KNN 

    int trian_my2()
    {    
        //split_data();
        ////===============================读取训练数据===============================////
        //图片共有10类
        const int classSum = 10;
        //每类共50张图片
        const int imagesSum = 6;
        //图片尺寸
        const int imageRows = 17;
        const int imageCols = 12;
        //每一行一个训练图片
        float trainingData[classSum * imagesSum][imageRows * imageCols] = { {0} };
        //训练样本标签
        float labels[classSum * imagesSum] = { 0 };
    
        for (int i = 0; i < classSum; i++)
        {
            //目标文件夹路径
            std::string inPath = "D:/Works/KNN-letters/letters3/";
            char label = '0';
            int k = 0;
            label = label + i;
            inPath = inPath + label + "/*.jpg";
            std::cout << inPath << std::endl;
            //用于查找的句柄
            _int64 handle;
            struct _finddata_t fileinfo;
            int r;
            //第一次查找
            handle = _findfirst(inPath.c_str(), &fileinfo);
            if (handle == -1)
                return -1;
            do
            {
                //找到的文件的文件名
                std::string imgname = "D:/Works/KNN-letters/letters3/";
                imgname = imgname + label + "/" + fileinfo.name;
                std::cout<<imgname<<std::endl;
                Mat src = imread(imgname, 0);
                if (src.empty())
                {
                    std::cout << "can not load image 
    " << std::endl;
                    return -1;
                }
                //序列化后放入作为样本矩阵的一行
                for (int j = 0; j < imageRows * imageCols; j++)
                {
                    trainingData[i * imagesSum + k][j] = (float)src.data[j];
                }
                // 设置样本标签 
                labels[i * imagesSum + k] = label;
                k++;
                std::cout << label << std::endl;
            } while (!_findnext(handle, &fileinfo));
            _findclose(handle);
            
        }
        Mat trainingDataMat(classSum * imagesSum, imageRows * imageCols, CV_32FC1, trainingData);
        Mat labelsMat(classSum * imagesSum, 1, CV_32FC1, labels);
        //std::cout<<trainingDataMat<<std::endl;
        //std::cout<<labelsMat<<std::endl;
    
        ////===============================创建KNN模型===============================////
        Ptr<ml::KNearest> model = ml::KNearest::create();
    
        model->setDefaultK(3);
        model->setIsClassifier(true);
        Ptr<TrainData>trainData = TrainData::create(trainingDataMat, ROW_SAMPLE, labelsMat);
    
        model->train(trainData);
    
        model->save("D:/Works/KNN-letters/KNN_NUM.xml"); 
        ////===============================预测部分===============================////
        
        //Ptr<ml::KNearest> model = StatModel::load<KNearest>("D:/Works/KNN-letters/KNN_NUM.xml");
        Mat src, dst;
        src = imread("D:/Works/KNN-letters/my.png");
        if (src.empty())
        {
            std::cout << "can not load image 
    " << std::endl;
            return -1;
        }
        dst = src.clone();
        //创建感兴趣区域,选取右侧10列作为预测数据
        cvtColor(src, src, COLOR_BGR2GRAY);
        blur(src, src, Size(5, 5));
        threshold(src, src, 230, 255, THRESH_BINARY);
        Canny(src, src, 20, 80, 3, false);
        std::vector<std::vector<Point>> contours;
        std::vector<Vec4i>hierarchy;
        findContours(src, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
    
        for (int i = 0; i < contours.size(); i++)
        {
            Rect rect = boundingRect(contours[i]);
            //以矩形中心及指定的宽高作为字符区域
            Rect reRect = Rect(Point(rect.x + rect.width / 2.0 - imageCols / 2.0, rect.y + rect.height / 2.0 - imageRows / 2.0), Point(rect.x + rect.width / 2.0 + imageCols / 2.0, rect.y + rect.height / 2.0 + imageRows / 2.0));
            Mat sampleImg;
            cvtColor(dst, sampleImg, COLOR_BGR2GRAY);
            threshold(sampleImg, sampleImg, 0, 255, THRESH_BINARY | THRESH_OTSU);
            Mat sample = Mat::zeros(Size(imageCols, imageRows), sampleImg.type());
    
            float sampleData[imageRows * imageCols];
            int nub = 0;
            for (int r = 0; r < imageRows; r++)
            {
                for (int c = 0; c < imageCols; c++)
                {
                    sampleData[nub] = sampleImg.at<uchar>(reRect.y + r, reRect.x + c);
                    nub++;
                }
            }
    
            Mat sampleDataMat(1, imageRows * imageCols, CV_32FC1, sampleData);
            char f;
            f = model->predict(sampleDataMat);
            char temp[256];
            sprintf_s(temp, "%c", f);
            std::cout << temp << "
    " << std::endl;
            std::string text(temp);
            RNG rng(f);
            Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
            putText(dst, text, Point(reRect.x, reRect.y + reRect.height), 1, 1.5, color, 2);
        }
        imshow("output", dst);
        waitKey();
        return 0;
    }

    代码粘贴下去可以直接使用;

  • 相关阅读:
    HttpWebRequest 的一个 异步封装
    AcWing 6 多重背包问题III【单调对列优化】
    AcWing 8. 二维费用的背包问题
    AcWing 1019. 庆功会
    P1421 小玉买文具
    P5709 【深基2.习6】Apples Prologue / 苹果和虫子
    P2181 对角线
    AcWing 1020. 潜水员
    AcWing 1013. 机器分配【分组背包+求方案数】
    AcWing 7. 混合背包问题
  • 原文地址:https://www.cnblogs.com/luofeel/p/12857247.html
Copyright © 2011-2022 走看看