Распознавание символов с помощью KNN и OpenCV 3

У меня есть вопрос о KNN и OpenCV, я надеюсь, что кто-то с большим опытом в этом может пролить свет... Я пытаюсь сделать распознавание символов на изображениях, поступающих через веб-камеру. У меня есть термометр с 4 входами, и я хотел бы провести некоторые измерения и записать отображаемые температуры с отметкой времени. В моей настройке у меня есть прямоугольник, нарисованный на изображении, поступающем с веб-камеры, я помещаю его туда, чтобы всегда размещать измеритель в одном и том же месте и избегать ненужной работы по поиску на дисплее.

Что я сделал: - Я использовал веб-камеру, чтобы сохранить последние цифры каждого из 4 измерений, при этом обдувая датчики горячим воздухом. Я собрал в общей сложности 200 образцов цифр и скопировал их в одно изображение - это формирует мои тренировочные данные. - Я повторил это изображение с прямоугольником и прочитал с клавиатуры правильный ответ для соответствующей цифры. Я сделал это для всех 200 номеров и собрал 200 пар.

Теперь код строится нормально, но я продолжаю получать сообщение об ошибке, когда findnearest вызывается в функции RecognizeDigit. В черном окне консоли, которое появляется при запуске программы, я получаю сообщение об ошибке, утверждающее, что либо столбец test_sample, либо его тип неверен. Я давно не работал над openCV, и я просто не понимаю, в чем дело. Насколько я понимаю, и пример данных, и ответ имеют форму, состоящую из 1 строки и n столбцов. В моем случае test_samples, переданные Mat RecignizeDigit( Mat), имеют размер 80 x 80, это означает, что - после изменения формы (1, 1) я получу 200 выборок * 6400 пикселей в моем Mat. Это правильно, я проверил с отладкой, пошагово переходя к точке, где все идет плохо. Ответы, пришедшие с клавиатуры, также изменяются, и во время отладки я вижу, что он имеет 1 строку и 200 столбцов, как и ожидалось. Если я передам 80x80 test_sample моей функции и изменим его форму, я получу 1 x 6400 Mat в результате. В моей голове, KNN должен просто перебрать свои доступные образцы и найти ближайших соседей и дать мне лучший ответ.

Я что-то не так делаю? Пожалуйста, смотрите мой код прилагается..

   #include <opencv2/opencv.hpp>

using namespace cv;
using namespace ml;
using namespace std;

void CreateSampleData(void);
void TrainSampleData(void);
Mat RecognizeDigit(Mat matSample);

Ptr<TrainData> trainingData;
Ptr<KNearest> kclassifier = KNearest::create();

