线缆颜色顺序检测

问题描述

从下图中得到线缆的颜色顺序
在这里插入图片描述

问题分析

  1. 光照条件变化时,同样颜色的线缆在图像中颜色深度会有变化,所以不能使用RGB颜色空间,应该使用符合人类颜色距离认知的颜色空间,比如HSV和LAB。
  2. 所有的线缆都是并排的一起的,所以识别时可以只识别它们的边界线,任意相邻边界线的中间区域就是线缆。
  3. 线缆只在竖直方向上摆放,为提高算法速度,可以只在高度方向上截取一段进行处理。

算法流程

图片预处理

图片读取(从文件或相机)

Mat src = imread("D:/1.jpg", IMREAD_COLOR);

//从src中截取一个区域,等比例缩放
int cor = src.cols * 0.2;
float ratio = src.rows / src.cols;
Mat srctemp(src, Rect(cor, (int)(cor*ratio), src.cols - 2 * cor, src.rows - 2 * (int)(cor*ratio)));
Size dsize = Size(src.cols, src.rows);
resize(srctemp, src_all, dsize);

对图片中间区域截取一段

int position = 550;
src_all.convertTo(bgr, CV_32FC3, 1.0 / 255, 0);
Mat roi(bgr, Rect(0, position, 1920, 20));
imwrite("roi.jpg", roi);

颜色空间转换

cvtColor(roi, hsv, CV_BGR2HSV);

边界识别

首先在处理过的图片长度方向上得到其hsv颜色空间的平均值

float hh[1920] = { 0 };
float ss[1920] = { 0 };
float vv[1920] = { 0 };
float var[1920] = { 0 };
for (int i = 0; i < hsv.size().width; i++)
{
	float h, s, v;
	h = 0;
	s = 0;
	v = 0;
	for (int j = 0; j < 2; j++)   //hsv.size().height
	{
		Vec3f vec3f = hsv.at<Vec3f>(j, i);
		h += vec3f[0];
		s += vec3f[1];
		v += vec3f[2];
	}
	hh[i] = h;
	ss[i] = s * 255;
	vv[i] = v * 255;
}

然后对这3个1920的数组绘制折线图
在这里插入图片描述
从图中可以分析出,任意两种颜色变化的边界处,其H,S,V值都在突变,突变在数学上的表征但是导数。然后这H,S,V三条线的导数相乘,得到的函数极大值点就是线缆的分界线。

分析虽简单,但在实现时要考虑几个问题:

  1. 数组是离散的,怎么求导
  2. 在跳变区域,其中一个导数值是0,相乘结果为0,不是极大值。
  3. 极值点附近函数值和极值相等,极值点横坐标怎么获取

如上分析的简单算法实现

float x[1920] = { 0 };
float y[1920] = { 0 };
float z[1920] = { 0 };
float xx[1920] = { 0 };
float yy[1920] = { 0 };
float zz[1920] = { 0 };
float sum[1920] = { 0 };
for (int i = 3; i < 1917; i++)
{
	x[i] = abs(hh[i + 3] - hh[i - 3]);
	xx[i] = (hh[i + 3] + hh[i + 2] + hh[i + 1] + hh[i - 3] + hh[i - 2] + hh[i - 1] - 6 * hh[i]); 
	y[i] = (ss[i + 3] + ss[i + 2] + ss[i + 1] + ss[i - 3] + ss[i - 2] + ss[i - 1] - 6 * ss[i]); 
	if (ss[i] < 50) y[i] = 0;
	if (vv[i] < 100) y[i] = 1; 

	yy[i] = abs(ss[i + 3] - ss[i - 3]);
	if (ss[i] < 50) yy[i] = 0;

	z[i] = (vv[i + 3] + vv[i + 2] + vv[i + 1] + vv[i - 3] + vv[i - 2] + vv[i - 1] - 6 * vv[i]);
	zz[i] = abs(vv[i + 3] - vv[i - 3]);

	sum[i] = abs(x[i] * xx[i] * y[i] * yy[i] * z[i] * zz[i]);

	if (sum[i] > 400000000)
		sum[i] = 400000000;
	sum[i] /= 1000000000;
	sum[i] *= 25;
	if (sum[i] < 10) sum[i] = 0;
}

int count = 0;
int tempcount = 0;
int left[50] = { 0 };
int right[50] = { 0 };
for (int i = 1; i < 1920; i++)
{
	if (sum[i] - sum[i - 1] < 0 && sum[i] == 0)
	{
		tempcount = count;
		left[tempcount] = i;
	}

	if (sum[i] - sum[i - 1] > 0 && sum[i - 1] == 0)
	{
		right[tempcount] = i;
		count++;
	}
}

算法处理完成后结果
在这里插入图片描述
可以看到除了白色和灰色不能分离外,其他都已经分离。

颜色识别

由于受光照强度和色温变化的影响,颜色识别要用到标定,然后得到颜色和对应标定H,S,V值,在使用时直接找欧式距离最短的标定颜色。

//使用欧式距离的方法判断颜色
struct colorspace
{
	string colorname;
	float  h;
	float  s;
	float  v;
};

//需要事先标定
colorspace cs[11] = {
	//颜色		  h    s    v
	{ "黑色",	236,   0,   0 },
	{ "白色",	236,   0,   1 },  
	{ "灰色",	236,   0, 0.5 }, 
	{ "褐色",	 10,0.47,0.30 },
	{ "橘色",	 19,0.73,0.68 },
	{ "黄色",	 56,0.69,0.65 },
	{ "绿色",	160,0.95,0.34 },
	{ "蓝色",	226,0.98,0.45 },
	{ "紫色",	285,0.50,0.31 },
	{ "红色",	340,0.83,0.66 },
	{ "背景",   105,0.05,0.54} };

//对框选区域进行颜色识别
for (int c = 0; c < rightborder.size(); c++)
{
	float h, s, v;
	h = 0;
	s = 0;
	v = 0;
	for (int i = leftborder.at(c); i < rightborder.at(c); i++)
	{
		for (int j = 0; j < 20; j++)   //hsv.size().height
		{
			Vec3f vec3f = hsv.at<Vec3f>(j, i);
			h += vec3f[0];
			s += vec3f[1];
			v += vec3f[2];
		}
	}
	h = h / (20 * (rightborder.at(c) - leftborder.at(c)));
	s = s / (20 * (rightborder.at(c) - leftborder.at(c)));
	v = v / (20 * (rightborder.at(c) - leftborder.at(c)));
	cout << h << " " << s << " " << v << endl;

	int minindex = 0;
	int mindistance = 400000;

	for (int i = 0; i < 11; i++)       //背景不参与运算
	{
		int distance = (h - cs[i].h)*(h - cs[i].h) +
			(s - cs[i].s)*(s - cs[i].s) * 129600 +
			(v - cs[i].v)*(v - cs[i].v) * 129600;
		if (distance < mindistance)
		{
			minindex = i;
			mindistance = distance;
		}
	}

	cout << cs[minindex].colorname << endl;
}

最终识别结果

在这里插入图片描述

优化方向

  1. 最近发现使用CIELAB颜色空间比使用HSV颜色空间效果更好,可以把使用HSV方法不能区分的白色和灰色区分出来。
  2. 线缆的分区其实是有空间约束的,如果能加到算法中,会对识别效率和准确率有一定的提高。
  3. 颜色的识别与光源的色温和光强关系很大,但是没有一个光源条件对所以的颜色区分度都能达到最好。比如10lx,4000k对蓝绿色区分最好,20lx,6500k对黄绿色区分最好。所以还需要在实际使用时根据识别要求选择合适的光源。
  • 4
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

仟人斩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值