Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .env.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ OPENMPF_PROJECTS_PATH=..

# Takes the form: "<registry-host>:<registry-port>/<repository>/", where
# <repository> is usually "openmpf". Make sure to include the "/" at the end.
# Leave blank to use images on the local host or Docker Hub.
# Leave blank to use images on the local host.
# Use "openmpf/" to use images on Docker Hub.
REGISTRY=

TAG=latest
Expand Down
20 changes: 10 additions & 10 deletions components/cli_runner/mpf_cli_job_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def run_job(self):
fps = 0

result_dicts = ComponentResultToDictConverter.convert(
fps, self._component_handle.detection_type, component_results)
fps, self._component_handle.track_type, component_results)

if self._media_type == util.MediaType.IMAGE:
log.info(f'Found {len(result_dicts)} detections.\n')
Expand Down Expand Up @@ -246,7 +246,7 @@ def _wrap_component_results(
start_time: datetime.datetime) -> Union[List[Dict[str, Any]], Dict[str, Any]]:
if self._brief_output:
return result_dicts
detection_type = self._component_handle.detection_type
track_type = self._component_handle.track_type

# Create a structure that will be parsable by the mpf-interop package. Some fields
# don't exactly make sense, but are necessary for compatibility. For example, the media
Expand All @@ -261,7 +261,7 @@ def _wrap_component_results(
'mimeType': self._mime_type,
'mediaMetadata': self._media_metadata,
'output': {
detection_type: [
track_type: [
{
'tracks': result_dicts
}
Expand Down Expand Up @@ -302,29 +302,29 @@ def _get_media_path(media_path: str, media_type: util.MediaType, job_stdin: Text
class ComponentResultToDictConverter:

@classmethod
def convert(cls, fps: float, detection_type: str,
def convert(cls, fps: float, track_type: str,
component_results: Iterable) -> List[Dict[str, Any]]:
"""
Convert component_results to JSON-serializable dictionaries
:param fps: For video jobs, the video's frames per second. Otherwise, 0.
:param detection_type: Name of the detection type produced by the component.
:param track_type: Name of the track type produced by the component.
:param component_results: Output from the component
:return: A JSON-serializable representation of component_results
"""
return cls(fps, detection_type).to_dict_list(component_results)
return cls(fps, track_type).to_dict_list(component_results)


_convert_frame_to_time: Callable[[int], float]
_detection_type: str
_track_type: str

def __init__(self, fps: float, detection_type: str):
def __init__(self, fps: float, track_type: str):
if fps == 0:
self._convert_frame_to_time = lambda x: 0
else:
ms_per_frame = 1000 / fps
self._convert_frame_to_time = lambda fr: round(fr * ms_per_frame)

self._detection_type = detection_type
self._track_type = track_type

def to_dict_list(self, component_results: Iterable) -> List[Dict[str, Any]]:
result_dicts = [self._create_track_dict(obj) for obj in component_results]
Expand Down Expand Up @@ -355,7 +355,7 @@ def _create_track_dict(self, obj) -> Dict[str, Any]:
stopOffsetFrame=stop_frame,
startOffsetTime=start_time,
stopOffsetTime=stop_time,
type=self._detection_type,
type=self._track_type,
confidence=obj.confidence,
trackProperties=sort_property_dict(obj.detection_properties),
exemplar=serialized_exemplar,
Expand Down
5 changes: 2 additions & 3 deletions components/cli_runner/mpf_cli_runner_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ class ComponentHandle(Protocol):
Manages the lifetime of a language-specific component.
"""

# The type of detection produced by the component.
detection_type: str
# The type of track produced by the component.
track_type: str

# A reference to the module containing the MPF job and result objects.
# The classes and fields are named identically in mpf_cpp_sdk and mpf_component_api so the
Expand Down Expand Up @@ -116,4 +116,3 @@ def get_job_props_from_env(env: Mapping[str, str]) -> Iterator[Tuple[str, str]]:
if len(var_name) > len(property_prefix) and var_name.startswith(property_prefix):
prop_name = var_name[len(property_prefix):]
yield prop_name, var_value

2 changes: 1 addition & 1 deletion components/cli_runner/mpf_cpp_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def __init__(self, descriptor: Dict[str, Any]):
if not self._component.Init():
raise RuntimeError('The component failed to initialized.')

self.detection_type = self._component.GetDetectionType()
self.track_type = descriptor['algorithm']['trackType']


def __exit__(self, *exc_details):
Expand Down
2 changes: 1 addition & 1 deletion components/cli_runner/mpf_python_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class PythonComponentHandle(util.ComponentHandle):
def __init__(self, descriptor: Mapping[str, Any]):
component_cls = self._load_component(descriptor)
self._component = component_cls()
self.detection_type = self._component.detection_type
self.track_type = descriptor['algorithm']['trackType']


@classmethod
Expand Down
22 changes: 11 additions & 11 deletions components/cli_runner/tests/test_cli_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class BaseTestCliRunner(unittest.TestCase):

# Provided by subclass
image_name: ClassVar[str]
detection_type: ClassVar[str]
track_type: ClassVar[str]

@classmethod
def setUpClass(cls):
Expand Down Expand Up @@ -141,7 +141,7 @@ def get_video_tracks(

@classmethod
def _get_tracks(cls, output_object: Dict[str, Any]) -> List[Dict[str, Any]]:
return output_object['media'][0]['output'][cls.detection_type][0]['tracks']
return output_object['media'][0]['output'][cls.track_type][0]['tracks']



Expand All @@ -163,20 +163,20 @@ def _assertOuterJsonCorrect(
self.assertEqual(expected_media_metadata, media_entry['mediaMetadata'])

self.assertEqual(1, len(media_entry['output']))
self.assertIn(self.detection_type, media_entry['output'])
self.assertIn(self.track_type, media_entry['output'])

detection_type_entry = media_entry['output'][self.detection_type]
self.assertEqual(1, len(detection_type_entry))
self.assertEqual(1, len(detection_type_entry[0]))
self.assertIn('tracks', detection_type_entry[0])
track_type_entry = media_entry['output'][self.track_type]
self.assertEqual(1, len(track_type_entry))
self.assertEqual(1, len(track_type_entry))
self.assertIn('tracks', track_type_entry[0])


def _assertTrackIsFromImage(self, track):
self.assertEqual(0, track['startOffsetFrame'])
self.assertEqual(0, track['stopOffsetFrame'])
self.assertEqual(0, track['startOffsetTime'])
self.assertEqual(0, track['stopOffsetTime'])
self.assertEqual(self.detection_type, track['type'])
self.assertEqual(self.track_type, track['type'])

detections = track['detections']
self.assertEqual(1, len(detections))
Expand All @@ -191,7 +191,7 @@ def _assertTrackIsFromImage(self, track):
# noinspection DuplicatedCode
class TestCppCliRunnerWithOcvFace(BaseTestCliRunner):
image_name = 'openmpf_ocv_face_detection'
detection_type = 'FACE'
track_type = 'FACE'
_face_image = get_test_media('meds-af-S419-01_40deg.jpg')
_default_job_properties = {'MAX_FEATURE': '250',
'MAX_OPTICAL_FLOW_ERROR': '4.7',
Expand Down Expand Up @@ -361,7 +361,7 @@ def test_video_with_begin_end_set(self):

class TestCppCliRunnerWithTesseract(BaseTestCliRunner):
image_name = 'openmpf_tesseract_ocr_text_detection'
detection_type = 'TEXT'
track_type = 'TEXT'
_default_job_properties = {'ADAPTIVE_HIST_CLIP_LIMIT': '2.0',
'ADAPTIVE_HIST_TILE_SIZE': '5',
'ADAPTIVE_THRS_BLOCKSIZE': '51',
Expand Down Expand Up @@ -441,7 +441,7 @@ def test_can_run_generic_job(self):
# noinspection DuplicatedCode
class TestPythonCliRunner(BaseTestCliRunner):
image_name = 'openmpf_east_text_detection'
detection_type = 'TEXT REGION'
track_type = 'TEXT REGION'
_text_image = get_test_media('hello-world.png')
_default_job_properties = {'BATCH_SIZE': '1',
'CONFIDENCE_THRESHOLD': '0.8',
Expand Down