digits.png 영상으로부터 HOG 특징 벡터를 추출하여 SVM 알고리즘으로 학습시키고, 사용자가 마우스로 쓴 필기체 숫자를 인식하는 svmdigits 예제 프로그램 소스 코드를 코드 15-6에 나타냈습니다. svmdigits 예제 프로그램은 15.2.3절에서 설명한 knndigits 예제 프로그램과 동작 방식이 거의 동일합니다. 다만 내부적으로 사용하는 머신 러닝 알고리즘과 머신 러닝에서 학습에 사용하는 특징 벡터 종류만 다를 뿐입니다. 코드 15-6의 svmdigits 전체 소스 코드 파일과 사용된 digits.png 영상 파일은 내려받은 예제 파일 중 ch15/svmdigits 프로젝트에서 확인하기 바랍니다.6
코드 15-6 SVM 알고리즘을 이용한 필기체 숫자 인식 [ch15/svmdigits]
01 #include "opencv2/opencv.hpp" 02 #include <iostream> 03 04 using namespace cv; 05 using namespace cv::ml; 06 using namespace std; 07 08 Ptr<SVM> train_hog_svm(const HOGDescriptor& hog); 09 void on_mouse(int event, int x, int y, int flags, void* userdata); 10 11 int main() 12 { 13 #if _DEBUG 14 cout << "svmdigits.exe should be built as Release mode!" << endl; 15 return 0; 16 #endif 17 18 HOGDescriptor hog(Size(20, 20), Size(10, 10), Size(5, 5), Size(5, 5), 9); 19 20 Ptr<SVM> svm = train_hog_svm(hog); 21 22 if (svm.empty()) { 23 cerr << "Training failed!" << endl; 24 return -1; 25 } 26 27 Mat img = Mat::zeros(400, 400, CV_8U); 28 29 imshow("img", img); 30 setMouseCallback("img", on_mouse, (void*)&img); 31 32 while (true) { 33 int c = waitKey(); 34 35 if (c = = 27) { 36 break; 37 } else if (c = = ' ') { 38 Mat img_resize; 39 resize(img, img_resize, Size(20, 20), 0, 0, INTER_AREA); 40 41 vector<float> desc; 42 hog.compute(img_resize, desc); 43 44 Mat desc_mat(desc); 45 int res = cvRound(svm->predict(desc_mat.t())); 46 cout << res << endl; 47 48 img.setTo(0); 49 imshow("img", img); 50 } 51 } 52 53 return 0; 54 } 55 56 Ptr<SVM> train_hog_svm(const HOGDescriptor& hog) 57 { 58 Mat digits = imread("digits.png", IMREAD_GRAYSCALE); 59 60 if (digits.empty()) { 61 cerr << "Image load failed!" << endl; 62 return 0; 63 } 64 65 Mat train_hog, train_labels; 66 67 for (int j = 0; j < 50; j++) { 68 for (int i = 0; i < 100; i++) { 69 Mat roi = digits(Rect(i * 20, j * 20, 20, 20)); 70 71 vector<float> desc; 72 hog.compute(roi, desc); 73 74 Mat desc_mat(desc); 75 train_hog.push_back(desc_mat.t()); 76 train_labels.push_back(j / 5); 77 } 78 } 79 80 Ptr<SVM> svm = SVM::create(); 81 svm->setType(SVM::Types::C_SVC); 82 svm->setKernel(SVM::KernelTypes::RBF); 83 svm->setC(2.5); 84 svm->setGamma(0.50625); 85 svm->train(train_hog, ROW_SAMPLE, train_labels); 86 87 return svm; 88 } 89 90 Point ptPrev(-1, -1); 91 92 void on_mouse(int event, int x, int y, int flags, void* userdata) 93 { 94 Mat img = *(Mat*)userdata; 95 96 if (event = = EVENT_LBUTTONDOWN) 97 ptPrev = Point(x, y); 98 else if (event = = EVENT_LBUTTONUP) 99 ptPrev = Point(-1, -1); 100 else if (event = = EVENT_MOUSEMOVE && (flags & EVENT_FLAG_LBUTTON)) 101 { 102 line(img, ptPrev, Point(x, y), Scalar::all(255), 40, LINE_AA, 0); 103 ptPrev = Point(x, y); 104 105 imshow("img", img); 106 } 107 }
6 svmdigits 프로그램은 HOGDescriptor 클래스 구현상의 문제로 디버그 모드에서는 동작하지 않고 릴리스 모드에서만 동작합니다. 그러므로 Visual Studio 상단 솔루션 구성을 Release로 변경한 후 실행하기 바랍니다.