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;
    }

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

  • 相关阅读:
    HDU 4024 Dwarven Sniper’s hunting(数学公式 或者是二分)
    二分图最大匹配总结
    HDU 4022 Bombing (STL应用)
    HDU 1847 Good Luck in CET4 Everybody!(组合博弈)
    HDU 1556 Color the ball(树状数组)
    HDU 4023 Game(博弈)
    HDU 1406 完数(水题)
    HDU 4021 24 Puzzle
    Oracle 多表查询优化
    【编程之美】字符串移位包含的问题(续)
  • 原文地址:https://www.cnblogs.com/luofeel/p/12857247.html
Copyright © 2011-2022 走看看