目前项目组在做这个跟结构光相机相关的课题,我在网上调研了几款相机后,最终确定了使用国产奥比中光的相机,主要原因还是性价比高。
下面介绍如何通过python代码实现调用相机的彩色图像和深度图像:
首先你要配备相应的环境:
具有opencv,openni,numpy库
1,首先定义一个鼠标事件,让他能够通过二维像素点的坐标,输出对应的深度坐标:
def mousecallback(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDBLCLK:
print(y, x, dpt[y, x])
2,其次就是调用深度相机里面openni2里面的一些配置函数,让其开始:
#创建摄像头对象
cap = cv2.VideoCapture(0)
openni2.initialize()
#设备的型号
dev = openni2.Device.open_any()
#输出设备的型号
print(dev.get_device_info())
#创建深度流的通道
depth_stream = dev.create_depth_stream()
# 彩色和深度图像对齐
dev.set_image_registration_mode(True)
#开始录制深度图像
depth_stream.start()
3,创建windows窗口,把鼠标事件定义在这个窗口里面:
cv2.namedWindow('depth')
cv2.setMouseCallback('depth', mousecallback)
4.接下来就是循环每一帧图像,以及对每一帧图像进行处理:
while True:
frame = depth_stream.read_frame()
#转换数据格式
dframe_data = np.array(frame.get_buffer_as_triplet()).reshape([480, 640, 2])
dpt1 = np.asarray(dframe_data[:, :, 0], dtype='float32')
dpt2 = np.asarray(dframe_data[:, :, 1], dtype='float32')
dpt2 *= 255
#对于为什么要乘于255的解答
#深度图像的深度值 是按照16位长度(两字节)的数据格式存储的,也可以认为前八位是高字节,后八位是低字节。
#因此一张深度图像如果是 640480分辨率的话,那么图像字节大小 就是 640480*2,其中一个字节是8位(255)
dpt = dpt1 + dpt2
#cv2里面的函数,就是类似于一种筛选
'假设我们需要让我们的深度摄像头感兴趣的距离范围有差别地显示,那么我们就需要确定一个合适的alpha值,公式为:有效距离*alpha=255,' \
'假设我们想让深度摄像头8m距离内的深度被显示,>8m的与8m的颜色显示相同,那么alpha=255/(8*10^3)≈0.03,' \
'假设我们想让深度摄像头6m距离内的深度被显示,>6m的与6m的颜色显示相同,那么alpha=255/(6*10^3)≈0.0425'
dim_gray = cv2.convertScaleAbs(dpt, alpha=0.17)
#对深度图像进行一种图像的渲染,目前有11种渲染方式,大家可以逐一去试下
depth_colormap = cv2.applyColorMap(dim_gray, 2) # 有0~11种渲染的模式
cv2.imshow('depth', depth_colormap)
ret, frame = cap.read()
cv2.imshow('color', frame)
key = cv2.waitKey(1)
if int(key) == ord('q'):
break
depth_stream.stop()
dev.close()
总结下来,完整的代码是:
from openni import openni2
import numpy as np
import cv2
def mousecallback(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDBLCLK:
print(y, x, dpt[y, x])
if __name__ == "__main__":
openni2.initialize()
dev = openni2.Device.open_any()
print(dev.get_device_info())
depth_stream = dev.create_depth_stream()
dev.set_image_registration_mode(True)
depth_stream.start()
cap = cv2.VideoCapture(0)
cv2.namedWindow('depth')
cv2.setMouseCallback('depth', mousecallback)
while True:
frame = depth_stream.read_frame()
#转换数据格式
dframe_data = np.array(frame.get_buffer_as_triplet()).reshape([480, 640, 2])
dpt1 = np.asarray(dframe_data[:, :, 0], dtype='float32')
dpt2 = np.asarray(dframe_data[:, :, 1], dtype='float32')
dpt2 *= 255
#对于为什么要乘于255的解答
#深度图像的深度值 是按照16位长度(两字节)的数据格式存储的,也可以认为前八位是高字节,后八位是低字节。
#因此一张深度图像如果是 640480分辨率的话,那么图像字节大小 就是 640480*2,其中一个字节是8位(255)
dpt = dpt1 + dpt2
#cv2里面的函数,就是类似于一种筛选
'假设我们需要让我们的深度摄像头感兴趣的距离范围有差别地显示,那么我们就需要确定一个合适的alpha值,公式为:有效距离*alpha=255,' \
'假设我们想让深度摄像头8m距离内的深度被显示,>8m的与8m的颜色显示相同,那么alpha=255/(8*10^3)≈0.03,' \
'假设我们想让深度摄像头6m距离内的深度被显示,>6m的与6m的颜色显示相同,那么alpha=255/(6*10^3)≈0.0425'
dim_gray = cv2.convertScaleAbs(dpt, alpha=0.17)
#对深度图像进行一种图像的渲染,目前有11种渲染方式,大家可以逐一去试下
depth_colormap = cv2.applyColorMap(dim_gray, 2) # 有0~11种渲染的模式
cv2.imshow('depth', depth_colormap)
ret, frame = cap.read()
cv2.imshow('color', frame)
key = cv2.waitKey(1)
if int(key) == ord('q'):
break
depth_stream.stop()
dev.close()
运行结果是:
#彩色图像我就不上传了哈
✳至于深度图像上有一些黑色的点点,区域,如果我们点击会显示深度值为0,官方回答没有找到合适的距离,但我经过不断调试,还是有黑色的点点,不知道是什么原因,
✳经过在网上的查找,我发现可以通过:卡勒曼滤波,直方图均衡化,时序数据的均值法这几种方法对深度图像进行处理,后续我如果调试到合适的图像,让其精度达到官方文档说的3mm,之后会将代码发出来。