Openpose人體骨骼、手勢--靜態圖像標記及分類(附源碼)

一、背景

我的環境是:Windows10 + python3.7 + anaconda3 + jupyter5.6.0

安裝 Openpose開源庫時,有點費力,在前面一篇文章中講述過,這裏不再重複;前文有模型下載鏈接。

本次涉及的模型有:hand和pose-coco模型
在這裏插入圖片描述

手部:22個關鍵點(21個骨骼點,第22個表示背景),骨骼:coco模型18個特徵點
在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述
前文講述了安裝和基本使用方法,本文來將骨骼和手勢融合在一張圖片中同時檢測並標記。

二、標記

1.標記骨骼特徵

1)剔除不必要點

上一次是基於危險駕駛的探討:
在這裏插入圖片描述
本次我需要手語圖像識別,那麼這裏需要標記的上半身參考點的關鍵信息更多了。

圖中是我訓練時的截圖,可以發現手語所表達的肢體動作均在上半身,所以我們參考點可忽略(點9,10,12,13)
在這裏插入圖片描述
(圖片參考於:中國手語數據集DEVISIGN 數據集以及手語公益網站視頻)

2)特徵

在這裏插入圖片描述
圖像識別,需要以上流程,目前我們在(特徵提取和選擇階段),提取哪些特徵是有價值的特徵呢?

示例:

  1. 危險駕駛判斷標準:

    • 抽菸:可以用雙手到鼻的距離來進行判斷,即點4,7到點0的距離。
    • 接電話:可以計算右手到右耳的距離(左手倒左耳的距離)來進行判斷,即點4到點16的距離(點7到點17的距離)。
      在這裏插入圖片描述
  2. 基於普通攝像頭的太極姿勢識別
    太極姿勢分爲23式,原作者根據需求提取手臂姿勢、腿部姿勢:在這裏插入圖片描述
    原作者筆記:十五組人體姿態骨骼關鍵點之間的距離作爲特徵,同時選擇
    了十五組夾角作爲角度特徵整合到一個數組中去。
    在這裏插入圖片描述
    爲什麼需要角度作爲輔助判斷參數呢?

    僅選擇距離判斷因素,當人離攝像頭更遠一些,人就會縮小,距離會變短;人靠近攝像頭,距離會變大,距離因素遠遠不夠。

    通過引入角度信息,我們都知道:一條直線不能確定其方向和大小,若是一個向量(有方向有大小的定點線段),那麼這就可以在圖像表示唯一。所以,這裏是通過角度來約束距離

    引入角度有哪些弊端呢?

    出自太極手勢識別:
    組合特徵:距離和角度,能夠提高複雜關係的擬合能力,同時由於有些角度在某些情況下的值爲零值,比如 2-3-4(整個手臂:手,胳膊肘,肩膀之間的夾角的餘弦值)夾角爲直角的時候餘弦值是零值,當 OpenPose 丟失一個點比如說 4 號位置手的信息沒有檢測出來的時候,返回零值,它的餘弦值就和肩膀之間的夾角的餘弦值)夾角爲直角的時候餘弦值相同了,因此僅僅依據距離信息有時候也會對數據訓練產生一定的誤導作用,所以就按照距離約束角度,角度約束距離的設計思路設計了獨特的太極姿態識別的訓練數據。

通過上述的分析,我們暫且提煉出25組關鍵特徵,如圖:
在這裏插入圖片描述
現在特徵點也規劃好了,上代碼——在其中連線,圈圈畫畫,計算長度角度。

三、實現

1.獲取關鍵點座標

主要還是參考前一文:Openpose駕駛員危險駕駛檢測(抽菸打電話)

