Skip to content

Commit c402bf4

Browse files
committed
posetnet python版本
0 parents  commit c402bf4

File tree

84 files changed

+2125
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+2125
-0
lines changed

build_part_with_score_queue.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/usr/bin/python3
2+
# -*- coding: UTF-8 -*-
3+
4+
def scoreIsMaximumInLocalWindow(keypointId, score, heatmapY, heatmapX, localMaximumRadius, scores):
5+
height, width, numKeypoints = scores.shape
6+
localMaximum = True
7+
yStart = max(heatmapY - localMaximumRadius, 0)
8+
yEnd = min(heatmapY + localMaximumRadius + 1, height)
9+
for yCurrent in range(yStart, yEnd):
10+
xStart = max(heatmapX - localMaximumRadius, 0)
11+
xEnd = min(heatmapX + localMaximumRadius + 1, width)
12+
for xCurrent in range(xStart, xEnd):
13+
if scores[yCurrent][xCurrent][keypointId] > score:
14+
localMaximum = False
15+
break
16+
if False == localMaximum:
17+
break
18+
return localMaximum
19+
20+
'''
21+
* Builds a priority queue with part candidate positions for a specific image in
22+
* the batch. For this we find all local maxima in the score maps with score
23+
* values above a threshold. We create a single priority queue across all parts.
24+
'''
25+
def buildPartWithScoreQueue(scoreThreshold, localMaximumRadius, scores, queue):
26+
height, width, numKeypoints = scores.shape
27+
for heatmapY in range(height):
28+
for heatmapX in range(width):
29+
for keypointId in range(numKeypoints):
30+
score = scores[heatmapY][heatmapX][keypointId]
31+
if score < scoreThreshold:
32+
continue
33+
if scoreIsMaximumInLocalWindow(keypointId, score, \
34+
heatmapY, heatmapX, \
35+
localMaximumRadius, scores) is True:
36+
keypoint = {'score':score, 'part':{'y':heatmapY, 'x':heatmapX, 'id':keypointId}}
37+
queue.enqueue(keypoint)
38+
return None

config.yaml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
chk: 1 # 1=mobilenet_v1_075
2+
imageSize: 337
3+
GOOGLE_CLOUD_STORAGE_DIR: 'https://storage.googleapis.com/tfjs-models/weights/posenet/'
4+
checkpoints: [ 'mobilenet_v1_050', 'mobilenet_v1_075', 'mobilenet_v1_100', 'mobilenet_v1_101']
5+
outputStride: 16
6+
mobileNet100Architecture: [
7+
['conv2d', 2],
8+
['separableConv', 1],
9+
['separableConv', 2],
10+
['separableConv', 1],
11+
['separableConv', 2],
12+
['separableConv', 1],
13+
['separableConv', 2],
14+
['separableConv', 1],
15+
['separableConv', 1],
16+
['separableConv', 1],
17+
['separableConv', 1],
18+
['separableConv', 1],
19+
['separableConv', 2],
20+
['separableConv', 1]
21+
]
22+
mobileNet75Architecture: [
23+
['conv2d', 2],
24+
['separableConv', 1],
25+
['separableConv', 2],
26+
['separableConv', 1],
27+
['separableConv', 2],
28+
['separableConv', 1],
29+
['separableConv', 2],
30+
['separableConv', 1],
31+
['separableConv', 1],
32+
['separableConv', 1],
33+
['separableConv', 1],
34+
['separableConv', 1],
35+
['separableConv', 1],
36+
['separableConv', 1]
37+
]
38+
mobileNet50Architecture: [
39+
['conv2d', 2],
40+
['separableConv', 1],
41+
['separableConv', 2],
42+
['separableConv', 1],
43+
['separableConv', 2],
44+
['separableConv', 1],
45+
['separableConv', 2],
46+
['separableConv', 1],
47+
['separableConv', 1],
48+
['separableConv', 1],
49+
['separableConv', 1],
50+
['separableConv', 1],
51+
['separableConv', 1],
52+
['separableConv', 1]
53+
]

