交通标识牌检测及识别c++代码实例及运行结果 (可自行在网上下载图片测试)

运行环境:vs2013+opencv2.4.9+win10ios

数据来源于GTSRBc++

效果不是很理想(预处理方法、检测用的rgb2hsv、圆度检测,、参数,总之改变程序中不少东西能够尝试提升准确率),但检测及识别的道路是打通了app

c++代码测试

#include<iostream>
#include<opencv2/opencv.hpp>
#include<string>
#define PI 3.1415926

using namespace std;
using namespace cv;

void RGB2HSV(double red, double green, double blue, double& hue, double& saturation, double& intensity)
{

	double r, g, b;
	double h, s, i;

	double sum;
	double minRGB, maxRGB;
	double theta;

	r = red / 255.0;
	g = green / 255.0;
	b = blue / 255.0;

	minRGB = ((r<g) ? (r) : (g));
	minRGB = (minRGB<b) ? (minRGB) : (b);

	maxRGB = ((r>g) ? (r) : (g));
	maxRGB = (maxRGB>b) ? (maxRGB) : (b);

	sum = r + g + b;
	i = sum / 3.0;

	if (i<0.001 || maxRGB - minRGB<0.001)
	{
		h = 0.0;
		s = 0.0;
		//return ;
	}
	else
	{
		s = 1.0 - 3.0*minRGB / sum;
		theta = sqrt((r - g)*(r - g) + (r - b)*(g - b));
		theta = acos((r - g + r - b)*0.5 / theta);
		if (b <= g)
			h = theta;
		else
			h = 2 * PI - theta;
		if (s <= 0.01)
			h = 0;
	}

	hue = (int)(h * 180 / PI);
	saturation = (int)(s * 100);
	intensity = (int)(i * 100);
}

void fillHole(const Mat srcBw, Mat &dstBw)
{
	Size m_Size = srcBw.size();
	Mat Temp = Mat::zeros(m_Size.height + 2, m_Size.width + 2, srcBw.type());
	srcBw.copyTo(Temp(Range(1, m_Size.height + 1), Range(1, m_Size.width + 1)));

	cv::floodFill(Temp, Point(0, 0), Scalar(255));

	Mat cutImg;
	Temp(Range(1, m_Size.height + 1), Range(1, m_Size.width + 1)).copyTo(cutImg);

	dstBw = srcBw | (~cutImg);
}

