HumanSD / mmpose /apis /webcam /nodes /helper_nodes /object_assigner_node.py
liyy201912's picture
Upload folder using huggingface_hub
cc0dd3c
# Copyright (c) OpenMMLab. All rights reserved.
import time
from typing import List, Union
from mmpose.utils.timer import RunningAverage
from ..node import Node
from ..registry import NODES
@NODES.register_module()
class ObjectAssignerNode(Node):
"""Assign the object information to the frame message.
:class:`ObjectAssignerNode` enables asynchronous processing of model
inference and video I/O, so the video will be captured and displayed
smoothly regardless of the model inference speed. Specifically,
:class:`ObjectAssignerNode` takes messages from both model branch and
video I/O branch as its input, indicated as "object message" and "frame
message" respectively. When an object message arrives it will update the
latest object information; and when a frame message arrives, it will be
assigned with the latest object information and output.
Specially, if the webcam executor is set to synchrounous mode, the
behavior of :class:`ObjectAssignerNode` will be different: When an object
message arrives, it will trigger an output of itself; and the frame
messages will be ignored.
Args:
name (str): The node name (also thread name)
frame_buffer (str): Buffer name for frame messages
object_buffer (str): Buffer name for object messages
output_buffer (str): The name(s) of the output buffer(s)
Example::
>>> cfg =dict(
... type='ObjectAssignerNode',
... name='object assigner',
... frame_buffer='_frame_',
... # `_frame_` is an executor-reserved buffer
... object_buffer='animal_pose',
... output_buffer='frame')
>>> from mmpose.apis.webcam.nodes import NODES
>>> node = NODES.build(cfg)
"""
def __init__(self, name: str, frame_buffer: str, object_buffer: str,
output_buffer: Union[str, List[str]]):
super().__init__(name=name, enable=True)
self.synchronous = None
# Cache the latest model result
self.last_object_msg = None
self.last_output_msg = None
# Inference speed analysis
self.frame_fps = RunningAverage(window=10)
self.frame_lag = RunningAverage(window=10)
self.object_fps = RunningAverage(window=10)
self.object_lag = RunningAverage(window=10)
# Register buffers
# The trigger buffer depends on the executor.synchronous attribute,
# so it will be set later after the executor is assigned in
# ``set_executor``.
self.register_input_buffer(object_buffer, 'object', trigger=False)
self.register_input_buffer(frame_buffer, 'frame', trigger=False)
self.register_output_buffer(output_buffer)
def set_executor(self, executor):
super().set_executor(executor)
# Set synchronous according to the executor
if executor.synchronous:
self.synchronous = True
trigger = 'object'
else:
self.synchronous = False
trigger = 'frame'
# Set trigger input buffer according to the synchronous setting
for buffer_info in self._input_buffers:
if buffer_info.input_name == trigger:
buffer_info.trigger = True
def process(self, input_msgs):
object_msg = input_msgs['object']
# Update last result
if object_msg is not None:
# Update result FPS
if self.last_object_msg is not None:
self.object_fps.update(
1.0 /
(object_msg.timestamp - self.last_object_msg.timestamp))
# Update inference latency
self.object_lag.update(time.time() - object_msg.timestamp)
# Update last inference result
self.last_object_msg = object_msg
if not self.synchronous:
# Asynchronous mode:
# Assign the latest object information to the
# current frame.
frame_msg = input_msgs['frame']
self.frame_lag.update(time.time() - frame_msg.timestamp)
# Assign objects to frame
if self.last_object_msg is not None:
frame_msg.update_objects(self.last_object_msg.get_objects())
frame_msg.merge_route_info(
self.last_object_msg.get_route_info())
output_msg = frame_msg
else:
# Synchronous mode:
# The current frame will be ignored. Instead,
# the frame from which the latest object information is obtained
# will be used.
self.frame_lag.update(time.time() - object_msg.timestamp)
output_msg = object_msg
# Update frame fps and lag
if self.last_output_msg is not None:
self.frame_lag.update(time.time() - output_msg.timestamp)
self.frame_fps.update(
1.0 / (output_msg.timestamp - self.last_output_msg.timestamp))
self.last_output_msg = output_msg
return output_msg
def _get_node_info(self):
info = super()._get_node_info()
info['object_fps'] = self.object_fps.average()
info['object_lag (ms)'] = self.object_lag.average() * 1000
info['frame_fps'] = self.frame_fps.average()
info['frame_lag (ms)'] = self.frame_lag.average() * 1000
return info