0
点赞
收藏
分享

微信扫一扫

opencv c++单字符数字分类(HOG+SVM)

环境:win10+opencv3.4.4+C++

1、准备单字符数据,数字:

这里是生成数据,生成参考:https://blog.51cto.com/u_8681773/6004679

opencv c++单字符数字分类(HOG+SVM)_SVM

 

opencv c++单字符数字分类(HOG+SVM)_数字分类_02

 

2、使用脚本生成tran.txt和test.txt列表(注意文件编码格式utf-8):

opencv c++单字符数字分类(HOG+SVM)_opencv_03

 

opencv c++单字符数字分类(HOG+SVM)_HOG_04

import os
import cv2
import glob
import pathlib
import random

from os import listdir, getcwd

from os.path import join

# 将程序生成的数字数据整理到train.txt文件中,train.txt中的格式如下:D:\dataset\icdar2017rctw\recognition\train\image_0_0.jpg	金氏眼镜	Latin

# 图片路径
data_path = r'D:\datasets\gen_number_str_char_boxes\test'

# 写入到文件
trainfile = r'D:\datasets\gen_number_str_char_boxes\test.txt'

if __name__ == '__main__':

    file_list = glob.glob(data_path + '/*.jpg', recursive=True)

    train_file = open(trainfile, 'a', encoding='utf-8-sig')  # 带BOM的UTF-8格式
    for file_obj in file_list:
        file_path = os.path.join(data_path, file_obj)

        file_name, file_extend = os.path.splitext(file_obj)
        d = pathlib.Path(file_obj)
        imagename = str(d.stem)
        lineData = imagename.split('_')
        image_label = lineData[1]
        train_file.write(file_path + ' ' + image_label + '\n')

    train_file.close()

3、开始训练:

opencv c++单字符数字分类(HOG+SVM)_HOG_05

 

#include<iostream>
#include<opencv.hpp>
#include <string>
#include <fstream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/ml/ml.hpp>

//参考:https://www.cnblogs.com/xuanyuyt/p/6405944.html

using namespace std;
using namespace cv;

int main()
{
    vector<string> img_path;//输入文件名变量     
    vector<int> img_catg;
    int nLine = 0;
    string line;
    size_t pos;
    ifstream svm_data("./train.txt");//训练样本图片的路径都写在这个txt文件中,使用bat批处理文件可以得到这个txt文件       
    unsigned long n;
    while (svm_data)//将训练样本文件依次读取进来      
    {
        if (getline(svm_data, line))
        {
            nLine++;
            pos = line.find_last_of(' ');
            img_path.push_back(line.substr(0, pos));//图像路径      
            img_catg.push_back(atoi(line.substr(pos + 1).c_str()));//atoi将字符串转换成整型,标志(0,1,2,...,9),注意这里至少要有两个类别,否则会出错      
        }
    }

    svm_data.close();//关闭文件      
    int nImgNum = nLine; //nImgNum是样本数量,只有文本行数的一半,另一半是标签         
    cv::Mat data_mat(nImgNum, 324, CV_32FC1);//第二个参数,即矩阵的列是由下面的descriptors的大小决定的,可以由descriptors.size()得到,且对于不同大小的输入训练图片,这个值是不同的    
    data_mat.setTo(cv::Scalar(0));
    //类型矩阵,存储每个样本的类型标志      
    cv::Mat res_mat(nImgNum, 1, CV_32S);
    res_mat.setTo(cv::Scalar(0));
    cv::Mat src;
    cv::Mat trainImg(cv::Size(28, 28), 8, 3);//需要分析的图片,这里默认设定图片是28*28大小,所以上面定义了324,如果要更改图片大小,可以先用debug查看一下descriptors是多少,然后设定好再运行      

    //处理HOG特征    
    for (string::size_type i = 0; i != img_path.size(); i++)
    {
        src = cv::imread(img_path[i].c_str(), 1);
        if (src.data == NULL)//if (src == NULL)
        {
            cout << " can not load the image: " << img_path[i].c_str() << endl;
            continue;
        }

        //cout << " 处理: " << img_path[i].c_str() << endl;

        cv::resize(src, trainImg, trainImg.size());
        cv::HOGDescriptor* hog = new cv::HOGDescriptor(cv::Size(28, 28), cv::Size(14, 14), cv::Size(7, 7), cv::Size(7, 7), 9);
        vector<float>descriptors;//存放结果       
        hog->compute(trainImg, descriptors, cv::Size(1, 1), cv::Size(0, 0)); //Hog特征计算        
        //cout << "HOG dims: " << descriptors.size() << endl;
        n = 0;
        for (vector<float>::iterator iter = descriptors.begin(); iter != descriptors.end(); iter++)
        {
            //cvmSet(data_mat, i, n, *iter);
            data_mat.at<float>(i, n) = *iter;//存储HOG特征  
            n++;
        }
        //cvmSet(res_mat, i, 0, img_catg[i]);
        res_mat.at<int>(i, 0) = img_catg[i];
        //cout << " 处理完毕: " << img_path[i].c_str() << " " << img_catg[i] << endl;
    }
    cout << "computed features!" << endl;

    cv::Ptr<cv::ml::SVM> svm = cv::ml::SVM::create();//新建一个SVM        
    svm->setType(cv::ml::SVM::C_SVC);
    svm->setKernel(cv::ml::SVM::LINEAR);
    svm->setC(1);
    //-------------------不使用参数优化-------------------------//
    svm->setTermCriteria(cv::TermCriteria(CV_TERMCRIT_EPS, 1000, FLT_EPSILON));
    svm->train(data_mat, cv::ml::ROW_SAMPLE, res_mat);//训练数据   
    //-------------------参数优化-------------------------//
    //svm->setTermCriteria = cv::TermCriteria(cv::TermCriteria::MAX_ITER, (int)1e7, 1e-6);
    //cv::Ptr<cv::ml::TrainData> td = cv::ml::TrainData::create(data_mat, cv::ml::ROW_SAMPLE, res_mat);
    //svm->trainAuto(td, 10);

    //保存训练好的分类器        
    svm->save("HOG_SVM_DATA.xml");
    cout << "saved model!" << endl;
    //检测样本      
    cv::Mat test;//IplImage *test;
    char result[512];
    vector<string> img_test_path;
    vector<int> img_test_catg;
    int coorect = 0;
    ifstream img_tst("./test.txt");  //加载需要预测的图片集合,这个文本里存放的是图片全路径,不要标签  
    while (img_tst)
    {
        if (getline(img_tst, line))
        {
            pos = line.find_last_of(' ');
            img_test_catg.push_back(atoi(line.substr(pos + 1).c_str()));//atoi将字符串转换成整型,标志(0,1,2,...,9),注意这里至少要有两个类别,否则会出错      
            img_test_path.push_back(line.substr(0, pos));//图像路径      
        }
    }
    img_tst.close();

    ofstream predict_txt("SVM_PREDICT.txt");//把预测结果存储在这个文本中     
    for (string::size_type j = 0; j != img_test_path.size(); j++)//依次遍历所有的待检测图片      
    {
        test = cv::imread(img_test_path[j].c_str(), 1);
        if (test.data == NULL)//test == NULL
        {
            cout << " can not load the image: " << img_test_path[j].c_str() << endl;
            continue;
        }
        cv::Mat trainTempImg(cv::Size(28, 28), 8, 3);
        trainTempImg.setTo(cv::Scalar(0));
        cv::resize(test, trainTempImg, trainTempImg.size());
        cv::HOGDescriptor* hog = new cv::HOGDescriptor(cv::Size(28, 28), cv::Size(14, 14), cv::Size(7, 7), cv::Size(7, 7), 9);
        vector<float>descriptors;//结果数组         
        hog->compute(trainTempImg, descriptors, cv::Size(1, 1), cv::Size(0, 0));
        //cout << "HOG dims: " << descriptors.size() << endl;
        cv::Mat SVMtrainMat(1, descriptors.size(), CV_32FC1);
        int n = 0;
        for (vector<float>::iterator iter = descriptors.begin(); iter != descriptors.end(); iter++)
        {
            SVMtrainMat.at<float>(0, n) = *iter;
            n++;
        }

        int ret = svm->predict(SVMtrainMat);//检测结果  
        if (ret == img_test_catg[j])
            coorect++;
        sprintf(result, "%s  %d\r\n", img_test_path[j].c_str(), ret);
        predict_txt << result;  //输出检测结果到文本  
    }
    predict_txt.close();
    cout << coorect * 100.0 / img_test_path.size() << "%" << endl;
    return 0;
}

