Handwritten Digit Recognition [QT + OpenCV], handwritten digit qtopencv

Source: Internet
Author: User

Handwritten Digit Recognition [QT + OpenCV], handwritten digit qtopencv

[Description]

There are many ways to implement Handwritten Digit Recognition.

This article tries to simplify it so that you can quickly understand how to implement a dynamic system.

【]




[Idea]

1. Feature Extraction

Divide the image into 5x5 areas, and then calculate the proportion of black (or white) pixels in the area.

Extract the image to be tested and the image to be classified.

2. Calculate the Euclidean distance between the current test image and the image used for classification.

3. Find out the image with the least Euclidean distance, that is, the most matched image with the current test image, that is, the number represented by the image as the result of the current test image.

4. For ease of processing, the simplified processing is as follows:

4.1 select only 10 images for classification.

In practical applications, 10 images are far from enough. However, to simplify the process, only 10 images are used here, that is, numbers 0 ~ 9 each number selects only one feature.

In the actual system, the more feature images are selected, the higher the system accuracy.

4.2 uses the nearest neighbor. That is, the image with the smallest Euclidean distance is used as the result of the current test image.

In the actual system, K nearest neighbor is often used, that is, the minimum K Euclidean distance is selected to determine which class they belong to determine the current numerical result.

Because of the simplification, the accuracy of digital recognition is not very high. However, it can basically meet the learning needs.

[Part of code]

The system is developed using QT + OpenCV. Some code is as follows:

[Main class internal variables and slot functions]

Public: explicit MainWindow (QWidget * parent = 0 );~ MainWindow (); cv: Mat testImage, srcImage [10], tempImage; // the digital image to be tested for the testImage value. srcImage refers to the existing digital image QImage img for classification; float testFeature [25]; // This array is used to store the feature values of the digital image to be detected. Float srcFeature [10] [25]; // stores the feature values of the original digital image. Only 10 digits 0 ~ 9. Image void getFeature (cv: Mat m, float a [25]); // define a function to obtain image features. Float ouDistance (float a [25], float B [25]); float oDistance (float a [25], float B [25]); private slots: void on_openLenaJpg_triggered (); void Merge (); void on_about_triggered (); void on_showImage_triggered (); void Merge ();

[Open the custom path to the image to be tested]