前文是單獨提取骨骼特徵點和手勢特徵點,這裏對其進行一個融合,思路是:

  1. 傳入原圖像,獲取骨骼的coco模型18特徵點
    在這裏插入圖片描述

  2. 手勢特徵點:通過骨骼特徵點point[4]point[7]標註出兩隻手首的位置,以手首爲中心,取小臂長範圍對圖片進行分割;再別對兩個圖片進行識別。
    在這裏插入圖片描述
    手勢檢測:
    在這裏插入圖片描述
    (當然這張圖片裏的dancer戴了手套,會影響手勢部分的檢測。)
    此部分代碼:
    1. 在裁剪的時候注意左右相反的,我一開始弄錯了,裁剪框老不對
    rimg = img_cv2[y1:y2,x1:x2]# 裁剪座標爲[y0:y1, x0:x1]
    2. 注意判斷圖像中沒有顯示左手和右手的情況,以及標註框範圍過大時,只裁取到圖像邊緣:

      def getHandROI(self,imgfile,bonepoints):
            """hand手部感興趣的區域尋找到雙手圖像
            
            :param 圖像路徑,骨骼關鍵點
            :return 左手關鍵點,右手關鍵點座標集合
            """
            img_cv2 = cv2.imread(imgfile)#原圖像
            img_height, img_width, _ = img_cv2.shape
            rimg = img_cv2.copy()#圖像備份
            limg = img_cv2.copy()
            # 以右手首爲中心,裁剪長度爲小臂長的圖片
            if bonepoints[4] and bonepoints[3]:#右手
                h = int(self.__distance(bonepoints[4],bonepoints[3]))#小臂長
                x_center = bonepoints[4][0]
                y_center = bonepoints[4][1]
                x1 = x_center-h
                y1 = y_center-h
                x2 = x_center+h
                y2 = y_center+h
                print(x1,x2,x_center,y_center,y1,y2)
                if x1< 0:
                    x1 = 0
                if x2>img_width:
                    x2 = img_width
                if y1< 0:
                    y1 = 0
                if y2>img_height:
                    y2 = img_height
                rimg = img_cv2[y1:y2,x1:x2]# 裁剪座標爲[y0:y1, x0:x1]
                
            if bonepoints[7] and bonepoints[6]:#左手
                h = int(self.__distance(bonepoints[7],bonepoints[6]))#小臂長
                x_center = bonepoints[7][0]
                y_center = bonepoints[7][1]
                x1 = x_center-h
                y1 = y_center-h
                x2 = x_center+h
                y2 = y_center+h
                print(x1,x2,x_center,y_center,y1,y2)
                if x1< 0:
                    x1 = 0
                if x2>img_width:
                    x2 = img_width
                if y1< 0:
                    y1 = 0
                if y2>img_height:
                    y2 = img_height
                limg = img_cv2[y1:y2,x1:x2]# 裁剪座標爲[y0:y1, x0:x1]    
            
            plt.figure(figsize=[10, 10])
            plt.subplot(1, 2, 1)
            plt.imshow(cv2.cvtColor(rimg, cv2.COLOR_BGR2RGB))
            plt.axis("off")
            plt.subplot(1, 2, 2)
            plt.imshow(cv2.cvtColor(limg, cv2.COLOR_BGR2RGB))
            plt.axis("off")
            plt.show()
            # 分別獲取手部特徵點
            rhandpoints = self.getHandKeypoints(rimg)
            lhandpoints = self.getHandKeypoints(limg)
            #顯示
            pose_model.vis_hand_pose(rimg, rhandpoints)
            pose_model.vis_hand_pose(limg, lhandpoints)
            
            return rhandpoints,lhandpoints
    

    ok,現在你已經get了手勢和骨骼的座標了

2.計算特徵

1)距離

我們圖片是二維的,
在這裏插入圖片描述

    def __distance(self,A,B):
        """距離輔助函數
        
        :param 兩個座標A(x1,y1)B(x2,y2)
        :return 距離d=AB的距離
        """
        if A is None or B is None:
            return 0
        else:
            return math.sqrt((A[0]-B[0])**2+(A[1]-B[1])**2)

在openpose返回的關鍵點座標中,未識別的關鍵點返回None;因此,我們這裏也要做一個簡單的None判斷,座標都沒有了,還怎麼計算距離呢?🤣

2)角度

我們之前保留的參考點爲三個點:A-B-C式(2-3-4代表右手的手臂角度)
在這裏插入圖片描述

