汽车产业(特别是新能源汽车和智能网联汽车)无疑是中国目前最耀眼、最具代表性的“旗舰产业”。它与半导体、人工智能、生物医药等一同,构成了支撑中国经济高质量发展的 “新支柱集群”。汽车氛围灯亮度和色度检测也已经成为了计算机视觉和工业质量控制的热门应用。

本文重点是如何利用OpenCV这一强大工具,对汽车氛围灯的亮度和色度数据进行量化提取和计算,为您提供一个坚实的、基础的计算方法,为后续汽车氛围亮度色度检测和校准提供有力的支持,为主机厂和零部件供应商提供数据驱动的决策依据,是实现高品质氛围灯生产的核心技术保障。本文假设您已经利用成像色度计获取了XYZ三刺激值和RGB参照图像。
计算举例,如下图:

1.1、左边是参考图像
1.2、右边是CIE色度分析图
1.3、底部是关注点数据列表
1.4、鼠标跟随信息
2.1、关注点的位置尺寸及形状:Left、Top、CenterX、CenterY、Width、Height、Radius、Area、ShapeType
2.2、三刺激值值:X、Y、Z
2.3、色度值:CIE-x、CIE-y、CIE-u'、CIE-v'
2.4、色温:CCT
这里就直接上代码,涉及到Opencv相关函数,在之前的文章中都有详细介绍。
步骤:灰度图》滤波》二值化》边缘检测》获取轮廓。需要注意的2个参数:一是滤波值、二是二值化灰度值。这两个值根据实际情况调整。图像噪音大小就调整滤波值,亮度高低调整二值化灰度值。
/// <summary>
/// 查询关注点
/// </summary>
/// <param name="lstPoints">关注点边框点集合</param>
/// <returns></returns>
private List<OpenCvSharp.Rect> FindRoi(out List<OpenCvSharp.Point[]> lstPoints)
{
lstPoints = new List<OpenCvSharp.Point[]>();
//灰度图
Mat gray = new Mat();
Cv2.CvtColor(this.rgb, gray, ColorConversionCodes.BGR2GRAY);
//参数依据拍摄的图像进行调整,当环境固定后参数不会变化
int ksize = 5;
double thresh = 30;
//均值滤波
Cv2.Blur(gray, gray, new OpenCvSharp.Size(ksize, ksize));
//二值化
Mat thresholdMat = new Mat();
Cv2.Threshold(gray, thresholdMat, thresh, 255, ThresholdTypes.Binary);
//Canny边缘检测
Mat canny = new Mat();
Cv2.Canny(thresholdMat, canny, thresh, 255);
//获得轮廓
OpenCvSharp.Point[][] contours;
HierarchyIndex[] hierarchly;
Cv2.FindContours(canny, out contours, out hierarchly, RetrievalModes.External, ContourApproximationModes.ApproxNone);
int contourCount = contours.Length;
List<OpenCvSharp.Rect> lstRoi = new List<Rect>();
for (int i = 0; i < contourCount; i++)
{
Rect roiRect = Cv2.BoundingRect(contours[i]);
lstRoi.Add(roiRect);
lstPoints.Add(contours[i]);
}
return lstRoi;
}
2.1、绘制掩膜,利用掩膜计算所以关注点XYZ图像数据的平均XYZ值。(此步骤可以省略)
2.2、依据关注点的形状,计算每个关注点XYZ数据。
2.3、依据XYZ数据,计算CIE-x,CIE-y,CIE-u',CIE-v',cct

3.4.1、显示鼠标当前位置所在的像素点的信息,例如:亮度、Cx,Cy,X,Z,鼠标屏幕位置,鼠标图像位置、RGB值。如下图:

