去年七月份由於學校項目須要開始接觸圖像處理,但那時候只是到網上找車牌識別代碼,而後加入到本身的項目中,不太清楚細節原理。html
如今本身從新一步步實現車牌識別。 ios
車牌識別流程:算法
高斯模糊:數組
車牌識別中利用高斯模糊將圖片平滑化,去除干擾的噪聲對後續圖像處理的影響。ide
高斯模糊(GaussianBlur()),也叫高斯平滑。函數
1 Mat Gaussian(Mat &img) { 2 Mat out; 3 GaussianBlur(img, out, Size(3, 3), 4 0, 0, BORDER_DEFAULT); 5 return out; 6 7 }
原圖:(來自百度)學習
灰度化:測試
在車牌識別中咱們須要將圖像轉化爲灰度圖像,這樣有利於後續步驟的開展,如Soble算子只能做用於灰度圖像。網站
灰度化,在RGB模型中,若是R=G=B時,則彩色表示一種灰度顏色,其中R=G=B的值叫灰度值,所以,灰度圖像每一個像素只需一個字節存放灰度值(又稱強度值、亮度值),灰度範圍爲0-255。ui
Opencv中函數
void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0 )
參數詳解:
src:輸入圖像:8位無符號的16位無符號(cv_16uc…)或單精度浮點。
dst:的大小和深度src.
code:輸出圖像顏色空間轉換的代碼。
dstCn:目標圖像中的信道數;若是參數爲0,則從SRC和代碼自動導出信道的數目。
1 Mat Grayscale(Mat &img) { 2 Mat out; 3 cvtColor(img, out, CV_RGB2GRAY); 4 5 return out; 6 }
Sobel算子(X方向):
車牌定位的核心算法,水平方向上的邊緣檢測,檢測出車牌區域。
主要用於得到數字圖像的一階梯度,常見的應用和物理意義是邊緣檢測。在技術上,它是一個離散的一階差分算子,用來計算圖像亮度函數的一階梯度之近似值。在圖像的任何一點使用此算子,將會產生該點對應的梯度矢量或是其法矢量。
參數:
src: 源圖像。
dst:相同大小和相同數量的通道的目標圖像。
ddepth:目標圖像的深度。
xorder:階導數的X.
yorder:階導數的Y.
ksize:擴展Sobel算子–大小。它必須是1, 3, 5,或者7。
scale:計算衍生值的可選刻度因子。默認狀況下,不該用縮放。看到getderivkernels()詳情。
delta :可選的delta值,在將它們存儲在DST以前添加到結果中。
bordertype:像素外推方法。
convertScaleAbs()——先縮放元素再取絕對值,最後轉換格式爲8bit型。
1 Mat Sobel(Mat &img) { 2 Mat out; 3 Mat grad_x, grad_y; 4 Mat abs_grad_x, abs_grad_y; 5 6 //X方向 7 //Sobel(img, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT); 8 //convertScaleAbs(grad_x, abs_grad_x); 9 Sobel(img, img, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT); 10 convertScaleAbs(img, out); 11 12 //Y方向 13 //Sobel(img, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT); 14 //convertScaleAbs(grad_y, abs_grad_y); 15 //convertScaleAbs(img, out); 16 17 //合併 18 //addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, out); 19 20 return out; 21 }
二值化:
進一步對圖像進行處理,強化目標區域,弱化背景。
圖像的二值化,就是將圖像上的像素點的灰度值設置爲0或255,也就是將整個圖像呈現出明顯的只有黑和白的視覺效果。
OpenCV中函數
double threshold(InputArray src, OutputArray dst, double thresh, double maxVal, int thresholdType)
參數:
src:源陣列(單通道,32位浮點8位)。
dst:相同大小和類型的目標數組。
thresh:門限閾值。
Maxval:最大值使用的thresh_binary和thresh_binary_inv閾值類型。
thresholdtype:閾值型,以下。
THRESH_BINARY 當前點值大於閾值時,取Maxval,也就是第四個參數,下面再不說明,不然設置爲0
THRESH_BINARY_INV 當前點值大於閾值時,設置爲0,不然設置爲Maxval
THRESH_TRUNC 當前點值大於閾值時,設置爲閾值,不然不改變
THRESH_TOZERO 當前點值大於閾值時,不改變,不然設置爲0
THRESH_TOZERO_INV 當前點值大於閾值時,設置爲0,不然不改變
1 Mat TwoValued(Mat &img) { 2 Mat out; 3 threshold(img, out, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY); 4 //threshold(img, out, 100, 255, CV_THRESH_BINARY); 5 6 return out; 7 }
閉操做:
閉操做能夠將目標區域連成一個總體,便於後續輪廓的提取。
閉操做可以使輪廓線更光滑,但與開操做相反的是,閉操做一般消彌狹窄的間斷和長細的鴻溝,消除小的空洞,並填補輪廓線中的斷裂。
參數:
src:源圖像。
dst:相同大小和類型的目標圖像。
element:內核類型 用getStructuringElement函數獲得。
OP:
能夠是如下形式之一的形態學操做的類型:
morph_open -開啓操做
morph_close -閉合操做
morph_gradient -形態學梯度
morph_tophat「頂帽」
morph_blackhat -「黑帽」
iterations:侵蝕和膨脹的次數被應用。
bordertype–像素外推方法。
bordervalue–邊界值在一個恆定的邊界狀況。默認值有特殊含義。
關注前4個參數便可,後面用默認參數。
1 Mat Close(Mat &img) { 2 Mat out; 3 //Mat element(5, 5, CV_8U, cv::Scalar(1)); 4 Mat element = getStructuringElement(MORPH_RECT, Size(17, 5)); 5 morphologyEx(img, out, cv::MORPH_CLOSE, element); 6 7 return out; 8 }
取輪廓:
將前面處理的車牌目標區域提取出來。
相關函數:
查找輪廓:
void findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point())
image: 輸入的 8-比特、單通道圖像. 非零元素被當成 1, 0 象素值保留爲 0 - 從而圖像被當作二值的。爲了從灰度圖像中獲得這樣的二值圖像,可使用 cvThreshold, cvAdaptiveThreshold 或 cvCanny. 本函數改變輸入圖像內容。
storage :獲得的輪廓的存儲容器
first_contour :輸出參數:包含第一個輸出輪廓的指針
header_size :若是 method=CV_CHAIN_CODE,則序列頭的大小 >=sizeof(CvChain),不然 >=sizeof(CvContour) .
mode :
提取模式.
CV_RETR_EXTERNAL - 只提取最外層的輪廓
CV_RETR_LIST - 提取全部輪廓,而且放置在 list 中
CV_RETR_CCOMP - 提取全部輪廓,而且將其組織爲兩層的 hierarchy: 頂層爲連通域的外圍邊界,次層爲洞的內層邊界。
CV_RETR_TREE - 提取全部輪廓,而且重構嵌套輪廓的所有 hierarchy
method :
逼近方法 (對全部節點, 不包括使用內部逼近的 CV_RETR_RUNS).
CV_CHAIN_CODE - Freeman 鏈碼的輸出輪廓. 其它方法輸出多邊形(定點序列).
CV_CHAIN_APPROX_NONE - 將全部點由鏈碼形式翻譯(轉化)爲點序列形式
CV_CHAIN_APPROX_SIMPLE - 壓縮水平、垂直和對角分割,即函數只保留末端的象素點;
CV_CHAIN_APPROX_TC89_L1,
CV_CHAIN_APPROX_TC89_KCOS - 應用 Teh-Chin 鏈逼近算法. CV_LINK_RUNS - 經過鏈接爲 1 的水平碎片使用徹底不一樣的輪廓提取算法。僅有 CV_RETR_LIST 提取模式能夠在本方法中應用.
offset :
每個輪廓點的偏移量. 當輪廓是從圖像 ROI 中提取出來的時候,使用偏移量有用,由於能夠從整個圖像上下文來對輪廓作分析.
函數 cvFindContours 從二值圖像中提取輪廓,而且返回提取輪廓的數目。指針 first_contour 的內容由函數填寫。它包含第一個最外層輪廓的指針,若是指針爲 NULL,則沒有檢測到輪廓(好比圖像是全黑的)。其它輪廓能夠從 first_contour 利用 h_next 和 v_next 連接訪問到。 在 cvDrawContours 的樣例顯示如何使用輪廓來進行連通域的檢測。輪廓也能夠用來作形狀分析和對象識別 - 見CVPR2001 教程中的 squares 樣例。該教程能夠在 SourceForge 網站上找到。
繪製輪廓:
void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, intthickness=1, int lineType=8, InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point() )
相關參數參考——http://www.opencv.org.cn/opencvdoc/2.3.2/html/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=drawcontours#cv.DrawContours
漫水填充算法:
int floodFill(InputOutputArray image, Point seed, Scalar newVal, Rect* rect=0, Scalar loDiff=Scalar(), ScalarupDiff=Scalar(), int flags=4 )
相關參數參考——http://www.opencv.org.cn/opencvdoc/2.3.2/html/modules/imgproc/doc/miscellaneous_transformations.html?highlight=floodfill#cv.FloodFill
尺寸判斷函數
1 bool verifySizes(RotatedRect mr) 2 { 3 float error = 0.3; 4 //Spain car plate size: 52x11 aspect 4,7272 5 //China car plate size: 440mm*140mm,aspect 3.142857 6 float aspect = 3.142857; 7 //Set a min and max area. All other patchs are discarded 8 int min= 1*aspect*1; // minimum area 9 int max= 2000*aspect*2000; // maximum area 10 //int min = 44 * 14 * m_verifyMin; // minimum area 11 //int max = 44 * 14 * m_verifyMax; // maximum area 12 //Get only patchs that match to a respect ratio. 13 float rmin = aspect - aspect*error; 14 float rmax = aspect + aspect*error; 15 16 int area = mr.size.height * mr.size.width; 17 float r = (float)mr.size.width / (float)mr.size.height; 18 if (r < 1) 19 { 20 r = (float)mr.size.height / (float)mr.size.width; 21 } 22 23 if ((area < min || area > max) || (r < rmin || r > rmax)) 24 { 25 return false; 26 } 27 else 28 { 29 return true; 30 } 31 }
均衡直方圖:
1 Mat histeq(Mat in) 2 { 3 Mat out(in.size(), in.type()); 4 if (in.channels() == 3) { 5 Mat hsv; 6 vector<Mat> hsvSplit; 7 cvtColor(in, hsv, CV_BGR2HSV); 8 split(hsv, hsvSplit); 9 equalizeHist(hsvSplit[2], hsvSplit[2]); 10 merge(hsvSplit, hsv); 11 cvtColor(hsv, out, CV_HSV2BGR); 12 } 13 else if (in.channels() == 1) { 14 equalizeHist(in, out); 15 } 16 17 return out; 18 19 }
總體代碼:
1 void Contour(Mat &img, Mat &out) { 2 RNG rng(12345); 3 4 vector< Mat > contours(1000); 5 vector<Vec4i> hierarchy(1000); 6 findContours(img, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); 7 8 9 vector< Mat >::iterator itc = contours.begin(); 10 vector<RotatedRect> rects; 11 int t = 0; 12 while (itc != contours.end()) { 13 //Create bounding rect of object 14 RotatedRect mr = minAreaRect(Mat(*itc)); 15 //large the rect for more 16 if (!verifySizes(mr)) { 17 itc = contours.erase(itc); 18 } 19 else { 20 ++itc; 21 rects.push_back(mr); 22 } 23 } 24 25 cv::Mat result; 26 img.copyTo(result); 27 for (int i = 0; i< contours.size(); i++) 28 { 29 drawContours(result, contours, i, Scalar(0, 0, 255), 2, 8, vector<Vec4i>(), 0, Point()); 30 //drawContours(result, contours, i, Scalar(255), 2); 31 } 32 33 //imshow("MASK11", result); 34 35 for (int i = 0; i < rects.size(); i++) { 36 circle(result, rects[i].center, 3, Scalar(0, 255, 0), -1); 37 38 float minSize = (rects[i].size.width < rects[i].size.height) ? rects[i].size.width : rects[i].size.height; 39 //minSize = minSize - minSize*0.5; 40 41 srand(time(NULL)); 42 Mat mask; 43 mask.create(out.rows + 2, out.cols + 2, CV_8UC1); 44 mask = Scalar::all(0); 45 int loDiff = 30; 46 int upDiff = 30; 47 int connectivity = 4; 48 int newMaskVal = 255; 49 int NumSeeds = 10; 50 Rect ccomp; 51 int flags = connectivity + (newMaskVal << 8) + CV_FLOODFILL_FIXED_RANGE + CV_FLOODFILL_MASK_ONLY; 52 53 for (int j = 0; j < NumSeeds; j++) { 54 Point seed; 55 seed.x = rects[i].center.x + rand() % (int)minSize - (minSize / 2); 56 seed.y = rects[i].center.y + rand() % (int)minSize - (minSize / 2); 57 circle(result, seed, 1, Scalar(0, 255, 255), -1); 58 int area = floodFill(out, mask, seed, Scalar(255, 0, 0), &ccomp, Scalar(loDiff, loDiff, loDiff), Scalar(upDiff, upDiff, upDiff), flags); 59 } 60 61 //imshow("MASK", mask); 62 63 vector<Point> pointsInterest; 64 Mat_<uchar>::iterator itMask = mask.begin<uchar>(); 65 Mat_<uchar>::iterator end = mask.end<uchar>(); 66 for (; itMask != end; ++itMask) 67 if (*itMask == 255) 68 pointsInterest.push_back(itMask.pos()); 69 70 RotatedRect minRect = minAreaRect(pointsInterest); 71 72 if (verifySizes(minRect)) { 73 // rotated rectangle drawing 74 Point2f rect_points[4]; minRect.points(rect_points); 75 for (int j = 0; j < 4; j++) 76 line(result, rect_points[j], rect_points[(j + 1) % 4], Scalar(0, 0, 255), 1, 8); 77 78 //Get rotation matrix 79 float r = (float)minRect.size.width / (float)minRect.size.height; 80 float angle = minRect.angle; 81 if (r < 1) 82 angle = 90 + angle; 83 Mat rotmat = getRotationMatrix2D(minRect.center, angle, 1); 84 85 //Create and rotate image 86 Mat img_rotated; 87 warpAffine(out, img_rotated, rotmat, out.size(), CV_INTER_CUBIC);//實現旋轉 88 89 //Crop image 90 Size rect_size = minRect.size; 91 if (r < 1) 92 swap(rect_size.width, rect_size.height); 93 Mat img_crop; 94 getRectSubPix(img_rotated, rect_size, minRect.center, img_crop); 95 96 Mat resultResized; 97 resultResized.create(33, 144, CV_8UC3); 98 resize(img_crop, resultResized, resultResized.size(), 0, 0, INTER_CUBIC);; 99 100 ////Equalize croped image 101 Mat grayResult; 102 cvtColor(resultResized, grayResult, CV_BGR2GRAY);// CV_RGB2GRAY 103 blur(grayResult, grayResult, Size(3, 3)); 104 grayResult = histeq(grayResult); 105 106 if (1) { 107 stringstream ss(stringstream::in | stringstream::out); 108 ss << "haha" << "_" << i << ".jpg"; 109 imwrite(ss.str(), grayResult); 110 } 111 112 } 113 } 114 }
主函數:
1 int main() { 2 Mat img; 3 Mat out; 4 //Mat result; 5 6 //載入圖片 7 img = imread("test1.jpg");//, CV_LOAD_IMAGE_GRAYSCALE); 8 img.copyTo(out); 9 //imshow ("原始圖", img); 10 11 img = Gaussian(img); 12 //imshow ("高斯模糊", img); 13 14 img = Grayscale(img); 15 //imshow("灰度化", img); 16 17 img = Sobel(img); 18 //imshow("Sobel_X", img); 19 20 img = TwoValued(img); 21 //imshow("二值化", img); 22 23 img = Close(img); 24 //imshow("閉操做", img); 25 26 // 27 Contour(img, out); 28 29 waitKey(0); 30 cvDestroyAllWindows(); 31 }
車牌定位部分完整代碼:
1 /*------------------------------ - 程序介紹------------------------------*/ 2 //版本:VS2017 + Opencv2.4.9 3 //描述:OpenCV學習之路——車牌識別之車牌定位 4 /*-----------------------------------------------------------------------*/ 5 6 7 #include "opencv.hpp" 8 #include "opencv2/highgui/highgui.hpp" 9 #include "opencv2/imgproc/imgproc.hpp" 10 #include "opencv2\core\core.hpp" 11 #include "vector" 12 #include "iostream" 13 #include "time.h" 14 15 using namespace cv; 16 using namespace std; 17 18 Mat histeq(Mat in) 19 { 20 Mat out(in.size(), in.type()); 21 if (in.channels() == 3) { 22 Mat hsv; 23 vector<Mat> hsvSplit; 24 cvtColor(in, hsv, CV_BGR2HSV); 25 split(hsv, hsvSplit); 26 equalizeHist(hsvSplit[2], hsvSplit[2]); 27 merge(hsvSplit, hsv); 28 cvtColor(hsv, out, CV_HSV2BGR); 29 } 30 else if (in.channels() == 1) { 31 equalizeHist(in, out); 32 } 33 34 return out; 35 36 } 37 38 //! 對minAreaRect得到的最小外接矩形,用縱橫比進行判斷 39 bool verifySizes(RotatedRect mr) 40 { 41 float error = 0.3; 42 //Spain car plate size: 52x11 aspect 4,7272 43 //China car plate size: 440mm*140mm,aspect 3.142857 44 float aspect = 3.142857; 45 //Set a min and max area. All other patchs are discarded 46 int min= 1*aspect*1; // minimum area 47 int max= 2000*aspect*2000; // maximum area 48 //int min = 44 * 14 * m_verifyMin; // minimum area 49 //int max = 44 * 14 * m_verifyMax; // maximum area 50 //Get only patchs that match to a respect ratio. 51 float rmin = aspect - aspect*error; 52 float rmax = aspect + aspect*error; 53 54 int area = mr.size.height * mr.size.width; 55 float r = (float)mr.size.width / (float)mr.size.height; 56 if (r < 1) 57 { 58 r = (float)mr.size.height / (float)mr.size.width; 59 } 60 61 if ((area < min || area > max) || (r < rmin || r > rmax)) 62 { 63 return false; 64 } 65 else 66 { 67 return true; 68 } 69 } 70 71 Mat Gaussian(Mat &img) { 72 Mat out; 73 GaussianBlur(img, out, Size(3, 3), 74 0, 0, BORDER_DEFAULT); 75 return out; 76 77 } 78 79 Mat Grayscale(Mat &img) { 80 Mat out; 81 cvtColor(img, out, CV_RGB2GRAY); 82 83 return out; 84 } 85 86 Mat Sobel(Mat &img) { 87 Mat out; 88 Mat grad_x, grad_y; 89 Mat abs_grad_x, abs_grad_y; 90 91 //X方向 92 //Sobel(img, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT); 93 //convertScaleAbs(grad_x, abs_grad_x); 94 Sobel(img, img, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT); 95 convertScaleAbs(img, out); 96 97 //Y方向 98 //Sobel(img, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT); 99 //convertScaleAbs(grad_y, abs_grad_y); 100 //convertScaleAbs(img, out); 101 102 //合併 103 //addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, out); 104 105 return out; 106 } 107 108 Mat TwoValued(Mat &img) { 109 Mat out; 110 threshold(img, out, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY); 111 //threshold(img, out, 100, 255, CV_THRESH_BINARY); 112 113 return out; 114 } 115 116 Mat Close(Mat &img) { 117 Mat out; 118 //Mat element(5, 5, CV_8U, cv::Scalar(1)); 119 Mat element = getStructuringElement(MORPH_RECT, Size(17, 5)); 120 morphologyEx(img, out, cv::MORPH_CLOSE, element); 121 122 return out; 123 } 124 125 126 void Contour(Mat &img, Mat &out) { 127 RNG rng(12345); 128 129 vector< Mat > contours(1000); 130 vector<Vec4i> hierarchy(1000); 131 findContours(img, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); 132 133 134 vector< Mat >::iterator itc = contours.begin(); 135 vector<RotatedRect> rects; 136 int t = 0; 137 while (itc != contours.end()) { 138 //Create bounding rect of object 139 RotatedRect mr = minAreaRect(Mat(*itc)); 140 //large the rect for more 141 if (!verifySizes(mr)) { 142 itc = contours.erase(itc); 143 } 144 else { 145 ++itc; 146 rects.push_back(mr); 147 } 148 } 149 150 cv::Mat result; 151 img.copyTo(result); 152 for (int i = 0; i< contours.size(); i++) 153 { 154 drawContours(result, contours, i, Scalar(0, 0, 255), 2, 8, vector<Vec4i>(), 0, Point()); 155 //drawContours(result, contours, i, Scalar(255), 2); 156 } 157 //imshow("畫輪廓", out); 158 159 for (int i = 0; i < rects.size(); i++) { 160 circle(result, rects[i].center, 3, Scalar(0, 255, 0), -1); 161 162 float minSize = (rects[i].size.width < rects[i].size.height) ? rects[i].size.width : rects[i].size.height; 163 //minSize = minSize - minSize*0.5; 164 165 srand(time(NULL)); 166 Mat mask; 167 mask.create(out.rows + 2, out.cols + 2, CV_8UC1); 168 mask = Scalar::all(0); 169 int loDiff = 30; 170 int upDiff = 30; 171 int connectivity = 4; 172 int newMaskVal = 255; 173 int NumSeeds = 10; 174 Rect ccomp; 175 int flags = connectivity + (newMaskVal << 8) + CV_FLOODFILL_FIXED_RANGE + CV_FLOODFILL_MASK_ONLY; 176 177 for (int j = 0; j < NumSeeds; j++) { 178 Point seed; 179 seed.x = rects[i].center.x + rand() % (int)minSize - (minSize / 2); 180 seed.y = rects[i].center.y + rand() % (int)minSize - (minSize / 2); 181 circle(result, seed, 1, Scalar(0, 255, 255), -1); 182 int area = floodFill(out, mask, seed, Scalar(255, 0, 0), &ccomp, Scalar(loDiff, loDiff, loDiff), Scalar(upDiff, upDiff, upDiff), flags); 183 } 184 imshow("漫水填充", mask); 185 186 vector<Point> pointsInterest; 187 Mat_<uchar>::iterator itMask = mask.begin<uchar>(); 188 Mat_<uchar>::iterator end = mask.end<uchar>(); 189 for (; itMask != end; ++itMask) 190 if (*itMask == 255) 191 pointsInterest.push_back(itMask.pos()); 192 193 RotatedRect minRect = minAreaRect(pointsInterest); 194 195 if (verifySizes(minRect)) { 196 // rotated rectangle drawing 197 Point2f rect_points[4]; minRect.points(rect_points); 198 for (int j = 0; j < 4; j++) 199 line(result, rect_points[j], rect_points[(j + 1) % 4], Scalar(0, 0, 255), 1, 8); 200 201 //Get rotation matrix 202 float r = (float)minRect.size.width / (float)minRect.size.height; 203 float angle = minRect.angle; 204 if (r < 1) 205 angle = 90 + angle; 206 Mat rotmat = getRotationMatrix2D(minRect.center, angle, 1); 207 208 //Create and rotate image 209 Mat img_rotated; 210 warpAffine(out, img_rotated, rotmat, out.size(), CV_INTER_CUBIC);//實現旋轉 211 212 //Crop image 213 Size rect_size = minRect.size; 214 if (r < 1) 215 swap(rect_size.width, rect_size.height); 216 Mat img_crop; 217 getRectSubPix(img_rotated, rect_size, minRect.center, img_crop); 218 219 Mat resultResized; 220 resultResized.create(33, 144, CV_8UC3); 221 resize(img_crop, resultResized, resultResized.size(), 0, 0, INTER_CUBIC);; 222 223 ////Equalize croped image 224 Mat grayResult; 225 cvtColor(resultResized, grayResult, CV_BGR2GRAY);// CV_RGB2GRAY 226 blur(grayResult, grayResult, Size(3, 3)); 227 grayResult = histeq(grayResult); 228 229 if (1) { 230 stringstream ss(stringstream::in | stringstream::out); 231 ss << "haha" << "_" << i << ".jpg"; 232 imwrite(ss.str(), grayResult); 233 } 234 235 } 236 } 237 } 238 239 240 int main() { 241 Mat img; 242 Mat out; 243 //Mat result; 244 245 //載入圖片 246 img = imread("test1.jpg");//, CV_LOAD_IMAGE_GRAYSCALE); 247 img.copyTo(out); 248 //imshow ("原始圖", img); 249 img = Gaussian(img); 250 imshow ("高斯模糊", img); 251 252 img = Grayscale(img); 253 imshow("灰度化", img); 254 255 img = Sobel(img); 256 imshow("Sobel_X", img); 257 258 img = TwoValued(img); 259 imshow("二值化", img); 260 261 img = Close(img); 262 imshow("閉操做", img); 263 264 Contour(img, out); 265 266 waitKey(0); 267 cvDestroyAllWindows(); 268 }
總結:
車牌定位部分到此告一段落,但這方面的研究還要繼續。
本算法僅適用於特定的圖片,對於另外一些場合的圖片須要從新進行參數測試以判斷準確率。須要對算法進一步完善,實現複雜背景下車牌的識別。
同時想要獲得更準確的車牌區域,須要進行SVM訓練。
注:
註解部分來自百度百科和http://www.opencv.org.cn
學習自——http://www.cnblogs.com/subconscious/p/3979988.html