int main()
{
    // CreateSampleData();
    TrainSampleData();

    Mat sample;
    Mat gray, blur, thresh, kernel;
    int BSrows = 0, BScols = 0;

    Mat webcam;                                     // source image refreshed from webcam
    Mat livecam;
    Mat webcamroi;
    Mat drawing = Mat::zeros(thresh.size(), CV_8UC3);
    Mat BigSample = Mat::zeros(Size(600, 470), CV_8UC1);
    Mat BigSampleROI = Mat::zeros(Size(30, 47), CV_8UC1);
    Mat toconv, convres;

    // this is the input stream from the webcam that has to be processed
    VideoCapture cap;

    if (!cap.open(0)) return 0;

    for (;;)
    {
        while (!cap.read(webcam));
        cap.read(webcam);
        livecam = webcam;

        // image processing, thresholding, converting, cutting...
        cvtColor(webcam, webcam, COLOR_BGR2GRAY);
        GaussianBlur(webcam, webcam, Size(13, 13), 0, 0);
        adaptiveThreshold(webcam, webcam, 255, 1, 1, 13, 2);

        kernel = getStructuringElement(MORPH_CROSS, Size(5, 5));
        morphologyEx(webcam, webcam, MORPH_CLOSE, kernel);

        kernel = getStructuringElement(MORPH_ELLIPSE, Size(5, 5));
        morphologyEx(webcam, webcam, MORPH_CLOSE, kernel);
        rectangle(livecam, Point(295, 0), Point(490,250), Scalar(0, 0, 255), 2, LINE_8, 0);
        cvNamedWindow("Use this window to tune the position of the camera", WINDOW_AUTOSIZE);
        imshow("Use this window to tune the position of the camera", livecam);

        webcamroi = webcam(Rect(Point(295, 0), Point(490, 250)));
        drawing = webcamroi;

        rectangle(drawing, Point(68, 25), Point(96, 70), Scalar(255, 0, 0), 2, LINE_8, 0);
        rectangle(drawing, Point(100, 25), Point(128, 70), Scalar(255, 0, 0), 2, LINE_8, 0);
        rectangle(drawing, Point(132, 25), Point(160, 70), Scalar(255, 0, 0), 2, LINE_8, 0);

        rectangle(drawing, Point(68, 78), Point(96, 123), Scalar(255, 0, 0), 2, LINE_8, 0);
        rectangle(drawing, Point(100, 78), Point(128, 123), Scalar(255, 0, 0), 2, LINE_8, 0);
        rectangle(drawing, Point(132, 78), Point(160, 123), Scalar(255, 0, 0), 2, LINE_8, 0);

        rectangle(drawing, Point(68, 132), Point(96, 176), Scalar(255, 0, 0), 2, LINE_8, 0);
        rectangle(drawing, Point(100, 132), Point(128, 176), Scalar(255, 0, 0), 2, LINE_8, 0);
        rectangle(drawing, Point(132, 132), Point(160, 176), Scalar(255, 0, 0), 2, LINE_8, 0);

        rectangle(drawing, Point(68, 185), Point(96, 229), Scalar(255, 0, 0), 2, LINE_8, 0);
        rectangle(drawing, Point(100, 185), Point(128, 229), Scalar(255, 0, 0), 2, LINE_8, 0);
        rectangle(drawing, Point(132, 185), Point(160, 229), Scalar(255, 0, 0), 2, LINE_8, 0);

        toconv = drawing(Rect(68, 25, 30, 47));
        convres = RecognizeDigit(toconv);

#ifdef CREATE_TRAINING_IMAGE
        // this collects samples of known size onto a learning image
        if (BScols < 10)
        {
            if (BSrows < 20)
            {
                BigSampleROI = drawing(Rect(132, ((BSrows%4 *53) + 28), 30, 47));
                BigSampleROI.copyTo(BigSample(Rect((BSrows * 30), (BScols * 47), 30, 47)));
                waitKey(300);
                cvNamedWindow("what gets saved", WINDOW_AUTOSIZE);          // Create a window for display.
                imshow("what gets saved", BigSample);

                BSrows++;
            }
            else
            {
                BSrows = 0;
                BScols++;
            }
        }
        else
        {
            // BScols = 0;
            // BSrows = 0;
        }
        imshow("Processed Display Window", drawing);
#endif

        if (waitKey(10) == 27)
        {
            imwrite("BigSampleImage.bmp", BigSample);
            break;
        }
    }

    waitKey(0);                                          // Wait for a keystroke in the window
    return 0;
}