Void MainWindow: on_openCustomeFile_triggered () {QString filename = QFileDialog: getOpenFileName (this, tr ("Open Image"), "", tr ("Image File (*. bmp *. jpg *. jpeg *. png) "); QTextCodec * code = QTextCodec: codecForName (" gb18030 "); std: string name = code-> fromUnicode (filename ). data (); testImage = cv: imread (name); if (! TestImage. data) {QMessageBox msgBox; msgBox. setText (tr ("data not found"); msgBox.exe c () ;}else {cv: cvtColor (testImage, testImage, CV_BGR2RGB ); img = QImage (const unsigned char *) (testImage. data), testImage. cols, testImage. rows, testImage. cols * testImage. channels (), QImage: Format_RGB888); ui-> label1-> clear (); img = img. scaled (ui-> label1-> width (), ui-> label1-> height (); ui-> label1-> setPixmap (QPixmap: fromImage (img )); // ui-> processPushButton-> setEnabled (true); // ui-> label1-> resize (ui-> label1-> pixmap ()-> size ()); // set the current label to the image size. // ui-> label1-> resize (img. width (), img. height (); // this-> setWidget (label1 );}}

[Image Feature Extraction: 5x5 = 25 features are completed. Each feature indicates the number of white pixels in the subarea]

Void MainWindow: getFeature (cv: Mat m, float a [25]) {int M, N; // used to store the width and height of image m int I, j; M = m. cols; N = m. rows; for (I = 0; I <25; I ++) a [I] = 0; // QMessageBox: information (NULL, "Title", QString :: number (m. at <uchar> (188, 88), QMessageBox: Yes | QMessageBox: No, QMessageBox: Yes); for (I = 0; I <M; I ++) for (j = 0; j <N; j ++) if (m. at <uchar> (I, j) = 255) {// a [I/5*5 + j/5] ++; // The calculation error is returned, cannot be placed in the corresponding feature value // QMessageBox: information (NULL, "Title", QString: number (5), QMessageBox: Yes | QMessageBox: No, QMessageBox :: yes); // a [M/I * 5 + N/j] ++; // a [M/(I + 1) * 5 + N/(j + 1)] ++; a [I/(M/5) * 5 + j/(N/5)] ++; // QMessageBox: information (NULL, "Title", "add", QMessageBox: Yes | QMessageBox: No, QMessageBox: Yes);} for (I = 0; I <25; I ++) {// QMessageBox: information (NULL, "Title", QString: number (a [I]), QMessageBox: Yes | QMessageBox:: No, QMessageBox: Yes); a [I] = a [I]/(M/5) * (N/5); // QMessageBox :: information (NULL, "Title", QString: number (a [I]), QMessageBox: Yes | QMessageBox: No, QMessageBox: Yes); // QMessageBox :: information (NULL, "Title", QString: number (5), QMessageBox: Yes | QMessageBox: No, QMessageBox: Yes);} // QMessageBox :: information (NULL, "Title", QString: number (a [5]), QMessageBox: Yes | QMessageBox: No, QMessageBox: Yes );}

[Euclidean distance calculation, the second function is used for testing]

Float MainWindow: ouDistance (float a [25], float B [25]) // This function forgets to write the class relationship of MainWindow. It has been tested for a long time and falls in sweat! {Int I; float distance = 0; // you forgot to set it to zero. An error occurred !!! For (I = 0; I <25; I ++) distance + = (a [I]-B [I]) * (a [I]-B [I]); distance = sqrt (distance); return distance;} float MainWindow: oDistance (float a [25], float B [25]) // This function is tested when an ouDistance problem occurs. It does not use {int I; float distance = 0; // you forgot to set it to zero. An error occurred !!! // To test the ouDistance function, rewrite oDistance to find the problem. The problem occurs again but remains unchanged. OuDistance for (I = 0; I <25; I ++) distance + = (a [I]-B [I]) * (a [I]-B [I]); distance = sqrt (distance); return distance ;}

[Description]

Void MainWindow: on_copyright_triggered () {QMessageBox: information (this, "Copyright", tr ("copyright owner of this software: Tianjin Vocational and Technical Normal University. If you want to use it, contact lilizong # gmail ");} void MainWindow: on_about_triggered () {QMessageBox: information (this," about ", tr ("the current version of this software is 1.0, developed by Li lizong and others. If you have any questions, contact lilizong # gmail "); return ;}




[Display test results: an image and an Information Box]

Void MainWindow: on_ImageAndMessage_triggered () {int I; float min; // used to store the smallest Euclidean distance int mini; // used to store the smallest Euclidean distance number. GetFeature (testImage, testFeature); // obtain the feature value of the test image and put it in the testFeature array. // QMessageBox: information (NULL, "Title", QString: number (testFeature [6]), QMessageBox: Yes | QMessageBox: No, QMessageBox: Yes ); // test whether the current testFeature is normal/* for (I = 0; I <25; I ++) QMessageBox: information (NULL, "Title", QString :: number (testFeature [I]), QMessageBox: Yes | QMessageBox: No, QMessageBox: Yes); * // QMessageBox: information (NULL, "Title ", QString: number (testImage. rows), QMessageBox: Yes | QMessageBox: No, QMessageBox: Yes); for (I = 0; I <10; I ++) {QString filePath, fileName, allName; filePath = "image \ stand \"; // The current image directory fileName = ". bmp "; // The current image extension allName = filePath +" \ "+ QString: number (I) + fileName; // I is the file name, using QString :: number (I) is converted to QString type, which is currently numeric String s = allName. toStdString (); // converted to the standard string type. imread does not recognize the QString type srcImage [I] = cv: imread (s );} // The following part is used to test whether the above Code can obtain the srcImage value. /* Cv: cvtColor (srcImage [3], srcImage [3], CV_BGR2RGB); img = QImage (const unsigned char *) (srcImage [3]. data), srcImage [1]. cols, srcImage [1]. rows, srcImage [1]. cols * srcImage [1]. channels (), QImage: Format_RGB888); ui-> label1-> clear (); img = img. scaled (ui-> label1-> width (), ui-> label1-> height (); ui-> label1-> setPixmap (QPixmap: fromImage (img )); * /// obtain the feature value of the original digital image. For (I = 0; I <10; I ++) getFeature (srcImage [I], srcFeature [I]);/* for (I = 0; I <25; I ++) QMessageBox: information (NULL, "Title", QString: number (srcFeature [0] [I]), QMessageBox: Yes | QMessageBox: No, QMessageBox: Yes); */float ouDistanceValue [10] = {0 }; // store the Euclidean distance between the current test image and the Ten known digital images for (I = 0; I <10; I ++) {ouDistanceValue [I] = ouDistance (testFeature, srcFeature [I]); // ouDistanceValue [I] = I;} // No results are obtained. In the test, ouDistance has No problem. /* For (I = 0; I <10; I ++) QMessageBox: information (NULL, "Title", QString: number (ouDistanceValue [I]), QMessageBox:: Yes | QMessageBox: No, QMessageBox: Yes); */mini = 0; min = ouDistanceValue [0]; // assign an initial value to min, assume that the distance from the number 0 is the smallest. For (I = 0; I <10; I ++) {if (min> ouDistanceValue [I]) {min = ouDistanceValue [I]; mini = I ;}} // QMessageBox: information (NULL, "Title", QString: number (mini), QMessageBox: Yes | QMessageBox: No, QMessageBox: Yes ); // test whether the mini can obtain the correct value in the preceding statement. // display the image matching the current test image in label2. cv: cvtColor (srcImage [mini], srcImage [mini], CV_BGR2RGB); img = QImage (const unsigned char *) (srcImage [mini]. data), srcImage [mini]. cols, srcImage [mini]. rows, srcImage [mini]. cols * srcImage [mini]. channels (), QImage: Format_RGB888); ui-> label2-> clear (); img = img. scaled (ui-> label2-> width (), ui-> label2-> height (); ui-> label2-> setPixmap (QPixmap: fromImage (img )); // display the matching result of the current image in a message box QMessageBox: information (NULL, "test result", "recognition result of the current test image is digit:" + QString:: number (mini), QMessageBox: Yes | QMessageBox: No, QMessageBox: Yes );}



Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.