车牌识别之定位篇

  • Post author:
  • Post category:其他


``# 车牌识别之定位篇

	
/*车牌定位:
读取图片-- > 高斯模糊-- >
灰度化-- > Sobel算子边缘检测-- >
二值化-- > 闭操作-- >
膨胀腐蚀-- > 矩形轮廓查找-- >
背景分割(grabCut)—— > 字符分割—— >
字符识别-- >
*/


#include<opencv2/opencv.hpp>
#include"iostream"
#include<opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include"opencv2/highgui/highgui.hpp"
using namespace std;
using namespace cv;

int main(int argc, char* argv[], char** env)
{//读取图像
	Mat img = imread("12.jpg");
	if (img.empty())
		return 0;
	//高斯模糊
	Mat blurr_image;
	GaussianBlur(img, blurr_image, Size(3, 3), 0, 0);
	//灰度化图像
	Mat gray_image;
	cvtColor(blurr_image, gray_image, CV_RGB2GRAY);
	//sobel算子
	Mat gx, gy;
	Mat abs_gx, abs_gy, margin_image;
	//求x方向梯度
	Sobel(gray_image, gx, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT);
	convertScaleAbs(gx, abs_gx);
`

```python
``
	//求y方向梯度
	Sobel(gray_image, gy, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT);
	convertScaleAbs(gy, abs_gy);
	//合并梯度
	addWeighted(abs_gx, 0.5, abs_gy, 0.5, 0, margin_image);
	//二值化图像
	int threshval = 170;//设定阈值
	Mat bin;
	bin = (threshval < 100) ? (abs_gx < 160) : (abs_gx > 160);//二值化

	//namedWindow("二值化后的图像",0);
	//imshow("二值化后的图像", tn);

	//形态学处理


	//闭操作将目标区域连成一个整体,便于后续轮廓的提取
	Mat dst;
	//定义核
	Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
	morphologyEx(bin, dst, MORPH_CLOSE, element);
	//图片膨胀处理
	Mat dilate_image, erode_image;
	//自定义 核进行 x 方向的膨胀腐蚀
	Mat elementX = getStructuringElement(MORPH_RECT, Size(24, 1));
	Mat elementY = getStructuringElement(MORPH_RECT, Size(1, 20));
	Point point(-1, -1);
	//膨胀
	dilate(dst, dilate_image, elementX, point, 5);
	//腐蚀
	erode(dilate_image, erode_image, elementX, point, 8);
	dilate(erode_image, dilate_image, elementX, point, 6);

	//自定义 核进行 Y 方向的膨胀腐蚀
	erode(dilate_image, erode_image, elementY, point, 4);
	dilate(erode_image, dilate_image, elementY, point, 4);

	//取轮廓
	//矩形轮廓查找与筛选:


	vector<vector<Point> > contours;
	
	vector<Vec4i> hierarchy;
	RNG rng;//随机数生成
	findContours(dilate_image, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
	Scalar color = Scalar(0, 255, 0);
	int i = 0;
	CvRect aRect = boundingRect(contours[i]);
	for (int i = 0; i < contours.size(); i++)
	{
		//使用边界框的方式  ,计算轮廓的垂直边界最小矩形,矩形是与图像上下边界平行的
		//CvRect aRect = boundingRect(contours[i]);
		int tmparea = aRect.height*aRect.height;
		if (((double)aRect.width / (double)aRect.height > 2.7) && ((double)aRect.width / (double)aRect.height < 6) && tmparea >= 100 && tmparea <= 25000)
		{
			rectangle(img, cvPoint(aRect.x, aRect.y), cvPoint(aRect.x + aRect.width, aRect.y + aRect.height), color, 4);

		}
	}
	namedWindow("contour", 0);
	resizeWindow("contour", 900, 800);
	//显示最终图像
	imshow("contour", img);

	Mat roi1;
	Rect rect1(aRect.x, aRect.y, aRect.width, aRect.height);
	img(rect1).copyTo(roi1);
	//namedWindow("last", 0);
	resizeWindow("last", 1000, 250);
	imshow("last", roi1);
	//字符分割
	Mat Gray_Carimage;
	//pic_gray(roi1, Gray_Carimage);
	cvtColor(roi1, Gray_Carimage, CV_RGB2GRAY);
	/*Mat Candy_Carimage;
	Canny(roi1, Candy_Carimage, 450, 120, 3);*/

	resizeWindow("cargrayimage", 1000, 250);
	imshow("cargrayimage", Gray_Carimage);
	Mat roi_threadhold_image;
	threshold(Gray_Carimage, roi_threadhold_image, 0, 255, CV_THRESH_OTSU);
	resizeWindow("test", 1000, 250);
	imshow("test", roi_threadhold_image);


	//****倾斜矫正
	//****去除边框

	//**************************去除边框
	//水平投影和垂直投影
	int imgR[100] = { 0 };

	int imgTop = 0; int imgBottom = 0;
	
	for (int ht = 0; ht < roi_threadhold_image.rows; ht++)
	{
		for (int wt = 0; wt < roi_threadhold_image.cols; wt++)
		{
			if (roi_threadhold_image.at<uchar>(ht, wt) != 0)
			{
				imgR[ht]++;
			}
		}
		if ( imgR[ht] > 10)
		{
			imgTop = ht;
			break;
		}
	}

	for (int ht = roi_threadhold_image.rows - 1; ht > 0; ht--)
	{
		for (int wt = 0; wt < roi_threadhold_image.cols; wt++)
		{
			if (roi_threadhold_image.at<uchar>(ht, wt) == 255)
			{
				imgR[ht]++;
			}
		}
		if (imgR[ht] > 10)
		{
			imgBottom = ht;
			break;
		}
	}
	int imgR_w[350] = { 0 };
	int imgRight = 0;
	int imgLeft = 0;
	for (int wt_new = 2; wt_new < roi_threadhold_image.cols; wt_new++)
	{
		for (int ht_new = imgTop + 15; ht_new < imgBottom; ht_new++)
		{
			if (255 == roi_threadhold_image.at<uchar>(ht_new, wt_new))
			{
				imgR_w[wt_new]++;
			}
		}
		if ((imgR_w[wt_new - 2] + imgR_w[wt_new - 1] + imgR_w[wt_new]) > 10)
		{
			imgLeft = wt_new;
			break;
		}
	}
	for (int wt_new = roi_threadhold_image.cols - 3; wt_new > 0; wt_new--)
	{
		for (int ht_new = imgTop + 15; ht_new < imgBottom; ht_new++)
		{
			if (255 == roi_threadhold_image.at<uchar>(ht_new, wt_new))
			{
				imgR_w[wt_new]++;
			}
		}
		if ((imgR_w[wt_new] + imgR_w[wt_new + 1] + imgR_w[wt_new + 2]) > 10)
		{
			imgRight = wt_new - 3;
			break;
		}
	}
	Mat roi_fix;

	roi_fix = roi_threadhold_image(Rect(imgLeft + 5, imgTop + 8, imgRight - (imgLeft + 5), (imgBottom - (imgTop + 10))));
	//去除字符串上下边界外的区域
	GaussianBlur(roi_fix, roi_fix, Size(3, 3), 3.0);
	threshold(roi_fix, roi_fix, 0, 255, CV_THRESH_OTSU);
	int a[100] = { 0 };
	int b[350] = { 0 };
	int imgT = 0;
	int	imgB = 0;
	for (int ht = 0; ht < roi_fix.rows; ht++)
	{
		for (int wt = 0; wt < roi_fix.cols; wt++)
		{
			if (roi_fix.at<uchar>(ht, wt) == 255)
			{
				a[ht]++;
			}
		}
		if (a[ht] > 30)
		{
			imgT = ht;
			break;
		}
	}
	for (int ht = roi_fix.rows - 1; ht > 0; ht--)
	{
		for (int wt = 0; wt < roi_fix.cols; wt++)
		{
			if (roi_fix.at<uchar>(ht, wt) == 255)
			{
				b[ht]++;
			}
		}
		if (b[ht] > 20)
		{
			imgB = ht;
			break;
		}
	}
	Mat roi_fix2 = roi_fix(Rect(0, imgT, roi_fix.cols, imgB - imgT));
	resizeWindow("roi", 1000, 255);
	imshow("roi", roi_fix2);
	cout << "roi rows: " << roi_fix2.rows << "  roi cols: " << roi_fix2.cols << endl;
	//****分割字符
	Mat roi_bi = roi_fix2;
	cout << "row:" << roi_fix2.rows << "  cols: " << roi_fix2.cols << endl;
	bool lab = false;	//是否进入一个字符分割状态
	bool black = false;	//是否发现黑点
	bool change = false;
	int xnum = 0;
	int rect_left;
	int rect_right;
	Mat fg1, fg2, fg3, fg4, fg5, fg6, fg7,fg8;
	for (int wt = 0; wt < roi_bi.cols; wt++)
	{
		int count = 0;
		for (int ht = 0; ht < roi_bi.rows; ht++)
		{
			if ((255 == roi_bi.at<uchar>(ht, wt)) )
			{
				count++;
				
			}
			
		}
		if (!lab && (count > 5))
		{
			rect_left = wt ;
			lab = true;
		}
		if (lab && (count < 5) && (wt > (rect_left + 20)) && (xnum < 7))
		{
			rect_right = wt;
			lab = false;
			CvPoint pt1, pt2;
			pt1.x = rect_left;
			pt1.y = 0;
			pt2.x = rect_right;
			pt2.y = roi_bi.cols - 1;
			int s_x = pt1.x ;
			int s_y = pt1.y;
			int s_width = rect_right - rect_left + 1;
			int s_height = roi_bi.rows - 1;
			if (xnum == 0)
			{
				fg1 = roi_bi(Rect(s_x, s_y, s_width, s_height));
			}
			if (xnum == 1)
			{
				fg2 = roi_bi(Rect(s_x, s_y, s_width, s_height));
			}
			if (xnum == 2)
			{
				fg3 = roi_bi(Rect(s_x, s_y, s_width, s_height));
			}
			if (xnum == 3)
			{
				fg4 = roi_bi(Rect(s_x, s_y, s_width, s_height));
			}
			if (xnum == 4)
			{
				fg5 = roi_bi(Rect(s_x, s_y, s_width, s_height));
			}
			if (xnum == 5)
			{
				fg6 = roi_bi(Rect(s_x, s_y, s_width, s_height));
			}
			if (xnum == 6)
			{
				fg7 = roi_bi(Rect(s_x, s_y, s_width, s_height));
			}
			if (xnum == 7)
			{
				fg8 = roi_bi(Rect(s_x, s_y, s_width, s_height));
			}
			xnum++;
		}
	}

	imshow("1", fg1); imshow("2", fg2); imshow("3", fg3);
	imshow("4", fg4); imshow("5", fg5); imshow("6", fg6);
	imshow("7", fg7); imshow("8", fg8);
	
	
	
	waitKey(0);
    return 0;
	}



版权声明:本文为l315676原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。