轉自 http://blog.csdn.net/yiluoyan/article/details/45308785ios
這篇文章接着以前的車牌識別,從輸入的車圖片中分割識別出車牌以後,將進行下一步:車牌號的識別,這裏主要使用光學字符識別車牌字符。對每一個檢測到的車牌,將其每一個字符分割出來,而後使用人工神經網絡(artificial neural network,ANN)學習算法識別字符。算法
1.字符分割
將得到的車牌圖像進行直方圖均衡,而後採用閾值濾波器對圖像進行處理,而後查找字符輪廓。數組
原圖像: 網絡
閾值圖像: 數據結構
查找輪廓,後畫出其外接矩形圖像: 函數
而後將字符逐一分割,學習
分割code:測試
#include <iostream> #include <stdlib.h> #include <vector> #include <cv.h> #include <highgui.h> #include <ml.h> #include <cvaux.h> using namespace std; using namespace cv; #define HORIZONTAL 1 #define VERTICAL 0 bool verifySizes(Mat r) //驗證框出來的區域是否爲字符 { //char sizes 45*77 float aspect = 45.0f / 77.0f; //字符的寬高比爲 45/77 float charAspect = (float) r.cols / (float) r.rows; float error = 0.35; float minHeight = 15; float maxHeight = 28; float minAspect = 0.2; float maxAspect = aspect + aspect * error; float area = countNonZero(r); //統計區域像素 float bbArea = r.cols * r.rows; //區域面積 float percPixels = area / bbArea; //像素比值 if(percPixels < 0.8 && charAspect > minAspect && charAspect < maxAspect && r.rows >= minHeight && r.rows < maxHeight) return true; else return false; } Mat preprocessChar(Mat in) { int h = in.rows; int w = in.cols; int charSize = 20; //統一字符大小 Mat transformMat = Mat :: eye(2, 3, CV_32F); int m = max (w, h); transformMat.at<float>(0,2) = m/2 -w/2; transformMat.at<float>(1,2) = m/2 -h/2; Mat warpImage(m, m, in.type()); warpAffine(in, warpImage, transformMat, warpImage.size(), INTER_LINEAR, BORDER_CONSTANT,Scalar(0)); Mat out; resize(warpImage, out, Size( charSize, charSize)); return out; } //計算累積直方圖 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); //統計這一行/列中的非零元素個數,保存到mhist中 } double min, max; minMaxLoc(mhist, &min, &max); if (max > 0) { mhist.convertTo(mhist, -1, 1.0f / max, 0); // 用mhist直方圖的最大值,歸一化直方圖 } return mhist; } Mat getVisualHistogram(Mat *hist, int type) { int size =100; Mat imHist; if(type == HORIZONTAL) imHist.create(Size(size, hist->cols), CV_8UC3 ); else imHist.create(Size(hist->cols, size), CV_8UC3); imHist = Scalar(55, 55, 55); for (int i = 0; i < hist->cols; i++) { float value = hist->at<float>(i); int maxval = (int) (value * size); Point pt1; Point pt2, pt3, pt4; if (type == HORIZONTAL) { pt1.x = pt3.x = 0; pt2.x = pt4.x = maxval; pt1.y = pt2.y = i; pt3.y = pt4.y = i+1; line(imHist, pt1, pt2, CV_RGB(220, 220, 220), 1, 8, 0); line(imHist, pt3, pt4, CV_RGB(34, 34, 34), 1, 8, 0); pt3.y = pt4.y = i+2; line(imHist, pt3, pt4, CV_RGB(44, 44, 44), 1, 8, 0); pt3.y = pt4.y = i+3; line(imHist, pt3, pt4, CV_RGB(50, 50, 50), 1, 8, 0); } else { pt1.x = pt2.x = i; pt3.x = pt4.x = i+1; pt1.y = pt3.y = 100; pt2.y = pt4.y = 100 - maxval; line(imHist, pt1, pt2, CV_RGB(220, 220, 220), 1, 8, 0); line(imHist, pt3, pt4, CV_RGB(34, 34, 34), 1, 8, 0); pt3.x = pt4.x = i+2; line(imHist, pt3, pt4, CV_RGB(44, 44, 44), 1, 8, 0); pt3.x = pt4.x =i + 3; line(imHist, pt3, pt4, CV_RGB(50, 50, 50), 1, 8, 0); } } return imHist; } void drawVisualFeatures(Mat charcter, Mat hhist, Mat vhist, Mat lowData, int count) { Mat img(121, 121, CV_8UC3, Scalar(0,0,0)); Mat ch; Mat ld; char res[20]; cvtColor(charcter, ch, CV_GRAY2BGR); resize(lowData, ld, Size(100, 100), 0, 0, INTER_NEAREST); //將ld從15*15擴大到100*100 cvtColor(ld, ld, CV_GRAY2BGR); Mat hh = getVisualHistogram(&hhist, HORIZONTAL); Mat hv = getVisualHistogram(&vhist, VERTICAL); Mat subImg = img(Rect(0, 101, 20, 20)); //ch:20*20 ch.copyTo(subImg); subImg = img(Rect(21, 101, 100, 20)); //hh:100*hist.cols hh.copyTo(subImg); subImg = img(Rect(0, 0, 20, 100)); //hv:hist.cols*100 hv.copyTo(subImg); subImg = img(Rect(21, 0, 100, 100)); //ld:100*100 ld.copyTo(subImg); line( img, Point(0, 100), Point(121, 100), Scalar(0,0,255) ); line( img, Point(20, 0), Point(20, 121), Scalar(0,0,255) ); stringstream ss(stringstream::in | stringstream::out); ss << "E://opencvcodetext//ANPR//"<<"hist"<< "_" << count <<" .jpg"; imwrite(ss.str(), img); imshow("visual feature",img); //顯示特徵 cvWaitKey(0); } Mat features(Mat in, int sizeData, int count) { //直方圖特徵 Mat vhist = ProjectedHistogram(in, VERTICAL); Mat hhist = ProjectedHistogram(in, HORIZONTAL); Mat lowdata; //低分辨圖像特徵 sizeData * sizeData resize(in, lowdata, Size(sizeData, sizeData)); drawVisualFeatures(in, hhist, vhist, lowdata, count); //畫出直方圖 int numCols = vhist.cols + hhist.cols + lowdata.cols * 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 x = 0; x <lowdata.cols; x++) { for (int y = 0; y < lowdata.rows; y++) { out.at<float>(j) = (float)lowdata.at<unsigned char>(x, y); j++; } } return out; } int main(int argc, char