multi-person-openpose.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. import cv2
  2. import time
  3. import numpy as np
  4. from random import randint
  5. import argparse
  6. parser = argparse.ArgumentParser(description='Run keypoint detection')
  7. parser.add_argument("--device", default="cpu", help="Device to inference on")
  8. parser.add_argument("--image_file", default="group.jpg", help="Input image")
  9. args = parser.parse_args()
  10. image1 = cv2.imread(args.image_file)
  11. protoFile = "pose/coco/pose_deploy_linevec.prototxt"
  12. weightsFile = "pose/coco/pose_iter_440000.caffemodel"
  13. nPoints = 18
  14. # COCO Output Format
  15. keypointsMapping = ['Nose', 'Neck', 'R-Sho', 'R-Elb', 'R-Wr', 'L-Sho', 'L-Elb', 'L-Wr', 'R-Hip', 'R-Knee', 'R-Ank', 'L-Hip', 'L-Knee', 'L-Ank', 'R-Eye', 'L-Eye', 'R-Ear', 'L-Ear']
  16. POSE_PAIRS = [[1,2], [1,5], [2,3], [3,4], [5,6], [6,7],
  17. [1,8], [8,9], [9,10], [1,11], [11,12], [12,13],
  18. [1,0], [0,14], [14,16], [0,15], [15,17],
  19. [2,17], [5,16] ]
  20. # index of pafs correspoding to the POSE_PAIRS
  21. # e.g for POSE_PAIR(1,2), the PAFs are located at indices (31,32) of output, Similarly, (1,5) -> (39,40) and so on.
  22. mapIdx = [[31,32], [39,40], [33,34], [35,36], [41,42], [43,44],
  23. [19,20], [21,22], [23,24], [25,26], [27,28], [29,30],
  24. [47,48], [49,50], [53,54], [51,52], [55,56],
  25. [37,38], [45,46]]
  26. colors = [ [0,100,255], [0,100,255], [0,255,255], [0,100,255], [0,255,255], [0,100,255],
  27. [0,255,0], [255,200,100], [255,0,255], [0,255,0], [255,200,100], [255,0,255],
  28. [0,0,255], [255,0,0], [200,200,0], [255,0,0], [200,200,0], [0,0,0]]
  29. def getKeypoints(probMap, threshold=0.1):
  30. mapSmooth = cv2.GaussianBlur(probMap,(3,3),0,0)
  31. mapMask = np.uint8(mapSmooth>threshold)
  32. keypoints = []
  33. #find the blobs
  34. contours, _ = cv2.findContours(mapMask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
  35. #for each blob find the maxima
  36. for cnt in contours:
  37. blobMask = np.zeros(mapMask.shape)
  38. blobMask = cv2.fillConvexPoly(blobMask, cnt, 1)
  39. maskedProbMap = mapSmooth * blobMask
  40. _, maxVal, _, maxLoc = cv2.minMaxLoc(maskedProbMap)
  41. keypoints.append(maxLoc + (probMap[maxLoc[1], maxLoc[0]],))
  42. return keypoints
  43. # Find valid connections between the different joints of a all persons present
  44. def getValidPairs(output):
  45. valid_pairs = []
  46. invalid_pairs = []
  47. n_interp_samples = 10
  48. paf_score_th = 0.1
  49. conf_th = 0.7
  50. # loop for every POSE_PAIR
  51. for k in range(len(mapIdx)):
  52. # A->B constitute a limb
  53. pafA = output[0, mapIdx[k][0], :, :]
  54. pafB = output[0, mapIdx[k][1], :, :]
  55. pafA = cv2.resize(pafA, (frameWidth, frameHeight))
  56. pafB = cv2.resize(pafB, (frameWidth, frameHeight))
  57. # Find the keypoints for the first and second limb
  58. candA = detected_keypoints[POSE_PAIRS[k][0]]
  59. candB = detected_keypoints[POSE_PAIRS[k][1]]
  60. nA = len(candA)
  61. nB = len(candB)
  62. # If keypoints for the joint-pair is detected
  63. # check every joint in candA with every joint in candB
  64. # Calculate the distance vector between the two joints
  65. # Find the PAF values at a set of interpolated points between the joints
  66. # Use the above formula to compute a score to mark the connection valid
  67. if( nA != 0 and nB != 0):
  68. valid_pair = np.zeros((0,3))
  69. for i in range(nA):
  70. max_j=-1
  71. maxScore = -1
  72. found = 0
  73. for j in range(nB):
  74. # Find d_ij
  75. d_ij = np.subtract(candB[j][:2], candA[i][:2])
  76. norm = np.linalg.norm(d_ij)
  77. if norm:
  78. d_ij = d_ij / norm
  79. else:
  80. continue
  81. # Find p(u)
  82. interp_coord = list(zip(np.linspace(candA[i][0], candB[j][0], num=n_interp_samples),
  83. np.linspace(candA[i][1], candB[j][1], num=n_interp_samples)))
  84. # Find L(p(u))
  85. paf_interp = []
  86. for k in range(len(interp_coord)):
  87. paf_interp.append([pafA[int(round(interp_coord[k][1])), int(round(interp_coord[k][0]))],
  88. pafB[int(round(interp_coord[k][1])), int(round(interp_coord[k][0]))] ])
  89. # Find E
  90. paf_scores = np.dot(paf_interp, d_ij)
  91. avg_paf_score = sum(paf_scores)/len(paf_scores)
  92. # Check if the connection is valid
  93. # If the fraction of interpolated vectors aligned with PAF is higher then threshold -> Valid Pair
  94. if ( len(np.where(paf_scores > paf_score_th)[0]) / n_interp_samples ) > conf_th :
  95. if avg_paf_score > maxScore:
  96. max_j = j
  97. maxScore = avg_paf_score
  98. found = 1
  99. # Append the connection to the list
  100. if found:
  101. valid_pair = np.append(valid_pair, [[candA[i][3], candB[max_j][3], maxScore]], axis=0)
  102. # Append the detected connections to the global list
  103. valid_pairs.append(valid_pair)
  104. else: # If no keypoints are detected
  105. print("No Connection : k = {}".format(k))
  106. invalid_pairs.append(k)
  107. valid_pairs.append([])
  108. return valid_pairs, invalid_pairs
  109. # This function creates a list of keypoints belonging to each person
  110. # For each detected valid pair, it assigns the joint(s) to a person
  111. def getPersonwiseKeypoints(valid_pairs, invalid_pairs):
  112. # the last number in each row is the overall score
  113. personwiseKeypoints = -1 * np.ones((0, 19))
  114. for k in range(len(mapIdx)):
  115. if k not in invalid_pairs:
  116. partAs = valid_pairs[k][:,0]
  117. partBs = valid_pairs[k][:,1]
  118. indexA, indexB = np.array(POSE_PAIRS[k])
  119. for i in range(len(valid_pairs[k])):
  120. found = 0
  121. person_idx = -1
  122. for j in range(len(personwiseKeypoints)):
  123. if personwiseKeypoints[j][indexA] == partAs[i]:
  124. person_idx = j
  125. found = 1
  126. break
  127. if found:
  128. personwiseKeypoints[person_idx][indexB] = partBs[i]
  129. personwiseKeypoints[person_idx][-1] += keypoints_list[partBs[i].astype(int), 2] + valid_pairs[k][i][2]
  130. # if find no partA in the subset, create a new subset
  131. elif not found and k < 17:
  132. row = -1 * np.ones(19)
  133. row[indexA] = partAs[i]
  134. row[indexB] = partBs[i]
  135. # add the keypoint_scores for the two keypoints and the paf_score
  136. row[-1] = sum(keypoints_list[valid_pairs[k][i,:2].astype(int), 2]) + valid_pairs[k][i][2]
  137. personwiseKeypoints = np.vstack([personwiseKeypoints, row])
  138. return personwiseKeypoints
  139. frameWidth = image1.shape[1]
  140. frameHeight = image1.shape[0]
  141. t = time.time()
  142. net = cv2.dnn.readNetFromCaffe(protoFile, weightsFile)
  143. if args.device == "cpu":
  144. net.setPreferableBackend(cv2.dnn.DNN_TARGET_CPU)
  145. print("Using CPU device")
  146. elif args.device == "gpu":
  147. net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)
  148. net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)
  149. print("Using GPU device")
  150. # Fix the input Height and get the width according to the Aspect Ratio
  151. inHeight = 368
  152. inWidth = int((inHeight/frameHeight)*frameWidth)
  153. inpBlob = cv2.dnn.blobFromImage(image1, 1.0 / 255, (inWidth, inHeight),
  154. (0, 0, 0), swapRB=False, crop=False)
  155. net.setInput(inpBlob)
  156. output = net.forward()
  157. print("Time Taken in forward pass = {}".format(time.time() - t))
  158. detected_keypoints = []
  159. keypoints_list = np.zeros((0,3))
  160. keypoint_id = 0
  161. threshold = 0.1
  162. for part in range(nPoints):
  163. probMap = output[0,part,:,:]
  164. probMap = cv2.resize(probMap, (image1.shape[1], image1.shape[0]))
  165. keypoints = getKeypoints(probMap, threshold)
  166. print("Keypoints - {} : {}".format(keypointsMapping[part], keypoints))
  167. keypoints_with_id = []
  168. for i in range(len(keypoints)):
  169. keypoints_with_id.append(keypoints[i] + (keypoint_id,))
  170. keypoints_list = np.vstack([keypoints_list, keypoints[i]])
  171. keypoint_id += 1
  172. detected_keypoints.append(keypoints_with_id)
  173. frameClone = image1.copy()
  174. for i in range(nPoints):
  175. for j in range(len(detected_keypoints[i])):
  176. cv2.circle(frameClone, detected_keypoints[i][j][0:2], 5, colors[i], -1, cv2.LINE_AA)
  177. cv2.imshow("Keypoints",frameClone)
  178. valid_pairs, invalid_pairs = getValidPairs(output)
  179. personwiseKeypoints = getPersonwiseKeypoints(valid_pairs, invalid_pairs)
  180. for i in range(17):
  181. for n in range(len(personwiseKeypoints)):
  182. index = personwiseKeypoints[n][np.array(POSE_PAIRS[i])]
  183. if -1 in index:
  184. continue
  185. B = np.int32(keypoints_list[index.astype(int), 0])
  186. A = np.int32(keypoints_list[index.astype(int), 1])
  187. cv2.line(frameClone, (B[0], A[0]), (B[1], A[1]), colors[i], 3, cv2.LINE_AA)
  188. cv2.imshow("Detected Pose" , frameClone)
  189. cv2.waitKey(0)