這裏採用餘弦定理:(a,b,c分別是A,B,C的對邊長度)
在這裏插入圖片描述
關於角B的計算公式:
在這裏插入圖片描述在這裏插入圖片描述
其中,我們計算先根據三個點的座標信息,計算各邊長;再計算餘弦的弧度值:
在這裏插入圖片描述
弧度值轉角度值:math.degrees(),均可(這裏爲了我方便觀察,我暫時轉換了,實際運用時,不用轉換,多一份計算,減慢一分運行速度!)

  def __myAngle(self,A,B,C):
        """角度輔助函數
        
        :param 三個座標A(x1,y1)B(x2,y2)C(x3,y3)
        :return 角B的餘弦值(轉換爲角度)
        """
        if A is None or B is None or C is None:
            return 0
        else:
            a=self.__distance(B,C)
            b=self.__distance(A,C)
            c=self.__distance(A,B)
            if 2*a*c !=0:
                return math.degrees(a**2/+c**2-b**2)/(2*a*c)#計算出cos弧度,轉換爲角度
            return 0

根據我之前的25個(距離+角度)信息,存放那個在list中,還是比較好理解。
在這裏插入圖片描述
爲了演示,做了部分特徵值參數顯示,大致就是這個意思,這些數據都需要保存收集,爲後面生成模型和識別做準備。
在這裏插入圖片描述

3.演示

在這裏插入圖片描述

4.完整代碼

#!/usr/bin/python3
#!--*-- coding: utf-8 --*--
from __future__ import division# 精確除法
import cv2
import os
import time
import math
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei'] #用來正常顯示中文標籤
plt.rcParams['axes.unicode_minus']=False #用來正常顯示負號

