用KNN分类器进行数字识别之前的处理

现在我正在尝试使用OpenCV创建数字识别系统。 在WEB中有很多文章和例子(甚至在StackOverflow上)。 我决定使用KNN分类器,因为这种解决方案在WEB中最受欢迎。 我发现了一个手写数字数据库,其中包含60k个示例的训练集,错误率低于5%。

我使用本教程作为如何使用OpenCV处理此数据库的示例。 我使用完全相同的技术和测试数据( t10k-images.idx3-ubyte ),我有4%的错误率。 但是当我尝试对自己的数字进行分类时,我遇到了更大的错误。 例如:

  • 被确认为7
  • 和 被认定为5
  • 和 被确认为1
  • 被认定为8
  • 等等(如果需要,我可以上传所有图片)。

    正如你所看到的,所有的数字都有很好的质量,并且很容易被人识别。

    所以我决定在分类前做一些预处理。 从MNIST数据库网站的表格中我发现人们正在使用去偏移,去噪,模糊和像素移位技术。 不幸的是,几乎所有的文章链接都被打破了。 所以我决定自己做这样的预处理,因为我已经知道如何做到这一点。

    现在,我的算法如下:

  • 腐蚀图像(我认为我的原始数字也是
    粗)。
  • 去除小轮廓。
  • 阈值和模糊图像。
  • 中心数字(而不是移位)。
  • 我认为,在我的情况下,不需要纠错,因为所有的数字都是正常旋转的。 而且我也不知道如何找到一个正确的旋转角度。 所以在这之后我得到了这些图像:

  • 也是1
  • 3 (不像以前那样是5
  • 5 (不是8
  • 7 (利润!)
  • 所以,这样的预处理对我有点帮助,但是我需要更好的结果,因为在我看来,这些数字应该没有问题地被识别出来。

    任何人都可以给我任何意见与预处理? 谢谢你的帮助。

    PS我可以上传我的源代码(c ++)。


    我意识到自己的错误-它不是在所有前处理连接(感谢@DavidBrown@约翰 )。 我使用手写数字集而不是打印(大写)。 我没有在网上找到这样的数据库,所以我决定自己创建它。 我已将我的数据库上传到Google云端硬盘。

    以下是你如何使用它(训练和分类):

    int digitSize = 16;
    //returns list of files in specific directory
    static vector<string> getListFiles(const string& dirPath)
    {
        vector<string> result;
        DIR *dir;
        struct dirent *ent;
        if ((dir = opendir(dirPath.c_str())) != NULL)
        {
            while ((ent = readdir (dir)) != NULL)
            {
                if (strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0 )
                {
                    result.push_back(ent->d_name);
                }
            }
            closedir(dir);
        }
        return result;
    }
    
    void DigitClassifier::train(const string& imagesPath)
    {
        int num = 510;
        int size = digitSize * digitSize;
        Mat trainData = Mat(Size(size, num), CV_32FC1);
        Mat responces = Mat(Size(1, num), CV_32FC1);
    
        int counter = 0;
        for (int i=1; i<=9; i++)
        {
            char digit[2];
            sprintf(digit, "%d/", i);
            string digitPath(digit);
            digitPath = imagesPath + digitPath;
            vector<string> images = getListFiles(digitPath);
            for (int j=0; j<images.size(); j++)
            {
                Mat mat = imread(digitPath+images[j], 0);
                resize(mat, mat, Size(digitSize, digitSize));
                mat.convertTo(mat, CV_32FC1);
                mat = mat.reshape(1,1);
                for (int k=0; k<size; k++)
                {
                    trainData.at<float>(counter*size+k) = mat.at<float>(k);
                }
                responces.at<float>(counter) = i;
                counter++;
            }
        }
        knn.train(trainData, responces);
    }
    
    int DigitClassifier::classify(const Mat& img) const
    {
        Mat tmp = img.clone();
    
        resize(tmp, tmp, Size(digitSize, digitSize));
    
        tmp.convertTo(tmp, CV_32FC1);
    
        return knn.find_nearest(tmp.reshape(1, 1), 5);
    }
    

    5&6,1&7,9&8被认为是相同的,因为班级的中心点太相似了。 那这个呢 ?

  • 将连接的组件标签方法应用于数字,以获取数字的真实边界并在这些边界上裁剪图像。 所以,你会在更正确的区域工作,并且中心点被标准化。
  • 然后将数字水平分成两部分。 (例如分割“8”后你会有两个圆圈)
  • 结果,“9”和“8”更容易识别以及“5”和“6”。 上部分相同,但下部分不同。


    我不能给你一个比你自己的答案更好的答案,但我想提供建议。 您可以通过以下方式改进您的数字识别系统:

  • 在白色和黑色补丁上应用一个镂空过程

  • 之后,应用距离变换。

  • 通过这种方式,当数字不完全居中或者形态上不完全相同时,可以改善分类器的结果。

    链接地址: http://www.djcxy.com/p/13973.html

    上一篇: processing before digit recognition with KNN classifier

    下一篇: Recognition of numbers in images(Matlab)