//! 字符分割与排序 int CCharsSegment::charsSegment(Mat input, vector<Mat>& resultVec) { if( !input.data ) { return -3; } //判断车牌颜色以此确认threshold方法 int plateType = getPlateType(input); cvtColor(input, input, CV_RGB2GRAY); //Threshold input image Mat img_threshold; if (1 == plateType) threshold(input, img_threshold, 10, 255, CV_THRESH_OTSU+CV_THRESH_BINARY); else threshold(input, img_threshold, 10, 255, CV_THRESH_OTSU+CV_THRESH_BINARY_INV); if(m_debug) { stringstream ss(stringstream::in | stringstream::out); ss << "image/tmp/debug_char_threshold" << ".jpg"; imwrite(ss.str(), img_threshold); } //去除车牌上方的柳钉以及下方的横线等干扰 clearLiuDing(img_threshold); if(m_debug) { stringstream ss(stringstream::in | stringstream::out); ss << "image/tmp/debug_char_clearLiuDing" << ".jpg"; imwrite(ss.str(), img_threshold); } Mat img_contours; img_threshold.copyTo(img_contours); vector< vector< Point> > contours; findContours(img_contours, contours, // a vector of contours CV_RETR_EXTERNAL, // retrieve the external contours CV_CHAIN_APPROX_NONE); // all pixels of each contours //Start to iterate to each contour founded vector<vector<Point> >::iterator itc= contours.begin(); vector<Rect> vecRect; //Remove patch that are no inside limits of aspect ratio and area. //将不符合特定尺寸的图块排除出去 while (itc != contours.end()) { Rect mr = boundingRect(Mat(*itc)); Mat auxRoi(img_threshold, mr); if (verifySizes(auxRoi)) { vecRect.push_back(mr); } ++itc; } if (vecRect.size() == 0) return -3; vector<Rect> sortedRect; //对符合尺寸的图块按照从左到右进行排序 SortRect(vecRect, sortedRect); int specIndex = 0; //获得指示城市的特定Rect,如苏A的"A" specIndex = GetSpecificRect(sortedRect); if(m_debug) { if (specIndex < sortedRect.size()) { Mat specMat(img_threshold, sortedRect[specIndex]); stringstream ss(stringstream::in | stringstream::out); ss << "image/tmp/debug_specMat" <<".jpg"; imwrite(ss.str(), specMat); } } //根据特定Rect向左反推出中文字符 //这样做的主要原因是根据findContours方法很难捕捉到中文字符的准确Rect,因此仅能 //退过特定算法来指定 Rect chineseRect; if (specIndex < sortedRect.size()) chineseRect = GetChineseRect(sortedRect[specIndex]); else return -3; if(m_debug) { Mat chineseMat(img_threshold, chineseRect); stringstream ss(stringstream::in | stringstream::out); ss << "image/tmp/debug_chineseMat" <<".jpg"; imwrite(ss.str(), chineseMat); } //新建一个全新的排序Rect //将中文字符Rect第一个加进来,因为它肯定是最左边的 //其余的Rect只按照顺序去6个,车牌只可能是7个字符!这样可以避免阴影导致的“1”字符 vector<Rect> newSortedRect; newSortedRect.push_back(chineseRect); RebuildRect(sortedRect, newSortedRect, specIndex); if (newSortedRect.size() == 0) return -3; for (int i = 0; i < newSortedRect.size(); i++) { Rect mr = newSortedRect[i]; Mat auxRoi(img_threshold, mr); if (1) { auxRoi = preprocessChar(auxRoi); if(m_debug) { stringstream ss(stringstream::in | stringstream::out); ss << "image/tmp/debug_char_auxRoi_" << i <<".jpg"; imwrite(ss.str(), auxRoi); } resultVec.push_back(auxRoi); } } return 0; }
//! 字符分割与排序 int CCharsSegment::charsSegment(Mat input, vector<Mat>& resultVec) { if (!input.data) return -3; int w = input.cols; int h = input.rows; Mat tmpMat = input(Rect(w*0.1,h*0.1,w*0.8,h*0.8)); //判断车牌颜色以此确认threshold方法 Color plateType = getPlateType(tmpMat, true); Mat input_grey; cvtColor(input, input_grey, CV_BGR2GRAY); Mat img_threshold ; if (BLUE == plateType) { //cout << "BLUE" << endl; img_threshold = input_grey.clone(); int w = input_grey.cols; int h = input_grey.rows; Mat tmp = input_grey(Rect(w*0.1,h*0.1,w*0.8,h*0.8)); int threadHoldV = ThresholdOtsu(tmp); imwrite("E:/img_inputgray2.jpg",input_grey); threshold(input_grey, img_threshold, threadHoldV, 255, CV_THRESH_BINARY); imwrite("E:/img_threshold.jpg",img_threshold); //threshold(input_grey, img_threshold, 5, 255, CV_THRESH_OTSU + CV_THRESH_BINARY); } else if (YELLOW == plateType) { //cout << "YELLOW" << endl; img_threshold = input_grey.clone(); int w = input_grey.cols; int h = input_grey.rows; Mat tmp = input_grey(Rect(w*0.1,h*0.1,w*0.8,h*0.8)); int threadHoldV = ThresholdOtsu(tmp); imwrite("./image/tmp/inputgray2.jpg",input_grey); threshold(input_grey, img_threshold, threadHoldV, 255, CV_THRESH_BINARY_INV); //threshold(input_grey, img_threshold, 10, 255, CV_THRESH_OTSU + CV_THRESH_BINARY_INV); } else if (WHITE == plateType) { //cout << "WHITE" << endl; /*img_threshold = input_grey.clone(); int w = input_grey.cols; int h = input_grey.rows; Mat tmp = input_grey(Rect(w*0.1, h*0.1, w*0.8, h*0.8)); int threadHoldV = ThresholdOtsu(tmp); imwrite("./image/tmp/inputgray2.jpg", input_grey);*/ threshold(input_grey, img_threshold, 10, 255, CV_THRESH_OTSU + CV_THRESH_BINARY_INV); } else { //cout << "UNKNOWN" << endl; threshold(input_grey, img_threshold, 10, 255, CV_THRESH_OTSU + CV_THRESH_BINARY); } if (0) { imshow("threshold", img_threshold); waitKey(0); destroyWindow("threshold"); } if (m_debug) { stringstream ss(stringstream::in | stringstream::out); ss << "image/tmp/debug_char_threshold" <<iTag<< ".jpg"; imwrite(ss.str(), img_threshold); } //去除车牌上方的柳钉以及下方的横线等干扰 //并且也判断了是否是车牌 //并且在此对字符的跳变次数以及字符颜色所占的比重做了是否是车牌的判别条件 if(!clearLiuDing(img_threshold)) { return -3; } if (m_debug) { stringstream ss(stringstream::in | stringstream::out); ss << "image/tmp/debug_char_clearLiuDing" <<iTag<< ".jpg"; imwrite(ss.str(), img_threshold); } iTag++; Mat img_contours; img_threshold.copyTo(img_contours); vector< vector< Point> > contours; findContours(img_contours, contours, // a vector of contours CV_RETR_EXTERNAL, // retrieve the external contours CV_CHAIN_APPROX_NONE); // all pixels of each contours //Start to iterate to each contour founded vector<vector<Point> >::iterator itc = contours.begin(); vector<Rect> vecRect; //Remove patch that are no inside limits of aspect ratio and area. //将不符合特定尺寸的图块排除出去 while (itc != contours.end()) { Rect mr = boundingRect(Mat(*itc)); Mat auxRoi(img_threshold, mr); if (verifyCharSizes(auxRoi)) vecRect.push_back(mr); ++itc; } if (vecRect.size() == 0) return -3; vector<Rect> sortedRect; ////对符合尺寸的图块按照从左到右进行排序 SortRect(vecRect, sortedRect); /*vector<Rect> sortedRect(vecRect); std::sort (sortedRect.begin(), sortedRect.end(), [](const Rect &r1, const Rect &r2) { return r1.x < r2.x; } );*/ int specIndex = 0; //获得指示城市的特定Rect,如苏A的"A" specIndex = GetSpecificRect(sortedRect); if (m_debug) { if (specIndex < sortedRect.size()) { Mat specMat(img_threshold, sortedRect[specIndex]); stringstream ss(stringstream::in | stringstream::out); ss << "image/tmp/debug_specMat" << ".jpg"; imwrite(ss.str(), specMat); } } //根据特定Rect向左反推出中文字符 //这样做的主要原因是根据findContours方法很难捕捉到中文字符的准确Rect,因此仅能 //退过特定算法来指定 Rect chineseRect; if (specIndex < sortedRect.size()) chineseRect = GetChineseRect(sortedRect[specIndex]); else return -3; if (m_debug) { Mat chineseMat(img_threshold, chineseRect); stringstream ss(stringstream::in | stringstream::out); ss << "image/tmp/debug_chineseMat" << ".jpg"; imwrite(ss.str(), chineseMat); } //新建一个全新的排序Rect //将中文字符Rect第一个加进来,因为它肯定是最左边的 //其余的Rect只按照顺序去6个,车牌只可能是7个字符!这样可以避免阴影导致的“1”字符 vector<Rect> newSortedRect; newSortedRect.push_back(chineseRect); RebuildRect(sortedRect, newSortedRect, specIndex); if (newSortedRect.size() == 0) return -3; for (int i = 0; i < newSortedRect.size(); i++) { Rect mr = newSortedRect[i]; Mat auxRoi(img_threshold, mr); if (1) { auxRoi = preprocessChar(auxRoi); if (m_debug) { stringstream ss(stringstream::in | stringstream::out); ss << "image/tmp/debug_char_auxRoi_" << (i+staticIndex) << ".jpg"; imwrite(ss.str(), auxRoi); } resultVec.push_back(auxRoi); } } staticIndex+=newSortedRect.size(); return 0; }