Project import generated by Copybara.
GitOrigin-RevId: 373e3ac1e5839befd95bf7d73ceff3c5f1171969
This commit is contained in:
@@ -183,6 +183,23 @@ def get_default_face_mesh_tesselation_style() -> DrawingSpec:
|
||||
return DrawingSpec(color=_GRAY, thickness=_THICKNESS_TESSELATION)
|
||||
|
||||
|
||||
def get_default_face_mesh_iris_connections_style(
|
||||
) -> Mapping[Tuple[int, int], DrawingSpec]:
|
||||
"""Returns the default face mesh iris connections drawing style.
|
||||
|
||||
Returns:
|
||||
A mapping from each iris connection to its default drawing spec.
|
||||
"""
|
||||
face_mesh_iris_connections_style = {}
|
||||
left_spec = DrawingSpec(color=_GREEN, thickness=_THICKNESS_CONTOURS)
|
||||
for connection in face_mesh_connections.FACEMESH_LEFT_IRIS:
|
||||
face_mesh_iris_connections_style[connection] = left_spec
|
||||
right_spec = DrawingSpec(color=_RED, thickness=_THICKNESS_CONTOURS)
|
||||
for connection in face_mesh_connections.FACEMESH_RIGHT_IRIS:
|
||||
face_mesh_iris_connections_style[connection] = right_spec
|
||||
return face_mesh_iris_connections_style
|
||||
|
||||
|
||||
def get_default_pose_landmarks_style() -> Mapping[int, DrawingSpec]:
|
||||
"""Returns the default pose landmarks drawing style.
|
||||
|
||||
|
||||
@@ -138,9 +138,12 @@ def draw_landmarks(
|
||||
landmark_drawing_spec: Either a DrawingSpec object or a mapping from
|
||||
hand landmarks to the DrawingSpecs that specifies the landmarks' drawing
|
||||
settings such as color, line thickness, and circle radius.
|
||||
If this argument is explicitly set to None, no landmarks will be drawn.
|
||||
connection_drawing_spec: Either a DrawingSpec object or a mapping from
|
||||
hand connections to the DrawingSpecs that specifies the
|
||||
connections' drawing settings such as color and line thickness.
|
||||
If this argument is explicitly set to None, no landmark connections will
|
||||
be drawn.
|
||||
|
||||
Raises:
|
||||
ValueError: If one of the followings:
|
||||
|
||||
@@ -28,8 +28,8 @@ from mediapipe.calculators.util import non_max_suppression_calculator_pb2
|
||||
# pylint: enable=unused-import
|
||||
from mediapipe.python.solution_base import SolutionBase
|
||||
|
||||
SHORT_RANGE_GRAPH_FILE_PATH = 'mediapipe/modules/face_detection/face_detection_short_range_cpu.binarypb'
|
||||
FULL_RANGE_GRAPH_FILE_PATH = 'mediapipe/modules/face_detection/face_detection_full_range_cpu.binarypb'
|
||||
_SHORT_RANGE_GRAPH_FILE_PATH = 'mediapipe/modules/face_detection/face_detection_short_range_cpu.binarypb'
|
||||
_FULL_RANGE_GRAPH_FILE_PATH = 'mediapipe/modules/face_detection/face_detection_full_range_cpu.binarypb'
|
||||
|
||||
|
||||
def get_key_point(
|
||||
@@ -83,7 +83,7 @@ class FaceDetection(SolutionBase):
|
||||
https://solutions.mediapipe.dev/face_detection#model_selection.
|
||||
"""
|
||||
|
||||
binary_graph_path = FULL_RANGE_GRAPH_FILE_PATH if model_selection == 1 else SHORT_RANGE_GRAPH_FILE_PATH
|
||||
binary_graph_path = _FULL_RANGE_GRAPH_FILE_PATH if model_selection == 1 else _SHORT_RANGE_GRAPH_FILE_PATH
|
||||
subgraph_name = 'facedetectionfullrangecommon' if model_selection == 1 else 'facedetectionshortrangecommon'
|
||||
|
||||
super().__init__(
|
||||
|
||||
@@ -12,14 +12,14 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""MediaPipe FaceMesh."""
|
||||
"""MediaPipe Face Mesh."""
|
||||
|
||||
from typing import NamedTuple
|
||||
|
||||
import numpy as np
|
||||
|
||||
from mediapipe.calculators.core import constant_side_packet_calculator_pb2
|
||||
# pylint: disable=unused-import
|
||||
from mediapipe.calculators.core import constant_side_packet_calculator_pb2
|
||||
from mediapipe.calculators.core import gate_calculator_pb2
|
||||
from mediapipe.calculators.core import split_vector_calculator_pb2
|
||||
from mediapipe.calculators.tensor import image_to_tensor_calculator_pb2
|
||||
@@ -30,6 +30,7 @@ from mediapipe.calculators.tensor import tensors_to_landmarks_calculator_pb2
|
||||
from mediapipe.calculators.tflite import ssd_anchors_calculator_pb2
|
||||
from mediapipe.calculators.util import association_calculator_pb2
|
||||
from mediapipe.calculators.util import detections_to_rects_calculator_pb2
|
||||
from mediapipe.calculators.util import landmarks_refinement_calculator_pb2
|
||||
from mediapipe.calculators.util import logic_calculator_pb2
|
||||
from mediapipe.calculators.util import non_max_suppression_calculator_pb2
|
||||
from mediapipe.calculators.util import rect_transformation_calculator_pb2
|
||||
@@ -39,22 +40,26 @@ from mediapipe.python.solution_base import SolutionBase
|
||||
# pylint: disable=unused-import
|
||||
from mediapipe.python.solutions.face_mesh_connections import FACEMESH_CONTOURS
|
||||
from mediapipe.python.solutions.face_mesh_connections import FACEMESH_FACE_OVAL
|
||||
from mediapipe.python.solutions.face_mesh_connections import FACEMESH_IRISES
|
||||
from mediapipe.python.solutions.face_mesh_connections import FACEMESH_LEFT_EYE
|
||||
from mediapipe.python.solutions.face_mesh_connections import FACEMESH_LEFT_EYEBROW
|
||||
from mediapipe.python.solutions.face_mesh_connections import FACEMESH_LEFT_IRIS
|
||||
from mediapipe.python.solutions.face_mesh_connections import FACEMESH_LIPS
|
||||
from mediapipe.python.solutions.face_mesh_connections import FACEMESH_RIGHT_EYE
|
||||
from mediapipe.python.solutions.face_mesh_connections import FACEMESH_RIGHT_EYEBROW
|
||||
from mediapipe.python.solutions.face_mesh_connections import FACEMESH_RIGHT_IRIS
|
||||
from mediapipe.python.solutions.face_mesh_connections import FACEMESH_TESSELATION
|
||||
# pylint: enable=unused-import
|
||||
|
||||
|
||||
BINARYPB_FILE_PATH = 'mediapipe/modules/face_landmark/face_landmark_front_cpu.binarypb'
|
||||
FACEMESH_NUM_LANDMARKS = 468
|
||||
FACEMESH_NUM_LANDMARKS_WITH_IRISES = 478
|
||||
_BINARYPB_FILE_PATH = 'mediapipe/modules/face_landmark/face_landmark_front_cpu.binarypb'
|
||||
|
||||
|
||||
class FaceMesh(SolutionBase):
|
||||
"""MediaPipe FaceMesh.
|
||||
"""MediaPipe Face Mesh.
|
||||
|
||||
MediaPipe FaceMesh processes an RGB image and returns the face landmarks on
|
||||
MediaPipe Face Mesh processes an RGB image and returns the face landmarks on
|
||||
each detected face.
|
||||
|
||||
Please refer to https://solutions.mediapipe.dev/face_mesh#python-solution-api
|
||||
@@ -64,9 +69,10 @@ class FaceMesh(SolutionBase):
|
||||
def __init__(self,
|
||||
static_image_mode=False,
|
||||
max_num_faces=1,
|
||||
refine_landmarks=False,
|
||||
min_detection_confidence=0.5,
|
||||
min_tracking_confidence=0.5):
|
||||
"""Initializes a MediaPipe FaceMesh object.
|
||||
"""Initializes a MediaPipe Face Mesh object.
|
||||
|
||||
Args:
|
||||
static_image_mode: Whether to treat the input images as a batch of static
|
||||
@@ -74,6 +80,10 @@ class FaceMesh(SolutionBase):
|
||||
https://solutions.mediapipe.dev/face_mesh#static_image_mode.
|
||||
max_num_faces: Maximum number of faces to detect. See details in
|
||||
https://solutions.mediapipe.dev/face_mesh#max_num_faces.
|
||||
refine_landmarks: Whether to further refine the landmark coordinates
|
||||
around the eyes and lips, and output additional landmarks around the
|
||||
irises. Default to False. See details in
|
||||
https://solutions.mediapipe.dev/face_mesh#refine_landmarks.
|
||||
min_detection_confidence: Minimum confidence value ([0.0, 1.0]) for face
|
||||
detection to be considered successful. See details in
|
||||
https://solutions.mediapipe.dev/face_mesh#min_detection_confidence.
|
||||
@@ -82,16 +92,13 @@ class FaceMesh(SolutionBase):
|
||||
https://solutions.mediapipe.dev/face_mesh#min_tracking_confidence.
|
||||
"""
|
||||
super().__init__(
|
||||
binary_graph_path=BINARYPB_FILE_PATH,
|
||||
binary_graph_path=_BINARYPB_FILE_PATH,
|
||||
side_inputs={
|
||||
'num_faces': max_num_faces,
|
||||
'with_attention': refine_landmarks,
|
||||
'use_prev_landmarks': not static_image_mode,
|
||||
},
|
||||
calculator_params={
|
||||
'ConstantSidePacketCalculator.packet': [
|
||||
constant_side_packet_calculator_pb2
|
||||
.ConstantSidePacketCalculatorOptions.ConstantSidePacket(
|
||||
bool_value=not static_image_mode)
|
||||
],
|
||||
'facedetectionshortrangecpu__facedetectionshortrangecommon__TensorsToDetectionsCalculator.min_score_thresh':
|
||||
min_detection_confidence,
|
||||
'facelandmarkcpu__ThresholdingCalculator.threshold':
|
||||
|
||||
@@ -29,6 +29,9 @@ FACEMESH_LEFT_EYE = frozenset([(263, 249), (249, 390), (390, 373), (373, 374),
|
||||
(263, 466), (466, 388), (388, 387), (387, 386),
|
||||
(386, 385), (385, 384), (384, 398), (398, 362)])
|
||||
|
||||
FACEMESH_LEFT_IRIS = frozenset([(474, 475), (475, 476), (476, 477),
|
||||
(477, 474)])
|
||||
|
||||
FACEMESH_LEFT_EYEBROW = frozenset([(276, 283), (283, 282), (282, 295),
|
||||
(295, 285), (300, 293), (293, 334),
|
||||
(334, 296), (296, 336)])
|
||||
@@ -41,6 +44,9 @@ FACEMESH_RIGHT_EYE = frozenset([(33, 7), (7, 163), (163, 144), (144, 145),
|
||||
FACEMESH_RIGHT_EYEBROW = frozenset([(46, 53), (53, 52), (52, 65), (65, 55),
|
||||
(70, 63), (63, 105), (105, 66), (66, 107)])
|
||||
|
||||
FACEMESH_RIGHT_IRIS = frozenset([(469, 470), (470, 471), (471, 472),
|
||||
(472, 469)])
|
||||
|
||||
FACEMESH_FACE_OVAL = frozenset([(10, 338), (338, 297), (297, 332), (332, 284),
|
||||
(284, 251), (251, 389), (389, 356), (356, 454),
|
||||
(454, 323), (323, 361), (361, 288), (288, 397),
|
||||
@@ -56,6 +62,8 @@ FACEMESH_CONTOURS = frozenset().union(*[
|
||||
FACEMESH_RIGHT_EYEBROW, FACEMESH_FACE_OVAL
|
||||
])
|
||||
|
||||
FACEMESH_IRISES = frozenset().union(*[FACEMESH_LEFT_IRIS, FACEMESH_RIGHT_IRIS])
|
||||
|
||||
FACEMESH_TESSELATION = frozenset([
|
||||
(127, 34), (34, 139), (139, 127), (11, 0), (0, 37), (37, 11),
|
||||
(232, 231), (231, 120), (120, 232), (72, 37), (37, 39), (39, 72),
|
||||
|
||||
@@ -67,10 +67,24 @@ EYE_INDICES_TO_LANDMARKS = {
|
||||
398: [432, 175]
|
||||
}
|
||||
|
||||
IRIS_INDICES_TO_LANDMARKS = {
|
||||
468: [362, 175],
|
||||
469: [371, 175],
|
||||
470: [362, 167],
|
||||
471: [354, 175],
|
||||
472: [363, 182],
|
||||
473: [449, 174],
|
||||
474: [458, 174],
|
||||
475: [449, 167],
|
||||
476: [440, 174],
|
||||
477: [449, 181]
|
||||
}
|
||||
|
||||
|
||||
class FaceMeshTest(parameterized.TestCase):
|
||||
|
||||
def _annotate(self, frame: np.ndarray, results: NamedTuple, idx: int):
|
||||
def _annotate(self, frame: np.ndarray, results: NamedTuple, idx: int,
|
||||
draw_iris: bool):
|
||||
for face_landmarks in results.multi_face_landmarks:
|
||||
mp_drawing.draw_landmarks(
|
||||
frame,
|
||||
@@ -86,6 +100,14 @@ class FaceMeshTest(parameterized.TestCase):
|
||||
landmark_drawing_spec=None,
|
||||
connection_drawing_spec=drawing_styles
|
||||
.get_default_face_mesh_contours_style())
|
||||
if draw_iris:
|
||||
mp_drawing.draw_landmarks(
|
||||
frame,
|
||||
face_landmarks,
|
||||
mp_faces.FACEMESH_IRISES,
|
||||
landmark_drawing_spec=None,
|
||||
connection_drawing_spec=drawing_styles
|
||||
.get_default_face_mesh_iris_connections_style())
|
||||
path = os.path.join(tempfile.gettempdir(), self.id().split('.')[-1] +
|
||||
'_frame_{}.png'.format(idx))
|
||||
cv2.imwrite(path, frame)
|
||||
@@ -103,22 +125,29 @@ class FaceMeshTest(parameterized.TestCase):
|
||||
results = faces.process(image)
|
||||
self.assertIsNone(results.multi_face_landmarks)
|
||||
|
||||
@parameterized.named_parameters(('static_image_mode', True, 1),
|
||||
('video_mode', False, 5))
|
||||
def test_face(self, static_image_mode: bool, num_frames: int):
|
||||
@parameterized.named_parameters(
|
||||
('static_image_mode_no_attention', True, False, 5),
|
||||
('static_image_mode_with_attention', True, True, 5),
|
||||
('streaming_mode_no_attention', False, False, 10),
|
||||
('streaming_mode_with_attention', False, True, 10))
|
||||
def test_face(self, static_image_mode: bool, refine_landmarks: bool,
|
||||
num_frames: int):
|
||||
image_path = os.path.join(os.path.dirname(__file__),
|
||||
'testdata/portrait.jpg')
|
||||
image = cv2.imread(image_path)
|
||||
rows, cols, _ = image.shape
|
||||
with mp_faces.FaceMesh(
|
||||
static_image_mode=static_image_mode,
|
||||
refine_landmarks=refine_landmarks,
|
||||
min_detection_confidence=0.5) as faces:
|
||||
for idx in range(num_frames):
|
||||
results = faces.process(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
|
||||
self._annotate(image.copy(), results, idx)
|
||||
self._annotate(image.copy(), results, idx, refine_landmarks)
|
||||
multi_face_landmarks = []
|
||||
for landmarks in results.multi_face_landmarks:
|
||||
self.assertLen(landmarks.landmark, 468)
|
||||
self.assertLen(
|
||||
landmarks.landmark, mp_faces.FACEMESH_NUM_LANDMARKS_WITH_IRISES
|
||||
if refine_landmarks else mp_faces.FACEMESH_NUM_LANDMARKS)
|
||||
x = [landmark.x * cols for landmark in landmarks.landmark]
|
||||
y = [landmark.y * rows for landmark in landmarks.landmark]
|
||||
face_landmarks = np.column_stack((x, y))
|
||||
@@ -129,6 +158,12 @@ class FaceMeshTest(parameterized.TestCase):
|
||||
prediction_error = np.abs(
|
||||
np.asarray(multi_face_landmarks[0][eye_idx]) - np.asarray(gt_lds))
|
||||
npt.assert_array_less(prediction_error, DIFF_THRESHOLD)
|
||||
if refine_landmarks:
|
||||
for iris_idx, gt_lds in IRIS_INDICES_TO_LANDMARKS.items():
|
||||
prediction_error = np.abs(
|
||||
np.asarray(multi_face_landmarks[0][iris_idx]) -
|
||||
np.asarray(gt_lds))
|
||||
npt.assert_array_less(prediction_error, DIFF_THRESHOLD)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -19,8 +19,8 @@ from typing import NamedTuple
|
||||
|
||||
import numpy as np
|
||||
|
||||
from mediapipe.calculators.core import constant_side_packet_calculator_pb2
|
||||
# pylint: disable=unused-import
|
||||
from mediapipe.calculators.core import constant_side_packet_calculator_pb2
|
||||
from mediapipe.calculators.core import gate_calculator_pb2
|
||||
from mediapipe.calculators.core import split_vector_calculator_pb2
|
||||
from mediapipe.calculators.tensor import image_to_tensor_calculator_pb2
|
||||
@@ -67,7 +67,7 @@ class HandLandmark(enum.IntEnum):
|
||||
PINKY_TIP = 20
|
||||
|
||||
|
||||
BINARYPB_FILE_PATH = 'mediapipe/modules/hand_landmark/hand_landmark_tracking_cpu.binarypb'
|
||||
_BINARYPB_FILE_PATH = 'mediapipe/modules/hand_landmark/hand_landmark_tracking_cpu.binarypb'
|
||||
|
||||
|
||||
class Hands(SolutionBase):
|
||||
@@ -107,16 +107,12 @@ class Hands(SolutionBase):
|
||||
https://solutions.mediapipe.dev/hands#min_tracking_confidence.
|
||||
"""
|
||||
super().__init__(
|
||||
binary_graph_path=BINARYPB_FILE_PATH,
|
||||
binary_graph_path=_BINARYPB_FILE_PATH,
|
||||
side_inputs={
|
||||
'num_hands': max_num_hands,
|
||||
'use_prev_landmarks': not static_image_mode,
|
||||
},
|
||||
calculator_params={
|
||||
'ConstantSidePacketCalculator.packet': [
|
||||
constant_side_packet_calculator_pb2
|
||||
.ConstantSidePacketCalculatorOptions.ConstantSidePacket(
|
||||
bool_value=not static_image_mode)
|
||||
],
|
||||
'palmdetectioncpu__TensorsToDetectionsCalculator.min_score_thresh':
|
||||
min_detection_confidence,
|
||||
'handlandmarkcpu__ThresholdingCalculator.threshold':
|
||||
|
||||
@@ -32,20 +32,20 @@ from mediapipe.python.solutions import hands as mp_hands
|
||||
|
||||
|
||||
TEST_IMAGE_PATH = 'mediapipe/python/solutions/testdata'
|
||||
DIFF_THRESHOLD = 15 # pixels
|
||||
EXPECTED_HAND_COORDINATES_PREDICTION = [[[144, 345], [211, 323], [257, 286],
|
||||
DIFF_THRESHOLD = 20 # pixels
|
||||
EXPECTED_HAND_COORDINATES_PREDICTION = [[[138, 343], [211, 330], [257, 286],
|
||||
[289, 237], [322, 203], [219, 216],
|
||||
[238, 138], [249, 90], [253, 51],
|
||||
[177, 204], [184, 115], [187, 60],
|
||||
[185, 19], [138, 208], [131, 127],
|
||||
[124, 77], [117, 36], [106, 222],
|
||||
[92, 159], [79, 124], [68, 93]],
|
||||
[[577, 37], [504, 56], [459, 94],
|
||||
[429, 146], [397, 182], [496, 167],
|
||||
[[580, 36], [504, 50], [459, 94],
|
||||
[429, 146], [397, 182], [507, 167],
|
||||
[479, 245], [469, 292], [464, 330],
|
||||
[540, 177], [534, 265], [533, 319],
|
||||
[545, 180], [534, 265], [533, 319],
|
||||
[536, 360], [581, 172], [587, 252],
|
||||
[593, 304], [599, 346], [615, 157],
|
||||
[593, 304], [599, 346], [615, 168],
|
||||
[628, 223], [638, 258], [648, 288]]]
|
||||
|
||||
|
||||
|
||||
@@ -17,10 +17,10 @@ from typing import NamedTuple
|
||||
|
||||
import numpy as np
|
||||
|
||||
from mediapipe.calculators.core import constant_side_packet_calculator_pb2
|
||||
# The following imports are needed because python pb2 silently discards
|
||||
# unknown protobuf fields.
|
||||
# pylint: disable=unused-import
|
||||
from mediapipe.calculators.core import constant_side_packet_calculator_pb2
|
||||
from mediapipe.calculators.core import gate_calculator_pb2
|
||||
from mediapipe.calculators.core import split_vector_calculator_pb2
|
||||
from mediapipe.calculators.tensor import image_to_tensor_calculator_pb2
|
||||
@@ -49,7 +49,7 @@ from mediapipe.python.solutions.pose import PoseLandmark
|
||||
from mediapipe.python.solutions.pose_connections import POSE_CONNECTIONS
|
||||
# pylint: enable=unused-import
|
||||
|
||||
BINARYPB_FILE_PATH = 'mediapipe/modules/holistic_landmark/holistic_landmark_cpu.binarypb'
|
||||
_BINARYPB_FILE_PATH = 'mediapipe/modules/holistic_landmark/holistic_landmark_cpu.binarypb'
|
||||
|
||||
|
||||
def _download_oss_pose_landmark_model(model_complexity):
|
||||
@@ -78,6 +78,8 @@ class Holistic(SolutionBase):
|
||||
static_image_mode=False,
|
||||
model_complexity=1,
|
||||
smooth_landmarks=True,
|
||||
enable_segmentation=False,
|
||||
smooth_segmentation=True,
|
||||
min_detection_confidence=0.5,
|
||||
min_tracking_confidence=0.5):
|
||||
"""Initializes a MediaPipe Holistic object.
|
||||
@@ -91,6 +93,11 @@ class Holistic(SolutionBase):
|
||||
smooth_landmarks: Whether to filter landmarks across different input
|
||||
images to reduce jitter. See details in
|
||||
https://solutions.mediapipe.dev/holistic#smooth_landmarks.
|
||||
enable_segmentation: Whether to predict segmentation mask. See details in
|
||||
https://solutions.mediapipe.dev/holistic#enable_segmentation.
|
||||
smooth_segmentation: Whether to filter segmentation across different input
|
||||
images to reduce jitter. See details in
|
||||
https://solutions.mediapipe.dev/holistic#smooth_segmentation.
|
||||
min_detection_confidence: Minimum confidence value ([0.0, 1.0]) for person
|
||||
detection to be considered successful. See details in
|
||||
https://solutions.mediapipe.dev/holistic#min_detection_confidence.
|
||||
@@ -100,18 +107,16 @@ class Holistic(SolutionBase):
|
||||
"""
|
||||
_download_oss_pose_landmark_model(model_complexity)
|
||||
super().__init__(
|
||||
binary_graph_path=BINARYPB_FILE_PATH,
|
||||
binary_graph_path=_BINARYPB_FILE_PATH,
|
||||
side_inputs={
|
||||
'model_complexity': model_complexity,
|
||||
'smooth_landmarks': smooth_landmarks and not static_image_mode,
|
||||
'smooth_segmentation': not static_image_mode,
|
||||
'enable_segmentation': enable_segmentation,
|
||||
'smooth_segmentation':
|
||||
smooth_segmentation and not static_image_mode,
|
||||
'use_prev_landmarks': not static_image_mode,
|
||||
},
|
||||
calculator_params={
|
||||
'poselandmarkcpu__ConstantSidePacketCalculator.packet': [
|
||||
constant_side_packet_calculator_pb2
|
||||
.ConstantSidePacketCalculatorOptions.ConstantSidePacket(
|
||||
bool_value=not static_image_mode)
|
||||
],
|
||||
'poselandmarkcpu__posedetectioncpu__TensorsToDetectionsCalculator.min_score_thresh':
|
||||
min_detection_confidence,
|
||||
'poselandmarkcpu__poselandmarkbyroicpu__tensorstoposelandmarksandsegmentation__ThresholdingCalculator.threshold':
|
||||
@@ -119,7 +124,7 @@ class Holistic(SolutionBase):
|
||||
},
|
||||
outputs=[
|
||||
'pose_landmarks', 'pose_world_landmarks', 'left_hand_landmarks',
|
||||
'right_hand_landmarks', 'face_landmarks'
|
||||
'right_hand_landmarks', 'face_landmarks', 'segmentation_mask'
|
||||
])
|
||||
|
||||
def process(self, image: np.ndarray) -> NamedTuple:
|
||||
@@ -133,8 +138,8 @@ class Holistic(SolutionBase):
|
||||
ValueError: If the input image is not three channel RGB.
|
||||
|
||||
Returns:
|
||||
A NamedTuple that has five fields describing the landmarks on the most
|
||||
prominate person detected:
|
||||
A NamedTuple with fields describing the landmarks on the most prominate
|
||||
person detected:
|
||||
1) "pose_landmarks" field that contains the pose landmarks.
|
||||
2) "pose_world_landmarks" field that contains the pose landmarks in
|
||||
real-world 3D coordinates that are in meters with the origin at the
|
||||
@@ -142,6 +147,8 @@ class Holistic(SolutionBase):
|
||||
3) "left_hand_landmarks" field that contains the left-hand landmarks.
|
||||
4) "right_hand_landmarks" field that contains the right-hand landmarks.
|
||||
5) "face_landmarks" field that contains the face landmarks.
|
||||
6) "segmentation_mask" field that contains the segmentation mask if
|
||||
"enable_segmentation" is set to true.
|
||||
"""
|
||||
|
||||
results = super().process(input_data={'image': image})
|
||||
|
||||
@@ -20,8 +20,8 @@ from typing import List, Tuple, NamedTuple, Optional
|
||||
import attr
|
||||
import numpy as np
|
||||
|
||||
from mediapipe.calculators.core import constant_side_packet_calculator_pb2
|
||||
# pylint: disable=unused-import
|
||||
from mediapipe.calculators.core import constant_side_packet_calculator_pb2
|
||||
from mediapipe.calculators.core import gate_calculator_pb2
|
||||
from mediapipe.calculators.core import split_vector_calculator_pb2
|
||||
from mediapipe.calculators.tensor import image_to_tensor_calculator_pb2
|
||||
@@ -75,7 +75,7 @@ class BoxLandmark(enum.IntEnum):
|
||||
BACK_TOP_RIGHT = 7
|
||||
FRONT_TOP_RIGHT = 8
|
||||
|
||||
BINARYPB_FILE_PATH = 'mediapipe/modules/objectron/objectron_cpu.binarypb'
|
||||
_BINARYPB_FILE_PATH = 'mediapipe/modules/objectron/objectron_cpu.binarypb'
|
||||
BOX_CONNECTIONS = frozenset([
|
||||
(BoxLandmark.BACK_BOTTOM_LEFT, BoxLandmark.FRONT_BOTTOM_LEFT),
|
||||
(BoxLandmark.BACK_BOTTOM_LEFT, BoxLandmark.BACK_TOP_LEFT),
|
||||
@@ -216,18 +216,14 @@ class Objectron(SolutionBase):
|
||||
# Create and init model.
|
||||
model = get_model_by_name(model_name)
|
||||
super().__init__(
|
||||
binary_graph_path=BINARYPB_FILE_PATH,
|
||||
binary_graph_path=_BINARYPB_FILE_PATH,
|
||||
side_inputs={
|
||||
'box_landmark_model_path': model.model_path,
|
||||
'allowed_labels': model.label_name,
|
||||
'max_num_objects': max_num_objects,
|
||||
'use_prev_landmarks': not static_image_mode,
|
||||
},
|
||||
calculator_params={
|
||||
'ConstantSidePacketCalculator.packet': [
|
||||
constant_side_packet_calculator_pb2
|
||||
.ConstantSidePacketCalculatorOptions.ConstantSidePacket(
|
||||
bool_value=not static_image_mode)
|
||||
],
|
||||
('objectdetectionoidv4subgraph'
|
||||
'__TensorsToDetectionsCalculator.min_score_thresh'):
|
||||
min_detection_confidence,
|
||||
|
||||
@@ -19,10 +19,10 @@ from typing import NamedTuple
|
||||
|
||||
import numpy as np
|
||||
|
||||
from mediapipe.calculators.core import constant_side_packet_calculator_pb2
|
||||
# The following imports are needed because python pb2 silently discards
|
||||
# unknown protobuf fields.
|
||||
# pylint: disable=unused-import
|
||||
from mediapipe.calculators.core import constant_side_packet_calculator_pb2
|
||||
from mediapipe.calculators.core import gate_calculator_pb2
|
||||
from mediapipe.calculators.core import split_vector_calculator_pb2
|
||||
from mediapipe.calculators.image import warp_affine_calculator_pb2
|
||||
@@ -87,7 +87,7 @@ class PoseLandmark(enum.IntEnum):
|
||||
RIGHT_FOOT_INDEX = 32
|
||||
|
||||
|
||||
BINARYPB_FILE_PATH = 'mediapipe/modules/pose_landmark/pose_landmark_cpu.binarypb'
|
||||
_BINARYPB_FILE_PATH = 'mediapipe/modules/pose_landmark/pose_landmark_cpu.binarypb'
|
||||
|
||||
|
||||
def _download_oss_pose_landmark_model(model_complexity):
|
||||
@@ -144,20 +144,16 @@ class Pose(SolutionBase):
|
||||
"""
|
||||
_download_oss_pose_landmark_model(model_complexity)
|
||||
super().__init__(
|
||||
binary_graph_path=BINARYPB_FILE_PATH,
|
||||
binary_graph_path=_BINARYPB_FILE_PATH,
|
||||
side_inputs={
|
||||
'model_complexity': model_complexity,
|
||||
'smooth_landmarks': smooth_landmarks and not static_image_mode,
|
||||
'enable_segmentation': enable_segmentation,
|
||||
'smooth_segmentation':
|
||||
smooth_segmentation and not static_image_mode,
|
||||
'use_prev_landmarks': not static_image_mode,
|
||||
},
|
||||
calculator_params={
|
||||
'ConstantSidePacketCalculator.packet': [
|
||||
constant_side_packet_calculator_pb2
|
||||
.ConstantSidePacketCalculatorOptions.ConstantSidePacket(
|
||||
bool_value=not static_image_mode)
|
||||
],
|
||||
'posedetectioncpu__TensorsToDetectionsCalculator.min_score_thresh':
|
||||
min_detection_confidence,
|
||||
'poselandmarkbyroicpu__tensorstoposelandmarksandsegmentation__ThresholdingCalculator.threshold':
|
||||
@@ -176,12 +172,14 @@ class Pose(SolutionBase):
|
||||
ValueError: If the input image is not three channel RGB.
|
||||
|
||||
Returns:
|
||||
A NamedTuple that has two fields describing the landmarks on the most
|
||||
prominate person detected:
|
||||
A NamedTuple with fields describing the landmarks on the most prominate
|
||||
person detected:
|
||||
1) "pose_landmarks" field that contains the pose landmarks.
|
||||
2) "pose_world_landmarks" field that contains the pose landmarks in
|
||||
real-world 3D coordinates that are in meters with the origin at the
|
||||
center between hips.
|
||||
3) "segmentation_mask" field that contains the segmentation mask if
|
||||
"enable_segmentation" is set to true.
|
||||
"""
|
||||
|
||||
results = super().process(input_data={'image': image})
|
||||
|
||||
@@ -29,7 +29,7 @@ from mediapipe.framework.tool import switch_container_pb2
|
||||
|
||||
from mediapipe.python.solution_base import SolutionBase
|
||||
|
||||
BINARYPB_FILE_PATH = 'mediapipe/modules/selfie_segmentation/selfie_segmentation_cpu.binarypb'
|
||||
_BINARYPB_FILE_PATH = 'mediapipe/modules/selfie_segmentation/selfie_segmentation_cpu.binarypb'
|
||||
|
||||
|
||||
class SelfieSegmentation(SolutionBase):
|
||||
@@ -52,7 +52,7 @@ class SelfieSegmentation(SolutionBase):
|
||||
https://solutions.mediapipe.dev/selfie_segmentation#model_selection.
|
||||
"""
|
||||
super().__init__(
|
||||
binary_graph_path=BINARYPB_FILE_PATH,
|
||||
binary_graph_path=_BINARYPB_FILE_PATH,
|
||||
side_inputs={
|
||||
'model_selection': model_selection,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user