EasyPR—颜色定位

最近在看EasyPR的实现教程,感觉还不错,自己也通过编程实现了几个小模块。写下自己的心得,一来是总结下最近的学习内容,二来是以后看的时候聊以慰藉。一直走,难免会错过路边的花朵,现在回过头来看看,采采野花,也对自己是个交代。

EasyPR是一个中文车牌识别系统,Git地址为:https:://github.com/liuruoze/EasyPR。

因为最近在学习VTK的使用,所以想利用VTK来实现类似的功能,巩固学习的内容。但是我发现VTK在很多功能上没有OpenCV强大,毕竟VTK主要针对于医学图像,对体绘制方面有很好的处理效果,而OpenCV对于普通的图片处理的功能上比VTK多很多,包括继承了机器学习的模块。(VTK可能和机器学习的模块结合?可以试试)

方法是一致的,可能具体实现不同。

针对于车牌识别,无外乎两类图片,包含车牌的图片和不包含车牌的图片。其实处理起来是一样的,因为不包含车牌的图片可能不具备车牌的特征,最后输出结果为空,其实都可以一样处理。

下面是一个车牌的图片。

这个车牌比较清晰,也是大多数情况下能看到的,车牌方方正正,颜色为蓝色,与其他背景色不相同,所以我们第一感觉就是颜色定位,定位到蓝色的那一块,然后提取特定区域就能将车牌提取出来了。

对于彩色图像,最常用的是RGB编码格式,R代表红,G代表绿,B代表蓝,对应自然界中的三原色。

那么什么样的比例是蓝色呢?

EasyPR—颜色定位_第1张图片

对应的RGB值很乱,不能按照一定的规则判断,或者说判断起来很麻烦。那么有没有其他的颜色模式,让蓝色出于一个规则的范围里面呢?除了RGB,还有YUV和HSV。具体参考https://www.cnblogs.com/justkong/p/6570914.html

可以发现,HSV颜色空间模型符合我们的预期。H表示色相(Hue),S表示饱和度(Saturation),V表示明度(value)。具体可以参考https://html-color-codes.info/old/colorpicker.html

通过颜色表可以发现,当H在200-260的范围内,属于蓝色。当H属于200-220时,浅蓝,S,V(80%-100%)大些,属于蓝色。当H属于220-240时,中蓝,S,V(60%-100%)即可属于蓝色。当H属于240-260时,深蓝,S,V(70%-100%)属于蓝色。

1、将图片由RGB转化为HSV

转换公式如下:

EasyPR—颜色定位_第2张图片

//传入读入的图片数据
vtkImageData *colorLocate(vtkImageData *data)
{
	//待处理图片
	vtkImageData* filter =
		vtkImageData::New();
	filter->DeepCopy(data);
	
	//转换为HSV
	int dims[3];
	filter->GetDimensions(dims);
	for (int k = 0; k < dims[2]; k++)
	{
		for (int j = 0; j < dims[1]; j++)
		{
			for (int i = 0; i < dims[0]; i++)
			{
				unsigned char *pixel = (unsigned char*)(filter->GetScalarPointer(i, j, k));
				RGB2HSV(pixel);
			}
		}
	}
	filter->Modified();
	cout << "转换成功" << endl;

	return filter;
}

void RGB2HSV(unsigned char *p)
{
	double onethird = 1.0 / 3.0;
	double onesixth = 1.0 / 6.0;
	double twothird = 2.0 / 3.0;

	double R, G, B, H, S, V;
	double x = 255;

	R = static_cast(*p) / x;//R
	G = static_cast(*(p + 1)) / x; //G
	B = static_cast(*(p + 2)) / x; //B

	double Cmax = max(R, G, B);
	double Cmin = min(R, G, B);

	V = Cmax;

	if (V == 0)
		S = 0.0;
	else
	{
		S = (Cmax - Cmin) / Cmax;
	}
	if (S > 0)
	{
		if (R == Cmax)
			H = onesixth * (G - B) / (Cmax - Cmin);
		else if (G == Cmax)
			H = onethird + onesixth * (B - R) / (Cmax - Cmin);
		else if (B == Cmax)
			H = twothird + onesixth * (R - G) / (Cmax - Cmin);
	}
	else
		H = 0.0;

	H = H * x;
	S = S * x;
	V = V * x;

	if (H > x)
	{
		H = x;
	}
	if (S > x)
	{
		S = x;
	}
	if (V > x)
	{
		V = x;
	}

	*p = H;
	*(p + 1) = S;
	*(p + 2) = V;

	//cout << "H:" << H << "S:" << S << "V:" << V << endl;
}

因为图片显示的是VtkImageActor类,vtkImageActor接收的图像vtkImageData数据类型必须为unsigned char类型,所以将HSV的值映射到0-255的方位内。

具体转换显示如下:

EasyPR—颜色定位_第3张图片

由于他按照RGB的形式,所以显示不一样,不过没关系,处理还是一样的。

 

2、确定蓝色区域

判断条件如下:H属于0-360,映射到0-255范围,S,V规则一样。

	vector region; //保存区域坐标

	int dims[3];
	imgData->GetDimensions(dims);

	for (int k = 0; k < dims[2]; k++)
	{
		for (int j = 0; j < dims[1]; j++)
		{
			for (int i = 0; i < dims[0]; i++)
			{
				unsigned char *p = static_cast(imgData->GetScalarPointer(i, j, k));
				//H:200-220;S,V:80%-100%
				if (*p >= 141.666 && *p <= 198.333 && *(p + 1) >= 89.25&&*(p + 1) <= 255 && *(p + 2) >= 89.25&&*(p + 2) <= 255)
				{
					region.push_back(i);
					region.push_back(j);
					region.push_back(k);
				}
			}
		}
	}

 

3、将原图二值化,该区域标记为白色,其他区域标记为黑色

	vtkImageLuminance* luminanceFilter =
		vtkImageLuminance::New();
	luminanceFilter->SetInputConnection(reader->GetOutputPort());
	luminanceFilter->Update();

	vtkImageThreshold* thresholdFilter =
		vtkImageThreshold::New();
	thresholdFilter->SetInputConnection(luminanceFilter->GetOutputPort());
	thresholdFilter->ThresholdByUpper(255);
	thresholdFilter->SetInValue(255);
	thresholdFilter->SetOutValue(0);
	thresholdFilter->Update();

	thresholdFilter->GetOutput()->GetDimensions(dims);
	
	int numOfComp = thresholdFilter->GetOutput()->GetNumberOfScalarComponents();
	cout << numOfComp << endl; //单通道
	vector::iterator itr;
	for (itr = region.begin(); itr != region.end(); itr = itr + 3)
	{
		unsigned char *pixel = (unsigned char*)(thresholdFilter->GetOutput()->GetScalarPointer(*itr, *(itr + 1), *(itr + 2)));
		*pixel = 255;
	}

EasyPR—颜色定位_第4张图片

4、闭操作

EasyPR—颜色定位_第5张图片

通过闭操作,就能将车牌区域提取出来,变成一块,为后面操作提供方便。

VTK中没有实现闭操作的类,我打算通过C++代码实现。

这里碰到瓶颈了。

EasyPR—颜色定位_第6张图片

还是硬着头皮继续搞吧。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

闭操作后的效果

EasyPR—颜色定位_第7张图片EasyPR—颜色定位_第8张图片还不错

 

5、求最小外接矩形,并绘制在原图上。

 

你可能感兴趣的:(EasyPR—颜色定位)