用opencv svm 折騰的識別程式
阿新 • • 發佈:2019-01-07
前面有過用halcon識別字符,現在用opencv折騰下。比較一下
排除svm演算法的問題,對我們來說就是構建合適的分類資料, 在這還是採用《Mastering OpenCV with Practical Computer Vision》中說的 水平方向字元投影 + 豎直方向字元投影 + 縮小後的字元畫素資訊矩陣(把它平鋪)
將所有16個字元的資訊 放在 一個 2維矩陣中 16X (characterOriginalWidth + characterOriginalHeight + characterWidth*characterHeight) 大小
還有需要注意的是 順序, 找到的輪廓順序不一定是你相應的分類順序
#include "stdafx.h" #include <opencv2/core.hpp> #include <opencv2/imgproc.hpp> #include "opencv2/imgcodecs.hpp" #include <opencv2/highgui.hpp> #include <opencv2/ml.hpp> #include <vector> #include <string> #include <sstream> #define HORIZONTAL 1 #define VERTICAL 0 #define characterOriginalWidth 58 #define characterOriginalHeight 120 #define characterWidth 5 #define characterHeight 10 #define testCount 16 using namespace cv; using namespace cv::ml; using std::vector; using std::string; Mat ProjectedHistogram(Mat img, int t) { int sz = (t) ? img.rows : img.cols; Mat mhist = Mat::zeros(1, sz, CV_32F); for (int j = 0; j < sz; j++) { Mat data = (t) ? img.row(j) : img.col(j); mhist.at<float>(j) = countNonZero(data); } //Normalize histogram double min, max; minMaxLoc(mhist, &min, &max); if (max > 0) mhist.convertTo(mhist, -1, 1.0f / max, 0); return mhist; } Mat features(Mat in, int sizeData_X, int sizeData_Y) { Mat vhist = ProjectedHistogram(in, VERTICAL); Mat hhist = ProjectedHistogram(in, HORIZONTAL); Mat lowData; resize(in, lowData, Size(sizeData_X, sizeData_Y)); int numCols = vhist.cols + hhist.cols + lowData.rows*lowData.cols; Mat out = Mat::zeros(1, numCols, CV_32F); int j = 0; for (int i = 0; i < vhist.cols; i++) { out.at<float>(j) = vhist.at<float>(i); j++; } for (int i = 0; i < hhist.cols; i++) { out.at<float>(j) = hhist.at<float>(i); j++; } for (int y = 0; y<lowData.rows; y++) { for (int x = 0; x<lowData.cols; x++) { out.at<float>(j) = (float)lowData.at<unsigned char>(y, x); j++; } } return out; } bool SortByIndex(Rect i, Rect j) { return (i.x<j.x); } int main() { char res[20]; vector<string> letters{"0","1","2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" }; Mat img = imread("D:\\Visual Studio 2015\\Projects\\numbers\\Debug\\1.bmp", CV_LOAD_IMAGE_GRAYSCALE); imshow("輸入原影象", img); Mat binaryImg, meanImg, contoursImg(img.size(), CV_8U, Scalar(255)); GaussianBlur(img, meanImg, Size(5, 19), 0, 0); threshold(meanImg,binaryImg,200,255,CV_THRESH_BINARY_INV); vector<vector<Point>> contours; findContours(binaryImg,contours,CV_RETR_EXTERNAL,CHAIN_APPROX_NONE); drawContours(contoursImg, contours, -1, Scalar(0), 3); int numCols = characterOriginalWidth + characterOriginalHeight + characterWidth*characterHeight; Mat data = Mat::zeros(testCount, numCols, CV_32FC1); //預先產生一個 testCount X 2 的矩陣 Mat labels = Mat::zeros(testCount, 1, CV_32SC1); // Draw blue contours on a white image cv::Mat result; img.copyTo(result); cvtColor(result, result, CV_GRAY2RGB); vector<vector<Point> >::iterator itc = contours.begin(); vector<cv::Rect> contoursRect; //構建輪廓的最小矩形 while (itc != contours.end()) { Rect mr = boundingRect(Mat(*itc)); contoursRect.push_back(mr); ++itc; } //最小矩形輪廓按左上角的x值由小到達排序為了和分類順序對應 sort(contoursRect.begin(),contoursRect.end(), SortByIndex); vector<Rect> ::iterator itcontoursRect = contoursRect.begin(); int i = 0; while (itcontoursRect != contoursRect.end()) { //用矩形切割影象 Mat auxRoi(img, *itcontoursRect); sprintf_s(res, "train_data_%d.jpg", i); //把分割好的影象統一大小(characterOriginalWidth * characterOriginalHeight) resize(auxRoi, auxRoi, Size(characterOriginalWidth, characterOriginalHeight)); imwrite(res, auxRoi); rectangle(result, *itcontoursRect, Scalar(0, 0, 255), 2); Mat f = features(auxRoi, characterWidth, characterHeight); f.row(0).copyTo(data.row(i)); labels.at<int>(i, 0) = i; ++itcontoursRect; i++; } imshow("矩形分割後的輸入原影象", result); Ptr<SVM> svm = SVM::create(); svm->setType(SVM::C_SVC); svm->setKernel(SVM::LINEAR); svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6)); svm->train(data, ROW_SAMPLE, labels); Mat imgPredict = imread("D:\\Visual Studio 2015\\Projects\\numbers\\Debug\\2.bmp", CV_LOAD_IMAGE_GRAYSCALE); Mat binaryImgPredict, meanImgPredict, contoursImgPredict(img.size(), CV_8U, Scalar(255)); imshow("需要預測的影象", imgPredict); GaussianBlur(imgPredict, meanImgPredict, Size(5, 19), 0, 0); threshold(meanImgPredict, binaryImgPredict, 200, 255, CV_THRESH_BINARY_INV); vector<vector<Point>> contoursPredict; findContours(binaryImgPredict, contoursPredict, CV_RETR_EXTERNAL, CHAIN_APPROX_NONE); drawContours(contoursImgPredict, contoursPredict, -1, Scalar(0), 3); vector<vector<Point> >::iterator itcPredict = contoursPredict.begin(); Mat imgPredicted(imgPredict.size().height, imgPredict.size().width,CV_8UC3,Scalar(255,255,255)); while (itcPredict != contoursPredict.end()) { Rect mr = boundingRect(Mat(*itcPredict)); Point point(mr.x, 80); Mat auxRoi(imgPredict, mr); resize(auxRoi, auxRoi, Size(characterOriginalWidth, characterOriginalHeight)); Mat f = features(auxRoi, characterWidth, characterHeight); float response = svm->predict(f); ++itcPredict; int index = response; putText(imgPredicted, letters[index], point, CV_FONT_HERSHEY_SIMPLEX, 1, Scalar(255,0,0)); } imshow("預測結果", imgPredicted); waitKey(0); return 0; }