本课程实现了获取彩色图像以及使用mediapipe的框架来检测手部关节点的功能。本节内容需要在终端中输入指令,这里根据主板类型来选择打开终端。本节课程以树莓派5为例。
树莓派和Jetson-Nano主板,需要在宿主机中打开终端,然后输入进入docker容器的指令,进入到docker容器后的终端里边输入本节课程提及的指令,宿主机进入docker容器的教程可以参考本产品教程【0.说明书和安装步骤】中的【进入小车Dockder(Jetson-Nano和树莓派5用户看这里)】的内容。
Orin主板直接打开终端,输入本节课程提及的指令即可。
首先,在终端中,输入以下指令启动相机,
xxxxxxxxxxros2 launch orbbec_camera dabai_dcw2.launch.py成功启动相机后,另外开启一个终端,终端输入以下指令,启动手部检测的程序,
xxxxxxxxxxros2 run yahboomcar_mediapipe 01_HandDetector程序运行后如下图所示,图像右边会显示检测到手部的关节点,

程序代码路径:
树莓派5和Jetson-Nano主板
程序代码在运行的docker中。docker中的路径为/root/yahboomcar_ws/src/yahboomcar_mediapipe/yahboomcar_mediapipe/01_HandDetector.py
Orin主板
程序代码路径为/home/jetson/yahboomcar_ws/src/yahboomcar_mediapipe/yahboomcar_mediapipe/01_HandDetector.py
导入用到的库文件,
xxxxxxxxxximport rclpyfrom rclpy.node import Nodeimport mediapipe as mpimport cv2 as cvimport numpy as npimport timeimport osfrom cv_bridge import CvBridgefrom sensor_msgs.msg import Imagefrom arm_msgs.msg import ArmJointsimport cv2初始化数据并且定义发布者和订阅者,
xxxxxxxxxxdef __init__(self,name, mode=False, maxHands=2, detectorCon=0.5, trackCon=0.5): super().__init__(name) self.mpHand = mp.solutions.hands self.mpDraw = mp.solutions.drawing_utils self.hands = self.mpHand.Hands( static_image_mode=mode, max_num_hands=maxHands, min_detection_confidence=detectorCon, min_tracking_confidence=trackCon) self.lmDrawSpec = mp.solutions.drawing_utils.DrawingSpec(color=(0, 0, 255), thickness=-1, circle_radius=6) self.drawSpec = mp.solutions.drawing_utils.DrawingSpec(color=(0, 255, 0), thickness=2, circle_radius=2) #create a publisher self.rgb_bridge = CvBridge() #定义控制6个舵机的话题,并且发布手部检测的位姿 self.TargetAngle_pub = self.create_publisher(ArmJoints, "arm6_joints", 10) self.init_joints = [90, 150, 10, 20, 90, 90] self.pubSix_Arm(self.init_joints) #定义彩色图像话题的订阅者 self.sub_rgb = self.create_subscription(Image,"/camera/color/image_raw",self.get_RGBImageCallBack,100)彩色图像回调函数,
xxxxxxxxxxdef get_RGBImageCallBack(self,msg): #使用CvBridge把彩色图像消息数据转换成图像数据 rgb_image = self.rgb_bridge.imgmsg_to_cv2(msg, "bgr8") #把得到的图像传入定义的pubHandsPoint函数中,draw=False表示不在原来的彩色图像上画上关节点 frame, img = self.pubHandsPoint(rgb_image, draw=False) dist = self.frame_combine(frame, img) key = cv2.waitKey(1) cv.imshow('dist', dist)pubHandsPoint函数,
xxxxxxxxxxdef pubHandsPoint(self, frame, draw=True): #根据传入的图像大小,创建一个新的图像,图像的数据类型是uint8 img = np.zeros(frame.shape, np.uint8) #转换传入图像的色彩空间,由BGR转换从RGB,方便后续图像处理 img_RGB = cv.cvtColor(frame, cv.COLOR_BGR2RGB) #调用mediapipe库中的process函数进行图像处理,在init的时候,创建了self.hands对象,并且进行了初始化 self.results = self.hands.process(img_RGB) #判断self.results.multi_hand_landmarks是否存在,也就是是否识别到了手掌 if self.results.multi_hand_landmarks: #遍历手掌列表,获取到每个点的信息 for i in range(len(self.results.multi_hand_landmarks)): if draw: self.mpDraw.draw_landmarks(frame, self.results.multi_hand_landmarks[i], self.mpHand.HAND_CONNECTIONS, self.lmDrawSpec, self.drawSpec) #在之前创建的空白图像上,把每个关节点连接起来 self.mpDraw.draw_landmarks(img, self.results.multi_hand_landmarks[i], self.mpHand.HAND_CONNECTIONS, self.lmDrawSpec, self.drawSpec) return frame, imgframe_combine合并图像函数,
def frame_combine(slef,frame, src): #判断图像是否为3通道,也就是RGB图像 if len(frame.shape) == 3: #获取两张图像的大小,并且把它们拼接在一起 frameH, frameW = frame.shape[:2] srcH, srcW = src.shape[:2] dst = np.zeros((max(frameH, srcH), frameW + srcW, 3), np.uint8) dst[:, :frameW] = frame[:, :] dst[:, frameW:] = src[:, :] else: src = cv.cvtColor(src, cv.COLOR_BGR2GRAY) frameH, frameW = frame.shape[:2] imgH, imgW = src.shape[:2] dst = np.zeros((frameH, frameW + imgW), np.uint8) dst[:, :frameW] = frame[:, :] dst[:, frameW:] = src[:, :] return dst