前言:
Kinect是微軟在2009年公布的XBOX360體感周邊外設(shè)。它是一種3D體感攝影機,同時它導(dǎo)入了即時動態(tài)捕捉、影像辨識、麥克風(fēng)輸入、語音辨識、社群互動等功能。而相比Kinect V1,Kinect V2具有較大的紅外傳感器尺寸,并且(相對于其他深度相機)具有較寬闊的視場角,生成的深度圖質(zhì)量比較高。此外,Kinect V2的SDK非常給力,SDK中提供了同時最多進行六個人的骨架追蹤、基本的手勢操作和臉部跟蹤,支持 Cinder 和 Open Frameworks,并且具有內(nèi)置的Unity 3D插件。下面是Kinect V1和Kinect V2的一些對比。
種類 | V1 | V2 |
彩色圖分辨率 | 640*480 | 1920*1280 |
深度圖分辨率 | 320*240 | 512*424 |
紅外圖分辨率 | -- | 512*424 |
深度檢測距離 | 0.4m~4m | 0.4m~4.5m |
垂直方向視角 | 57度 | 70度 |
水平方向視角 | 43度 | 60度 |
同時,相對V1版相機基本是通過C++進行讀取與開發(fā),V2版也提供了一些開源Python接口對相機進行讀取,如(Kinect/Pykinect2)。接著就可以方便地使用OpenCV、Open3D或深度學(xué)習(xí)等算法了。目前應(yīng)用Python開發(fā)KinectV2主要有三種思路:
A. Libfreenect2以及OpenNI2:此方法在ROS端配置比較方便(參考博客),但在Windows端配置比較復(fù)雜(參考博客)。且對UsbDk或libusbK和libfreenect2等文件通過Visual Studio編譯的過程依賴工具多,不同電腦總會出現(xiàn)各種問題,解決起來比較繁瑣。
B. Matlab(讀?。┖蚉ython的聯(lián)合編程:通過kin2工具箱(參考開源項目)調(diào)用C++封裝好的Kinect SDK,并通過Matlab和Python的實時通訊接口傳輸圖片。缺點是占用內(nèi)存大、傳輸延時大、調(diào)試復(fù)雜。
C. 應(yīng)用Pykinect2庫:通過開源的Pykinect2工具庫讀取,但數(shù)據(jù)方面只提供RGB和深度圖接口,且該庫是使用Python2開發(fā)。在應(yīng)用Python3的安裝和開發(fā)過程中會遇到一系列的問題,在本文中列出相應(yīng)的解決方案。
工作環(huán)境:
系統(tǒng):windows10家庭版
Anaconda版本:4.14.0
Python版本:3.8.12
IDE:Pycharm
安裝流程:
1、下載Kinect for Windows SDK2.0,并正確安裝至本機,打開Kinect Studio檢查安裝是否成功。參考博客
2、在Anaconda的Terminal下載Pykinect2庫:
pip install pykinect2 -i https://pypi.tuna.tsinghua.edu.cn/simple
3、進入Pykinect2(Github)下載最新庫,并把其中的這兩個文件替換(Anaconda所在路徑)\envs\(環(huán)境名稱)\Lib\site-packages\pykinect2下的同名文件。
此步驟可以解決這個報錯:
4、接下來會遇到這個報錯,此報錯是由于Pykinect2依賴庫comtypes連接的版本與最新版本不兼容。
此時需要重新安裝comtypes庫:
pip install comtypes==1.1.4 -i https://pypi.tuna.tsinghua.edu.cn/simple
5、接下來會遇到這個報錯,此報錯是由于該版本的comtypes庫是基于Python2編寫的,與現(xiàn)在環(huán)境的Python3版本不兼容。
此時需要將comtypes庫中用到的Python2文件轉(zhuǎn)換為Python3文件才能夠正常執(zhí)行,先找到Anaconda安裝路徑中的2to3.py文件,位于(Anaconda安裝路徑)\envs\(環(huán)境名稱)\Tools\scripts:
打開電腦cmd(Win+R),進入到對應(yīng)路徑下:
找到comtypes中報錯的文件路徑,使用2to3.py將其轉(zhuǎn)為Python3文件,例如輸入:
python 2to3.py -w D:\Anaconda\envs\paddle\lib\site-packages\comtypes\__init__.py
順序解決所有類似的報錯,此步驟涉及近10個文件,需要耐心重復(fù)執(zhí)行。執(zhí)行完后便可正常引用Pykinect2庫了。文章來源:http://www.zghlxwxcb.cn/news/detail-851194.html
6、編寫Python調(diào)用Pykinect2的讀取程序,此處參考(開源博客)中提供的示例代碼進行修改:文章來源地址http://www.zghlxwxcb.cn/news/detail-851194.html
#coding=utf-8
from pykinect2 import PyKinectV2
from pykinect2.PyKinectV2 import *
from pykinect2 import PyKinectRuntime
import numpy as np
import ctypes
import math
import cv2 as cv
import time
import copy
class Kinect(object):
def __init__(self):
self._kinect = PyKinectRuntime.PyKinectRuntime(PyKinectV2.FrameSourceTypes_Color | PyKinectV2.FrameSourceTypes_Depth | PyKinectV2.FrameSourceTypes_Infrared)
self.depth_ori = None
self.infrared_frame = None
self.color_frame = None
self.w_color = 1920
self.h_color = 1080
self.w_depth = 512
self.h_depth = 424
self.csp_type = _ColorSpacePoint * int(1920 * 1080)
self.csp = ctypes.cast(self.csp_type(), ctypes.POINTER(_DepthSpacePoint))
self.color = None
self.depth = None
self.depth_draw = None
self.color_draw = None
self.infrared = None
self.first_time = True
def get_the_last_color(self):
if self._kinect.has_new_color_frame():
frame = self._kinect.get_last_color_frame()
gbra = frame.reshape([self._kinect.color_frame_desc.Height, self._kinect.color_frame_desc.Width, 4])
self.color_frame = gbra[:, :, 0:3]
return self.color_frame
def get_the_last_depth(self):
if self._kinect.has_new_depth_frame():
frame = self._kinect.get_last_depth_frame()
image_depth_all = frame.reshape([self._kinect.depth_frame_desc.Height,
self._kinect.depth_frame_desc.Width])
self.depth_ori = image_depth_all
return self.depth_ori
def get_the_last_infrared(self):
if self._kinect.has_new_infrared_frame():
frame = self._kinect.get_last_infrared_frame()
image_infrared_all = frame.reshape([self._kinect.infrared_frame_desc.Height,
self._kinect.infrared_frame_desc.Width])
self.infrared_frame = image_infrared_all
return self.infrared_frame
def map_depth_point_to_color_point(self, depth_point):
depth_point_to_color = copy.deepcopy(depth_point)
n = 0
while 1:
self.get_the_last_depth()
self.get_the_last_color()
if self.depth_ori is None:
continue
color_point = self._kinect._mapper.MapDepthPointToColorSpace(
_DepthSpacePoint(511-depth_point_to_color[1], depth_point_to_color[0]), self.depth_ori[depth_point_to_color[0], 511-depth_point_to_color[1]])
# color_point = self._kinect._mapper.MapDepthPointToColorSpace(
# _DepthSpacePoint(depth_point[0], depth_point[1]), self.depth[depth_point[1], depth_point[0]])
if math.isinf(float(color_point.y)):
n += 1
if n >= 50000:
print('')
color_point = [0, 0]
break
else:
color_point = [np.int0(color_point.y), 1920-np.int0(color_point.x)]
break
return color_point
def map_color_points_to_depth_points(self, color_points):
self.get_the_last_depth()
self.get_the_last_color()
self._kinect._mapper.MapColorFrameToDepthSpace(
ctypes.c_uint(512 * 424), self._kinect._depth_frame_data, ctypes.c_uint(1920 * 1080), self.csp)
depth_points = [self.map_color_point_to_depth_point(x, True) for x in color_points]
return depth_points
#將彩色像素點映射到深度圖像中
def map_color_point_to_depth_point(self, color_point, if_call_flg=False):
n = 0
color_point_to_depth = copy.deepcopy(color_point)
color_point_to_depth[1] = 1920 - color_point_to_depth[1]
while 1:
self.get_the_last_depth()
self.get_the_last_color()
# self.depth = cv.medianBlur(image_depth_all, 5)
if not if_call_flg:
self._kinect._mapper.MapColorFrameToDepthSpace(
ctypes.c_uint(512 * 424), self._kinect._depth_frame_data, ctypes.c_uint(1920 * 1080), self.csp)
if math.isinf(float(self.csp[color_point_to_depth[0]*1920+color_point_to_depth[1]-1].y)) or np.isnan(self.csp[color_point_to_depth[0]*1920+color_point_to_depth[1]-1].y):
n += 1
if n >= 50000:
print('彩色映射深度,無效的點')
depth_point = [0, 0]
break
else:
self.cor = self.csp[color_point_to_depth[0]*1920+color_point_to_depth[1]-1].y
try:
depth_point = [np.int0(self.csp[color_point_to_depth[0]*1920+color_point_to_depth[1]-1].y),
np.int0(self.csp[color_point_to_depth[0]*1920+color_point_to_depth[1]-1].x)]
except OverflowError as e:
print('彩色映射深度,無效的點')
depth_point = [0, 0]
break
depth_point[1] = 512-depth_point[1]
return depth_point
# depth_points = [self._kinect._mapper.MapColorPointToDepthSpace(_ColorSpacePoint(color_point[0],color_point[1]),self.color_frame[depth_point]))
# for depth_point in depth_points]
# return color_points
#獲得最新的彩色和深度圖像以及紅外圖像
def get_the_data_of_color_depth_infrared_image(self, Infrared_threshold = 16000):
# 訪問新的RGB幀
time_s = time.time()
if self.first_time:
while 1:
n = 0
if self._kinect.has_new_color_frame():
# # 獲得的圖像數(shù)據(jù)是二維的,需要轉(zhuǎn)換為需要的格式
frame = self._kinect.get_last_color_frame()
# 返回的是4通道,還有一通道是沒有注冊的
gbra = frame.reshape([self._kinect.color_frame_desc.Height, self._kinect.color_frame_desc.Width, 4])
# 取出彩色圖像數(shù)據(jù)
# self.color = gbra[:, :, 0:3]
self.color = gbra[:, :, 0:3][:,::-1,:]
# 這是因為在python中直接復(fù)制該圖像的效率不如直接再從C++中獲取一幀來的快
frame = self._kinect.get_last_color_frame()
# 返回的是4通道,還有一通道是沒有注冊的
gbra = frame.reshape([self._kinect.color_frame_desc.Height, self._kinect.color_frame_desc.Width, 4])
# 取出彩色圖像數(shù)據(jù)
# self.color_draw = gbra[:, :, 0:3][:,::-1,:]
self.color_draw = gbra[:, :, 0:3][:,::-1,:]
n += 1
# 訪問新的Depth幀
if self._kinect.has_new_depth_frame():
# 獲得深度圖數(shù)據(jù)
frame = self._kinect.get_last_depth_frame()
# 轉(zhuǎn)換為圖像排列
image_depth_all = frame.reshape([self._kinect.depth_frame_desc.Height,
self._kinect.depth_frame_desc.Width])
# 轉(zhuǎn)換為(n,m,1) 形式
image_depth_all = image_depth_all.reshape(
[self._kinect.depth_frame_desc.Height, self._kinect.depth_frame_desc.Width, 1])
self.depth_ori = np.squeeze(image_depth_all)
self.depth = np.squeeze(image_depth_all)[:,::-1]
"""————————————————(2019/5/11)——————————————————"""
# 獲得深度圖數(shù)據(jù)
frame = self._kinect.get_last_depth_frame()
# 轉(zhuǎn)換為圖像排列
depth_all_draw = frame.reshape([self._kinect.depth_frame_desc.Height,
self._kinect.depth_frame_desc.Width])
# 轉(zhuǎn)換為(n,m,1) 形式
depth_all_draw = depth_all_draw.reshape(
[self._kinect.depth_frame_desc.Height, self._kinect.depth_frame_desc.Width, 1])
depth_all_draw[depth_all_draw >= 1500] = 0
depth_all_draw[depth_all_draw <= 500] = 0
depth_all_draw = np.uint8(depth_all_draw / 1501 * 255)
self.depth_draw = depth_all_draw[:,::-1,:]
n += 1
# 獲取紅外數(shù)據(jù)
if self._kinect.has_new_infrared_frame():
# 獲得深度圖數(shù)據(jù)
frame = self._kinect.get_last_infrared_frame()
# 轉(zhuǎn)換為圖像排列
image_infrared_all = frame.reshape([self._kinect.depth_frame_desc.Height,
self._kinect.depth_frame_desc.Width])
# 轉(zhuǎn)換為(n,m,1) 形式
image_infrared_all[image_infrared_all > Infrared_threshold] = 0
image_infrared_all = image_infrared_all / Infrared_threshold * 255
self.infrared = image_infrared_all[:,::-1]
n += 1
t = time.time() - time_s
if n == 3:
self.first_time = False
break
elif t > 5:
print('未獲取圖像數(shù)據(jù),請檢查Kinect2連接是否正常')
break
else:
if self._kinect.has_new_color_frame():
# # 獲得的圖像數(shù)據(jù)是二維的,需要轉(zhuǎn)換為需要的格式
frame = self._kinect.get_last_color_frame()
# 返回的是4通道,還有一通道是沒有注冊的
gbra = frame.reshape([self._kinect.color_frame_desc.Height, self._kinect.color_frame_desc.Width, 4])
# 取出彩色圖像數(shù)據(jù)
# self.color = gbra[:, :, 0:3]
self.color = gbra[:, :, 0:3][:, ::-1, :]
# 這是因為在python中直接復(fù)制該圖像的效率不如直接再從C++中獲取一幀來的快
frame = self._kinect.get_last_color_frame()
# 返回的是4通道,還有一通道是沒有注冊的
gbra = frame.reshape([self._kinect.color_frame_desc.Height, self._kinect.color_frame_desc.Width, 4])
# 取出彩色圖像數(shù)據(jù)
# self.color_draw = gbra[:, :, 0:3][:,::-1,:]
self.color_draw = gbra[:, :, 0:3][:, ::-1, :]
# 訪問新的Depth幀
if self._kinect.has_new_depth_frame():
# 獲得深度圖數(shù)據(jù)
frame = self._kinect.get_last_depth_frame()
# 轉(zhuǎn)換為圖像排列
image_depth_all = frame.reshape([self._kinect.depth_frame_desc.Height,
self._kinect.depth_frame_desc.Width])
# 轉(zhuǎn)換為(n,m,1) 形式
image_depth_all = image_depth_all.reshape(
[self._kinect.depth_frame_desc.Height, self._kinect.depth_frame_desc.Width, 1])
self.depth_ori = np.squeeze(image_depth_all)
self.depth = np.squeeze(image_depth_all)[:, ::-1]
# 獲得深度圖數(shù)據(jù)
frame = self._kinect.get_last_depth_frame()
# 轉(zhuǎn)換為圖像排列
depth_all_draw = frame.reshape([self._kinect.depth_frame_desc.Height,
self._kinect.depth_frame_desc.Width])
# 轉(zhuǎn)換為(n,m,1) 形式
depth_all_draw = depth_all_draw.reshape(
[self._kinect.depth_frame_desc.Height, self._kinect.depth_frame_desc.Width, 1])
depth_all_draw[depth_all_draw >= 1500] = 0
depth_all_draw[depth_all_draw <= 500] = 0
depth_all_draw = np.uint8(depth_all_draw / 1501 * 255)
self.depth_draw = depth_all_draw[:, ::-1, :]
# 獲取紅外數(shù)據(jù)
if self._kinect.has_new_infrared_frame():
# 獲得深度圖數(shù)據(jù)
frame = self._kinect.get_last_infrared_frame()
# 轉(zhuǎn)換為圖像排列
image_infrared_all = frame.reshape([self._kinect.depth_frame_desc.Height,
self._kinect.depth_frame_desc.Width])
# 轉(zhuǎn)換為(n,m,1) 形式
image_infrared_all[image_infrared_all > Infrared_threshold] = 0
image_infrared_all = image_infrared_all / Infrared_threshold * 255
self.infrared = image_infrared_all[:, ::-1]
return self.color, self.color_draw, self.depth, self.depth_draw, self.infrared
#顯示各種圖像的視頻流
def Kinect_imshow(self,type_im='rgb'):
"""
Time :2019/9/3
FunC:
Input: color_data
Return: color_data
"""
if type_im =='all':
pass
elif type_im =='rgb':
pass
elif type_im =='depth':
pass
elif type_im =='grared':
pass
if __name__ == '__main__':
a = Kinect()
while 1:
t = time.time()
#color_data = a.get_the_data_of_color_depth_infrared_image()
color, color_draw, depth, depth_draw, infrared = a.get_the_data_of_color_depth_infrared_image()
cv.imshow('a',color)
cv.waitKey(1)
到了這里,關(guān)于Kinect系列1:(Windows環(huán)境配置)Python3+Pykinect2+KinectV2相機讀取彩色圖與深度圖的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!