void CreateSampleData(void)
{
    Mat src = imread("C:\\Users\\****\\Documents\\Visual Studio 2015\\Projects\\MeterRecognizer\\MeterRecognizer\\TrainData.bmp", 0);

    // 
    vector< vector <Point> > contours;
    vector< Vec4i > hierarchy;
    Mat image;
    Mat sample;
    Mat sample_array, response_array;

    for (int BSrows = 0; BSrows < 10; BSrows++)
    {
        for (int BScols = 0; BScols < 20; BScols++)
        {
            rectangle(src, Point((BScols * 30), (BSrows * 47)), Point(((BScols * 30) + 30), ((BSrows * 47) + 47)), Scalar(0, 0, 255), 1, 8, 0);
            image = src(Rect((BScols * 30), (BSrows * 47), 30, 47));
            cvNamedWindow("Processed image", WINDOW_AUTOSIZE);          // Create a window for display.
            imshow("Processed image", src);                             // processed image          

            Mat tmp1, tmp2;
            resize(image, tmp1, Size(80, 80), 0, 0, INTER_LINEAR); 
            tmp1.convertTo(tmp2, CV_32FC1); 
            cvNamedWindow("Character to be stored", WINDOW_AUTOSIZE);   // Create a window for display.
            imshow("Character to be stored", image);                    // processed image  

            sample_array.push_back(tmp2);                   // Store  sample data
            int c = waitKey(0);                                         // Read corresponding label for contour from keyoard
            c -= 0x30;                                                  // Convert ascii to intiger value
            response_array.push_back(c);                                // Store label to a mat
        }
    }

    // Store the data to file
    Mat response, tmp;

    tmp = response_array.reshape(1, 1); //make continuous
    tmp.convertTo(response, CV_32FC1); // Convert  to float
    tmp = sample_array.reshape(1, 1);
    tmp.convertTo(sample, CV_32FC1); // Convert  to float

    FileStorage Data("C:\\Users\\****\\Documents\\Visual Studio 2015\\Projects\\MeterRecognizer\\MeterRecognizer\\TrainingData.yml", FileStorage::WRITE); // Store the sample data in a file
    Data << "data" << sample;
    Data.release();

    FileStorage Label("C:\\Users\\****\\Documents\\Visual Studio 2015\\Projects\\MeterRecognizer\\MeterRecognizer\\LabelData.yml", FileStorage::WRITE); // Store the label data in a file
    Label << "label" << response;
    Label.release();
    printf("Training and Label data created successfully.\n");

    imshow("src", src);
    waitKey();

}

void TrainSampleData(void)
{
    // Read stored sample and label for training
    Mat sample, response;

    FileStorage Data("C:\\Users\\Gautinfo\\Documents\\Visual Studio 2015\\Projects\\MeterRecognizer\\MeterRecognizer\\TrainingData.yml",FileStorage::READ); // Read traing data to a Mat
    Data["data"] >> sample;
    Data.release();
    FileStorage Label("C:\\Users\\Gautinfo\\Documents\\Visual Studio 2015\\Projects\\MeterRecognizer\\MeterRecognizer\\LabelData.yml",FileStorage::READ); // Read label data to a Mat
    Label["label"] >> response;
    Label.release();

    // KNN algorithm related variables and procedures
    int number_of_train_elements = 200;
    int number_of_sample_elements = 200;
    // Mat matTrainFeatures(0, number_of_train_elements, CV_32F);
    // Mat matTrainLabels(0, number_of_train_elements, CV_32F);

    sample.convertTo(sample, CV_32FC1);
    response.convertTo(response, CV_32FC1);

    Mat matTrainLabels = Mat::zeros(response.size(), CV_32FC1);
    Mat matTrainFeatures = Mat::zeros(sample.size(), CV_32FC1);

    trainingData = TrainData::create(matTrainFeatures, SampleTypes::ROW_SAMPLE, matTrainLabels);
    kclassifier->setIsClassifier(true);
    kclassifier->setAlgorithmType(KNearest::Types::BRUTE_FORCE);
    kclassifier->setDefaultK(1);
    kclassifier->train(trainingData);

    printf("Training completed.\n");

    waitKey();
}

Mat RecognizeDigit( Mat matSample)
{
    Mat matResults;
    Mat tmp1, tmp2;

    resize(matSample, tmp1, Size(80, 80), 0, 0, INTER_LINEAR);
    tmp2 = tmp1.reshape(1, 1); //make continuous
    tmp2.convertTo(tmp2, CV_32FC1);

    cvNamedWindow("What KNN gets", WINDOW_AUTOSIZE);            // Create a 
    window for display.
    imshow("What KNN gets", tmp2);

    if(tmp2.type() == CV_32FC1)
    { 
        printf("Type is OK.\n");
        printf("Column number: %i\n", tmp2.cols);
    }

    waitKey(0);

    kclassifier->findNearest(tmp2, kclassifier->getDefaultK(), matResults);

    return matResults;
}

0 ответов

Другие вопросы по тегам