数字识别

#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <string>
#include <io.h>
#include <vector>
#include <iostream>
#include <fstream>
using namespace cv;
using namespace std;


//author  dedong
//机器学习实战   矩阵运算问题

/************************************************************************/
/*  获取文件夹下所有文件名
输入:
path    :   文件夹路径
exd     :   所要获取的文件名后缀,如jpg、png等;如果希望获取所有
文件名, exd = ""
输出:
files   :   获取的文件名列表
*/
/************************************************************************/
void getFiles(string path, string exd, vector<string>& files)
{
    //文件句柄
    long   hFile = 0;
    //文件信息
    struct _finddata_t fileinfo;
    string pathName, exdName;

    if (0 != strcmp(exd.c_str(), ""))
    {
        exdName = "\\*." + exd;
    }
    else
    {
        exdName = "\\*";
    }

    if ((hFile = _findfirst(pathName.assign(path).append(exdName).c_str(), &fileinfo)) != -1)
    {
        do
        {
            //如果是文件夹中仍有文件夹,迭代之
            //如果不是,加入列表
            if ((fileinfo.attrib &  _A_SUBDIR))
            {
                if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
                    getFiles(pathName.assign(path).append("\\").append(fileinfo.name), exd, files);
            }
            else
            {
                if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
                    files.push_back(pathName.assign(path).append("\\").append(fileinfo.name));
            }
        } while (_findnext(hFile, &fileinfo) == 0);
        _findclose(hFile);
    }
}

//字符串分割
void SplitString(const string& s, vector<string>& v, const string& c)
{
    string::size_type pos1, pos2;
    pos2 = s.find(c);
    pos1 = 0;
    while (string::npos != pos2)
    {
        v.push_back(s.substr(pos1, pos2 - pos1));

        pos1 = pos2 + c.size();
        pos2 = s.find(c, pos1);
    }
    if (pos1 != s.length())
        v.push_back(s.substr(pos1));
}

vector<string> split(const string &s, const string &seperator){
    vector<string> result;
    typedef string::size_type string_size;
    string_size i = 0;

    while (i != s.size()){
        //找到字符串中首个不等于分隔符的字母;
        int flag = 0;
        while (i != s.size() && flag == 0){
            flag = 1;
            for (string_size x = 0; x < seperator.size(); ++x)
            if (s[i] == seperator[x]){
                ++i;
                flag = 0;
                break;
            }
        }

        //找到又一个分隔符,将两个分隔符之间的字符串取出;
        flag = 0;
        string_size j = i;
        while (j != s.size() && flag == 0){
            for (string_size x = 0; x < seperator.size(); ++x)
            if (s[j] == seperator[x]){
                flag = 1;
                break;
            }
            if (flag == 0)
                ++j;
        }
        if (i != j){
            result.push_back(s.substr(i, j - i));
            i = j;
        }
    }
    return result;
}

//读取txt数据
void getFromText(String pathStr, Mat &myMat, uchar *pCurrentFace)
{
    ifstream myFaceFile;
    myFaceFile.open(pathStr, ios::in);
    int temp;
    for (int r = 0; r < 1024; r++)
    {
        myFaceFile >> temp;
        pCurrentFace[r] = (uchar)temp;
    }

    for (int i = 0; i < 32; i++)
    {
        uchar *pixelPtr = myMat.ptr<uchar>(i);
        for (int j = 0; j < 32; j++)
        {
            pixelPtr[j] = pCurrentFace[i*j + j];
        }
    }
    myFaceFile.close();
}