3.4.2、获取RGB值:参考图是一张RGB三通道图,At函数一次读取3通道值,然后将字节转换十进制值。代码如下:
var vec = rgb.At<Vec3b>(ty, tx);
3.4.3、三刺激值(X,Y,Z),也可以先合并成一个三通道的图像,然后用AT函数一次读取X,Y,Z值。代码如下:
Cv2.Merge(new Mat[] { xmat, ymat, zmat } , xyzMat);
var vec = xyzMat.At<Vec3f>(ty,tx);
循环统计矩形框中每个像素点的值,排查亮度为零的暗点。
/// <summary>
/// 获取矩形框关注点XYZ值
/// </summary>
/// <param name="xyzMat">XYZ数据</param>
/// <param name="minXZY">最低亮度值</param>
/// <param name="poi">关注点</param>
/// <returns></returns>
private double GetRectangleShapeXYZ(Mat xyzMat, double minXZY, Poi poi)
{
int left = poi.CenterX - poi.Radius;
int top = poi.CenterY - poi.Radius;
int width = poi.CenterX + poi.Radius;
int height = poi.CenterY + poi.Radius;
double sumXYZ = 0;
int sumCount = 0;
OpenCvSharp.Point pc = new OpenCvSharp.Point(poi.CenterX, poi.CenterY);
for (int x = left; x < width; x++)
{
for (int y = top; y < height; y++)
{
float xyzVal = xyzMat.At<float>(y, x);
if (xyzVal > minXZY)
{
sumXYZ += xyzVal;
sumCount++;
}
}
}
return sumXYZ / sumCount;
}
1、以关注点的中心点为圆心,半径范围内的点。
2、循环统计圆框中每个像素点的值,排查亮度为零的暗点。
/// <summary>
/// 获取圆形关注点XYZ值
/// </summary>
/// <param name="xyzMat">XYZ数据</param>
/// <param name="minXZY">最低亮度值</param>
/// <param name="poi">关注点</param>
/// <returns></returns>
private double GetCircleShapeXYZ(Mat xyzMat, double minXZY, Poi poi)
{
int left = poi.CenterX - poi.Radius;
int top = poi.CenterY - poi.Radius;
int width = poi.CenterX + poi.Radius;
int height = poi.CenterY + poi.Radius;
double sumXYZ = 0;
int sumCount = 0;
OpenCvSharp.Point pc = new OpenCvSharp.Point(poi.CenterX, poi.CenterY);
for (int x = left; x <= width; x++)
{
for (int y = top; y <= height; y++)
{
float xyzVal = xyzMat.At<float>(y, x);
if (xyzVal > minXZY)
{
OpenCvSharp.Point p1 = new OpenCvSharp.Point(x, y);
double dist = Distance(p1, pc);
if (dist <= poi.Radius)
{
//圆内及边框上的点
sumXYZ += xyzVal;
sumCount++;
}
}
}
}
return sumXYZ / sumCount;
}
1、函数Cv2.PointPolygonTest检测一个点是否在多边形框内。
2、循环统计多边形框中每个像素点的值,排查亮度为零的暗点。
/// <summary>
/// 获取多边形关注点XYZ值
/// </summary>
/// <param name="xyzMat">XYZ数据</param>
/// <param name="minXZY">最低亮度值</param>
/// <param name="poi">关注点</param>
/// <returns></returns>
private double GetPolygonShapeXYZ(Mat xyzMat, double minXZY, Poi poi)
{
List<OpenCvSharp.Point> lstPoints = poi.ShapePoints.Select(s => new OpenCvSharp.Point(s.X, s.Y)).ToList();
OpenCvSharp.Rect poiRect = Cv2.BoundingRect(lstPoints);
double sumXYZ = 0;
int sumCount = 0;
int left = poiRect.X;
int top = poiRect.Y;
int width = poiRect.X + poiRect.Width;
int height = poiRect.Y + poiRect.Height;
for (int x = left; x <= width; x++)
{
for (int y = top; y <= height; y++)
{
float xyzVal = xyzMat.At<float>(y, x);
if (xyzVal > minXZY)
{
OpenCvSharp.Point2f p1 = new OpenCvSharp.Point2f(x, y);
if (Cv2.PointPolygonTest(lstPoints, p1, false) >= 0)
{
//多边形内及边框上的点
sumXYZ += xyzVal;
sumCount++;
}
}
}
}
return sumXYZ / sumCount;
}
5.1、例如关注点P01的X值:5.571,与ImageJ读取的值一致。

上述实例要达到实用的程度,还需要进一步扩展,例如:
6.1、将关注点的亮度色度数据,增加上下限阈值。
6.2、采集一个标准样品的数据,计算出亮度色度数据的上下限。
6.3、生产线上获取的产品数据,与标准数据进行对比,亮度色度数据在标准范围内,即判断此产品合格,否则为不合格。
6.4、上述工具在计算关注点的XYZ值时,采用循环矩形框面积算法,而不是采用Cv2.Mean函数掩膜计算,依据经验当图像越大,计算一个关注点的时间比循环面积的时间要长,所以不采用。

¥16.00
仙剑奇侠传1 仙剑1 Sword and Fairy steam 游戏 Steam正版游戏 国区cdkey激活码
¥259.00
正版现货steam 英雄连3 英雄连steam 英雄连3激活码 英雄连合集 国区激活码下单自动秒发
¥276.00
PC中文正版 Steam SD高达激斗同盟 SD GUNDAM 激斗同盟 国区激活码
¥221.00
steam 大航海时代4 国区激活码CDKEY 大航海时代Ⅳ 威力加强版套装 HD 30周年纪念数字版 PC游戏正版中文
¥440.00
战国无双真田丸 steam SAMURAI WARRIORS: Spirit of Sanada 正版激活码 国区 cdkey
¥155.00
PC正版 steam游戏 小缇娜的奇幻之地 Tiny Tina's Wonderlands 国区激活码CDKey