class general_pose_model(object):
    def __init__(self, modelpath):
        # 指定採用的模型
        #   hand: 22 points(21個手勢關鍵點,第22個點表示背景)
        #   COCO:   18 points()
        self.inWidth = 368
        self.inHeight = 368
        self.threshold = 0.1
        self.pose_net = self.general_coco_model(modelpath)
        self.hand_num_points = 22
        self.hand_point_pairs = [[0,1],[1,2],[2,3],[3,4],
                            [0,5],[5,6],[6,7],[7,8],
                            [0,9],[9,10],[10,11],[11,12],
                            [0,13],[13,14],[14,15],[15,16],
                            [0,17],[17,18],[18,19],[19,20]]
        self.hand_net = self.get_hand_model(modelpath)
        self.MIN_DESCRIPTOR = 32  # surprisingly enough, 2 descriptors are already enough

    """提取骨骼特徵點,並可視化顯示"""

    def general_coco_model(self, modelpath):
        self.points_name = {
            "Nose": 0, "Neck": 1, 
            "RShoulder": 2, "RElbow": 3, "RWrist": 4,
            "LShoulder": 5, "LElbow": 6, "LWrist": 7, 
            "RHip": 8, "RKnee": 9, "RAnkle": 10, 
            "LHip": 11, "LKnee": 12, "LAnkle": 13, 
            "REye": 14, "LEye": 15, 
            "REar": 16, "LEar": 17, 
            "Background": 18}
        self.bone_num_points = 18
        self.bone_point_pairs = [[1, 0], [1, 2], [1, 5], 
                            [2, 3], [3, 4], [5, 6], 
                            [6, 7], [1, 8], [8, 9],
                            [9, 10], [1, 11], [11, 12], 
                            [12, 13], [0, 14], [0, 15], 
                            [14, 16], [15, 17]]
        prototxt   = os.path.join(modelpath,"pose/coco/pose_deploy_linevec.prototxt")
        caffemodel = os.path.join(modelpath, "pose/coco/pose_iter_440000.caffemodel")
        coco_model = cv2.dnn.readNetFromCaffe(prototxt, caffemodel)

        return coco_model

    def getBoneKeypoints(self, imgfile):
        """COCO身體關鍵點檢測
        
        :param 圖像路徑
        :return 關鍵點座標集合
        """
        img_cv2 = cv2.imread(imgfile)
        img_height, img_width, _ = img_cv2.shape
        inpBlob = cv2.dnn.blobFromImage(img_cv2,1.0 / 255,(self.inWidth, self.inHeight),(0, 0, 0), swapRB=False, crop=False)
        self.pose_net.setInput(inpBlob)
        self.pose_net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)
        self.pose_net.setPreferableTarget(cv2.dnn.DNN_TARGET_OPENCL)

        output = self.pose_net.forward()

        H = output.shape[2]
        W = output.shape[3]
        print("形狀:")
        print(output.shape)

        # vis heatmaps
        self.vis_bone_heatmaps(img_file, output)

        #
        points = []
        for idx in range(self.bone_num_points):
            probMap = output[0, idx, :, :] # confidence map.

            # 提取關鍵點區域的局部最大值
            minVal, prob, minLoc, point = cv2.minMaxLoc(probMap)

            # Scale the point to fit on the original image
            x = (img_width * point[0]) / W
            y = (img_height * point[1]) / H

            if prob > self.threshold:
                points.append((int(x), int(y)))
            else:
                points.append(None)
        #print(points)
        return points
    
    def __distance(self,A,B):
        """距離輔助函數
        
        :param 兩個座標A(x1,y1)B(x2,y2)
        :return 距離d=AB的距離
        """
        if A is None or B is None:
            return 0
        else:
            return math.sqrt((A[0]-B[0])**2+(A[1]-B[1])**2)
        
    def __myAngle(self,A,B,C):
        """角度輔助函數
        
        :param 三個座標A(x1,y1)B(x2,y2)C(x3,y3)
        :return 角B的餘弦值(轉換爲角度)
        """
        if A is None or B is None or C is None:
            return 0
        else:
            a=self.__distance(B,C)
            b=self.__distance(A,C)
            c=self.__distance(A,B)
            if 2*a*c !=0:
                return math.degrees(a**2/+c**2-b**2)/(2*a*c)#計算出cos弧度,轉換爲角度
            return 0
    
    def bonepointDistance(self, keyPoint):
        """距離輔助函數
        :param keyPoint:
        :return:list
        :distance:
        """
        distance0 = self.__distance(keyPoint[4],keyPoint[8])#右手右腰
        distance1 = self.__distance(keyPoint[7],keyPoint[11])#左手左腰
        distance2 = self.__distance(keyPoint[2],keyPoint[4])#手肩
        distance3 = self.__distance(keyPoint[5],keyPoint[7])
        distance4 = self.__distance(keyPoint[0],keyPoint[4])#頭手
        distance5 = self.__distance(keyPoint[0],keyPoint[7])
        distance6 = self.__distance(keyPoint[4],keyPoint[7])#兩手
        distance7 = self.__distance(keyPoint[4],keyPoint[16])#手耳
        distance8 = self.__distance(keyPoint[7],keyPoint[17])
        distance9 = self.__distance(keyPoint[4],keyPoint[14])#手眼
        distance10 = self.__distance(keyPoint[7],keyPoint[15])
        distance11 = self.__distance(keyPoint[4],keyPoint[1])#手脖
        distance12 = self.__distance(keyPoint[7],keyPoint[1])
        distance13 = self.__distance(keyPoint[4],keyPoint[5])#左手左臂
        distance14 = self.__distance(keyPoint[4],keyPoint[6])#右手左肩
        distance15 = self.__distance(keyPoint[7],keyPoint[2])#右手左肩
        distance16 = self.__distance(keyPoint[7],keyPoint[3])#左手右臂

        return [distance0, distance1, distance2, distance3, distance4, distance5, distance6, distance7,distance8,
                distance9, distance10, distance11, distance12, distance13, distance14, distance15, distance16]

    def bonepointAngle(self, keyPoint):
        """角度輔助函數
        
        :param keyPoint:
        :return:list
        :角度:
        """
        angle0 = self.__myAngle(keyPoint[2], keyPoint[3], keyPoint[4])#右手臂夾角
        angle1 = self.__myAngle(keyPoint[5], keyPoint[6], keyPoint[7])#左手臂夾角
        angle2 = self.__myAngle(keyPoint[3], keyPoint[2], keyPoint[1])#右肩夾角
        angle3 = self.__myAngle(keyPoint[6], keyPoint[5], keyPoint[1])
        angle4 = self.__myAngle(keyPoint[4], keyPoint[0], keyPoint[7])#頭手頭
        if keyPoint[8] is None or keyPoint[11] is None:
            angle5 = 0
        else:
            temp = ((keyPoint[8][0]+keyPoint[11][0])/2,(keyPoint[8][1]+keyPoint[11][1])/2)#兩腰的中間值
            angle5 = self.__myAngle(keyPoint[4], temp, keyPoint[7])#手腰手
        angle6 = self.__myAngle(keyPoint[4], keyPoint[1], keyPoint[8])#右手脖腰
        angle7 = self.__myAngle(keyPoint[7], keyPoint[1], keyPoint[11])#右手脖腰

        return [angle0, angle1, angle2, angle3, angle4, angle5, angle6, angle7]

    def vis_bone_pose(self,imgfile,points):
        """顯示標註骨骼點後的圖像
        
        :param 圖像路徑,COCO檢測關鍵點座標
        """
        img_cv2 = cv2.imread(imgfile)
        img_cv2_copy = np.copy(img_cv2)
        for idx in range(len(points)):
            if points[idx]:
                cv2.circle(img_cv2_copy, points[idx], 5, (0, 255, 255), thickness=-1,lineType=cv2.FILLED)
                cv2.putText(img_cv2_copy, "{}".format(idx), points[idx], cv2.FONT_HERSHEY_SIMPLEX,1,(0, 0, 255),4, lineType=cv2.LINE_AA)
        h = int(self.__distance(points[4],points[3]))#小臂周長
        if points[4]:
            x_center = points[4][0]
            y_center = points[4][1]
            cv2.rectangle(img_cv2, (x_center-h, y_center-h), (x_center+h, y_center+h), (255, 0, 0), 2)#框
            cv2.circle(img_cv2,(x_center, y_center), 3, (0, 0, 255), thickness=-1,lineType=cv2.FILLED)#座標點
            cv2.putText(img_cv2,"%d,%d" % (x_center,y_center),(x_center, y_center), cv2.FONT_HERSHEY_SIMPLEX,
                            0.6, (0, 0, 255), 2, lineType=cv2.LINE_AA)#右手首
        if points[7]:
            x_center = points[7][0]
            y_center = points[7][1]
            cv2.rectangle(img_cv2, (x_center-h, y_center-h), (x_center+h, y_center+h), (255, 0, 0), 2)
            cv2.putText(img_cv2,"%d,%d" % (x_center,y_center),(x_center, y_center), cv2.FONT_HERSHEY_SIMPLEX,
                            0.6, (0, 0, 255), 2, lineType=cv2.LINE_AA)#左手首
            cv2.circle(img_cv2,(x_center-h, y_center-h), 3, (225, 225, 255), thickness=-1,lineType=cv2.FILLED)#對角點
            cv2.putText(img_cv2, "{}".format(x_center-h),(x_center-h, y_center-h), cv2.FONT_HERSHEY_SIMPLEX,
                            0.6, (255, 0, 0), 2, lineType=cv2.LINE_AA)
            cv2.circle(img_cv2,(x_center+h, y_center+h), 3, (225, 225, 255), thickness=-1,lineType=cv2.FILLED)
            cv2.putText(img_cv2, "{}".format(x_center+h),(x_center+h, y_center+h), cv2.FONT_HERSHEY_SIMPLEX,
                            0.6, (255, 0, 0), 2, lineType=cv2.LINE_AA)#對角點
        
        # 骨骼連線
        for pair in self.bone_point_pairs:
            partA = pair[0]
            partB = pair[1]

            if points[partA] and points[partB]:
                cv2.line(img_cv2, points[partA], points[partB], (0, 255, 255), 3)
                cv2.circle(img_cv2, points[partA],4, (0, 0, 255),thickness=-1, lineType=cv2.FILLED)

        plt.figure(figsize=[10, 10])
        plt.subplot(1, 2, 1)
        plt.imshow(cv2.cvtColor(img_cv2, cv2.COLOR_BGR2RGB))
        plt.axis("off")
        plt.subplot(1, 2, 2)
        plt.imshow(cv2.cvtColor(img_cv2_copy, cv2.COLOR_BGR2RGB))
        plt.axis("off")
        plt.show()
        
    def vis_bone_heatmaps(self, imgfile, net_outputs):
        """顯示骨骼關鍵點熱力圖
        
        :param 圖像路徑,神經網絡
        """
        img_cv2 = cv2.imread(imgfile)
        plt.figure(figsize=[10, 10])
        for pdx in range(self.bone_num_points):
            probMap = net_outputs[0, pdx, :, :]#全部heatmap都初始化爲0
            probMap = cv2.resize(probMap,(img_cv2.shape[1], img_cv2.shape[0]))
            plt.subplot(5, 5, pdx+1)
            plt.imshow(cv2.cvtColor(img_cv2, cv2.COLOR_BGR2RGB))# background
            plt.imshow(probMap, alpha=0.6)
            plt.colorbar()
            plt.axis("off")
        plt.show()
    
    """提取手勢圖像(在骨骼基礎上定位左右手圖片),handpose特徵點,並可視化顯示"""
    def get_hand_model(self, modelpath):

        prototxt   = os.path.join(modelpath, "hand/pose_deploy.prototxt")
        caffemodel = os.path.join(modelpath, "hand/pose_iter_102000.caffemodel")
        hand_model = cv2.dnn.readNetFromCaffe(prototxt, caffemodel)

        return hand_model
    
    def getOneHandKeypoints(self, handimg):
        """hand手部關鍵點檢測(單手)
        
        :param 手部圖像路徑,手部關鍵點
        :return 單手關鍵點座標集合
        """
        img_height, img_width, _ = handimg.shape        
        aspect_ratio = img_width / img_height

        inWidth = int(((aspect_ratio * self.inHeight) * 8) // 8)
        inpBlob = cv2.dnn.blobFromImage(handimg, 1.0 / 255, (inWidth, self.inHeight), (0, 0, 0), swapRB=False, crop=False)

        self.hand_net.setInput(inpBlob)

        output = self.hand_net.forward()

        # vis heatmaps
        self.vis_hand_heatmaps(handimg, output)

        #
        points = []
        for idx in range(self.hand_num_points):
            probMap = output[0, idx, :, :] # confidence map.
            probMap = cv2.resize(probMap, (img_width, img_height))

            # Find global maxima of the probMap.
            minVal, prob, minLoc, point = cv2.minMaxLoc(probMap)

            if prob > self.threshold:
                points.append((int(point[0]), int(point[1])))
            else:
                points.append(None)

        return points
        
    def getHandROI(self,imgfile,bonepoints):
        """hand手部感興趣的區域尋找到雙手圖像
        
        :param 圖像路徑,骨骼關鍵點
        :return 左手關鍵點,右手關鍵點座標集合
        """
        img_cv2 = cv2.imread(imgfile)#原圖像
        img_height, img_width, _ = img_cv2.shape
        rimg = img_cv2.copy()#圖像備份
        limg = img_cv2.copy()
        # 以右手首爲中心,裁剪長度爲小臂長的圖片
        if bonepoints[4] and bonepoints[3]:#右手
            h = int(self.__distance(bonepoints[4],bonepoints[3]))#小臂長
            x_center = bonepoints[4][0]
            y_center = bonepoints[4][1]
            x1 = x_center-h
            y1 = y_center-h
            x2 = x_center+h
            y2 = y_center+h
            print(x1,x2,x_center,y_center,y1,y2)
            if x1< 0:
                x1 = 0
            if x2>img_width:
                x2 = img_width
            if y1< 0:
                y1 = 0
            if y2>img_height:
                y2 = img_height
            rimg = img_cv2[y1:y2,x1:x2]# 裁剪座標爲[y0:y1, x0:x1]
            
        if bonepoints[7] and bonepoints[6]:#左手
            h = int(self.__distance(bonepoints[7],bonepoints[6]))#小臂長
            x_center = bonepoints[7][0]
            y_center = bonepoints[7][1]
            x1 = x_center-h
            y1 = y_center-h
            x2 = x_center+h
            y2 = y_center+h
            print(x1,x2,x_center,y_center,y1,y2)
            if x1< 0:
                x1 = 0
            if x2>img_width:
                x2 = img_width
            if y1< 0:
                y1 = 0
            if y2>img_height:
                y2 = img_height
            limg = img_cv2[y1:y2,x1:x2]# 裁剪座標爲[y0:y1, x0:x1]    
        
        plt.figure(figsize=[10, 10])
        plt.subplot(1, 2, 1)
        plt.imshow(cv2.cvtColor(rimg, cv2.COLOR_BGR2RGB))
        plt.axis("off")
        plt.subplot(1, 2, 2)
        plt.imshow(cv2.cvtColor(limg, cv2.COLOR_BGR2RGB))
        plt.axis("off")
        plt.show()
        
        return rimg,limg
    
    def getHandsKeypoints(self,rimg,limg):
        """雙手圖像分別獲取特徵點
        
        :param 圖像路徑,骨骼關鍵點
        :return 左手關鍵點,右手關鍵點座標集合
        """
        # 分別獲取手部特徵點
        rhandpoints = self.getOneHandKeypoints(rimg)
        lhandpoints = self.getOneHandKeypoints(limg)
        #顯示
        pose_model.vis_hand_pose(rimg, rhandpoints)
        pose_model.vis_hand_pose(limg, lhandpoints)
        
        return rhandpoints,lhandpoints
    
    def vis_hand_heatmaps(self, handimg, net_outputs):
        """顯示手勢關鍵點熱力圖(單手)
        
        :param 圖像路徑,神經網絡
        """
        plt.figure(figsize=[10, 10])

        for pdx in range(self.hand_num_points):
            probMap = net_outputs[0, pdx, :, :]
            probMap = cv2.resize(probMap, (handimg.shape[1], handimg.shape[0]))
            plt.subplot(5, 5, pdx+1)
            plt.imshow(cv2.cvtColor(handimg, cv2.COLOR_BGR2RGB))
            plt.imshow(probMap, alpha=0.6)
            plt.colorbar()
            plt.axis("off")
        plt.show()

    def vis_hand_pose(self, handimg, points):
        """顯示標註手勢關鍵點後的圖像(單手)
        
        :param 圖像路徑,每隻手檢測關鍵點座標
        """
        img_cv2_copy = np.copy(handimg)
        for idx in range(len(points)):
            if points[idx]:
                cv2.circle(img_cv2_copy, points[idx], 2, (0, 255, 255), thickness=-1,lineType=cv2.FILLED)
                cv2.putText(img_cv2_copy, "{}".format(idx), points[idx], cv2.FONT_HERSHEY_SIMPLEX,0.3,
                            (0, 0, 255), 1, lineType=cv2.LINE_AA)

        # Draw Skeleton
        for pair in self.hand_point_pairs:
            partA = pair[0]
            partB = pair[1]

            if points[partA] and points[partB]:
                cv2.line(handimg, points[partA], points[partB], (0, 255, 255), 2)
                cv2.circle(handimg, points[partA], 2, (0, 0, 255), thickness=-1, lineType=cv2.FILLED)

        plt.figure(figsize=[10, 10])
        plt.subplot(1, 2, 1)
        plt.imshow(cv2.cvtColor(handimg, cv2.COLOR_BGR2RGB))
        plt.axis("off")
        plt.subplot(1, 2, 2)
        plt.imshow(cv2.cvtColor(img_cv2_copy, cv2.COLOR_BGR2RGB))
        plt.axis("off")
        plt.show()


if __name__ == '__main__':
    print("[INFO]Pose estimation.")

    img_file = "images/letter/melon.jpg"
    #
    start = time.time()
    modelpath = "models/"
    pose_model = general_pose_model(modelpath)
    print("[INFO]Model loads time: ", time.time() - start)

    start = time.time()
    bone_points = pose_model.getBoneKeypoints(img_file)
    print("[INFO]Model predicts time: ", time.time() - start)
    pose_model.vis_bone_pose(img_file, bone_points)
    print("骨骼關鍵距離信息: ")
    DistanceList = pose_model.bonepointDistance(bone_points)
    print(DistanceList)
    print("骨骼關鍵角度信息: ")
    AngleList = pose_model.bonepointAngle(bone_points)
    print(AngleList)
    # 手勢
    rimg,limg = pose_model.getHandROI(img_file,bone_points)# 左右手圖像
    rhandpoints,lhandpoints = pose_model.getHandsKeypoints(rimg,limg)#特徵點
    print("左右手關鍵點信息: ")
    print(rhandpoints)
    print(lhandpoints)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章