OpenCV是一个基于Apache2.0许可(开源)发行的跨平台计算机视觉和机器学习软件库。它轻量级而且高效,同时提供了许多语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。基于与本次海康sdk的数据结合,本文接下来介绍如何使用SDK读取RGB图像帧,并用其进行简单的检测和识别操作。
一. 本文环境介绍
1. opencv 4.3.0
2. visual studio 2019
2. 悉灵相机MV-EB435i
3. SDK_Mv3dRgbd_V1.0.0_Win
二. 海康RGB_D相机SDK图像结构解析和RGB图像提取
在RGB_D相机采集的图像中,SDK给出图像帧格式:MV3D_RGBD_FRAME_DATA,其中具体代码定义如下:
typedef struct _MV3D_RGBD_FRAME_DATA_
{
uint32_t nImageCount; // 图像个数,表示stImage数组的有效个数
MV3D_RGBD_IMAGE_DATA stImageData[MV3D_RGBD_MAX_IMAGE_COUNT]; // 图像数组,每一个代表一种类型的图像
uint8_t nReserved[16]; // 保留字节
} MV3D_RGBD_FRAME_DATA;
可看出,每一帧产生的图像是由一个 stImageData 图像数组包容的,其中图像含有多种图像类型,具体定义如下:
typedef enum Mv3dRgbdImageType
{
ImageType_Undefined = MV3D_RGBD_UNDEFINED,
ImageType_Mono8 = (MV3D_RGBD_PIXEL_MONO | MV3D_RGBD_PIXEL_BIT_COUNT(8) | 0x0001), //0x01080001
ImageType_Depth = (MV3D_RGBD_PIXEL_MONO | MV3D_RGBD_PIXEL_BIT_COUNT(16) | 0x00B8), //0x011000B8
ImageType_YUV422 = (MV3D_RGBD_PIXEL_COLOR | MV3D_RGBD_PIXEL_BIT_COUNT(16) | 0x0032), //0x02100032
ImageType_YUV420SP_NV12 = (MV3D_RGBD_PIXEL_COLOR | MV3D_RGBD_PIXEL_BIT_COUNT(12) | 0x8001), //0x020C8001
ImageType_YUV420SP_NV21 = (MV3D_RGBD_PIXEL_COLOR | MV3D_RGBD_PIXEL_BIT_COUNT(12) | 0x8002), //0x020C8002
ImageType_RGB8_Planar = (MV3D_RGBD_PIXEL_COLOR | MV3D_RGBD_PIXEL_BIT_COUNT(24) | 0x0021), //0x02180021
ImageType_PointCloud = (MV3D_RGBD_PIXEL_COLOR | MV3D_RGBD_PIXEL_BIT_COUNT(96) | 0x00C0), //0x026000C0,
ImageType_Jpeg = (MV3D_RGBD_PIXEL_CUSTOM| MV3D_RGBD_PIXEL_BIT_COUNT(24) | 0x0001) //0x80180001, 自定义的图片格式
} Mv3dRgbdImageType;
每帧中 stImageData 图像数组包含了 ImageType_Depth, ImageType_YUV422, ImageType_Mono8 三种图像类型。
而 stImageData 代表的图像数据 MV3D_RGBD_IMAGE_DATA 定义如下:
typedef struct _MV3D_RGBD_IMAGE_DATA_
{
Mv3dRgbdImageType enImageType; // 图像格式
uint32_t nWidth; // 图像宽
uint32_t nHeight; // 图像高
uint8_t* pData; // 相机输出的图像数据
uint32_t nDataLen; // 图像数据长度(字节)
uint32_t nFrameNum; // 帧号,代表第几帧图像
int64_t nTimeStamp; // 设备上报的时间戳 (设备上电从0开始,规则详见设备手册)
uint8_t nReserved[16]; // 保留字节
} MV3D_RGBD_IMAGE_DATA;
stImageData 数组中每一副图像的数据以 pdata 存储和表现。
此三种图像类型对应图像数据解释如下:
ImageType_Depth :体现深度图的图像深度信息;
ImageType_YUV422 : 以YUV 4:2:2 格式存储图像信息,体现图像亮度信息Y与色彩信息UV。
ImageType_Mono8 : 以Mono 格式存储图像信息,储存单色,一般以灰度图展示。
在本文中,需要提取RGB图像,即上述代码中 ImageType_RGB8_Planar 类型。
由于需要提取的是 ImageType_RGB8_Planar 类型,而 stImageData 数组的输出的主要部分是 ImageType_Depth 和 ImageType_YUV422 两个类型。 需要对采集的帧数据进行格式分析转换才能输出成我们能读懂的图像,刚好在SDK中 parseframe(MV3D_RGBD_FRAME_DATA* , RIFrameInfo* ,RIFrameInfo* ) 的静态函数中可将帧数据分别转换成 RIFrameInfo类型的 深度图格式和RGB格式(RIFrameInfo 类型定义与上述 MV3D_RGBD_IMAGE_DATA 基本相同)。
但是,此处的RGB图像其实在R(红色)、B(蓝色)通道表现相反,即相机采集图像转换时更类似于BGR图像, 这里可用 cv::cvtColor 的函数中 COLOR_BGR2RGB 的图像转换类型进行转换。
三. 实现基础人脸识别和小样物体的颜色检测
(1)基础人脸识别
在opencv中 Objdetect 模块中可检测特定的目标,其中包含 Cascade Classification(级联分类)的检测识别模式,主要是通过 CascadeClassifier 级联分类器类型定义的变量,读取opencv 自带的人脸识别haar面部特征文件 "haarcascade_frontalface_default.xml" ,对灰度图进行多尺度特征提取和检测,以下是主要源代码部分:
while (1)
{
// 获取图像数据
int nRet = MV3D_RGBD_FetchFrame(handle, &stFrameData, 5000);
if (MV3D_RGBD_OK == nRet)
{
LOGD("MV3D_RGBD_FetchFrame success.");
//分析获取每帧数据
parseFrame(&stFrameData, &depth, &rgb);
Mat rgb_frame(rgb.nHeight, rgb.nWidth, CV_8UC3, rgb.pData);
LOGD("rgb: FrameNum(%d), height(%d), width(%d)。", rgb.nFrameNum, rgb.nHeight, rgb.nWidth);
//B、R通道交换,显示正常彩色图像
Mat frame, gray_frame;
cvtColor(rgb_frame, frame, COLOR_BGR2RGB);
cvtColor(rgb_frame, gray_frame, COLOR_BGR2GRAY);
//以下进行人脸识别
faceCascade.load("haarcascade_frontalface_default.xml");
if (faceCascade.empty())
{
LOGD("xml not found!");
}
//进行直方图均衡化
equalizeHist(gray_frame, gray_frame);
//执行多尺度特征检测
vector faces;
faceCascade.detectMultiScale(gray_frame, faces, 1.1, 5, 0, Size(24, 24));
for (int i = 0; i < faces.size(); i++)
{
LOGD("catch_face: x(%d), y(%d)", faces[i].x, faces[i].y);
rectangle(frame, faces[i].tl(), faces[i].br(), Scalar(255, 255, 255), 4);
}
namedWindow("HIK_face", 0);
resizeWindow("HIK_face", 640, 360);
imshow("HIK_face", frame);
waitKey(1);
}
}
其中,发现由于在光线强度大的白天,图像采集的泛白部分过大,可能对面部显示并没有很精细,这里采用直方图均衡化 equalizeHist 函数,让灰度图中泛白的部分,在均衡化之后能够合并一些像素灰度, 从而增强对比度。最后在 detectMultiScale 多尺度特征检测函数中能够更为准确的进行面部识别。
下图是代码运行结果:

(2)基础小样物体的颜色检测(HSV格式的颜色向量范围预设)
对物体检测主要是通过同一线程轮询分析出的RGB图像分成两个方面的过程:
1. 其一RGB图像进行图像变换、处理,再将处理后的图像查找轮廓向量,得到该轮廓的外部矩形边界点。
2. 另一RGB图像用上述得到外部矩形边界点进行绘图。
在这里,首先简要介绍 HSV格式, HSV是一种将RGB色彩空间中的点在倒圆锥体中的表示方法。HSV即色相(Hue)、饱和度(Saturation)、明度(Value)。色相是色彩的基本属性,表现出是何种颜色。饱和度(S)是指色彩的纯度。明度(V)即色彩的亮暗。在本项目中,将RGB图像帧转换成HSV格式,能够更有利的得到色彩的明暗,色调,以及鲜艳程度,方便进行提取不同的颜色。以下是 getcolor 色彩转换函数代码:
void getcolor(Mat ero_frame)
{
Mat hsv_frame;
cvtColor(ero_frame, hsv_frame, COLOR_BGR2HSV);
for (int i = 0; i < ColorValues.size(); i++)
{
Mat mask;
Scalar lower(ColorValues[i][0], ColorValues[i][1], ColorValues[i][2]);
Scalar upper(ColorValues[i][3], ColorValues[i][4], ColorValues[i][5]);
//二值化图像
inRange(hsv_frame, lower, upper, mask);
Point po = getcontours(mask);
if (po.x != 0)
{
LOGD("findPoint: x(%d), y(%d)", po.x, po.y);
String t_color = coltypes(i);
putText(after_frame, t_color, {po.x -5, po.y }, FONT_HERSHEY_PLAIN, 2, Scalar(0, 0, 255), 2);
}
}
}
传入函数之前已经对图像进行高斯滤波和膨胀腐蚀的形态学滤波的操作。这里用 inRange 函数控制 HSV格式图像在预设范围的二值化输出,能够更好的界定接下来寻找轮廓的点集位置。以下是寻找轮廓和矩阵点向量的 getcontours 函数代码:
Point getcontours(Mat image)
{
//轮廓点向量contours
vector> contours;
vector hierarchy;
findContours(image, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
//矩形点向量和矩形向量
vector> conpoly(contours.size());
vector boundirect(contours.size());
Point myPoint(0, 0);
for (int i = 0; i < contours.size(); i++)
{
int area = contourArea(contours[i]);
//控制检测像素面积大小
if (area> 3000 && area < 10000)
{
//多边形曲线拟合
float peri = arcLength(contours[i], true);
approxPolyDP(contours[i], conpoly[i], 0.03 * peri, true);
LOGD("contours: area(%d); conpoly[%d]: size(%d)", area, i, conpoly[i].size());
boundirect[i] = boundingRect(conpoly[i]);
//图框的左上角
myPoint.x = boundirect[i].x;
myPoint.y = boundirect[i].y;
//图像绘图
//drawContours(frame, conpoly, i, Scalar(255, 0, 255), 2);
rectangle(after_frame, boundirect[i].tl(), boundirect[i].br(), Scalar(0, 0, 255), 2);
LOGD("draw finish!");
}
}
return myPoint;
}
用轮廓面积的大小确定小型物体的大致图像面积范围,有效的避免了大型图像颜色的泛查,由于对轮廓线长的曲线拟合,较好得到邻近的矩形框点。
以下是代码运行结果:

四. 总结
本文基础的检测功能能够实现初步的人脸识别和颜色识别,但需要进一步优化,类似颜色检测,对颜色的精细界定和对无关事物和图像背景的误差检测也是需要考究的方面。
开源代码:https://github.com/JiaHao-YU03/HIKROBOT_opencv/tree/master
来自 南京工程学院-丁可可团队