4、开始测试:

opencv c++单字符数字分类(HOG+SVM)_HOG_06

 

#include<iostream>
#include<opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/ml/ml.hpp>

using namespace std;
using namespace cv;

using namespace cv::ml;

int main(int argc, char* argv[])
{
    cv::Ptr<cv::ml::SVM> svm = cv::ml::SVM::create();
    svm = cv::ml::SVM::load("HOG_SVM_DATA.xml");;//加载训练好的xml文件,这里训练的是10K个手写数字  
    //检测样本      
    cv::Mat test;
    char result[300]; //存放预测结果   
    test = cv::imread("./img/100293_3_2895.jpg", 1); //待预测图片,用系统自带的画图工具随便手写  
    if (!test.data)
    {
        return -1;
    }
    cv::Mat trainTempImg(cv::Size(28, 28), 8, 3);
    trainTempImg.setTo(cv::Scalar(0));
    cv::resize(test, trainTempImg, trainTempImg.size());
    cv::HOGDescriptor* hog = new cv::HOGDescriptor(cv::Size(28, 28), cv::Size(14, 14), cv::Size(7, 7), cv::Size(7, 7), 9);
    vector<float>descriptors;//结果数组         
    hog->compute(trainTempImg, descriptors, cv::Size(1, 1), cv::Size(0, 0));
    //cout << "HOG dims: " << descriptors.size() << endl;
    cv::Mat SVMtrainMat(1, descriptors.size(), CV_32FC1);
    int n = 0;
    for (vector<float>::iterator iter = descriptors.begin(); iter != descriptors.end(); iter++)
    {
        SVMtrainMat.at<float>(0, n) = *iter;
        n++;
    }
    int ret = svm->predict(SVMtrainMat);//检测结果  
    cout << ret << endl;
    cv::Mat svm_result;
    svm->predict(SVMtrainMat, svm_result, cv::ml::StatModel::Flags::RAW_OUTPUT);
    float dist = svm_result.at<float>(0, 0);
    float confidence = (1.0 / (1.0 + exp(-dist)));
    return 0;
}

举报

相关推荐

PTA乙级-1012 数字分类 c++

0 条评论