int main()
{
	char path[512];
	CvSVM classifier;//载入分类器
	classifier.load("E:\\vs2013\\opencv_code\\GTSRBtrafficSign\\train\\train.xml");//路径
	for (int k = 0; k<10; k++)//k为测试图片数量
	{
		sprintf_s(path, "E:\\vs2013\\opencv_code\\GTSRBtrafficSign\\extractAndPredict\\image\\%d.jpg",k+1);
 		cout << path << endl;
		Mat src = imread(path);
		Mat copy;
		src.copyTo(copy);
		int width = src.cols;   //图像宽度
		int height = src.rows;   //图像高度
		//色彩分割
		double B = 0.0, G = 0.0, R = 0.0, H = 0.0, S = 0.0, V = 0.0;
		Mat matRgb = Mat::zeros(src.size(), CV_8UC1);
		Mat Mat_rgb_copy;//一个暂存单元
		int x, y;
		for (y = 0; y<height; y++)
		{
			for (x = 0; x<width; x++)
			{
				B = src.at<Vec3b>(y, x)[0];
				G = src.at<Vec3b>(y, x)[1];
				R = src.at<Vec3b>(y, x)[2];
				RGB2HSV(R, G, B, H, S, V);
				//红色:337-360
				if ((H >= 337 && H <= 360 || H >= 0 && H <= 10) && S >= 12 && S <= 100 && V>20 && V<99)
				{
					matRgb.at<uchar>(y, x) = 255;
				}
			}
		}
		//imshow("hsi",Mat_rgb);
		//imshow("Mat_rgb",Mat_rgb);
		medianBlur(matRgb, matRgb, 3);
		//imshow("medianBlur", Mat_rgb);
		Mat element = getStructuringElement(MORPH_ELLIPSE,Size(2 * 1 + 1, 2 * 1 + 1),Point(1, 1));
		Mat element1 = getStructuringElement(MORPH_ELLIPSE,Size(2 * 3 + 1, 2 * 3 + 1),Point(3, 3));
		erode(matRgb, matRgb, element);//腐蚀
		//imshow("erode", Mat_rgb);
		dilate(matRgb, matRgb, element1);//膨胀
		//imshow("dilate", Mat_rgb);
		fillHole(matRgb, matRgb);//填充 
		//imshow("fillHole", Mat_rgb);
		matRgb.copyTo(Mat_rgb_copy);
		vector<vector<Point> > contours;//轮廓
		vector<Vec4i> hierarchy;//分层
		findContours(matRgb, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
		/// 多边形逼近轮廓 + 获取矩形和圆形边界框
		vector<vector<Point> > contours_poly(contours.size());//近似后的轮廓点集 
		vector<Rect> boundRect(contours.size()); //包围点集的最小矩形vector  
		vector<Point2f>center(contours.size());//包围点集的最小圆形vector 
		vector<float>radius(contours.size());//包围点集的最小圆形半径vector 

		for (int i = 0; i < contours.size(); i++)
		{
			approxPolyDP(Mat(contours[i]), contours_poly[i], 3, true);//对多边形曲线作适当近似,contours_poly[i]是输出的近似点集
			boundRect[i] = boundingRect(Mat(contours_poly[i]));//计算并返回包围轮廓点集的最小矩形 
			minEnclosingCircle(contours_poly[i], center[i], radius[i]);//计算并返回包围轮廓点集的最小圆形及其半径
		}
		Mat drawing = Mat::zeros(matRgb.size(), CV_8UC3);
		int count1 = 0; 
		for (int i = 0; i< contours.size(); i++)
		{
			Rect rect = boundRect[i];
			//cout << rect<<endl;
			//高宽比限制
			float ratio = (float)rect.width / (float)rect.height;
			//轮廓面积     
			float Area = (float)rect.width * (float)rect.height;
			float dConArea = (float)contourArea(contours[i]);
			float dConLen = (float)arcLength(contours[i], 1);
			if (dConArea <400)
				continue;
			if (ratio>2 || ratio<0.5)
				continue;

			//进行圆筛选,经过四块的缺失像素比较
			Mat roiImage;
			Mat_rgb_copy(rect).copyTo(roiImage);
			//imshow("roiImage",roiImage);
			//imshow("test",roiImage);
			Mat temp;
			copy(rect).copyTo(temp);
			//imshow("test2",temp);//显示从场景图中提取出的标识,留着。

			copy(rect).copyTo(roiImage);
			//*********svm*********
			Mat temp2 = Mat::zeros(temp.size(), CV_8UC1);
			cvtColor(temp, temp2, CV_BGR2GRAY);
			//resize(temp2, temp2, Size(48, 48));
			resize(temp2, temp2, Size(30, 30));//30*30=900
			temp2 = temp2.reshape(0, 1);
			temp2.convertTo(temp2, CV_32F);
			cout << temp2.size() << endl;
			
 			int result = (int)classifier.predict(temp2) - 1;//svm预测
			Scalar color = (0, 0, 255);//蓝色线画轮廓 
			drawContours(drawing, contours_poly, i, color, 1, 8, vector<Vec4i>(), 0, Point());
			rectangle(drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0);
			rectangle(src, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0);
			//putText(src, labelname[result], cvPoint(boundRect[i].x, boundRect[i].y - 10), 1, 1, CV_RGB(255, 0, 0), 2);//红色字体注释
			//circle( drawing, center[i], (int)radius[i], color, 2, 8, 0 );
			count1++;
			//sprintf_s(path, "E:\\vs2013\\opencv_code\\GTSRBtrafficSign\\extractAndPredict\\image\\result/%d_%d.jpg", k, count1);
			sprintf_s(path, "E:\\vs2013\\opencv_code\\GTSRBtrafficSign\\extractAndPredict\\image\\%d_%d.jpg",k+1, count1);
			imwrite(path, src);//保存最终的检测识别结果
		}
	}
	system("pause");
	waitKey(0);
	return 0;
}


运行结果字体