关于c ++:使用KNN分类器进行数字识别前的预处理

Pre-processing before digit recognition with KNN classifier

现在我正在尝试使用OpenCV创建数字识别系统。Web中有许多文章和示例(甚至在StackOverflow中)。我决定使用knn分类器,因为这个解决方案在web中最流行。我发现了一个手写数字的数据库,其中有一组60k个例子,错误率小于5%。

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

  • enter image description here为7。
  • enter image description hereenter image description here被认为是5。
  • enter image description hereenter image description here被确认为1。
  • enter image description here为8。

等等(如果需要,我可以上传所有图片)。

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

所以我决定在分类之前做一些预处理。从mnist数据库站点的表中,我发现人们正在使用去纸、噪声消除、模糊和像素移动技术。不幸的是,几乎所有的文章链接都被破坏了。所以我决定自己做这样的预处理,因为我已经知道怎么做了。

现在,我的算法如下:

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

    • enter image description here也是1
    • enter image description here是3(不是以前的5)
    • enter image description here为5(非8)
    • List item为7(利润!)

    所以,这样的预处理对我有点帮助,但我需要更好的结果,因为在我看来,这些数字应该毫无问题地被识别出来。

    有人能给我一些关于预处理的建议吗?谢谢你的帮助。

    P.S.我可以上传我的源代码(C++)。


    我意识到我的错误-这不是连通与预处理在所有(的davidbrown和约翰@ @)。使用的数据集从一handwritten学院数字印刷(capitalized)。我不喜欢在网上搜索数据库,所以我决定创建自己的。我有我的数据库上传到谷歌。

    在这里你可以怎么使用它(列车和主分类表):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    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,7,9 1 &;&;八是公认的为一类,因为中央点是非常相似的。这个呢?

    • 应用连通分量标记位的方法。因此,真正的边界和边界图像进行作物数过。那么,你想要更多的正确的工作区和中央点是标准化。
    • 然后分为两个位的horizontally配件。(例如你想界划分后有两个"8")

    As a result,"9"、"8"更可识别的现代建筑物的工作人员"5"和"6"。上下配件配件将是相同的,但不同的。


    我可以给你一个更好的答案需要比你自己的答案,但我想以一个建议。你可以提高你的数字识别系统在以下的方式:

    • 在白色和黑色的应用补丁的骨架化过程。

    • 这之后,将距离变换。

    在这种方式,你可以提高分类器的结果是不准确的,当数为中心或他们是不完全一样的,morphologically说。