/*----------------------------
* 功能 : 从 .txt 文件中读入数据,保存到 cv::Mat 矩阵
*      - 默认按 float 格式读入数据,
*      - 如果没有指定矩阵的行、列和通道数,则输出的矩阵是单通道、N 行 1 列的
*----------------------------
* 函数 : LoadData
* 访问 : public
* 返回 : -1:打开文件失败;0:按设定的矩阵参数读取数据成功;1:按默认的矩阵参数读取数据
*
* 参数 : fileName    [in]    文件名
* 参数 : matData [out]   矩阵数据
* 参数 : matRows [in]    矩阵行数,默认为 0
* 参数 : matCols [in]    矩阵列数,默认为 0
* 参数 : matChns [in]    矩阵通道数,默认为 0
*/
int LoadData(string fileName, cv::Mat& matData, int matRows = 0, int matCols = 0, int matChns = 0)
{
    int retVal = 0;
    //ifstream myFaceFile;
    //myFaceFile.open(pathStr, ios::in);
    // 打开文件  
    ifstream inFile(fileName.c_str(), ios_base::in);
    //ifstream inFile;
    //inFile.open(fileName.c_str(), ios::in);
    if (!inFile.is_open())
    {
        cout << "读取文件失败" << endl;
        retVal = -1;
        return (retVal);
    }

    // 载入数据  
    istream_iterator<float> begin(inFile);    //按 float 格式取文件数据流的起始指针  
    istream_iterator<float> end;          //取文件流的终止位置  
    vector<float> inData(begin, end);      //将文件数据保存至 std::vector 中  
    cv::Mat tmpMat = cv::Mat(inData);       //将数据由 std::vector 转换为 cv::Mat  
    cout << inData.at(0) << endl;
    // 输出到命令行窗口  
    //copy(vec.begin(),vec.end(),ostream_iterator<double>(cout,"\t"));   

    // 检查设定的矩阵尺寸和通道数  
    size_t dataLength = inData.size();   //32
    //1.通道数  
    if (matChns == 0)
    {
        matChns = 1;
    }
    //2.行列数  
    if (matRows != 0 && matCols == 0)
    {
        matCols = dataLength / matChns / matRows;
    }
    else if (matCols != 0 && matRows == 0)
    {
        matRows = dataLength / matChns / matCols;
    }
    else if (matCols == 0 && matRows == 0)
    {
        matRows = dataLength / matChns;
        matCols = 1;
    }
    //3.数据总长度  
    //cout << dataLength << endl;
    //cout << matRows * matCols * matChns << endl;
    if (dataLength != (matRows * matCols * matChns))
    {
        cout << "读入的数据长度 不满足 设定的矩阵尺寸与通道数要求,将按默认方式输出矩阵!" << endl;
        retVal = 1;
        matChns = 1;
        matRows = dataLength;
    }

    // 将文件数据保存至输出矩阵  
    matData = tmpMat.reshape(matChns, matRows).clone();

    return (retVal);
}


//图片转矩阵
Mat img2Vec(const string &fileName){
    Mat returnVec = Mat::zeros(1, 1024, CV_8UC1);
    //cout << "returnVec=" << endl << " " << returnVec << endl << endl;

    //uchar *pCurrentFace = (uchar*)malloc(1024 * sizeof(uchar));
    //getFromText(fileName, returnVec, pCurrentFace);

    LoadData(fileName, returnVec, 1, 1024, 1);
    //imshow("读取txt", returnVec);
    return returnVec;
    //ifstream infile;
    //int data;
    //cout << "存入矩阵" << endl;
    //int a[3][4];
    //int*p = &returnVec[0][0];
    //while (infile >> data)             //遇到空白符结束
    //{
    //  *p = data;
    //  p++;
    //}
    //infile.close();
    //for (int i = 0; i<3; i++)
    //{
    //  for (int j = 0; j<4; j++)
    //      cout << a[i][j] << "\t";
    //  cout << endl;
    //}
}

//获取字符串最后的数字D:\\workspace\\Spyder\\MLinAct\\Ch02\\trainingDigits\\0
int getnum(string s)
{
    //return s[s.length() - 1];
    int num = 0;
    int n = s.length();
    int wei = 1;
    for (int i = n - 1; i >= 0; i--){
        if (s[i] == '\\'){ return num; }
        else {
            num += (s[i] - '0')*wei;
            wei *= 10;
        }
    }
    return wei;
}

//txt数据文件转矩阵
Mat txt2Vec(const string &fileName)
{
    Mat returnVec = Mat::zeros(1, 1024, CV_8UC1);
    fstream testByCharFile;
    char c;
    //testByCharFile.open("D:\\workspace\\Spyder\\MLinAct\\Ch02\\trainingDigits\\0_0.txt", ios::in);
    testByCharFile.open(fileName, ios::in);
    while (!testByCharFile.eof())
    {
        testByCharFile >> c;
        //cout << c;
        for (int i = 0; i < 1024; i++)
        {
            returnVec.at<char>(0, i) = c;
        }
    }
    testByCharFile.close();
    return returnVec;
}