decode_multi_pose.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/usr/bin/python3
2+
# -*- coding: UTF-8 -*-
3+
from decode_utils import squaredDistance, getImageCoords
4+
from build_part_with_score_queue import buildPartWithScoreQueue
5+
from decode_pose import decodePose
6+
from max_heap import MaxHeap
7+
import numpy as np
8+
9+
kLocalMaximumRadius = 1
10+
11+
def withinNmsRadiusOfCorrespondingPoint(poses, squaredNmsRadius, coordinate, keypointId):
12+
x = coordinate['x']
13+
y = coordinate['y']
14+
for pose in poses:
15+
correspondingKeypoint = pose['keypoints'][keypointId]['position']
16+
distance = squaredDistance(y, \
17+
x, \
18+
correspondingKeypoint['y'], \
19+
correspondingKeypoint['x'])
20+
if distance <= squaredNmsRadius:
21+
return True
22+
return False
23+
24+
'''
25+
/* Score the newly proposed object instance without taking into account
26+
* the scores of the parts that overlap with any previously detected
27+
* instance.
28+
*/
29+
'''
30+
def getInstanceScore(existingPoses, squaredNmsRadius, instanceKeypoints):
31+
notOverlappedKeypointScores = 0.0
32+
for idx in range(len(instanceKeypoints)):
33+
position = instanceKeypoints[idx]['position']
34+
score = instanceKeypoints[idx]['score']
35+
if withinNmsRadiusOfCorrespondingPoint(existingPoses, \
36+
squaredNmsRadius, \
37+
position, idx) is False:
38+
notOverlappedKeypointScores += score
39+
notOverlappedKeypointScores /= len(instanceKeypoints)
40+
return notOverlappedKeypointScores
41+
42+
def decodeMultiplePoses(scores, offsets, displacementsFwd, displacementsBwd, \
43+
width_factor, height_factor, \
44+
outputStride=16, maxPoseDetections=5, scoreThreshold= 0.5,
45+
nmsRadius= 30):
46+
poses = []
47+
squaredNmsRadius = nmsRadius * nmsRadius
48+
scoresBuffer = np.squeeze(scores)
49+
offsetsBuffer = np.squeeze(offsets)
50+
displacementsBwdBuffer = np.squeeze(displacementsBwd)
51+
displacementsFwdBuffer = np.squeeze(displacementsFwd)
52+
height, width, numKeypoints = scoresBuffer.shape
53+
queue = MaxHeap(height * width * numKeypoints, scoresBuffer)
54+
buildPartWithScoreQueue(scoreThreshold, kLocalMaximumRadius, scoresBuffer, queue)
55+
while len(poses) < maxPoseDetections and queue.empty() is False:
56+
root = queue.dequeue()
57+
rootImageCoords = getImageCoords(root['part'], outputStride, offsetsBuffer)
58+
if withinNmsRadiusOfCorrespondingPoint(poses, \
59+
squaredNmsRadius, \
60+
rootImageCoords, \
61+
root['part']['id']) is True:
62+
continue
63+
#Start a new detection instance at the position of the root.
64+
keypoints = decodePose(root, \
65+
scoresBuffer, \
66+
offsetsBuffer, \
67+
outputStride, \
68+
displacementsFwdBuffer, \
69+
displacementsBwdBuffer)
70+
for keypoint in keypoints:
71+
keypoint['position']['y'] *= (height_factor)
72+
keypoint['position']['x'] *= (width_factor)
73+
score = getInstanceScore(poses, squaredNmsRadius, keypoints)
74+
poses.append({'keypoints':keypoints, 'score':score})
75+
return poses

