这周我们小组的同学有两门考试,还要准备周五的报告,但是我们还是坚持完成两项工作,一是获取深度中的人脸,二是人脸矫正。
获取深度帧人脸 Kinect SDK
中自带的脸部帧接口是在1920×1080
彩色帧上操作,而512×484
深度帧与彩色帧是两个独立的数据流,考虑到两点,一是若直接在彩色帧上进行后续人脸相关工作,会非常耗时,另一个是彩色数据到深度数据的转换不能单点操作,因此为了获得3D
人脸,我们尝试了三种思路:
提取深度图上对应点的RGB
信息,用OpenCV
人脸检测器在该512×484
彩色图上检测人脸,关键代码如下:
1 2 3 4 5 6 7 8 9 for (int y = 0 ; y < DEPTH_HEIGHT; y++){ for (int x = 0 ; x < DEPTH_WIDTH; x++){ RGBQUAD color = app.depth2Color(depthBuffer, x, y, colorBuffer); colorImg.at<Vec3b>(Point(x, y))[0 ] = (int )color.rgbBlue; colorImg.at<Vec3b>(Point(x, y))[1 ] = (int )color.rgbGreen; colorImg.at<Vec3b>(Point(x, y))[2 ] = (int )color.rgbRed; } }
用Kinect SDK
面部帧接口在1920×1080
彩色图上检测出人脸区域,再利用MapColorFrameToCameraSpace
接口将彩色帧转换到相机空间,从而获得彩色图范围上人脸区域的三维坐标,在此基础上也可以获得5
个关键点以及头部偏转角等,因此相关代码处理如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 DepthSpacePoint* pPointArray = new DepthSpacePoint[COLOR_WIDTH * COLOR_HEIGHT]; hr = app.pCoordinateMapper->MapColorFrameToDepthSpace(DEPTH_WIDTH * DEPTH_HEIGHT, &depthBuffer[0 ], \ COLOR_WIDTH * COLOR_HEIGHT, pPointArray); for (int y = r.y; y < (r.y + r.height); y++){ for (int x = r.x; x < (r.x + r.width); x++) { pcl::PointXYZRGB point; point.r = colorBuffer[y * COLOR_WIDTH + x].rgbRed; point.g = colorBuffer[y * COLOR_WIDTH + x].rgbGreen; point.b = colorBuffer[y * COLOR_WIDTH + x].rgbBlue; CameraSpacePoint cameraSpacePoint; const DepthSpacePoint& dPoint = pPointArray[y * COLOR_WIDTH + x]; if (dPoint.X >= 0 && dPoint.X < DEPTH_WIDTH && dPoint.Y >= 0 && dPoint.Y < DEPTH_HEIGHT) { UINT16 depth = depthBuffer[dPoint.Y * DEPTH_WIDTH + dPoint.X]; app.pCoordinateMapper->MapDepthPointToCameraSpace(dPoint, depth, &cameraSpacePoint); point.x = cameraSpacePoint.X; point.y = cameraSpacePoint.Y; point.z = cameraSpacePoint.Z; } pointCloud->push_back(point); } }
首先在彩色图上检出人脸区域,同时得到深度图上每个点的三维坐标,遍历深度图上所有点,对应判断其是否在彩色图的人脸区域范围内,若是,则归为人脸区域,从而在深度图中确定出人脸区域。
综合比较上述三种方法,方法1
依赖的是OpenCV
人脸检测接口,实时性没有Kinect SDK
好,并且不能同时获得面部关键点位置以及头部偏转角信息,而方法2
是基于1920×1080
的大图操作,性能低下,因此,最后我们采用第三种方法,效果图如下,图中右半部分可以看出,恢复过来的深度帧边缘部分有较多毛刺,这与Kinect
深度图获取原理有关,从脸部区域来看,深度帧中人脸位置基本准确,边缘有稍许晕染。
人脸矫正 我们获取到的原始深度数据是距离值,也就是目标人物到深度摄像头的位置,考虑到后续配准建模等任务都是基于人脸操作,如果人脸3D
信息依赖于摄像头位置的话,会非常不方便,因此我们考虑将三维坐标系转换到以鼻尖为原点的坐标系,随后应用欧拉角对每个三维点进行旋正处理。可见下方视频,目标人物面部朝左、右、上、下时,右侧可视化窗口内基本可以得到正面人脸。
视频链接