//快排
void quick_sort(int *arr, int low, int high) {
    if (low < high) {
        int i = low, j = high, pivot = arr[low];
        while (i < j) {
            while (i < j&&arr[j] >= pivot)  //从右开始遍历,直到找到小于pivot的值为止    
                --j;
            if (i < j)
                arr[i++] = arr[j];
            while (i < j&&arr[i] <= pivot)  //从左开始遍历直到找到大于pivot的值为止    
                ++i;
            if (i < j)
                arr[j--] = arr[i];
        }
        arr[i] = pivot;
        quick_sort(arr, low, i - 1);
        quick_sort(arr, i + 1, high);
    }
}

//排序,然后返回前K位在原数组中的下标  
void argsort(int K, float *arr, int *label, int Size_trainData){
    int *tmp = (int *)malloc(sizeof(int)*Size_trainData);
    int *cmp = (int *)malloc(sizeof(int)*Size_trainData);
    int i;
    for (i = 0; i < Size_trainData; cmp[i] = (int)
        (arr[i++] * 1000));
    for (i = 0; i < Size_trainData; tmp[i] = (int)
        (arr[i++] * 1000));
    quick_sort(tmp, 0, Size_trainData - 1);
    for (i = 0; i < K; ++i) {
        for (int j = 0; j < Size_trainData; ++j) {
            if (abs(tmp[i] == cmp[j]))
                label[i] = j;
        }
    }
}

typedef pair<string, int> PAIR;

bool cmp_by_value(const PAIR& lhs, const PAIR& rhs) {
    return lhs.second < rhs.second;
}

struct CmpByValue {
    bool operator()(const PAIR& lhs, const PAIR& rhs) {
        return lhs.second > rhs.second;
    }
};

//kNN算法  根据机器学习实战python代码改编
string kNNClassifier(Mat inX, Mat dataSet, vector<string> labels, int k){
    int dataSetSize = dataSet.size().height;

    Mat inMat = Mat::zeros(dataSetSize, 1024, CV_8UC1);
    Mat diffMat = Mat::zeros(dataSetSize, 1024, CV_8UC1);
    Mat rowMat(dataSetSize, 1, CV_8UC1, Scalar(0));
    Mat resultMat = Mat::zeros(dataSetSize, dataSetSize, CV_8UC1);
    float *dist = (float *)malloc(sizeof(float)*dataSetSize);
    int distance = 0;                                             //平方差距离
    //for (int i = 0; i < dataSetSize; i++)
    //{
    //  for (int j = 0; j < 1024; j++)
    //  {
    //      diffMat.at<int>(i, j) = pow(inX.at<int>(j) -dataSet.at<int>(i, j), 2);
    //      distance += diffMat.at<int>(i, j);
    //  }
    //  dist[i] = pow(distance, 0.5);
    //}
    //cout << endl << inX.reshape(0, 1).clone() << endl;
    for (int i = 0; i < dataSetSize; i++)
    {
        inX.reshape(0, 1).clone().row(0).copyTo(inMat.row(i));    //inX矩阵转换成一行再复制给inMat
    }

    diffMat = inMat - dataSet;                                    //矩阵差值
    //cout << endl << diffMat << endl << endl;
    resultMat = diffMat.mul(diffMat);                             //矩阵对应项相乘  1934*1024
    //cout << endl << resultMat << endl << endl;
    for (int i = 0; i < dataSetSize; i++)                         //对矩阵行求和   距离平方和
    {
        distance = 0;
        uchar* data = resultMat.ptr<uchar>(i);
        for (int j = 0; j < 1024; j++)
        {
            distance = data[j] + distance;
        }
        dist[i] = distance;
    }

    int *label = (int *)malloc(sizeof(int)*k);                    //
    argsort(k, dist, label, dataSetSize);                         //对kNN计算结果排序   返回K个  label
    map<string, int> class_count_map;
    int newValue;
    std::map<string, int>::iterator it;
    for (int i = 0; i < k; i++)
    {
        string vote = labels[label[i]];                           //计算结果,辨别出0-9,投票
        //if (class_count_map.count(vote)>0){
        //  class_count_map[vote] ++;
        //}
        //else{
        //  class_count_map[vote] = 1;
        //}

        it = class_count_map.find(vote);
        if (it == class_count_map.end())                          //如果没出现过,就赋值1
            class_count_map.insert(std::make_pair(vote, 1));
        else
        {
            newValue = ++class_count_map[vote];                  //出现过就++
            it->second = newValue;                                //对键值的修改
        }
    }
    //cout << endl << class_count_map << endl << endl;
    vector<PAIR> class_count_vec(class_count_map.begin(), class_count_map.end());
    sort(class_count_vec.begin(), class_count_vec.end(), CmpByValue());                   //排序从大到小
    return class_count_vec[0].first;
}