decode_pose.py

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#!/usr/bin/python3
2+
# -*- coding: UTF-8 -*-
3+
4+
import math
5+
from keypoints import poseChain, partIds, partNames
6+
from decode_utils import clamp, addVectors, getImageCoords, getOffsetPoint
7+
8+
parentChildrenTuples = []
9+
10+
for joint_name in poseChain:
11+
parent_joint_name = joint_name[0]
12+
child_joint_name = joint_name[1]
13+
parentChildrenTuples.append([partIds[parent_joint_name], \
14+
partIds[child_joint_name]])
15+
''''
16+
parentChildrenTuples = poseChain.map(
17+
([parentJoinName, childJoinName]): NumberTuple =>
18+
([partIds[parentJoinName], partIds[childJoinName]]));
19+
'''
20+
21+
parentToChildEdges = []
22+
for joint_id in parentChildrenTuples:
23+
parentToChildEdges.append(joint_id[1]) #child_joint_id
24+
25+
'''
26+
const parentToChildEdges: number[] =
27+
parentChildrenTuples.map(([, childJointId]) => childJointId);
28+
'''
29+
30+
childToParentEdges = []
31+
for joint_id in parentChildrenTuples:
32+
childToParentEdges.append(joint_id[0]) #child_joint_id
33+
34+
'''
35+
const childToParentEdges: number[] =
36+
parentChildrenTuples.map(([
37+
parentJointId,
38+
]) => parentJointId);
39+
'''
40+
41+
def getDisplacement(edgeId, point, displacements):
42+
numEdges = int(displacements.shape[2] / 2)
43+
point_x = int(point['x'])
44+
point_y = int(point['y'])
45+
y = displacements[point_y][point_x][edgeId]
46+
x = displacements[point_y][point_x][numEdges+edgeId]
47+
return {'y':y, 'x':x}
48+
49+
def getStridedIndexNearPoint(point, outputStride, height, width):
50+
return {'y':clamp(round(float(point['y']) / float(outputStride)), 0, height - 1), \
51+
'x':clamp(round(float(point['x']) / float(outputStride)), 0, width - 1)}
52+
53+
'''
54+
* We get a new keypoint along the `edgeId` for the pose instance, assuming
55+
* that the position of the `idSource` part is already known. For this, we
56+
* follow the displacement vector from the source to target part (stored in
57+
* the `i`-t channel of the displacement tensor).
58+
'''
59+
def traverseToTargetKeypoint(edgeId, sourceKeypoint, targetKeypointId,
60+
scoresBuffer, offsets, outputStride, displacements):
61+
height, width, numberScores = scoresBuffer.shape
62+
#Nearest neighbor interpolation for the source->target displacements.
63+
#最近邻插值(Nearest Neighbor interpolation)
64+
sourceKeypointIndices = getStridedIndexNearPoint(sourceKeypoint['position'], \
65+
outputStride, \
66+
height, \
67+
width)
68+
displacement = getDisplacement(edgeId, sourceKeypointIndices, displacements)
69+
displacedPoint = addVectors(sourceKeypoint['position'], displacement)
70+
displacedPointIndices = getStridedIndexNearPoint(displacedPoint, \
71+
outputStride, \
72+
height, \
73+
width)
74+
x = int(displacedPointIndices['x'])
75+
y = int(displacedPointIndices['y'])
76+
offsetPoint = getOffsetPoint(y, x, targetKeypointId, offsets)
77+
score = scoresBuffer[y][x][targetKeypointId]
78+
targetKeypoint = addVectors( \
79+
{'x': displacedPointIndices['x'] * outputStride, 'y': displacedPointIndices['y'] * outputStride}, \
80+
{'x': offsetPoint['x'], 'y': offsetPoint['y']})
81+
82+
return {"position": targetKeypoint, \
83+
"part": partNames[targetKeypointId], \
84+
"score":score}
85+
86+
'''
87+
* Follows the displacement fields to decode the full pose of the object
88+
* instance given the position of a part that acts as root.
89+
*
90+
* @return An array of decoded keypoints and their scores for a single pose
91+
'''
92+
def decodePose(root, scores, offsets, outputStride, displacementsFwd, displacementsBwd):
93+
numParts = scores.shape[2]
94+
numEdges = len(parentToChildEdges)
95+
96+
#const instanceKeypoints: Keypoint[] = new Array(numParts);
97+
instanceKeypoints = []
98+
for i in range(numParts):
99+
keypoint = {'position':{'x':0, 'y':0}, 'part':'null', 'score':0.0}
100+
instanceKeypoints.append(keypoint)
101+
#Start a new detection instance at the position of the root.
102+
rootPart, rootScore = root['part'], root['score']
103+
rootPoint = getImageCoords(rootPart, outputStride, offsets)
104+
id = rootPart['id']
105+
instanceKeypoints[id] = {'position':rootPoint, 'part':partNames[id], 'score':rootScore}
106+
107+
#Decode the part positions upwards in the tree, following the backward displacements.
108+
for edge in reversed(range(numEdges)):
109+
sourceKeypointId = parentToChildEdges[edge]
110+
targetKeypointId = childToParentEdges[edge]
111+
if instanceKeypoints[sourceKeypointId]['score'] > 0.0 \
112+
and math.isclose(instanceKeypoints[targetKeypointId]['score'], 0.0, rel_tol=1e-9) is True:
113+
instanceKeypoints[targetKeypointId] = traverseToTargetKeypoint(edge,
114+
instanceKeypoints[sourceKeypointId],
115+
targetKeypointId,
116+
scores,
117+
offsets,
118+
outputStride,
119+
displacementsBwd)
120+
121+
# Decode the part positions downwards in the tree, following the forward
122+
#displacements.
123+
for edge in range(numEdges):
124+
sourceKeypointId = childToParentEdges[edge]
125+
targetKeypointId = parentToChildEdges[edge]
126+
#if instanceKeypoints[sourceKeypointId] is not None and instanceKeypoints[targetKeypointId] is None:
127+
if instanceKeypoints[sourceKeypointId]['score'] > 0.0 \
128+
and math.isclose(instanceKeypoints[targetKeypointId]['score'], 0.0, rel_tol=1e-9) is True:
129+
instanceKeypoints[targetKeypointId] = traverseToTargetKeypoint(edge, \
130+
instanceKeypoints[sourceKeypointId], \
131+
targetKeypointId, \
132+
scores, \
133+
offsets, \
134+
outputStride, \
135+
displacementsFwd)
136+
return instanceKeypoints

0 commit comments

Comments
 (0)