Pre-processing before digit recognition with KNN classifier

后端 未结 3 1170
暖寄归人
暖寄归人 2021-02-07 11:03

Right now I\'m trying to create digit recognition system using OpenCV. There are many articles and examples in WEB (and even on StackOverflow). I decided to use KNN classifier b

相关标签:
3条回答
  • 2021-02-07 11:16

    I can not give you a better answer than your own answer, but I would like to contribute with an advise. You could improve your digits recognition system on the following way:

    • Apply over the white and black patch an skeletonization process.

    • After that, apply distance transform.

    On this way you can improve results of the classifier when digits are not exactly centered or they are not exactly the same, morphologically speaking.

    0 讨论(0)
  • 2021-02-07 11:31

    I realized my mistake - it wasn't connected with pre-processing at all (thanks to @DavidBrown and @John). I used handwritten dataset of digits instead of printed (capitalized). I didn't find such database in the web so I decided to create it by myself. I have uploaded my database to the Google Drive.

    And here's how you can use it (train and classify):

    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);
    }
    
    0 讨论(0)
  • 2021-02-07 11:41

    5 & 6 , 1 & 7, 9 & 8 are recognized as the same because central points of classes are too similar. What about this ?

    • Apply connected component labeling method to digits for getting real boundaries of digits and crop images over these boundaries. So, you will work on more correct area and central points are normalized.
    • Then divide digits into two parts as horizontally. (For example you will have two circles after dividing "8")

    As a result, "9" and "8" are more recognizable as well as "5" and "6". Upper parts will be same but lower parts are different.

    0 讨论(0)
提交回复
热议问题