int main()
{
    Mat srcImage = imread("F:\\Projects\\Elevator\\EleDigit\\digits-crop\\test-images\\2_6.bmp");
    Mat dstImage, grayImage, Image, normalImage, inverseImage, invNorImage, trainMat, diffImg;
    string fileNameStr, fileName, classNumStr;
    vector<string> v1, v2, labelVec, vRe;
    string realClass;
    srcImage.copyTo(dstImage);
    cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);
    threshold(grayImage, Image, 48, 1, CV_THRESH_BINARY);
    threshold(grayImage, inverseImage, 48, 1, CV_THRESH_BINARY_INV);
    resize(Image, normalImage, Size(32, 32), 0, 0, CV_INTER_LINEAR);
    resize(inverseImage, invNorImage, Size(32, 32), 0, 0, CV_INTER_LINEAR);
    cout << "normalImage=" << endl << " " << normalImage << endl << endl;
    //normalImage = ~normalImage;
    cout << "invNorImage=" << endl << " " << invNorImage << endl << endl;
    diffImg = normalImage.mul(normalImage);
    cout << "diffImg=" << endl << " " << diffImg << endl << endl;
    //waitKey(2000);


    //trainFileList
    string filePath = "F:\\Projects\\Elevator\\EleDigit\\trainingDigits";
    vector<string> fileVec;
    getFiles(filePath, "txt", fileVec);
    int fileVecSize = fileVec.size();
    //for (int i = 0; i < fileVecSize; i++)
    //{
    //  cout << fileVec[i].c_str() << endl;
    //}

    trainMat = Mat::zeros(fileVecSize, 1024, CV_8UC1); // 全零矩阵  
    //cout << "trainMat=" << endl << " " << trainMat << endl << endl;
    for (int i = 0; i < fileVecSize; i++)
    {
        fileNameStr = fileVec[i].c_str();
        v1 = split(fileNameStr, ".");
        fileName = v1[0];
        v2 = split(fileName, "_");
        classNumStr = v2[0];
        realClass = classNumStr[classNumStr.length() - 1];
        labelVec.push_back(realClass);    //数字标签  存入labelVec
        Mat returnVec = txt2Vec(fileNameStr);
        //cout << endl << i << endl;
        //cout << fileNameStr << endl;
        //cout << "returnVec=" << endl << " " << returnVec << endl << endl;
        returnVec.row(0).copyTo(trainMat.row(0));
        //for (int j = 0; j < 1024; j++)
        //{
        //  trainMat.at<int>(i, j) = returnVec.at<int>(j);
        //}
    }

    string classResult = kNNClassifier(normalImage, trainMat, labelVec, 3);    //kNN
    cout << endl << "识别结果:" << " " << classResult << endl << endl;
    //char result = classResult[classResult.length() - 1];
    //cout << endl << "识别结果:" << " " << result << endl << endl;
    //testFileList
    //string testFilePath = "D:\\workspace\\Spyder\\MLinAct\\Ch02\\testDigits\\";
    //vector<string> testFileVec;

    //getFiles(testFilePath, "txt", testFileVec);
    //int testFileVecSize = testFileVec.size();
    //for (int i = 0; i < testFileVecSize; i++){
    //  testFileNameStr = testFileVec[i].c_str();
    //  SplitString(testFileNameStr, v3, ".");
    //  testFileName = v3[0];
    //  SplitString(testFileName, v4, "_");
    //  classNumStr = v4[0];
    //}

    system("pause");

    //定义轮廓和层次结构
    //vector<vector<Point>> contours;
    //vector<Vec4i> hierarchy;
    //findContours(Image, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
    //int i = 0;
    //Point2f pp[5][4];
    //vector<vector<Point>>::iterator It;
    //Rect rect[10];
    return 0;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值