Source code for sdk.frame_iterators

# Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#    * Redistributions of source code must retain the above copyright
#      notice, this list of conditions and the following disclaimer.
#    * Redistributions in binary form must reproduce the above
#      copyright notice, this list of conditions and the following
#      disclaimer in the documentation and/or other materials provided
#      with the distribution.
#    * Neither the name of The Linux Foundation nor the names of its
#      contributors may be used to endorse or promote products derived
#      from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""
This module provides iterator for getting frame and inference.
"""

import json
import logging
import os
import subprocess
import time
import sys

[docs]class CameraInference(object): """ This is a class for inferences obtained from the camera. Attributes ---------- timestamp : int Timestamp at which the inferences where made by the camera. objects : list of `CameraInferenceObject` objects List of inferences obtained from the camera. """ def __init__(self, timestamp, objects): """ This is the constructor for the `CameraInference` class. """ self.timestamp = timestamp self.objects = objects
[docs]class CameraInferenceObject(object): """ This is a class for inference data obtained from the camera. Attributes ---------- id : int ID of the identified object. label : str Label of the identified object. confidence : int Confidence value for the object in %. position : object of `CameraInferenceObjectPosition` type Position of the identified object. """ def __init__(self, id, label, confidence, position=None): """ This is the constructor for `CameraInferenceObject` class. """ self.id = id self.label = label self.confidence = confidence self.position = position
[docs]class CameraInferenceObjectPosition(object): """ This is a class for inferenced object position. Attributes ---------- x : int x coordinate of the inferenced object. y : int y coordinate of the inferenced object. width : int width of the inferenced object from `x`. height : int height of the inferenced object from `y`. """ def __init__(self, x, y, width, height): """ This is the constructor for CameraInferenceObjectPosition class. """ self.x = x self.y = y self.width = width self.height = height
[docs]class VideoInferenceIterator(object): """ This is a class for inference generator. Provides an generator method which can be used to get inferences from RTSP VA stream from the camera. Attributes ---------- preview_width: int Preview stream width. This is required for object location calculation. preview_height: int Preview stream height. This is required for object location calculation. """ def __init__(self, preview_width, preview_height): """ This is the constructor for `VideoInferenceIterator` class. """ self.preview_width = preview_width self.preview_height = preview_height #: str: Holds the JSON inference metadata obtained from the camera self._json_str = "" #: subprocess: object where gstreamer pipeline for capture inference #: stream is run. self._sub_proc = None self.logger = logging.getLogger('iotccsdk')
[docs] def start(self, result_src): """ This is the inference generator method It gets inferences from the RTSP VA stream from the camera. Parameters ---------- result_src : str VA RTSP stream url. Yields ------ CameraInference An object of `CameraInference` type. Which has timestamp and list of `CameraInferenceObject` objects. Raises ------ Exception Any exception that occurs during inference handling. """ cmd = ['gst-launch-1.0 ', ' -q ', ' rtspsrc ', ' location=' + result_src, ' protocols=tcp ', ' ! ', " application/x-rtp, media=application ", ' ! ', ' fakesink ', ' dump=true'] cmd = ''.join(cmd) self.logger.info('result_src: ' + result_src) self.logger.info('gstreamer cmd: ' + str(cmd)) platform = sys.platform platform = platform.lower() self.logger.info('Platform: ' + platform) if 'win' in platform: data_idx = 78 elif 'linux' in platform: data_idx = 72 try: self._sub_proc = subprocess.Popen( cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=1, universal_newlines=True) for line in self._sub_proc.stdout: if 'ERROR' in line or 'error' in line: raise Exception(line) l_str = line[data_idx:] l_str = l_str.strip(os.linesep) self.logger.debug(l_str) if ":[" in self._json_str and "] }" in self._json_str + l_str: # Only yield if objects are present in the inferences self._json_str = self._json_str + l_str s_idx = self._json_str.index('{ "') e_idx = self._json_str.index("] }") + 3 self._json_str = self._json_str[s_idx:e_idx] self.logger.debug(self._json_str) result = self._get_inference_result() self._json_str = "" yield result elif ":[" not in self._json_str and '{ "' in self._json_str and " }" in self._json_str + l_str: self._json_str = "" else: self._json_str = self._json_str + l_str except (Exception, subprocess.CalledProcessError) as e: self.logger.exception(e) raise
[docs] def stop(self): """ This method stops the inference generator. """ if self._sub_proc: self._sub_proc.terminate()
def _get_inference_result(self): """ Private method for creating `CameraInference` object This method extracts the inference result from the VA json metadata string. Returns ------- CameraInference `CameraInference` object with extracted values on success. `CameraInference` object with None if the json_str does not have any values or there is a malformed string. """ try: j = json.loads(self._json_str) objects = [] for object in j["objects"]: x = (object["position"]["x"] * self.preview_width) / 10000 y = (object["position"]["y"] * self.preview_height) / 10000 w = (object["position"]["width"] * self.preview_width) / 10000 h = (object["position"]["height"] * self.preview_height) / 10000 position = CameraInferenceObjectPosition(x, y, w, h) result_object = CameraInferenceObject( object["id"], object["display_name"], object["confidence"], position) objects.append(result_object) return CameraInference(j["timestamp"], objects) except ValueError as e: self.logger.error(e) return CameraInference(None, None) except Exception as e: self.logger.exception(e) raise