这里面我要具体介绍的检测车牌方法的步骤如下:
Mat img_gray; cvtColor(input, img_gray, CV_BGR2GRAY); blur(img_gray, img_gray, Size(5,5)); // 突出垂直边缘 Mat img_sobel; Sobel(img_gray, img_sobel, CV_8U, 1, 0, 3, 1, 0, BORDER_DEFAULT); if(showSteps) imshow("Sobel", img_sobel); // 阈值化处理 Mat img_threshold; threshold(img_sobel, img_threshold, 0, 255, CV_THRESH_OTSU+CV_THRESH_BINARY); if(showSteps) imshow("Threshold", img_threshold);
// 形态学close处理(先膨胀再腐蚀,填充内部空隙) Mat element = getStructuringElement(MORPH_RECT, Size(17, 3) ); morphologyEx(img_threshold, img_threshold, CV_MOP_CLOSE, element); if(showSteps) imshow("Close", img_threshold);
// 利用findContours函数寻找车牌可能的轮廓 vector< vector< Point> > contours; findContours(img_threshold, contours, // 轮廓的数组 CV_RETR_EXTERNAL, // 获取外轮廓 CV_CHAIN_APPROX_NONE); // 获取每个轮廓的每个像素 // 排除非车牌的可能轮廓 vector<vector<Point> >::iterator itc= contours.begin(); vector<RotatedRect> rects; while (itc!=contours.end()) { // minAreaRect函数计算最小包围旋转矩形 RotatedRect mr= minAreaRect(Mat(*itc)); if( !verifySizes(mr)){ itc= contours.erase(itc); }else{ ++itc; rects.push_back(mr); } } // 画出轮廓 cv::Mat result; input.copyTo(result); cv::drawContours(result,contours, -1, // draw all contours cv::Scalar(255,0,0), // in blue 1); // with a thickness of 1
Flood-fill (node, target-color, replacement-color): If the color of node is not equal to target-color, return. Set the color of node to replacement-color. Perform Flood-fill (one step to the west of node, target-color, replacement-color). Perform Flood-fill (one step to the east of node, target-color, replacement-color). Perform Flood-fill (one step to the north of node, target-color, replacement-color). Perform Flood-fill (one step to the south of node, target-color, replacement-color). Return.
FLOODFILL_FIXED_RANGE If set, the difference between the current pixel and seed pixel is considered. Otherwise, the difference between neighbor pixels is considered (that is, the range is floating).FLOODFILL_MASK_ONLY If set, the function does not change the image ( newVal is ignored), but fills the mask. The flag can be used for the second variant only.
for(int i = 0; i < rects.size(); i++){ // 现在进一步利用车牌的颜色信息,运用floodfill算法。 // flood fill 算法是从一个区域中提取若干个连通的点与其他相邻区域分开的经典算法。它接收三个参数:起始结点, // 目标颜色和替换颜色。 circle(result, rects[i].center, 3, Scalar(0,255,0), -1); //get the min size between width and height float minSize = (rects[i].size.width < rects[i].size.height)? rects[i].size.width : rects[i].size.height; minSize=minSize-minSize*0.5; //initialize rand and get 5 points around center for floodfill algorithm srand ( time(NULL) ); //Initialize floodfill parameters and variables Mat mask; mask.create(input.rows + 2, input.cols + 2, CV_8UC1); mask= Scalar::all(0); int loDiff = 30; int upDiff = 30; int connectivity = 4; int newMaskVal = 255; int NumSeeds = 10; Rect ccomp; int flags = connectivity + (newMaskVal << 8 ) + CV_FLOODFILL_FIXED_RANGE + CV_FLOODFILL_MASK_ONLY; for(int j=0; j<NumSeeds; j++){ Point seed; seed.x=rects[i].center.x+rand()%(int)minSize-(minSize/2); seed.y=rects[i].center.y+rand()%(int)minSize-(minSize/2); circle(result, seed, 1, Scalar(0,255,255), -1); int area = floodFill(input, mask, seed, Scalar(255,0,0), &ccomp, Scalar(loDiff, loDiff, loDiff), Scalar(upDiff, upDiff, upDiff), flags); } if(showSteps) imshow("MASK", mask); //cvWaitKey(0);
关于SVM的相关内容,我以前写过几篇文章,大家可以参考:
支持向量机学习笔记:数学过程及经典Tutorial
支持向量机学习笔记:LIBSVM应用(人脸识别)
libsvm代码阅读
Code:
////////////////////////////////////////////////////////////////////////
// 以下利用SVM来进一步判断检测到的区域是否是车牌
////////////////////////////////////////////////////////////////////////
FileStorage fs;
fs.open("SVM.xml", FileStorage::READ);
Mat SVM_TrainingData;
Mat SVM_Classes;
fs["TrainingData"] >> SVM_TrainingData;
fs["classes"] >> SVM_Classes;
// 设置SVM参数,其中cvTermCriteria是迭代算法的终止准则
CvSVMParams SVM_params;
SVM_params.svm_type = CvSVM::C_SVC;
SVM_params.kernel_type = CvSVM::LINEAR;
SVM_params.degree = 0;
SVM_params.gamma = 1;
SVM_params.coef0 = 0;
SVM_params.C = 1;
SVM_params.nu = 0;
SVM_params.p = 0;
SVM_params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER,
1000, //最大迭代次数
0.01);//结果的精确性
// SVM的训练构造函数
CvSVM svmClassifier(SVM_TrainingData, SVM_Classes, Mat(), Mat(), SVM_params);
// 对上面detectRegions得到的区域利用svm进行判断
vector<Plate> plates;
for (int i = 0; i < posibles_regions.size(); ++i)
{
Mat img = posibles_regions[i].plateImg;
Mat p = img.reshape(1,1);
p.convertTo(p,CV_32FC1);
int response = (int)svmClassifier.predict(p);
if (response == 1)
{
plates.push_back(posibles_regions[i]);
}
}
cout<<"Number plates detected: "<< plates.size() << "\n";
更多图像处理、机器视觉资源请关注 博客:LinJM-机器视觉 微博:林建民-机器视觉