diff --git a/libraries/dl-streamer/docs/scripts/generate_elements_page.py b/libraries/dl-streamer/docs/scripts/generate_elements_page.py index 7c004c5ba..5774119ec 100755 --- a/libraries/dl-streamer/docs/scripts/generate_elements_page.py +++ b/libraries/dl-streamer/docs/scripts/generate_elements_page.py @@ -1,5 +1,5 @@ # ============================================================================== -# Copyright (C) 2023 Intel Corporation +# Copyright (C) 2023-2025 Intel Corporation # # SPDX-License-Identifier: MIT # ============================================================================== @@ -14,34 +14,38 @@ import re import sys import gi -gi.require_version('Gst', '1.0') + +gi.require_version("Gst", "1.0") from gi.repository import Gst import inspect + def get_elements(lib): elements = [] - result = subprocess.Popen(['gst-inspect-1.0', lib], stdout=subprocess.PIPE) + result = subprocess.Popen(["gst-inspect-1.0", lib], stdout=subprocess.PIPE) while True: line = result.stdout.readline() if not line: break - line = line.decode('utf-8').rstrip('\n') + line = line.decode("utf-8").rstrip("\n") match = re.match(r"^\s+([^\s]\w+):", str(line)) if match: elements.append(match.group(1)) return elements + def get_element_description(element_name): factory = Gst.ElementFactory.find(element_name) return factory.get_metadata("description") + def get_field_info(field, value, pfx): str = Gst.value_serialize(value) - return "{0:s} {1:15s}: {2:s}".format( - pfx, GLib.quark_to_string(field), str) + return "{0:s} {1:15s}: {2:s}".format(pfx, GLib.quark_to_string(field), str) + def get_caps_info(caps): if not caps: @@ -65,21 +69,34 @@ def get_caps_info(caps): return caps_info -def generate_table(table_data, table_header = ["", ""]): + +def generate_table(table_data, table_header=["", ""]): table = "" first_collumn_length = len(table_header[0]) second_collumn_length = len(table_header[1]) for first_column in table_data: - first_collumn_length = len(first_column) if len(first_column) > first_collumn_length else first_collumn_length + first_collumn_length = ( + len(first_column) if len(first_column) > first_collumn_length else first_collumn_length + ) for second_column in table_data[first_column]: - second_collumn_length = len(second_column) if len(second_column) > second_collumn_length else second_collumn_length + second_collumn_length = ( + len(second_column) + if len(second_column) > second_collumn_length + else second_collumn_length + ) if table_header[0]: table = "=" * first_collumn_length + " " + "=" * second_collumn_length + "\n" - table += table_header[0] + " " * (first_collumn_length - len(table_header[0])) + " " + table_header[1] + "\n" + table += ( + table_header[0] + + " " * (first_collumn_length - len(table_header[0])) + + " " + + table_header[1] + + "\n" + ) table += "=" * first_collumn_length + " " + "=" * second_collumn_length + "\n" @@ -88,19 +105,19 @@ def generate_table(table_data, table_header = ["", ""]): table += table_data[first_column][0] + "\n" i = 0 - for second_column_line in table_data[first_column]: + for second_column_line in table_data[first_column]: i += 1 if i == 1: continue table += " " * first_collumn_length + " " + second_column_line + "\n" - table += "=" * first_collumn_length + " " + "=" * second_collumn_length + "\n" return table + def get_pad_templates_information(factory): - + if factory.get_num_pad_templates() == 0: return None @@ -116,7 +133,7 @@ def get_pad_templates_information(factory): if pad.direction == Gst.PadDirection.SRC: pad_direction = "SRC template: {}".format(padtemplate.name_template) elif pad.direction == Gst.PadDirection.SINK: - pad_direction = "SINK template: {}".format(padtemplate.name_template) + pad_direction = "SINK template: {}".format(padtemplate.name_template) else: pad_direction = "UNKNOWN template: {}".format(padtemplate.name_template) @@ -141,6 +158,7 @@ def get_pad_templates_information(factory): return "\nCapabilities\r\n**********************\r\n" + generate_table(table) + "\n" + def get_properties_info(element): table = {} @@ -153,16 +171,31 @@ def get_properties_info(element): default_value = str(prop.default_value).replace("__main__.", "") if not default_value: - default_value = "\"\"" + default_value = '""' table[prop.name].append("*Default: {}*\n".format(default_value)) - return "\nProperties\r\n**********************\r\n" + generate_table(table, ["Name", "Description"]) + "\n" + return ( + "\nProperties\r\n**********************\r\n" + + generate_table(table, ["Name", "Description"]) + + "\n" + ) + def generate_elements_page(page_file_name): page = "------------\nElements 2.0\n------------\n\n" - - libraries = ["dlstreamer_bins", "dlstreamer_elements", "dlstreamer_cpu", "dlstreamer_openvino", "dlstreamer_opencv", "dlstreamer_vaapi", "dlstreamer_opencl", "dlstreamer_sycl", "python"] + + libraries = [ + "dlstreamer_bins", + "dlstreamer_elements", + "dlstreamer_cpu", + "dlstreamer_openvino", + "dlstreamer_opencv", + "dlstreamer_vaapi", + "dlstreamer_opencl", + "dlstreamer_sycl", + "python", + ] for lib in libraries: elements = get_elements(lib) @@ -186,7 +219,7 @@ def generate_elements_page(page_file_name): elements_list_file.write(page) elements_list_file.close() - + if __name__ == "__main__": Gst.init(sys.argv) @@ -195,5 +228,4 @@ def generate_elements_page(page_file_name): if len(sys.argv) > 1 and sys.argv[1]: page_file_name = sys.argv[1] - generate_elements_page(page_file_name) diff --git a/libraries/dl-streamer/docs/scripts/generate_models_table.py b/libraries/dl-streamer/docs/scripts/generate_models_table.py index 3051b14c4..d1bddc9b4 100755 --- a/libraries/dl-streamer/docs/scripts/generate_models_table.py +++ b/libraries/dl-streamer/docs/scripts/generate_models_table.py @@ -12,123 +12,148 @@ from argparse import ArgumentParser from jsonschema import validate -DLSTREAMER_URL='https://github.com/open-edge-platform/edge-ai-libraries/tree/main/libraries/dl-streamer/' -PIPELINE_ZOO_URL='https://github.com/dlstreamer/pipeline-zoo-models/tree/main/' +DLSTREAMER_URL = ( + "https://github.com/open-edge-platform/edge-ai-libraries/tree/main/libraries/dl-streamer/" +) +PIPELINE_ZOO_URL = "https://github.com/dlstreamer/pipeline-zoo-models/tree/main/" -dldt_str = 'dl' + 'dt' -openvino_str = 'open' + 'vino' -dlstreamer_name = 'Deep ' + 'Learning' + ' Streamer' +dldt_str = "dl" + "dt" +openvino_str = "open" + "vino" +dlstreamer_name = "Deep " + "Learning" + " Streamer" parser = ArgumentParser(add_help=False) -_args = parser.add_argument_group('Options') -_args.add_argument("-omz", "--open_model_zoo", help="Required. Path to Open Model Zoo cloned repo", required=True, type=str) -_args.add_argument("-mi", "--model_index", help="Required. Path to model_index.yaml file", required=True, type=str) -_args.add_argument("-o", "--output", help="Required. Path to output .rst file", required=True, type=str) -_args.add_argument("-a", "--all", help="If true, table will contain all models, not only supported", required=False, type=str) +_args = parser.add_argument_group("Options") +_args.add_argument( + "-omz", + "--open_model_zoo", + help="Required. Path to Open Model Zoo cloned repo", + required=True, + type=str, +) +_args.add_argument( + "-mi", "--model_index", help="Required. Path to model_index.yaml file", required=True, type=str +) +_args.add_argument( + "-o", "--output", help="Required. Path to output .rst file", required=True, type=str +) +_args.add_argument( + "-a", + "--all", + help="If true, table will contain all models, not only supported", + required=False, + type=str, +) args = parser.parse_args() -models={} +models = {} # read .yml and .md files from open_model_zoo -for root, dirs, files in os.walk(args.open_model_zoo + '/models', topdown=False): +for root, dirs, files in os.walk(args.open_model_zoo + "/models", topdown=False): name = os.path.basename(root) - if 'composite-model.yml' in files: - with open(os.path.join(root, 'composite-model.yml')) as f: + if "composite-model.yml" in files: + with open(os.path.join(root, "composite-model.yml")) as f: models[name] = yaml.safe_load(f) - if 'model.yml' in files and not os.path.exists(os.path.join(root, '../composite-model.yml')): - with open(os.path.join(root, 'model.yml')) as f: + if "model.yml" in files and not os.path.exists(os.path.join(root, "../composite-model.yml")): + with open(os.path.join(root, "model.yml")) as f: models[name] = yaml.safe_load(f) - if 'README.md' in files: + if "README.md" in files: if name not in models: print("WARNING: README.md without model.yml:", name) models[name] = {} - with open(os.path.join(root, 'README.md')) as f: + with open(os.path.join(root, "README.md")) as f: for line in f.readlines(): - vec = [x.strip() for x in line.split('|')] - if len(vec) < 3 or vec[1].startswith('---'): + vec = [x.strip() for x in line.split("|")] + if len(vec) < 3 or vec[1].startswith("---"): continue - #print(vec) + # print(vec) models[name][vec[1]] = vec[2] if name in models: - if '/intel/' in root: - models[name]['source'] = openvino_str - elif '/public/' in root: - models[name]['source'] = 'public' - format = models[name].get('framework', '').replace(dldt_str, openvino_str) + if "/intel/" in root: + models[name]["source"] = openvino_str + elif "/public/" in root: + models[name]["source"] = "public" + format = models[name].get("framework", "").replace(dldt_str, openvino_str) if openvino_str not in format: - format += ', ' + openvino_str - models[name]['format'] = format - models[name]['readme'] = 'https://docs.openvino.ai/latest/omz_models_model_' + name.replace('-', '_').replace('.', '_') + '.html' + format += ", " + openvino_str + models[name]["format"] = format + models[name]["readme"] = ( + "https://docs.openvino.ai/latest/omz_models_model_" + + name.replace("-", "_").replace(".", "_") + + ".html" + ) # for each model, find if OV supports CPU, GPU devices -for md in ['models/intel/device_support.md', 'models/public/device_support.md']: +for md in ["models/intel/device_support.md", "models/public/device_support.md"]: with open(os.path.join(args.open_model_zoo, md)) as f: for line in f.readlines(): - vec = [x.strip() for x in line.split('|')] + vec = [x.strip() for x in line.split("|")] if len(vec) < 4: continue name = vec[1] for composite_name, m in models.items(): - if name in m.get('stages_order', []): + if name in m.get("stages_order", []): name = composite_name break if name in models: - openvino_devices = '' - if vec[2] == 'YES': - openvino_devices += 'CPU' - if vec[3] == 'YES': - openvino_devices += ', GPU' - models[name]['openvino_devices'] = openvino_devices + openvino_devices = "" + if vec[2] == "YES": + openvino_devices += "CPU" + if vec[3] == "YES": + openvino_devices += ", GPU" + models[name]["openvino_devices"] = openvino_devices # for each model, find Accuracy, GFlops, mParams -for md in ['models/intel/index.md', 'models/public/index.md']: +for md in ["models/intel/index.md", "models/public/index.md"]: with open(os.path.join(args.open_model_zoo, md)) as f: for line in f.readlines(): for name in list(models.keys()): - if '[' + name + ']' in line or name + '-encoder' in line: - vec = [x.strip() for x in line.split('|')] + if "[" + name + "]" in line or name + "-encoder" in line: + vec = [x.strip() for x in line.split("|")] if len(vec) < 5: continue - #print(vec) - if '%' in vec[-4]: - models[name]['Accuracy'] = vec[-4] - models[name]['GFlops'] = vec[-3] - models[name]['mParams'] = vec[-2] + # print(vec) + if "%" in vec[-4]: + models[name]["Accuracy"] = vec[-4] + models[name]["GFlops"] = vec[-3] + models[name]["mParams"] = vec[-2] # read accuracy_checker parameters -accuracy_checker = os.path.join(args.open_model_zoo, 'tools/accuracy_checker/configs') +accuracy_checker = os.path.join(args.open_model_zoo, "tools/accuracy_checker/configs") for file in os.listdir(accuracy_checker): if not file.endswith(".yml"): continue with open(os.path.join(accuracy_checker, file)) as f: yml = yaml.safe_load(f) - if 'models' in yml: - models_list = yml['models'] + if "models" in yml: + models_list = yml["models"] else: - models_list = yml.get('evaluations', []) + models_list = yml.get("evaluations", []) for m in models_list: - name = m['name'] + name = m["name"] filename = os.path.splitext(file)[0] if name in models: models[name].update(m) elif filename in models: models[filename].update(m) else: - print('WARNING: model listed in OV accuracy_checker but not listed in OV model zoo:', name) + print( + "WARNING: model listed in OV accuracy_checker but not listed in OV model zoo:", + name, + ) # for each model, find which OMZ demo supports it for root, dirs, files in os.walk(args.open_model_zoo, topdown=False): - if 'models.lst' in files: - with open(os.path.join(root, 'models.lst')) as f: + if "models.lst" in files: + with open(os.path.join(root, "models.lst")) as f: omz_demo = os.path.basename(os.path.dirname(root)) for line in f.read().splitlines(): - if line[0] == '#': + if line[0] == "#": continue - name_regexp = line.replace('?', '.').replace('-encoder','') + name_regexp = line.replace("?", ".").replace("-encoder", "") for composite_name, m in models.items(): - for name in m.get('stages_order', [composite_name]): + for name in m.get("stages_order", [composite_name]): if re.match(name_regexp, name): - models[composite_name]['omz_demo'] = omz_demo + models[composite_name]["omz_demo"] = omz_demo break # read model_index.yaml @@ -138,142 +163,180 @@ model_index = yaml.safe_load(f) validate(model_index, json.load(mis)) for name, m in model_index.items(): - if 'dlstreamer_support' not in m: - m['dlstreamer_support'] = openvino_str - if 'labels-file' in m: - m['labels-file'] = DLSTREAMER_URL + 'samples/' + m['labels-file'] - if 'model-proc' in m: - m['model-proc'] = DLSTREAMER_URL + 'samples/' + m['model-proc'] - if m.get('source', '') == 'dlstreamer': - if 'readme' not in m: - m['readme'] = PIPELINE_ZOO_URL + 'storage/' + name - if 'model-proc' not in m: - m['model-proc'] = PIPELINE_ZOO_URL + 'storage/' + name # + '/' + name + '.json' + if "dlstreamer_support" not in m: + m["dlstreamer_support"] = openvino_str + if "labels-file" in m: + m["labels-file"] = DLSTREAMER_URL + "samples/" + m["labels-file"] + if "model-proc" in m: + m["model-proc"] = DLSTREAMER_URL + "samples/" + m["model-proc"] + if m.get("source", "") == "dlstreamer": + if "readme" not in m: + m["readme"] = PIPELINE_ZOO_URL + "storage/" + name + if "model-proc" not in m: + m["model-proc"] = PIPELINE_ZOO_URL + "storage/" + name # + '/' + name + '.json' if name in models: models[name].update(m) else: - if 'source' not in m and name + '-decoder' not in models: - print('WARNING: model listed in model_index.yaml but not listed in OV model zoo:', name) - if 'format' not in m: - m['format'] = openvino_str + if "source" not in m and name + "-decoder" not in models: + print( + "WARNING: model listed in model_index.yaml but not listed in OV model zoo:", + name, + ) + if "format" not in m: + m["format"] = openvino_str models[name] = m # remove models that we don't want to include, e.g. preview/deprecation -models_to_remove = ['icnet-camvid-ava-0001', 'road-segmentation-adas-0001', - 'semantic-segmentation-adas-0001', 'text-detection-0003'] +models_to_remove = [ + "icnet-camvid-ava-0001", + "road-segmentation-adas-0001", + "semantic-segmentation-adas-0001", + "text-detection-0003", +] for model_name in models_to_remove: if models.pop(model_name, None): print(f"Removed '{model_name}' from final models list") # update name, task_type, devices for name, m in models.items(): - m['name'] = name - if 'yolo' in name: - m['task_type'] = 'detection' - if 'task_type' not in m: - m['task_type'] = '~?' - format = m.get('format', '') - if 'pytorch_devices' not in m and 'pytorch' in format: - m['pytorch_devices'] = 'CPU' - if 'tf_devices' not in m and 'tf' in format: - m['tf_devices'] = 'CPU' + m["name"] = name + if "yolo" in name: + m["task_type"] = "detection" + if "task_type" not in m: + m["task_type"] = "~?" + format = m.get("format", "") + if "pytorch_devices" not in m and "pytorch" in format: + m["pytorch_devices"] = "CPU" + if "tf_devices" not in m and "tf" in format: + m["tf_devices"] = "CPU" # convert into list sorted by 'task_type' -models = sorted(models.values(), key=lambda x: x['task_type'] + x['name']) +models = sorted(models.values(), key=lambda x: x["task_type"] + x["name"]) for m in models: - with open(m['name'] + '_files.yml', 'w') as f: - yaml.dump(m.get('files', m.get('readme', {})), f, sort_keys=False) - if 'files' in m: - del m['files'] - with open(m['name'] + '.yml', 'w') as f: + with open(m["name"] + "_files.yml", "w") as f: + yaml.dump(m.get("files", m.get("readme", {})), f, sort_keys=False) + if "files" in m: + del m["files"] + with open(m["name"] + ".yml", "w") as f: yaml.dump(m, f, sort_keys=False) # write .rst -with open(args.output, 'w') as f: - f.write('Supported Models\n') - f.write('================\n') - f.write('\n') - f.write('This page contains table of pre-trained models with information ') - f.write('about model support on various inference backends and CPU/GPU devices.\n') - f.write('\n') - f.write('Each model has link (under model name) to original documentation with download instructions.\n') - f.write('\n') - f.write('Most models are from `OpenVINO™ Open Model Zoo `__\n') - f.write('but some models are from other sources (see column Source Repo).\n') - f.write('\n') - f.write('Abbreviations used in the table\n') - f.write('----------------\n') - f.write('.. list-table::\n') - f.write(' :header-rows: 1\n') - f.write('\n') - f.write(' * - Abbreviation\n') - f.write(' - Description\n') - f.write(' * - {0}\n'.format(openvino_str)) - f.write(' - `OpenVINO™ toolkit `__ - as model file format (*.xml + *.bin) and inference backend in {0}\n'.format(dlstreamer_name)) - f.write(' * - pytorch\n') - f.write(' - `PyTorch* framework `__ - as model file format and inference backend in {0}\n'.format(dlstreamer_name)) - f.write(' * - tf\n') - f.write(' - `TensorFlow* framework `__ - as model file format and inference backend in {0}\n'.format(dlstreamer_name)) - f.write(' * - onnx\n') - f.write(' - `ONNX `__ - Open Neural Network Exchange file format\n') - f.write(' * - caffe\n') - f.write(' - `Caffe* framework `__ - as model file format\n') - f.write(' * - dlstreamer\n') - f.write(' - {0}\n'.format(dlstreamer_name)) - f.write('\n') - f.write('Models Table\n') - f.write('----------------\n') - f.write('\n') - f.write('.. list-table::\n') - f.write(' :header-rows: 1\n') - f.write('\n') - f.write(' * - #\n') - f.write(' - Category\n') - f.write(' - Model Name\n') - f.write(' - Source Repo\n') - f.write(' - Available Format(s)\n') - f.write(' - GFLOPs\n') - f.write(' - {0} support\n'.format(dlstreamer_name)) - f.write(' - Open VINO™ support\n') - f.write(' - Py Torch* support\n') - f.write(' - Tensor Flow* support\n') - f.write(' - labels-file\n') - f.write(' - model-proc\n') - f.write(' - OpenVINO™ Open Model Zoo demo app\n') - f.write('\n') +with open(args.output, "w") as f: + f.write("Supported Models\n") + f.write("================\n") + f.write("\n") + f.write("This page contains table of pre-trained models with information ") + f.write("about model support on various inference backends and CPU/GPU devices.\n") + f.write("\n") + f.write( + "Each model has link (under model name) to original documentation " + + "with download instructions.\n" + ) + f.write("\n") + f.write( + "Most models are from `OpenVINO™ Open Model Zoo " + + "`__\n" + ) + f.write("but some models are from other sources (see column Source Repo).\n") + f.write("\n") + f.write("Abbreviations used in the table\n") + f.write("----------------\n") + f.write(".. list-table::\n") + f.write(" :header-rows: 1\n") + f.write("\n") + f.write(" * - Abbreviation\n") + f.write(" - Description\n") + f.write(" * - {0}\n".format(openvino_str)) + f.write( + " - `OpenVINO™ toolkit `__ - as model file " + + f"format (*.xml + *.bin) and inference backend in {dlstreamer_name}\n" + ) + f.write(" * - pytorch\n") + f.write( + " - `PyTorch* framework `__ - as model file " + + f"format and inference backend in {dlstreamer_name}\n" + ) + f.write(" * - tf\n") + f.write( + " - `TensorFlow* framework `__ - as model file " + + f"format and inference backend in {dlstreamer_name}\n" + ) + f.write(" * - onnx\n") + f.write(" - `ONNX `__ - Open Neural Network Exchange file format\n") + f.write(" * - caffe\n") + f.write(" - `Caffe* framework `__ - as model file format\n") + f.write(" * - dlstreamer\n") + f.write(f" - {dlstreamer_name}\n") + f.write("\n") + f.write("Models Table\n") + f.write("----------------\n") + f.write("\n") + f.write(".. list-table::\n") + f.write(" :header-rows: 1\n") + f.write("\n") + f.write(" * - #\n") + f.write(" - Category\n") + f.write(" - Model Name\n") + f.write(" - Source Repo\n") + f.write(" - Available Format(s)\n") + f.write(" - GFLOPs\n") + f.write(f" - {dlstreamer_name} support\n") + f.write(" - Open VINO™ support\n") + f.write(" - Py Torch* support\n") + f.write(" - Tensor Flow* support\n") + f.write(" - labels-file\n") + f.write(" - model-proc\n") + f.write(" - OpenVINO™ Open Model Zoo demo app\n") + f.write("\n") n = 0 for m in models: - if not args.all and 'dlstreamer_support' not in m: + if not args.all and "dlstreamer_support" not in m: continue - name = m['name'] - name_s = name.replace('torchvision.models.detection.', 'torchvision.models.detection. ') + name = m["name"] + name_s = name.replace("torchvision.models.detection.", "torchvision.models.detection. ") n = n + 1 - f.write(' * - {0}\n'.format(n)) - f.write(' - {0}\n'.format(string.capwords(m.get('task_type', '').replace('_',' ')))) - f.write(' - `{0} <{1}>`__\n'.format(name_s, m.get('readme', ''))) - f.write(' - {0}\n'.format(m.get('source', ''))) - f.write(' - {0}\n'.format(m.get('format', ''))) - f.write(' - {0}\n'.format(re.split(r"[^0-9\.]", m.get('GFLOPs', m.get('GFlops', ' ')))[0])) - f.write(' - {0}\n'.format(m.get('dlstreamer_support', ''))) - f.write(' - {0}\n'.format(m.get('openvino_devices', '?'))) - f.write(' - {0}\n'.format(m.get('pytorch_devices', ''))) - f.write(' - {0}\n'.format(m.get('tf_devices', ''))) - labels_file = m.get('labels-file', None) + task_type = string.capwords(m.get("task_type", "").replace("_", " ")) + readme = m.get("readme", "") + source = m.get("source", "") + format = m.get("format", "") + gflops = re.split(r"[^0-9\.]", m.get("GFLOPs", m.get("GFlops", " ")))[0] + dlstreamer_support = m.get("dlstreamer_support", "") + openvino_devices = m.get("openvino_devices", "?") + pytorch_devices = m.get("pytorch_devices", "") + tf_devices = m.get("tf_devices", "") + f.write(f" * - {n}\n") + f.write(f" - {task_type}\n") + f.write(f" - `{name_s} <{readme}>`__\n") + f.write(f" - {source}\n") + f.write(f" - {format}\n") + f.write(f" - {gflops}\n") + f.write(f" - {dlstreamer_support}\n") + f.write(f" - {openvino_devices}\n") + f.write(f" - {pytorch_devices}\n") + f.write(f" - {tf_devices}\n") + labels_file = m.get("labels-file", None) if labels_file: - f.write(' - `{0} <{1}>`__\n'.format(os.path.basename(labels_file), labels_file)) + path_labels_file = os.path.basename(labels_file) + f.write(f" - `{path_labels_file} <{labels_file}>`__\n") else: - #f.write(' - {0}\n'.format(m.get('datasets', [{}])[0].get('name','').replace('-',' ').replace('_',' '))) - f.write(' -\n') - model_proc = m.get('model-proc', None) + f.write(" -\n") + model_proc = m.get("model-proc", None) if model_proc: - f.write(' - `{0} <{1}>`__\n'.format("model-proc", model_proc)) + f.write(f" - `model-proc <{model_proc}>`__\n") else: - f.write(' -\n') - f.write(' - {0}\n'.format(m.get('omz_demo', ''))) - f.write('\n') - f.write('Legal Information\n') - f.write('----------------\n') - f.write('PyTorch, TensorFlow, Caffe, Keras, MXNet are trademarks or brand names of their respective owners.\n') - f.write('All company, product and service names used in this website are for identification purposes only.\n') - f.write('Use of these names,trademarks and brands does not imply endorsement.\n') + f.write(" -\n") + omz_demo = m.get("omz_demo", "") + f.write(f" - {omz_demo}\n") + f.write("\n") + f.write("Legal Information\n") + f.write("----------------\n") + f.write( + "PyTorch, TensorFlow, Caffe, Keras, MXNet are trademarks or brand names " + + "of their respective owners.\n" + ) + f.write( + "All company, product and service names used in this website are for " + + "identification purposes only.\n" + ) + f.write("Use of these names,trademarks and brands does not imply endorsement.\n") diff --git a/libraries/dl-streamer/docs/scripts/models_table_from_yaml.py b/libraries/dl-streamer/docs/scripts/models_table_from_yaml.py index 4f1689e7c..26ab78e04 100644 --- a/libraries/dl-streamer/docs/scripts/models_table_from_yaml.py +++ b/libraries/dl-streamer/docs/scripts/models_table_from_yaml.py @@ -12,18 +12,23 @@ import json from jsonschema import validate -dldt_str = 'dl' + 'dt' -openvino_str = 'open' + 'vino' -dlstreamer_name = 'Deep ' + 'Learning' + ' Streamer' +OPENVINO_STR = "open" + "vino" +DLSTREAMER_NAME = "Deep " + "Learning" + " Streamer" parser = ArgumentParser(add_help=False) -_args = parser.add_argument_group('Options') -_args.add_argument("-mi", "--model_index", help="Path to all_models.yaml file", required=True, type=str) -_args.add_argument("-vm", "--verified_models", help="Path to supported_models.json file", required=True, type=str) -_args.add_argument("-o", "--output", help="Required. Path to output.rst file", required=True, type=str) +_args = parser.add_argument_group("Options") +_args.add_argument( + "-mi", "--model_index", help="Path to all_models.yaml file", required=True, type=str +) +_args.add_argument( + "-vm", "--verified_models", help="Path to supported_models.json file", required=True, type=str +) +_args.add_argument( + "-o", "--output", help="Required. Path to output.rst file", required=True, type=str +) args = parser.parse_args() -models={} +models = {} with open(args.model_index) as f: models = yaml.safe_load(f) @@ -32,111 +37,96 @@ verified_models = json.load(f) # write .rst -with open(args.output, 'w') as f: - f.write('Supported Models\n') - f.write('================\n') - f.write('\n') - f.write('This page contains the table of models supported by Deep Learning Streamer.') - f.write('\n') - f.write('Each model has a link (under the model name) to the original documentation with download instructions.\n') - f.write('\n') - f.write('Most models are from `OpenVINO™ Open Model Zoo `__\n') - f.write('but some of them come from other sources.\n') - f.write('\n') - ''' - f.write('Abbreviations used in the table\n') - f.write('--------------------------------\n') - f.write('.. list-table::\n') - f.write(' :header-rows: 1\n') - f.write('\n') - f.write(' * - Abbreviation\n') - f.write(' - Description\n') - f.write(' * - {0}\n'.format(openvino_str)) - f.write(' - `OpenVINO™ toolkit `__ - as model file format ( .xml + .bin) and inference backend in {0}\n'.format(dlstreamer_name)) - f.write(' * - pytorch\n') - f.write(' - `PyTorch* framework `__ - as model file format and inference backend in {0}\n'.format(dlstreamer_name)) - f.write(' * - tf\n') - f.write(' - `TensorFlow* framework `__ - as model file format and inference backend in {0}\n'.format(dlstreamer_name)) - f.write(' * - onnx\n') - f.write(' - `ONNX `__ - Open Neural Network Exchange file format\n') - f.write(' * - caffe\n') - f.write(' - `Caffe* framework `__ - as model file format\n') - f.write(' * - dlstreamer\n') - f.write(' - {0}\n'.format(dlstreamer_name)) - ''' - f.write('\n') - f.write('Models Table\n') - f.write('----------------\n') - f.write('\n') - f.write('.. list-table::\n') - f.write(' :header-rows: 1\n') - f.write('\n') - f.write(' * - #\n') - f.write(' - Category\n') - f.write(' - Model Name\n') - #f.write(' - Source Repo\n') - #f.write(' - Available Format(s)\n') - f.write(' - GFLOPs\n') - #f.write(' - {0} support\n'.format(dlstreamer_name)) - #f.write(' - Open VINO™ support\n') - #f.write(' - Py Torch* support\n') - #f.write(' - Tensor Flow* support\n') - f.write(' - labels-file\n') - f.write(' - model-proc\n') - f.write(' - Demo app\n') - f.write('\n') +with open(args.output, "w", encoding="utf-8") as f: + f.write("Supported Models\n") + f.write("================\n") + f.write("\n") + f.write("This page contains the table of models supported by Deep Learning Streamer.") + f.write("\n") + f.write("Each model has a link (under the model name) to the original ") + f.write("documentation with download instructions.\n") + f.write("\n") + f.write("Most models are from `OpenVINO™ Open Model Zoo ") + f.write("`__\n") + f.write("but some of them come from other sources.\n") + f.write("\n") + f.write("\n") + f.write("Models Table\n") + f.write("----------------\n") + f.write("\n") + f.write(".. list-table::\n") + f.write(" :header-rows: 1\n") + f.write("\n") + f.write(" * - #\n") + f.write(" - Category\n") + f.write(" - Model Name\n") + # f.write(' - Source Repo\n') + # f.write(' - Available Format(s)\n') + f.write(" - GFLOPs\n") + # f.write(' - {0} support\n'.format(DLSTREAMER_NAME)) + # f.write(' - Open VINO™ support\n') + # f.write(' - Py Torch* support\n') + # f.write(' - Tensor Flow* support\n') + f.write(" - labels-file\n") + f.write(" - model-proc\n") + f.write(" - Demo app\n") + f.write("\n") n = 0 for name in models: - + if name not in verified_models: continue m = models[name] - - name_s = name.replace('torchvision.models.detection.', 'torchvision.models.detection. ') + name_s = name.replace("torchvision.models.detection.", "torchvision.models.detection. ") n = n + 1 - f.write(' * - {0}\n'.format(n)) - f.write(' - {0}\n'.format(string.capwords(m.get('task_type', '').replace('_',' ')))) - f.write(' - `{0} <{1}>`__\n'.format(name_s, m.get('readme', ''))) - #f.write(' - {0}\n'.format(m.get('source', ''))) - #f.write(' - {0}\n'.format(m.get('format', ''))) - f.write(' - {0}\n'.format(re.split(r"[^0-9\.]", m.get('GFLOPs', m.get('GFlops', ' ')))[0])) - #f.write(' - {0}\n'.format(m.get('dlstreamer_support', ''))) - #f.write(' - {0}\n'.format(m.get('openvino_devices', '?'))) - #f.write(' - {0}\n'.format(m.get('pytorch_devices', ''))) - #f.write(' - {0}\n'.format(m.get('tf_devices', ''))) - labels_file = m.get('labels-file', None) + task_type = string.capwords(m.get("task_type", "").replace("_", " ")) + readme = m.get("readme", "") + gflops = re.split(r"[^0-9\.]", m.get("GFLOPs", m.get("GFlops", " ")))[0] + f.write(f" * - {n}\n") + f.write(f" - {task_type}\n") + f.write(f" - `{name_s} <{readme}>`__\n") + # f.write(' - {0}\n'.format(m.get('source', ''))) + # f.write(' - {0}\n'.format(m.get('format', ''))) + f.write(f" - {gflops}\n") + # f.write(' - {0}\n'.format(m.get('dlstreamer_support', ''))) + # f.write(' - {0}\n'.format(m.get('openvino_devices', '?'))) + # f.write(' - {0}\n'.format(m.get('pytorch_devices', ''))) + # f.write(' - {0}\n'.format(m.get('tf_devices', ''))) + labels_file = m.get("labels-file", None) if labels_file: - f.write(' - `{0} <{1}>`__\n'.format(os.path.basename(labels_file), labels_file)) + path_labels_file = os.path.basename(labels_file) + f.write(f" - `{path_labels_file} <{labels_file}>`__\n") else: - #f.write(' - {0}\n'.format(m.get('datasets', [{}])[0].get('name','').replace('-',' ').replace('_',' '))) - f.write(' -\n') - model_proc = m.get('model-proc', None) + f.write(" -\n") + model_proc = m.get("model-proc", None) if model_proc: - if model_proc[0:4] != 'http': - f.write(' - {0}\n'.format(model_proc)) + if model_proc[0:4] != "http": + f.write(f" - {model_proc}\n") else: - f.write(' - `{0} <{1}>`__\n'.format("model-proc", model_proc)) + f.write(f" - `model-proc <{model_proc}>`__\n") else: - f.write(' -\n') - #f.write(' - {0}\n'.format(m.get('omz_demo', ''))) + f.write(" -\n") + # f.write(' - {0}\n'.format(m.get('omz_demo', ''))) + + t1 = t2 = "" + if "demo_apps" in m: + t1 = m["demo_apps"][0] - t1 = t2 ='' - if 'demo_apps' in m: - t1 = m['demo_apps'][0] - - if 'demo_urls' in m: - t2 = m['demo_urls'][0] + if "demo_urls" in m: + t2 = m["demo_urls"][0] - if (t1 == '') or (t2 == ''): - f.write(' -\n') + if (t1 == "") or (t2 == ""): + f.write(" -\n") else: - f.write(' - `{0} <{1}>`__\n'.format(t1, t2)) + f.write(f" - `{t1} <{t2}>`__\n") - f.write('\n') - f.write('Legal Information\n') - f.write('-------------------\n') - f.write('PyTorch, TensorFlow, Caffe, Keras, MXNet are trademarks or brand names of their respective owners.\n') - f.write('All company, product and service names used in this website are for identification purposes only.\n') - f.write('Use of these names,trademarks and brands does not imply endorsement.\n') + f.write("\n") + f.write("Legal Information\n") + f.write("-------------------\n") + f.write("PyTorch, TensorFlow, Caffe, Keras, MXNet are trademarks ") + f.write("or brand names of their respective owners.\n") + f.write("All company, product and service names used in this ") + f.write("website are for identification purposes only.\n") + f.write("Use of these names,trademarks and brands does not imply endorsement.\n") diff --git a/libraries/dl-streamer/docs/scripts/models_yaml_from_zoo.py b/libraries/dl-streamer/docs/scripts/models_yaml_from_zoo.py index 15b2ae480..a0250370a 100644 --- a/libraries/dl-streamer/docs/scripts/models_yaml_from_zoo.py +++ b/libraries/dl-streamer/docs/scripts/models_yaml_from_zoo.py @@ -12,204 +12,231 @@ from argparse import ArgumentParser from jsonschema import validate -OV_MODEL_ZOO_URL = 'https://github.com/openvinotoolkit/open_model_zoo/tree/master/' -DLSTREAMER_URL='https://github.com/open-edge-platform/edge-ai-libraries/tree/main/libraries/dl-streamer/' -PIPELINE_ZOO_URL='https://github.com/dlstreamer/pipeline-zoo-models/tree/main/' +OV_MODEL_ZOO_URL = "https://github.com/openvinotoolkit/open_model_zoo/tree/master/" +DLSTREAMER_URL = ( + "https://github.com/open-edge-platform/edge-ai-libraries/tree/main/libraries/dl-streamer/" +) +PIPELINE_ZOO_URL = "https://github.com/dlstreamer/pipeline-zoo-models/tree/main/" -dldt_str = 'dl' + 'dt' -openvino_str = 'open' + 'vino' -dlstreamer_name = 'Deep ' + 'Learning' + ' Streamer' +DLDT_STR = "dl" + "dt" +OPENVINO_STR = "open" + "vino" parser = ArgumentParser(add_help=False) -_args = parser.add_argument_group('Options') -_args.add_argument("-omz", "--open_model_zoo", help="Required. Path to Open Model Zoo cloned repo", required=True, type=str) -_args.add_argument("-mi", "--model_index", help="Path to existing model_index.yaml file", required=False, type=str) -_args.add_argument("-o", "--output", help="Required. Path to output model_index.yaml file", required=True, type=str) -_args.add_argument("-a", "--all", help="If true, table will contain all models, not only supported", required=False, type=str) +_args = parser.add_argument_group("Options") +_args.add_argument( + "-omz", + "--open_model_zoo", + help="Required. Path to Open Model Zoo cloned repo", + required=True, + type=str, +) +_args.add_argument( + "-mi", "--model_index", help="Path to existing model_index.yaml file", required=False, type=str +) +_args.add_argument( + "-o", "--output", help="Required. Path to output model_index.yaml file", required=True, type=str +) +_args.add_argument( + "-a", + "--all", + help="If true, table will contain all models, not only supported", + required=False, + type=str, +) args = parser.parse_args() -models={} -deffective_models=[] +models = {} +deffective_models = [] # read .yml and .md files from open_model_zoo -for root, dirs, files in os.walk(args.open_model_zoo + '/models', topdown=False): +for root, dirs, files in os.walk(args.open_model_zoo + "/models", topdown=False): name = os.path.basename(root) - if 'composite-model.yml' in files: - with open(os.path.join(root, 'composite-model.yml')) as f: + if "composite-model.yml" in files: + with open(os.path.join(root, "composite-model.yml"), encoding='utf-8') as f: models[name] = yaml.safe_load(f) - if 'model.yml' in files and not os.path.exists(os.path.join(root, '../composite-model.yml')): - with open(os.path.join(root, 'model.yml')) as f: + if "model.yml" in files and not os.path.exists(os.path.join(root, "../composite-model.yml")): + with open(os.path.join(root, "model.yml"), encoding='utf-8') as f: models[name] = yaml.safe_load(f) - if 'README.md' in files: + if "README.md" in files: if name not in models: print("WARNING: README.md without model.yml:", name) models[name] = {} - cnt=0 - with open(os.path.join(root, 'README.md')) as f: + cnt = 0 + with open(os.path.join(root, "README.md"), encoding='utf-8') as f: for line in f.readlines(): - vec = [x.strip() for x in line.split('|')] - if len(vec) < 3 or vec[1].startswith('---'): + vec = [x.strip() for x in line.split("|")] + if len(vec) < 3 or vec[1].startswith("---"): continue - #print(vec) - cnt+=1 + # print(vec) + cnt += 1 if cnt < 2: continue models[name][vec[1]] = vec[2] if name in models: - if 'models/intel/' in root: - models[name]['source'] = 'intel' #openvino_str - elif 'models/public/' in root: - models[name]['source'] = 'public' - format = models[name].get('framework', '').replace(dldt_str, openvino_str) - if openvino_str not in format: - format += ', ' + openvino_str - models[name]['format'] = format - #models[name]['readme'] = 'https://docs.openvino.ai/latest/omz_models_model_' + name.replace('-', '_').replace('.', '_') + '.html' - models[name]['readme'] = '/'.join((OV_MODEL_ZOO_URL, 'models', models[name]['source'], name)) - print(models[name]['readme']) - + if "models/intel/" in root: + models[name]["source"] = "intel" # OPENVINO_STR + elif "models/public/" in root: + models[name]["source"] = "public" + format_str = models[name].get("framework", "").replace(DLDT_STR, OPENVINO_STR) + if OPENVINO_STR not in format_str: + format_str += ", " + OPENVINO_STR + models[name]["format"] = format_str + models[name]["readme"] = "/".join( + (OV_MODEL_ZOO_URL, "models", models[name]["source"], name) + ) + print(models[name]["readme"]) # for each model, find if OV supports CPU, GPU devices -for md in ['models/intel/device_support.md', 'models/public/device_support.md']: +for md in ["models/intel/device_support.md", "models/public/device_support.md"]: with open(os.path.join(args.open_model_zoo, md)) as f: for line in f.readlines(): - vec = [x.strip() for x in line.split('|')] + vec = [x.strip() for x in line.split("|")] if len(vec) < 4: continue name = vec[1] for composite_name, m in models.items(): - if name in m.get('stages_order', []): + if name in m.get("stages_order", []): name = composite_name break if name in models: - openvino_devices = '' - if vec[2] == 'YES': - openvino_devices += 'CPU' - if vec[3] == 'YES': - openvino_devices += ', GPU' - models[name]['openvino_devices'] = openvino_devices + openvino_devices = "" + if vec[2] == "YES": + openvino_devices += "CPU" + if vec[3] == "YES": + openvino_devices += ", GPU" + models[name]["openvino_devices"] = openvino_devices # for each model, find Accuracy, GFlops, mParams -for md in ['models/intel/index.md', 'models/public/index.md']: +for md in ["models/intel/index.md", "models/public/index.md"]: with open(os.path.join(args.open_model_zoo, md)) as f: for line in f.readlines(): for name in list(models.keys()): - if '[' + name + ']' in line or name + '-encoder' in line: - vec = [x.strip() for x in line.split('|')] + if "[" + name + "]" in line or name + "-encoder" in line: + vec = [x.strip() for x in line.split("|")] if len(vec) < 5: continue - #print(vec) - if '%' in vec[-4]: - models[name]['Accuracy'] = vec[-4] - models[name]['GFlops'] = vec[-3] - models[name]['mParams'] = vec[-2] + # print(vec) + if "%" in vec[-4]: + models[name]["Accuracy"] = vec[-4] + models[name]["GFlops"] = vec[-3] + models[name]["mParams"] = vec[-2] # read accuracy_checker parameters -accuracy_checker = os.path.join(args.open_model_zoo, 'tools/accuracy_checker/configs') +accuracy_checker = os.path.join(args.open_model_zoo, "tools/accuracy_checker/configs") for file in os.listdir(accuracy_checker): if not file.endswith(".yml"): continue with open(os.path.join(accuracy_checker, file)) as f: yml = yaml.safe_load(f) - if 'models' in yml: - models_list = yml['models'] + if "models" in yml: + models_list = yml["models"] else: - models_list = yml.get('evaluations', []) + models_list = yml.get("evaluations", []) for m in models_list: - name = m['name'] + name = m["name"] filename = os.path.splitext(file)[0] if name in models: models[name].update(m) elif filename in models: models[filename].update(m) else: - print('WARNING: model listed in OV accuracy_checker but not listed in OV model zoo:', name) + print( + "WARNING: model listed in OV accuracy_checker but not listed in OV model zoo:", + name, + ) deffective_models.append(name) # for each model, find which OMZ demo supports it for root, dirs, files in os.walk(args.open_model_zoo, topdown=False): - if 'models.lst' in files: - with open(os.path.join(root, 'models.lst')) as f: - demo_url = root.split('/') - demo_url = '/'.join(demo_url[demo_url.index('demos'):]) - demo_url = '/'.join((OV_MODEL_ZOO_URL, demo_url)) + if "models.lst" in files: + with open(os.path.join(root, "models.lst"), encoding='utf-8') as f: + demo_url = root.split("/") + demo_url = "/".join(demo_url[demo_url.index("demos") :]) + demo_url = "/".join((OV_MODEL_ZOO_URL, demo_url)) demo_app = os.path.basename(os.path.dirname(root)) for line in f.read().splitlines(): - if line[0] == '#': + if line[0] == "#": continue - name_regexp = line.replace('?', '.').replace('-encoder','') + name_regexp = line.replace("?", ".").replace("-encoder", "") for composite_name, m in models.items(): - for name in m.get('stages_order', [composite_name]): + for name in m.get("stages_order", [composite_name]): if re.match(name_regexp, name): - if 'demo_apps' in models[composite_name]: - models[composite_name]['demo_apps'].append(demo_app) + if "demo_apps" in models[composite_name]: + models[composite_name]["demo_apps"].append(demo_app) else: - models[composite_name]['demo_apps'] = [demo_app] + models[composite_name]["demo_apps"] = [demo_app] - if 'demo_urls' in models[composite_name]: - models[composite_name]['demo_urls'].append(demo_url) + if "demo_urls" in models[composite_name]: + models[composite_name]["demo_urls"].append(demo_url) else: - models[composite_name]['demo_urls'] = [demo_url] + models[composite_name]["demo_urls"] = [demo_url] break # read model_index.yaml if args.model_index is not None: with open(args.model_index) as f: - #model_index_schema = args.model_index.replace(".yaml", "_schema.json") - #with open(model_index_schema) as mis: - model_index = yaml.safe_load(f) - #validate(model_index, json.load(mis)) - for name, m in model_index.items(): - if 'dlstreamer_support' not in m: - m['dlstreamer_support'] = openvino_str - if 'labels-file' in m: - m['labels-file'] = DLSTREAMER_URL + 'samples/' + m['labels-file'] - if 'model-proc' in m: - m['model-proc'] = DLSTREAMER_URL + 'samples/' + m['model-proc'] - if m.get('source', '') == 'dlstreamer': - if 'readme' not in m: - m['readme'] = PIPELINE_ZOO_URL + 'storage/' + name - if 'model-proc' not in m: - m['model-proc'] = PIPELINE_ZOO_URL + 'storage/' + name # + '/' + name + '.json' - if name in models: - models[name].update(m) - else: - if 'source' not in m and name + '-decoder' not in models: - print('WARNING: model listed in model_index.yaml but not listed in OV model zoo:', name) - deffective_models.append(name) - if 'format' not in m: - m['format'] = openvino_str - models[name] = m + # model_index_schema = args.model_index.replace(".yaml", "_schema.json") + # with open(model_index_schema) as mis: + model_index = yaml.safe_load(f) + # validate(model_index, json.load(mis)) + for name, m in model_index.items(): + if "dlstreamer_support" not in m: + m["dlstreamer_support"] = OPENVINO_STR + if "labels-file" in m: + m["labels-file"] = DLSTREAMER_URL + "samples/" + m["labels-file"] + if "model-proc" in m: + m["model-proc"] = DLSTREAMER_URL + "samples/" + m["model-proc"] + if m.get("source", "") == "dlstreamer": + if "readme" not in m: + m["readme"] = PIPELINE_ZOO_URL + "storage/" + name + if "model-proc" not in m: + m["model-proc"] = PIPELINE_ZOO_URL + "storage/" + name # + '/' + name + '.json' + if name in models: + models[name].update(m) + else: + if "source" not in m and name + "-decoder" not in models: + print( + "WARNING: model listed in model_index.yaml but not listed in OV model zoo:", + name, + ) + deffective_models.append(name) + if "format" not in m: + m["format"] = OPENVINO_STR + models[name] = m # remove models that we don't want to include, e.g. preview/deprecation -models_to_remove = ['icnet-camvid-ava-0001', 'road-segmentation-adas-0001', - 'semantic-segmentation-adas-0001', 'text-detection-0003'] -for model_name in (models_to_remove + deffective_models): +models_to_remove = [ + "icnet-camvid-ava-0001", + "road-segmentation-adas-0001", + "semantic-segmentation-adas-0001", + "text-detection-0003", +] +for model_name in models_to_remove + deffective_models: if models.pop(model_name, None): print(f"Removed '{model_name}' from final models list") # update name, task_type, devices for name, m in models.items(): - m['name'] = name - if 'yolo' in name: - m['task_type'] = 'detection' - if 'task_type' not in m: - m['task_type'] = '~?' - format = m.get('format', '') - if 'pytorch_devices' not in m and 'pytorch' in format: - m['pytorch_devices'] = 'CPU' - if 'tf_devices' not in m and 'tf' in format: - m['tf_devices'] = 'CPU' + m["name"] = name + if "yolo" in name: + m["task_type"] = "detection" + if "task_type" not in m: + m["task_type"] = "~?" + format = m.get("format", "") + if "pytorch_devices" not in m and "pytorch" in format: + m["pytorch_devices"] = "CPU" + if "tf_devices" not in m and "tf" in format: + m["tf_devices"] = "CPU" -models_filtered={} +models_filtered = {} for key, value in models.items(): - keys_to_del = [k for k, v in value.items() if k[0:5]=='[COCO'] + keys_to_del = [k for k, v in value.items() if k[0:5] == "[COCO"] for k in keys_to_del: value.pop(k) @@ -235,14 +262,12 @@ value.pop("launchers", None) value.pop("mParams", None) value.pop("model_optimizer_args", None) - tempv = value.get('files',[]) + tempv = value.get("files", []) if tempv != []: - tempv = tempv[0].get('source', '') - value.pop('files', None) + tempv = tempv[0].get("source", "") + value.pop("files", None) models_filtered[key] = value -with open(args.output, 'w') as file: +with open(args.output, "w", encoding='utf-8') as file: yaml.dump(models_filtered, file) - - diff --git a/libraries/dl-streamer/docs/scripts/specific_links_checker.py b/libraries/dl-streamer/docs/scripts/specific_links_checker.py index 7a0cda425..b069dd041 100644 --- a/libraries/dl-streamer/docs/scripts/specific_links_checker.py +++ b/libraries/dl-streamer/docs/scripts/specific_links_checker.py @@ -15,33 +15,34 @@ re.compile(r'https?://(?:[a-zA-Z0-9.-]+\.)?intel\.com(?:/[^\s<>"\'\)\]]*)?'), # add more regexes as needed ] -URL_EXCLUDED_KEYWORDS = ['apt', 'repos', 'repositories'] +URL_EXCLUDED_KEYWORDS = ["apt", "repos", "repositories"] # Set timeout for HTTP requests TIMEOUT = 10 + def extract_links_from_file(filepath): - with open(filepath, 'r', encoding='utf-8', errors='ignore') as f: + with open(filepath, "r", encoding="utf-8", errors="ignore") as f: content = f.read() all_links = set() for regex in URL_REGEXES: raw_links = set(regex.findall(content)) + cleaned_links = {link.rstrip(".,);:]>'\"") for link in raw_links} cleaned_links = { - link.rstrip('.,);:]>\'"') for link in raw_links - } - cleaned_links = { - link for link in cleaned_links + link + for link in cleaned_links if not any(word in link for word in URL_EXCLUDED_KEYWORDS) } all_links.update(cleaned_links) return all_links + def find_all_links(directory): link_sources = defaultdict(set) # link -> set of source files - allowed_extensions = {'.rst', '.html', '.md', '.yaml'} + allowed_extensions = {".rst", ".html", ".md", ".yaml"} for root, _, files in os.walk(directory): for filename in files: @@ -57,6 +58,7 @@ def find_all_links(directory): print(f"[WARN] Skipped file due to error: {filepath} – {e}") return link_sources + def check_link(url): try: response = requests.head(url, allow_redirects=True, timeout=TIMEOUT) @@ -66,8 +68,9 @@ def check_link(url): except requests.RequestException: return False + def main(): - directory = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) + directory = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) link_sources = find_all_links(directory) all_links = sorted(link_sources.keys()) @@ -91,5 +94,6 @@ def main(): print("\n✅ All links are working.") sys.exit(0) -if __name__ == '__main__': + +if __name__ == "__main__": main() diff --git a/libraries/dl-streamer/python/gstgva/__init__.py b/libraries/dl-streamer/python/gstgva/__init__.py index a83e982d2..cc16ad4c4 100644 --- a/libraries/dl-streamer/python/gstgva/__init__.py +++ b/libraries/dl-streamer/python/gstgva/__init__.py @@ -1,9 +1,11 @@ # ============================================================================== -# Copyright (C) 2018-2020 Intel Corporation +# Copyright (C) 2018-2025 Intel Corporation # # SPDX-License-Identifier: MIT # ============================================================================== +# pylint: disable=missing-module-docstring + from .region_of_interest import RegionOfInterest from .video_frame import VideoFrame from .tensor import Tensor diff --git a/libraries/dl-streamer/python/gstgva/audio/__init__.py b/libraries/dl-streamer/python/gstgva/audio/__init__.py index bb3e377c4..0c109256c 100644 --- a/libraries/dl-streamer/python/gstgva/audio/__init__.py +++ b/libraries/dl-streamer/python/gstgva/audio/__init__.py @@ -1,8 +1,10 @@ # ============================================================================== -# Copyright (C) 2018-2020 Intel Corporation +# Copyright (C) 2018-2025 Intel Corporation # # SPDX-License-Identifier: MIT # ============================================================================== +# pylint: disable=missing-module-docstring + from .audio_event_meta import AudioEventMeta from .audio_frame import AudioFrame diff --git a/libraries/dl-streamer/python/gstgva/audio/audio_event.py b/libraries/dl-streamer/python/gstgva/audio/audio_event.py index 8eb3265d3..fa0a81292 100644 --- a/libraries/dl-streamer/python/gstgva/audio/audio_event.py +++ b/libraries/dl-streamer/python/gstgva/audio/audio_event.py @@ -1,70 +1,84 @@ # ============================================================================== -# Copyright (C) 2018-2021 Intel Corporation +# Copyright (C) 2018-2025 Intel Corporation # # SPDX-License-Identifier: MIT # ============================================================================== ## @file audio_event.py -# @brief This file contains gstgva.audio_event.AudioEvent class to control audio events for particular gstgva.audio_frame.AudioFrame with gstgva.tensor.Tensor instances attached +# @brief This file contains gstgva.audio_event.AudioEvent class to control audio events +# for particular gstgva.audio_frame.AudioFrame with gstgva.tensor.Tensor instances attached + +# pylint: disable=missing-module-docstring -import ctypes -import numpy from typing import List from collections import namedtuple - +import ctypes +import numpy +import gi +from gi.repository import GstAudio, GLib, GObject, Gst from ..tensor import Tensor from ..util import libgst, libgobject, GLIST_POINTER from .audio_event_meta import AudioEventMeta -import gi -gi.require_version('GstAudio', '1.0') -gi.require_version('GLib', '2.0') -gi.require_version('Gst', '1.0') -from gi.repository import GstAudio, GLib, GObject, Gst + +gi.require_version("GstAudio", "1.0") +gi.require_version("GLib", "2.0") +gi.require_version("Gst", "1.0") + Segment = namedtuple("Segment", "start_time end_time") -## @brief This class represents audio event - object describing detection result (audio segment) and containing multiple -# Tensor objects (inference results) attached by multiple models. For example, it can be audio event with detected -# speech and converts speech to text. It can be produced by a pipeline with gvaaudiodetect with detection model and -# gvaspeechtotext element with speechtotext model. Such AudioEvent will have start and end timestamps filled and will -# have 2 Tensor objects attached - 1 Tensor object with detection result, other with speech to text tensor objectresult +## @brief This class represents audio event - object describing detection result (audio segment) +# and containing multiple Tensor objects (inference results) attached by multiple models. +# For example, it can be audio event with detected speech and converts speech to text. +# It can be produced by a pipeline with gvaaudiodetect with detection model and gvaspeechtotext +# element with speechtotext model. Such AudioEvent will have start and end timestamps filled +# and will have 2 Tensor objects attached - 1 Tensor object with detection result, other with +# speech to text tensor objectresult + -class AudioEvent(object): +class AudioEvent(): + # pylint: disable=missing-class-docstring ## @brief Get clip of AudioEvent as start and end time stamps # @return Start and end time of AudioEvent def segment(self): - return Segment(start_time = self.__event_meta.start_timestamp, - end_time = self.__event_meta.end_timestamp) + # pylint: disable=missing-function-docstring + return Segment( + start_time=self.__event_meta.start_timestamp, end_time=self.__event_meta.end_timestamp + ) ## @brief Get AudioEvent label # @return AudioEvent label def label(self) -> str: + # pylint: disable=missing-function-docstring return GLib.quark_to_string(self.__event_meta.event_type) ## @brief Get AudioEvent detection confidence (set by gvaaudiodetect) # @return last added detection Tensor confidence if exists, otherwise None def confidence(self) -> float: + # pylint: disable=missing-function-docstring detection = self.detection() return detection.confidence() if detection else None ## @brief Get all Tensor instances added to this AudioEvent # @return vector of Tensor instances added to this AudioEvent def tensors(self): + # pylint: disable=missing-function-docstring param = self.meta()._params while param: tensor_structure = param.contents.data yield Tensor(tensor_structure) param = param.contents.next - ## @brief Returns detection Tensor, last added to this AudioEvent. As any other Tensor, returned detection - # Tensor can contain arbitrary information. If you use AudioEvent based on GstGVAAudioEventMeta - # attached by gvaaudiodetect by default, then this Tensor will contain "label_id", "confidence", "start_timestamp", - # "end_timestamp" fields. + ## @brief Returns detection Tensor, last added to this AudioEvent. As any other Tensor, + # returned detection Tensor can contain arbitrary information. If you use AudioEvent based on + # GstGVAAudioEventMeta attached by gvaaudiodetect by default, then this Tensor will contain + # "label_id", "confidence", "start_timestamp", "end_timestamp" fields. # If AudioEvent doesn't have detection Tensor, it will be created in-place. - # @return detection Tensor, empty if there were no detection Tensor objects added to this AudioEvent when - # this method was called + # @return detection Tensor, empty if there were no detection Tensor objects added to this + # AudioEvent when this method was called def detection(self) -> Tensor: + # pylint: disable=missing-function-docstring for tensor in self.tensors(): if tensor.is_detection(): return tensor @@ -73,13 +87,17 @@ def detection(self) -> Tensor: ## @brief Get label_id from detection Tensor, last added to this AudioEvent # @return last added detection Tensor label_id if exists, otherwise None def label_id(self) -> int: + # pylint: disable=missing-function-docstring detection = self.detection() return detection.label_id() if detection else None - ## @brief Get AudioEventMeta containing start, end time information and tensors (inference results). + ## @brief Get AudioEventMeta containing start, end time information and tensors + # (inference results). # Tensors are represented as GstStructures added to GstGVAAudioEventMeta.params - # @return AudioEventMeta containing start, end time information and tensors (inference results) + # @return AudioEventMeta containing start, end time information and tensors + # (inference results) def meta(self) -> AudioEventMeta: + # pylint: disable=missing-function-docstring return self.__event_meta ## @brief Iterate by AudioEventMeta instances attached to buffer @@ -94,7 +112,9 @@ def _iterate(self, buffer: Gst.Buffer): gpointer = ctypes.c_void_p() while True: try: - value = libgst.gst_buffer_iterate_meta_filtered(hash(buffer), ctypes.byref(gpointer), meta_api) + value = libgst.gst_buffer_iterate_meta_filtered( + hash(buffer), ctypes.byref(gpointer), meta_api + ) except: value = None diff --git a/libraries/dl-streamer/python/gstgva/audio/audio_event_meta.py b/libraries/dl-streamer/python/gstgva/audio/audio_event_meta.py index 78e7a4d5d..e2db7aa25 100644 --- a/libraries/dl-streamer/python/gstgva/audio/audio_event_meta.py +++ b/libraries/dl-streamer/python/gstgva/audio/audio_event_meta.py @@ -1,20 +1,24 @@ # ============================================================================== -# Copyright (C) 2018-2021 Intel Corporation +# Copyright (C) 2018-2025 Intel Corporation # # SPDX-License-Identifier: MIT # ============================================================================== +# pylint: disable=missing-module-docstring + import ctypes from ..util import GLIST_POINTER + # AudioEventMeta class AudioEventMeta(ctypes.Structure): + # pylint: disable=missing-class-docstring,too-few-public-methods _fields_ = [ - ('_meta_flags', ctypes.c_int), - ('_info', ctypes.c_void_p), - ('event_type', ctypes.c_int), - ('id', ctypes.c_int), - ('start_timestamp', ctypes.c_ulong), - ('end_timestamp', ctypes.c_ulong), - ('_params', GLIST_POINTER) + ("_meta_flags", ctypes.c_int), + ("_info", ctypes.c_void_p), + ("event_type", ctypes.c_int), + ("id", ctypes.c_int), + ("start_timestamp", ctypes.c_ulong), + ("end_timestamp", ctypes.c_ulong), + ("_params", GLIST_POINTER), ] diff --git a/libraries/dl-streamer/python/gstgva/audio/audio_frame.py b/libraries/dl-streamer/python/gstgva/audio/audio_frame.py index 4a9b40f09..f571e8acf 100644 --- a/libraries/dl-streamer/python/gstgva/audio/audio_frame.py +++ b/libraries/dl-streamer/python/gstgva/audio/audio_frame.py @@ -1,24 +1,21 @@ # ============================================================================== -# Copyright (C) 2018-2021 Intel Corporation +# Copyright (C) 2018-2025 Intel Corporation # # SPDX-License-Identifier: MIT # ============================================================================== ## @file audio_frame.py -# @brief This file contains gstgva.audio_frame.AudioFrame class to control particular inferenced frame -# and attached gstgva.audio_event.AudioEvent and gstgva.tensor.Tensor instances +# @brief This file contains gstgva.audio_frame.AudioFrame class to control particular +# inferenced frame and attached gstgva.audio_event.AudioEvent and gstgva.tensor.Tensor instances + +# pylint: disable=missing-module-docstring -import ctypes -import numpy from contextlib import contextmanager from typing import List from warnings import warn - +import ctypes +import numpy import gi -gi.require_version('Gst', '1.0') -gi.require_version("GstAudio", "1.0") -gi.require_version('GObject', '2.0') - from gi.repository import GObject, Gst, GstAudio from .audio_event_meta import AudioEventMeta from .audio_event import AudioEvent @@ -28,19 +25,26 @@ from ..tensor import Tensor from ..util import libgst, gst_buffer_data, AudioInfoFromCaps - -## @brief This class represents audio frame - object for working with AudioEvent and Tensor objects which -# belong to this audio frame . AudioEvent describes detected object (segments) and its Tensor -# objects (inference results on AudioEvent level). Tensor describes inference results on AudioFrame level. -# AudioFrame also provides access to underlying GstBuffer and GstAudioInfo describing frame's audio information (such -# as format, channels, etc.). +gi.require_version("Gst", "1.0") +gi.require_version("GstAudio", "1.0") +gi.require_version("GObject", "2.0") + +## @brief This class represents audio frame - object for working with AudioEvent and Tensor +# objects which belong to this audio frame . AudioEvent describes detected object (segments) +# and its Tensor objects (inference results on AudioEvent level). Tensor describes inference +# results on AudioFrame level. +# AudioFrame also provides access to underlying GstBuffer and GstAudioInfo describing frame's +# audio information (such as format, channels, etc.). class AudioFrame: + # pylint: disable=missing-class-docstring ## @brief Construct AudioFrame instance from Gst.Buffer and GstAudio.AudioInfo or Gst.Caps. # The preferred way of creating AudioFrame is to use Gst.Buffer and GstAudio.AudioInfo # @param buffer Gst.Buffer to which metadata is attached and retrieved # @param audio_info GstAudio.AudioInfo containing audio information # @param caps Gst.Caps from which audio information is obtained - def __init__(self, buffer: Gst.Buffer, audio_info: GstAudio.AudioInfo = None, caps: Gst.Caps = None): + def __init__( + self, buffer: Gst.Buffer, audio_info: GstAudio.AudioInfo = None, caps: Gst.Caps = None + ): self.__buffer = buffer self.__audio_info = None @@ -51,43 +55,55 @@ def __init__(self, buffer: Gst.Buffer, audio_info: GstAudio.AudioInfo = None, ca else: raise RuntimeError("One of audio_info or caps is required") - ## @brief Get GstAudio.AudioInfo of this AudioFrame. This is preferrable way of getting audio information + ## @brief Get GstAudio.AudioInfo of this AudioFrame. This is preferrable way of + # getting audio information # @return GstAudio.AudioInfo of this AudioFrame def audio_info(self) -> GstAudio.AudioInfo: + # pylint: disable=missing-function-docstring return self.__audio_info ## @brief Get AudioEvent objects attached to AudioFrame # @return iterator of AudioEvent objects attached to AudioFrame def events(self): + # pylint: disable=missing-function-docstring return AudioEvent._iterate(self.__buffer) ## @brief Get Tensor objects attached to AudioFrame # @return iterator of Tensor objects attached to AudioFrame def tensors(self): + # pylint: disable=missing-function-docstring return Tensor._iterate(self.__buffer) ## @brief Get messages attached to this AudioFrame # @return GVAJSONMetaStr messages attached to this AudioFrame def messages(self) -> List[str]: + # pylint: disable=missing-function-docstring return [json_meta.get_message() for json_meta in GVAJSONMeta.iterate(self.__buffer)] ## @brief Attach message to this AudioFrame # @param message message to attach to this AudioFrame def add_message(self, message: str): + # pylint: disable=missing-function-docstring GVAJSONMeta.add_json_meta(self.__buffer, message) ## @brief Remove message from this AudioFrame # @param message GVAJSONMetaStr message to remove def remove_message(self, message: str): - if not isinstance(message,GVAJSONMetaStr) or not GVAJSONMeta.remove_json_meta(self.__buffer, message.meta): + # pylint: disable=missing-function-docstring + if not isinstance(message, GVAJSONMetaStr) or not GVAJSONMeta.remove_json_meta( + self.__buffer, message.meta + ): raise RuntimeError("AudioFrame: message doesn't belong to this AudioFrame") ## @brief Remove audio event with the specified index # @param event audio event to remove def remove_event(self, event) -> None: + # pylint: disable=missing-function-docstring if not libgst.gst_buffer_remove_meta(hash(self.__buffer), ctypes.byref(event.meta())): - raise RuntimeError("AudioFrame: Underlying GstGVAAudioEventMeta for AudioEvent " - "doesn't belong to this AudioFrame") + raise RuntimeError( + "AudioFrame: Underlying GstGVAAudioEventMeta for AudioEvent " + "doesn't belong to this AudioFrame" + ) @staticmethod def __get_label_by_label_id(event_tensor: Gst.Structure, label_id: int) -> str: @@ -100,6 +116,7 @@ def __get_label_by_label_id(event_tensor: Gst.Structure, label_id: int) -> str: ## @brief Get buffer data wrapped by numpy.ndarray # @return numpy array representing raw audio samples def data(self, flag: Gst.MapFlags = Gst.MapFlags.WRITE) -> numpy.ndarray: + # pylint: disable=missing-function-docstring with gst_buffer_data(self.__buffer, flag) as data: try: return numpy.ndarray((len(data)), buffer=data, dtype=numpy.uint8) diff --git a/libraries/dl-streamer/python/gstgva/region_of_interest.py b/libraries/dl-streamer/python/gstgva/region_of_interest.py index 00a011e95..bde2643b0 100644 --- a/libraries/dl-streamer/python/gstgva/region_of_interest.py +++ b/libraries/dl-streamer/python/gstgva/region_of_interest.py @@ -5,38 +5,43 @@ # ============================================================================== ## @file region_of_interest.py -# @brief This file contains gstgva.region_of_interest.RegionOfInterest class to control region of interest for particular gstgva.video_frame.VideoFrame with gstgva.tensor.Tensor instances attached +# @brief This file contains gstgva.region_of_interest.RegionOfInterest +# class to control region of interest for particular gstgva.video_frame.VideoFrame +# with gstgva.tensor.Tensor instances attached + +# pylint: disable=missing-module-docstring,wrong-import-position -import ctypes -import numpy from typing import List from collections import namedtuple - -from .tensor import Tensor -from .util import VideoRegionOfInterestMeta -from .util import libgst, libgobject, libgstvideo, GLIST_POINTER - +import ctypes +import numpy import gi gi.require_version("GstVideo", "1.0") gi.require_version("GLib", "2.0") gi.require_version("Gst", "1.0") gi.require_version("GstAnalytics", "1.0") + from gi.repository import GstVideo, GLib, GObject, Gst, GstAnalytics +from .tensor import Tensor +from .util import VideoRegionOfInterestMeta +from .util import libgst, libgobject, libgstvideo, GLIST_POINTER Rect = namedtuple("Rect", "x y w h") -## @brief This class represents region of interest - object describing detection result (bounding box) and containing -# multiple Tensor objects (inference results) attached by multiple models. For example, it can be region of interest with detected face and recognized age -# and sex of a person. It can be produced by a pipeline with gvadetect with detection model and two gvaclassify -# elements with two classification models. Such RegionOfInterest will have bounding box coordinates filled and will have 3 Tensor objects -# attached - 1 Tensor object with detection result and 2 Tensor objects with classification results coming from 2 classifications -class RegionOfInterest(object): +## @brief This class represents region of interest - object describing detection +# result (bounding box) and containing multiple Tensor objects (inference results) +# attached by multiple models. For example, it can be region of interest with detected +# face and recognized age and sex of a person. It can be produced by a pipeline with +# gvadetect with detection model and two gvaclassify +# elements with two classification models. Such RegionOfInterest will have bounding box +# coordinates filled and will have 3 Tensor objects attached - 1 Tensor object with +# detection result and 2 Tensor objects with classification results coming from 2 classifications +class RegionOfInterest(): + # pylint: disable=missing-class-docstring - def __init__( - self, od_meta: GstAnalytics.ODMtd, roi_meta: VideoRegionOfInterestMeta - ): + def __init__(self, od_meta: GstAnalytics.ODMtd, roi_meta: VideoRegionOfInterestMeta): self.__roi_meta = roi_meta self.__od_meta = od_meta self._detection = None @@ -48,10 +53,7 @@ def __init__( while param: tensor_structure = param.contents.data tensor = Tensor(tensor_structure) - if ( - tensor.name() != "object_id" - and tensor.type() != "classification_result" - ): + if tensor.name() != "object_id" and tensor.type() != "classification_result": self._tensors.append(tensor) if tensor.is_detection(): self._detection = tensor @@ -74,6 +76,7 @@ def __init__( ## @brief Get bounding box of the RegionOfInterest as pixel coordinates in original image # @return Bounding box coordinates of the RegionOfInterest def rect(self) -> Rect: + # pylint: disable=missing-function-docstring success, x, y, w, h, _, _ = self.__od_meta.get_oriented_location() if not success: @@ -86,6 +89,7 @@ def rect(self) -> Rect: ## @brief Get bounding box of the RegionOfInterest as normalized coordinates in the range [0, 1] # @return Bounding box coordinates of the RegionOfInterest def normalized_rect(self): + # pylint: disable=missing-function-docstring detection = self.detection() return Rect( x=detection["x_min"], @@ -113,6 +117,7 @@ def rotation(self) -> float: ## @brief Get class label of this RegionOfInterest # @return Class label of this RegionOfInterest def label(self) -> str: + # pylint: disable=missing-function-docstring label_quark = self.__od_meta.get_obj_type() if label_quark: @@ -124,11 +129,13 @@ def label(self) -> str: # @return detection confidence from analytics metadata # @throws std::runtime_error if confidence cannot be read from metadata def confidence(self) -> float: + # pylint: disable=missing-function-docstring success, confidence = self.__od_meta.get_confidence_lvl() if not success: raise RuntimeError( - "RegionOfInterest:confidence: Failed to get confidence level from analytics metadata" + "RegionOfInterest:confidence: Failed to get " + + "confidence level from analytics metadata" ) return confidence @@ -136,11 +143,9 @@ def confidence(self) -> float: ## @brief Get object id using analytics tracking metadata # @return object id as an int, None if failed to get def object_id(self) -> int | None: + # pylint: disable=missing-function-docstring for trk_mtd in self.__od_meta.meta: - if ( - trk_mtd.id == self.__od_meta.id - or type(trk_mtd) != GstAnalytics.TrackingMtd - ): + if trk_mtd.id == self.__od_meta.id or not isinstance(trk_mtd, GstAnalytics.TrackingMtd): continue rel = self.__od_meta.meta.get_relation(self.__od_meta.id, trk_mtd.id) @@ -152,7 +157,8 @@ def object_id(self) -> int | None: if not success: raise RuntimeError( - "RegionOfInterest:object_id: Failed to get tracking info from analytics metadata" + "RegionOfInterest:object_id: Failed to get " + + "tracking info from analytics metadata" ) return tracking_id @@ -162,6 +168,7 @@ def object_id(self) -> int | None: ## @brief Set object id using analytics tracking metadata # @param object_id Object ID to set def set_object_id(self, object_id: int): + # pylint: disable=missing-function-docstring # Set in ROI meta for backward compatibility if self.meta(): s_object_id = libgstvideo.gst_video_region_of_interest_meta_get_param( @@ -172,9 +179,7 @@ def set_object_id(self, object_id: int): tensor_object_id = Tensor(s_object_id) tensor_object_id["id"] = object_id else: - tensor_structure = libgst.gst_structure_new_empty( - "object_id".encode("utf-8") - ) + tensor_structure = libgst.gst_structure_new_empty("object_id".encode("utf-8")) tensor_object_id = Tensor(tensor_structure) tensor_object_id["id"] = object_id libgstvideo.gst_video_region_of_interest_meta_add_param( @@ -182,10 +187,7 @@ def set_object_id(self, object_id: int): ) for trk_mtd in self.__od_meta.meta: - if ( - trk_mtd.id == self.__od_meta.id - or type(trk_mtd) != GstAnalytics.TrackingMtd - ): + if trk_mtd.id == self.__od_meta.id or not isinstance(trk_mtd, GstAnalytics.TrackingMtd): continue rel = self.__od_meta.meta.get_relation(self.__od_meta.id, trk_mtd.id) @@ -197,15 +199,14 @@ def set_object_id(self, object_id: int): GstAnalytics.RelTypes.NONE, self.__od_meta.id, trk_mtd.id ): raise RuntimeError( - "RegionOfInterest:set_object_id: Failed to remove existing relation to tracking metadata" + "RegionOfInterest:set_object_id: Failed to remove " + + "existing relation to tracking metadata" ) success, trk_mtd = self.__od_meta.meta.add_tracking_mtd(object_id, 0) if not success: - raise RuntimeError( - "RegionOfInterest:set_object_id: Failed to add tracking metadata" - ) + raise RuntimeError("RegionOfInterest:set_object_id: Failed to add tracking metadata") if not self.__od_meta.meta.set_relation( GstAnalytics.RelTypes.RELATE_TO, self.__od_meta.id, trk_mtd.id @@ -217,13 +218,15 @@ def set_object_id(self, object_id: int): ## @brief Get all Tensor instances added to this RegionOfInterest # @return list of Tensor instances added to this RegionOfInterest def tensors(self) -> List[Tensor]: + # pylint: disable=missing-function-docstring return self._tensors ## @brief Get all Tensor instances added to this RegionOfInterest (in old metadata format) # @return list of Tensor instances added to this RegionOfInterest def get_gst_roi_params(self) -> List[Tensor]: + # pylint: disable=missing-function-docstring result = [] - + # pylint: disable=protected-access param = self.__roi_meta._params while param: tensor_structure = param.contents.data @@ -233,14 +236,16 @@ def get_gst_roi_params(self) -> List[Tensor]: return result - ## @brief Returns detection Tensor, last added to this RegionOfInterest. As any other Tensor, returned detection - # Tensor can contain arbitrary information. If you use RegionOfInterest based on VideoRegionOfInterestMeta - # attached by gvadetect by default, then this Tensor will contain "label_id", "confidence", "x_min", "x_max", - # "y_min", "y_max" fields. + ## @brief Returns detection Tensor, last added to this RegionOfInterest. + # As any other Tensor, returned detection + # Tensor can contain arbitrary information. If you use RegionOfInterest + # based on VideoRegionOfInterestMeta attached by gvadetect by default, then this + # Tensor will contain "label_id", "confidence", "x_min", "x_max", # "y_min", "y_max" fields. # If RegionOfInterest doesn't have detection Tensor, it will be created in-place - # @return detection Tensor, empty if there were no detection Tensor objects added to this RegionOfInterest when - # this method was called + # @return detection Tensor, empty if there were no detection Tensor objects added + # to this RegionOfInterest when this method was called def detection(self) -> Tensor: + # pylint: disable=missing-function-docstring if not self._detection: gst_structure = libgst.gst_structure_new_empty("detection".encode("utf-8")) detection_tensor = Tensor(gst_structure) @@ -250,19 +255,18 @@ def detection(self) -> Tensor: ## @brief Get label_id from analytics metadata or detection Tensor # @return label_id if exists, otherwise 0 def label_id(self) -> int: + # pylint: disable=missing-function-docstring label_quark = self.__od_meta.get_obj_type() cls_descriptor_mtd = None for cls_descriptor_mtd in self.__od_meta.meta: if ( cls_descriptor_mtd.id == self.__od_meta.id - or type(cls_descriptor_mtd) != GstAnalytics.ClsMtd + or not isinstance(cls_descriptor_mtd, GstAnalytics.ClsMtd) ): continue - rel = self.__od_meta.meta.get_relation( - self.__od_meta.id, cls_descriptor_mtd.id - ) + rel = self.__od_meta.meta.get_relation(self.__od_meta.id, cls_descriptor_mtd.id) if rel == GstAnalytics.RelTypes.RELATE_TO: break @@ -283,6 +287,7 @@ def label_id(self) -> int: # @param tensor Tensor object to add to this RegionOfInterest. # This function does not take ownership of tensor passed, but only copies its contents def add_tensor(self, tensor: Tensor): + # pylint: disable=missing-function-docstring s = tensor.get_structure() if not s: @@ -309,22 +314,26 @@ def add_tensor(self, tensor: Tensor): if tensor.is_detection(): self._detection = tensor - ## @brief Get VideoRegionOfInterestMeta containing bounding box information and tensors (inference results). + ## @brief Get VideoRegionOfInterestMeta containing bounding box information and + # tensors (inference results). # Tensors are represented as GstStructures added to GstVideoRegionOfInterestMeta.params # @return VideoRegionOfInterestMeta containing bounding box and tensors (inference results) def meta(self) -> VideoRegionOfInterestMeta: + # pylint: disable=missing-function-docstring return self.__roi_meta ## @brief Get region ID from analytics metadata # @return Region id as an int. Can be a positive or negative integer, but never zero. def region_id(self): + # pylint: disable=missing-function-docstring return self.__od_meta.id ## @brief Retrieves the parent object detection ID for this region of interest. # @return The ID of the parent object detection metadata if found, None otherwise. def parent_id(self) -> int | None: + # pylint: disable=missing-function-docstring for rlt_mtd in self.__od_meta.meta: - if rlt_mtd.id == self.__od_meta.id or type(rlt_mtd) != GstAnalytics.ODMtd: + if rlt_mtd.id == self.__od_meta.id or not isinstance(rlt_mtd, GstAnalytics.ODMtd): continue rel = self.__od_meta.meta.get_relation(self.__od_meta.id, rlt_mtd.id) @@ -347,7 +356,7 @@ def _iterate(cls, buffer: Gst.Buffer): return for od_mtd in relation_meta: - if type(od_mtd) != GstAnalytics.ODMtd: + if not isinstance(od_mtd, GstAnalytics.ODMtd): continue value = None @@ -357,11 +366,10 @@ def _iterate(cls, buffer: Gst.Buffer): if not value: raise RuntimeError( - "RegionOfInterest:_iterate: Failed to get VideoRegionOfInterestMeta by id from buffer" + "RegionOfInterest:_iterate: Failed to get " + + "VideoRegionOfInterestMeta by id from buffer" ) - roi_meta = ctypes.cast( - value, ctypes.POINTER(VideoRegionOfInterestMeta) - ).contents + roi_meta = ctypes.cast(value, ctypes.POINTER(VideoRegionOfInterestMeta)).contents yield RegionOfInterest(od_mtd, roi_meta) diff --git a/libraries/dl-streamer/python/gstgva/tensor.py b/libraries/dl-streamer/python/gstgva/tensor.py index 182d17250..42993c2d3 100644 --- a/libraries/dl-streamer/python/gstgva/tensor.py +++ b/libraries/dl-streamer/python/gstgva/tensor.py @@ -5,18 +5,17 @@ # ============================================================================== ## @file tensor.py -# @brief This file contains gstgva.tensor.Tensor class which contains and describes neural network inference result +# @brief This file contains gstgva.tensor.Tensor class which contains and describes neural +# network inference result + +# pylint: disable=missing-module-docstring -import ctypes -import numpy -import gi from typing import List from warnings import warn - -gi.require_version("Gst", "1.0") -gi.require_version("GstAnalytics", "1.0") - from enum import Enum +import ctypes +import numpy +import gi from gi.repository import GObject, Gst, GstAnalytics, GLib from .util import ( libgst, @@ -28,41 +27,47 @@ ) from .util import GVATensorMeta +gi.require_version("Gst", "1.0") +gi.require_version("GstAnalytics", "1.0") + -## @brief This class represents tensor - map-like storage for inference result information, such as output blob -# description (output layer dims, layout, rank, precision, etc.), inference result in a raw and interpreted forms. -# Tensor is based on GstStructure and, in general, can contain arbitrary (user-defined) fields of simplest data types, -# like integers, floats & strings. -# Tensor can contain only raw inference result (such Tensor is produced by gvainference in Gstreamer pipeline), -# detection result (such Tensor is produced by gvadetect in Gstreamer pipeline and it's called detection Tensor), or -# both raw & interpreted inference results (such Tensor is produced by gvaclassify in Gstreamer pipeline). -# Tensors can be created and used on their own, or they can be created within RegionOfInterest or VideoFrame instances. -# Usually, in Gstreamer pipeline with GVA elements (gvadetect, gvainference, gvaclassify) Tensor objects will be -# available for access and modification from RegionOfInterest and VideoFrame instances +## @brief This class represents tensor - map-like storage for inference result information, +# such as output blob description (output layer dims, layout, rank, precision, etc.), +# inference result in a raw and interpreted forms. +# Tensor is based on GstStructure and, in general, can contain arbitrary (user-defined) fields of +# simplest data types, like integers, floats & strings. +# Tensor can contain only raw inference result (such Tensor is produced by gvainference in +# Gstreamer pipeline), detection result (such Tensor is produced by gvadetect in Gstreamer +# pipeline and it's called detection Tensor), or both raw & interpreted inference results +# (such Tensor is produced by gvaclassify in Gstreamer pipeline). +# Tensors can be created and used on their own, or they can be created within +# RegionOfInterest or VideoFrame instances. +# Usually, in Gstreamer pipeline with GVA elements (gvadetect, gvainference, gvaclassify) +# Tensor objects will be available for access and modification from +# RegionOfInterest and VideoFrame instances class Tensor: - # TODO: find a way to get these enums from C/C++ code and avoid duplicating - + # pylint: disable=missing-class-docstring,too-many-public-methods ## @brief This enum describes model layer precision class PRECISION(Enum): - UNSPECIFIED = 255 # Unspecified value. Used by default - FP32 = 10 # 32bit floating point value - FP16 = 11 # 16bit floating point value, 5 bit for exponent, 10 bit for mantisa - BF16 = 12 # 16bit floating point value, 8 bit for exponent, 7 bit for mantis - FP64 = 13 # 64bit floating point value - Q78 = 20 # 16bit specific signed fixed point precision - I16 = 30 # 16bit signed integer value - U4 = 39 # 4bit unsigned integer value - U8 = 40 # 8bit unsigned integer value - I4 = 49 # 4bit signed integer value - I8 = 50 # 8bit signed integer value - U16 = 60 # 16bit unsigned integer value - I32 = 70 # 32bit signed integer value - U32 = 74 # 32bit unsigned integer value - I64 = 72 # 64bit signed integer value - U64 = 73 # 64bit unsigned integer value - BIN = 71 # 1bit integer value - BOOL = 41 # 8bit bool type - CUSTOM = 80 # custom precision has it's own name and size of elements + UNSPECIFIED = 255 # Unspecified value. Used by default + FP32 = 10 # 32bit floating point value + FP16 = 11 # 16bit floating point value, 5 bit for exponent, 10 bit for mantisa + BF16 = 12 # 16bit floating point value, 8 bit for exponent, 7 bit for mantis + FP64 = 13 # 64bit floating point value + Q78 = 20 # 16bit specific signed fixed point precision + I16 = 30 # 16bit signed integer value + U4 = 39 # 4bit unsigned integer value + U8 = 40 # 8bit unsigned integer value + I4 = 49 # 4bit signed integer value + I8 = 50 # 8bit signed integer value + U16 = 60 # 16bit unsigned integer value + I32 = 70 # 32bit signed integer value + U32 = 74 # 32bit unsigned integer value + I64 = 72 # 64bit signed integer value + U64 = 73 # 64bit unsigned integer value + BIN = 71 # 1bit integer value + BOOL = 41 # 8bit bool type + CUSTOM = 80 # custom precision has it's own name and size of elements __precision_str = { PRECISION.UNSPECIFIED: "UNSPECIFIED", @@ -110,11 +115,13 @@ class LAYOUT(Enum): ## @brief Get inference result blob dimensions info # @return list of dimensions def dims(self) -> List[int]: + # pylint: disable=missing-function-docstring return self["dims"] ## @brief Get inference results blob precision # @return PRECISION, PRECISION.UNSPECIFIED if can't be read def precision(self) -> PRECISION: + # pylint: disable=missing-function-docstring precision = self["precision"] if precision is None: @@ -125,6 +132,7 @@ def precision(self) -> PRECISION: ## @brief Get inference result blob layout # @return LAYOUT, LAYOUT.ANY if can't be read def layout(self) -> LAYOUT: + # pylint: disable=missing-function-docstring try: return self.LAYOUT(self["layout"]) except: @@ -133,31 +141,27 @@ def layout(self) -> LAYOUT: ## @brief Get raw inference result blob data # @return numpy.ndarray of values representing raw inference data, None if data can't be read def data(self) -> numpy.ndarray | None: + # pylint: disable=missing-function-docstring if self.precision() == self.PRECISION.UNSPECIFIED: return None precision = self.__precision_numpy_dtype[self.precision()] - gvalue = libgst.gst_structure_get_value( - self.__structure, "data_buffer".encode("utf-8") - ) + gvalue = libgst.gst_structure_get_value(self.__structure, "data_buffer".encode("utf-8")) if gvalue: gvariant = libgobject.g_value_get_variant(gvalue) nbytes = ctypes.c_size_t() - data_ptr = libgobject.g_variant_get_fixed_array( - gvariant, ctypes.byref(nbytes), 1 - ) + data_ptr = libgobject.g_variant_get_fixed_array(gvariant, ctypes.byref(nbytes), 1) array_type = ctypes.c_ubyte * nbytes.value - return numpy.ctypeslib.as_array(array_type.from_address(data_ptr)).view( - dtype=precision - ) + return numpy.ctypeslib.as_array(array_type.from_address(data_ptr)).view(dtype=precision) return None ## @brief Get name as a string # @return Tensor instance's name def name(self) -> str: + # pylint: disable=missing-function-docstring name = libgst.gst_structure_get_name(self.__structure) if name: return name.decode("utf-8") @@ -166,105 +170,104 @@ def name(self) -> str: ## @brief Get model name which was used for inference # @return model name as a string, None if failed to get def model_name(self) -> str: + # pylint: disable=missing-function-docstring return self["model_name"] ## @brief Get inference result blob layer name # @return layer name as a string, None if failed to get def layer_name(self) -> str: + # pylint: disable=missing-function-docstring return self["layer_name"] ## @brief Get inference result type # @return type as a string, None if failed to get def type(self) -> str: + # pylint: disable=missing-function-docstring return self["type"] ## @brief Get confidence of inference result # @return confidence of inference result as a float, None if failed to get def confidence(self) -> float: + # pylint: disable=missing-function-docstring return self["confidence"] - ## @brief Get label. This label is set for Tensor instances produced by gvaclassify element. It will raise exception + ## @brief Get label. This label is set for Tensor instances produced by gvaclassify element. + # It will raise exception # if called for detection Tensor. To get detection class label, use RegionOfInterest.label # @return label as a string, None if failed to get def label(self) -> str: + # pylint: disable=missing-function-docstring if not self.is_detection(): return self["label"] - else: - raise RuntimeError("Detection GVA::Tensor can't have label.") + raise RuntimeError("Detection GVA::Tensor can't have label.") ## @brief Get object id # @return object id as an int, None if failed to get def object_id(self) -> int: + # pylint: disable=missing-function-docstring return self["object_id"] ## @brief Get format # @return format as a string, None if failed to get def format(self) -> str: + # pylint: disable=missing-function-docstring return self["format"] ## @brief Get list of fields contained in Tensor instance # @return List of fields contained in Tensor instance def fields(self) -> List[str]: + # pylint: disable=missing-function-docstring return [ libgst.gst_structure_nth_field_name(self.__structure, i).decode("utf-8") - for i in range(self.__len__()) + for i in range(len(self)) ] ## @brief Get item by the field name # @param key Field name # @return Item, None if failed to get def __getitem__(self, key): + # pylint: disable=too-many-return-statements key = key.encode("utf-8") gtype = libgst.gst_structure_get_field_type(self.__structure, key) if gtype == hash(GObject.TYPE_INVALID): # key is not found return None - elif gtype == hash(GObject.TYPE_STRING): + if gtype == hash(GObject.TYPE_STRING): res = libgst.gst_structure_get_string(self.__structure, key) return res.decode("utf-8") if res else None - elif gtype == hash(GObject.TYPE_INT): + if gtype == hash(GObject.TYPE_INT): value = ctypes.c_int() - res = libgst.gst_structure_get_int( - self.__structure, key, ctypes.byref(value) - ) + res = libgst.gst_structure_get_int(self.__structure, key, ctypes.byref(value)) return value.value if res else None - elif gtype == hash(GObject.TYPE_DOUBLE): + if gtype == hash(GObject.TYPE_DOUBLE): value = ctypes.c_double() - res = libgst.gst_structure_get_double( - self.__structure, key, ctypes.byref(value) - ) + res = libgst.gst_structure_get_double(self.__structure, key, ctypes.byref(value)) return value.value if res else None - elif gtype == hash(GObject.TYPE_VARIANT): - # TODO Returning pointer for now that can be used with other ctypes functions - # Return more useful python value + if gtype == hash(GObject.TYPE_VARIANT): return libgst.gst_structure_get_value(self.__structure, key) - elif gtype == hash(GObject.TYPE_POINTER): - # TODO Returning pointer for now that can be used with other ctypes functions - # Return more useful python value + if gtype == hash(GObject.TYPE_POINTER): return libgst.gst_structure_get_value(self.__structure, key) - else: - # try to get value as GValueArray (e.g., "dims" key) - gvalue_array = G_VALUE_ARRAY_POINTER() - is_array = libgst.gst_structure_get_array( - self.__structure, key, ctypes.byref(gvalue_array) - ) - if not is_array: - # Fallback return value - libgst.g_value_array_free(gvalue_array) - return libgst.gst_structure_get_value(self.__structure, key) + + # try to get value as GValueArray (e.g., "dims" key) + gvalue_array = G_VALUE_ARRAY_POINTER() + is_array = libgst.gst_structure_get_array( + self.__structure, key, ctypes.byref(gvalue_array) + ) + if not is_array: + # Fallback return value + libgst.g_value_array_free(gvalue_array) + return libgst.gst_structure_get_value(self.__structure, key) + + value = [] + for i in range(0, gvalue_array.contents.n_values): + g_value = libgobject.g_value_array_get_nth(gvalue_array, ctypes.c_uint(i)) + if g_value.contents.g_type == hash(GObject.TYPE_FLOAT): + value.append(libgobject.g_value_get_float(g_value)) + elif g_value.contents.g_type == hash(GObject.TYPE_UINT): + value.append(libgobject.g_value_get_uint(g_value)) else: - value = list() - for i in range(0, gvalue_array.contents.n_values): - g_value = libgobject.g_value_array_get_nth( - gvalue_array, ctypes.c_uint(i) - ) - if g_value.contents.g_type == hash(GObject.TYPE_FLOAT): - value.append(libgobject.g_value_get_float(g_value)) - elif g_value.contents.g_type == hash(GObject.TYPE_UINT): - value.append(libgobject.g_value_get_uint(g_value)) - else: - raise TypeError("Unsupported value type for GValue array") - libgst.g_value_array_free(gvalue_array) - return value + raise TypeError("Unsupported value type for GValue array") + libgst.g_value_array_free(gvalue_array) + return value ## @brief Get number of fields contained in Tensor instance # @return Number of fields contained in Tensor instance @@ -290,38 +293,44 @@ def __delitem__(self, key: str) -> None: ## @brief Get label id # @return label id as an int, None if failed to get def label_id(self) -> int: + # pylint: disable=missing-function-docstring return self["label_id"] ## @brief Get inference-id property value of GVA element from which this Tensor came - # @return inference-id property value of GVA element from which this Tensor came, None if failed to get + # @return inference-id property value of GVA element from which this Tensor came, + # None if failed to get def element_id(self) -> str: + # pylint: disable=missing-function-docstring return self["element_id"] ## @brief Set Tensor instance's name def set_name(self, name: str) -> None: + # pylint: disable=missing-function-docstring libgst.gst_structure_set_name(self.__structure, name.encode("utf-8")) ## @brief Get inference result blob layout as a string # @return layout as a string, "ANY" if can't be read def layout_as_string(self) -> str: + # pylint: disable=missing-function-docstring layout = self.layout() if layout == self.LAYOUT.NCHW: return "NCHW" - elif layout == self.LAYOUT.NHWC: + if layout == self.LAYOUT.NHWC: return "NHWC" - elif layout == self.LAYOUT.NC: + if layout == self.LAYOUT.NC: return "NC" - else: - return "ANY" + return "ANY" ## @brief Get inference results blob precision as a string # @return precision as a string, "UNSPECIFIED" if can't be read def precision_as_string(self) -> str: + # pylint: disable=missing-function-docstring return self.__precision_str[self.precision()] ## @brief Set label. It will raise exception if called for detection Tensor # @param label label name as a string def set_label(self, label: str) -> None: + # pylint: disable=missing-function-docstring if not self.is_detection(): self["label"] = label else: @@ -331,21 +340,25 @@ def set_label(self, label: str) -> None: # @param field_name field name # @return True if field with this name is found, False otherwise def has_field(self, field_name: str) -> bool: - return True if self[field_name] else False + # pylint: disable=missing-function-docstring + return bool(self[field_name]) ## @brief Check if this Tensor is detection Tensor (contains detection results) # @return True if tensor contains detection results, False otherwise def is_detection(self) -> bool: + # pylint: disable=missing-function-docstring return self.name() == "detection" ## @brief Get underlying GstStructure # @return C-style pointer to GstStructure def get_structure(self) -> ctypes.c_void_p: + # pylint: disable=missing-function-docstring return self.__structure ## @brief Construct Tensor instance from C-style GstStructure # @param structure C-style pointer to GstStructure to create Tensor instance from. - # There are much simpler ways for creating and obtaining Tensor instances - see RegionOfInterest and VideoFrame classes + # There are much simpler ways for creating and obtaining Tensor instances - see + # RegionOfInterest and VideoFrame classes def __init__(self, structure: ctypes.c_void_p): self.__structure = structure if not self.__structure: @@ -356,16 +369,16 @@ def __init__(self, structure: ctypes.c_void_p): # @param item Item def __setitem__(self, key: str, item) -> None: gvalue = GObject.Value() - if type(item) is str: + if isinstance(item, str): gvalue.init(GObject.TYPE_STRING) gvalue.set_string(item) - elif type(item) is int: + elif isinstance(item, int): gvalue.init(GObject.TYPE_INT) gvalue.set_int(item) - elif type(item) is float: + elif isinstance(item, float): gvalue.init(GObject.TYPE_DOUBLE) gvalue.set_double(item) - elif type(item) is list: + elif isinstance(item, list): # code below doesn't work though it's very similar to C code used in GVA which works # gvalue_array = GObject.Value() # libgobject.g_value_init(hash(gvalue), ctypes.c_size_t(24)) # 24 is G_TYPE_INT @@ -373,13 +386,12 @@ def __setitem__(self, key: str, item) -> None: # for i in item: # libgobject.g_value_set_int(hash(gvalue),i) # libgst.gst_value_array_append_value(hash(gvalue_array),hash(gvalue)) - # libgst.gst_structure_set_value(self.__structure, key.encode('utf-8'), hash(gvalue_array)) + # libgst.gst_structure_set_value(self.__structure, key.encode('utf-8'), + # hash(gvalue_array)) raise NotImplementedError else: raise TypeError - libgst.gst_structure_set_value( - self.__structure, key.encode("utf-8"), hash(gvalue) - ) + libgst.gst_structure_set_value(self.__structure, key.encode("utf-8"), hash(gvalue)) @classmethod def _iterate(cls, buffer): @@ -394,7 +406,7 @@ def _iterate(cls, buffer): value = libgst.gst_buffer_iterate_meta_filtered( hash(buffer), ctypes.byref(gpointer), meta_api ) - except Exception as error: + except Exception: value = None if not value: @@ -403,34 +415,28 @@ def _iterate(cls, buffer): tensor_meta = ctypes.cast(value, ctypes.POINTER(GVATensorMeta)).contents yield Tensor(tensor_meta.data) - def convert_to_meta( - self, relation_meta: GstAnalytics.RelationMeta - ) -> GstAnalytics.Mtd | None: + def convert_to_meta(self, relation_meta: GstAnalytics.RelationMeta) -> GstAnalytics.Mtd | None: + # pylint: disable=missing-function-docstring mtd = None if self.type() == "classification_result": - confidence_level = ( - self.confidence() if self.confidence() is not None else 0.0 - ) + confidence_level = self.confidence() if self.confidence() is not None else 0.0 - class_quark = ( - GLib.quark_from_string(self.label()) if self.label() is not None else 0 - ) + class_quark = GLib.quark_from_string(self.label()) if self.label() is not None else 0 success, mtd = relation_meta.add_one_cls_mtd(confidence_level, class_quark) if not success: - raise RuntimeError( - "Failed to add classification metadata to RelationMeta" - ) + raise RuntimeError("Failed to add classification metadata to RelationMeta") return mtd @staticmethod def convert_to_tensor(mtd: GstAnalytics.Mtd) -> ctypes.c_void_p | None: + # pylint: disable=missing-function-docstring structure = libgst.gst_structure_new_empty("tensor".encode("utf-8")) tensor = Tensor(structure) - if type(mtd) == GstAnalytics.ClsMtd: + if isinstance(mtd, GstAnalytics.ClsMtd): class_count = mtd.get_length() result_confidence = 0.0 result_label = "" @@ -448,8 +454,7 @@ def convert_to_tensor(mtd: GstAnalytics.Mtd) -> ctypes.c_void_p | None: result_label += " " result_label += label - if confidence > result_confidence: - result_confidence = confidence + result_confidence = max(result_confidence, confidence) tensor.set_name("classification") tensor.set_label(result_label) @@ -460,7 +465,7 @@ def convert_to_tensor(mtd: GstAnalytics.Mtd) -> ctypes.c_void_p | None: for cls_descriptor_mtd in mtd.meta: if ( cls_descriptor_mtd.id == mtd.id - or type(cls_descriptor_mtd) != GstAnalytics.ClsMtd + or not isinstance(cls_descriptor_mtd, GstAnalytics.ClsMtd) ): continue diff --git a/libraries/dl-streamer/python/gstgva/util.py b/libraries/dl-streamer/python/gstgva/util.py index 2307ef2ea..70d912188 100644 --- a/libraries/dl-streamer/python/gstgva/util.py +++ b/libraries/dl-streamer/python/gstgva/util.py @@ -4,13 +4,17 @@ # SPDX-License-Identifier: MIT # ============================================================================== +# pylint: disable=missing-module-docstring,wrong-import-position + import ctypes from contextlib import contextmanager import gi -gi.require_version('GstVideo', '1.0') -gi.require_version('GstAudio', '1.0') -gi.require_version('GLib', '2.0') -gi.require_version('Gst', '1.0') + +gi.require_version("GstVideo", "1.0") +gi.require_version("GstAudio", "1.0") +gi.require_version("GLib", "2.0") +gi.require_version("Gst", "1.0") + from gi.repository import GstVideo, GstAudio, GLib, GObject, Gst # libgstreamer @@ -21,54 +25,65 @@ class GstMapInfo(ctypes.Structure): - _fields_ = [("memory", ctypes.c_void_p), # GstMemory *memory - ("flags", ctypes.c_int), # GstMapFlags flags - ("data", ctypes.POINTER(ctypes.c_byte)), # guint8 *data - ("size", ctypes.c_size_t), # gsize size - ("maxsize", ctypes.c_size_t), # gsize maxsize - ("user_data", ctypes.c_void_p * 4), # gpointer user_data[4] - ("_gst_reserved", ctypes.c_void_p * GST_PADDING)] + # pylint: disable=missing-class-docstring,too-few-public-methods + _fields_ = [ + ("memory", ctypes.c_void_p), # GstMemory *memory + ("flags", ctypes.c_int), # GstMapFlags flags + ("data", ctypes.POINTER(ctypes.c_byte)), # guint8 *data + ("size", ctypes.c_size_t), # gsize size + ("maxsize", ctypes.c_size_t), # gsize maxsize + ("user_data", ctypes.c_void_p * 4), # gpointer user_data[4] + ("_gst_reserved", ctypes.c_void_p * GST_PADDING), + ] GST_MAP_INFO_POINTER = ctypes.POINTER(GstMapInfo) class GUnion(ctypes.Union): - _fields_ = [('v_int', ctypes.c_int), - ('v_uint', ctypes.c_uint), - ('v_long', ctypes.c_long), - ('v_ulong', ctypes.c_ulong), - ('v_int64', ctypes.c_int64), - ('v_uint64', ctypes.c_uint64), - ('v_float', ctypes.c_float), - ('v_double', ctypes.c_double), - ('v_pointer', ctypes.c_void_p)] + # pylint: disable=missing-class-docstring,too-few-public-methods + _fields_ = [ + ("v_int", ctypes.c_int), + ("v_uint", ctypes.c_uint), + ("v_long", ctypes.c_long), + ("v_ulong", ctypes.c_ulong), + ("v_int64", ctypes.c_int64), + ("v_uint64", ctypes.c_uint64), + ("v_float", ctypes.c_float), + ("v_double", ctypes.c_double), + ("v_pointer", ctypes.c_void_p), + ] class GValue(ctypes.Structure): - _fields_ = [('g_type', ctypes.c_size_t), - ('data', GUnion)] + # pylint: disable=missing-class-docstring,too-few-public-methods + _fields_ = [("g_type", ctypes.c_size_t), ("data", GUnion)] G_VALUE_POINTER = ctypes.POINTER(GValue) class GValueArray(ctypes.Structure): - _fields_ = [("n_values", ctypes.c_uint32), - ("values", ctypes.c_void_p), - ("n_preallocated", ctypes.c_uint32)] + # pylint: disable=missing-class-docstring,too-few-public-methods + _fields_ = [ + ("n_values", ctypes.c_uint32), + ("values", ctypes.c_void_p), + ("n_preallocated", ctypes.c_uint32), + ] class GstMiniObject(ctypes.Structure): + # pylint: disable=missing-class-docstring,too-few-public-methods _fields_ = [ ("type", ctypes.c_void_p), ("refcount", ctypes.c_int), ("lockstate", ctypes.c_int), - ("flags", ctypes.c_uint) + ("flags", ctypes.c_uint), ] class GstMemory(ctypes.Structure): + # pylint: disable=missing-class-docstring,too-few-public-methods _fields_ = [ ("mini_object", GstMiniObject), ("allocator", ctypes.c_void_p), @@ -76,7 +91,7 @@ class GstMemory(ctypes.Structure): ("maxsize", ctypes.c_size_t), ("align", ctypes.c_size_t), ("offset", ctypes.c_size_t), - ("size", ctypes.c_size_t) + ("size", ctypes.c_size_t), ] @@ -84,18 +99,19 @@ class GstMemory(ctypes.Structure): G_VALUE_ARRAY_POINTER = ctypes.POINTER(GValueArray) # gst buffer -libgst.gst_buffer_map.argtypes = [ - ctypes.c_void_p, GST_MAP_INFO_POINTER, ctypes.c_int] +libgst.gst_buffer_map.argtypes = [ctypes.c_void_p, GST_MAP_INFO_POINTER, ctypes.c_int] libgst.gst_buffer_map.restype = ctypes.c_int libgst.gst_buffer_unmap.argtypes = [ctypes.c_void_p, GST_MAP_INFO_POINTER] libgst.gst_buffer_unmap.restype = None libgst.gst_buffer_iterate_meta_filtered.argtypes = [ - ctypes.c_void_p, ctypes.POINTER(ctypes.c_void_p), ctypes.c_void_p] + ctypes.c_void_p, + ctypes.POINTER(ctypes.c_void_p), + ctypes.c_void_p, +] libgst.gst_buffer_iterate_meta_filtered.restype = ctypes.c_void_p libgst.gst_buffer_remove_meta.argtypes = [ctypes.c_void_p, ctypes.c_void_p] libgst.gst_buffer_remove_meta.restype = ctypes.c_bool -libgst.gst_buffer_add_meta.argtypes = [ - ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] +libgst.gst_buffer_add_meta.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] libgst.gst_buffer_add_meta.restype = ctypes.c_void_p libgst.gst_buffer_get_memory.argtypes = [ctypes.c_void_p, ctypes.c_int] libgst.gst_buffer_get_memory.restype = GST_MEMORY_POINTER @@ -121,29 +137,35 @@ class GstMemory(ctypes.Structure): libgst.gst_structure_has_name.restype = ctypes.c_bool libgst.gst_structure_set_name.argtypes = [ctypes.c_void_p, ctypes.c_char_p] libgst.gst_structure_set_name.restypes = None -libgst.gst_structure_set_value.argtypes = [ - ctypes.c_void_p, ctypes.c_char_p, ctypes.c_void_p] +libgst.gst_structure_set_value.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_void_p] libgst.gst_structure_set_value.restypes = None -libgst.gst_structure_set_array.argtypes = [ - ctypes.c_void_p, ctypes.c_char_p, ctypes.c_void_p] +libgst.gst_structure_set_array.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_void_p] libgst.gst_structure_set_array.restypes = None libgst.gst_structure_remove_field.argtypes = [ctypes.c_void_p, ctypes.c_char_p] libgst.gst_structure_remove_field.restypes = None -libgst.gst_structure_get_field_type.argtypes = [ - ctypes.c_void_p, ctypes.c_char_p] +libgst.gst_structure_get_field_type.argtypes = [ctypes.c_void_p, ctypes.c_char_p] libgst.gst_structure_get_field_type.restypes = ctypes.c_size_t libgst.gst_structure_get_string.argtypes = [ctypes.c_void_p, ctypes.c_char_p] libgst.gst_structure_get_string.restype = ctypes.c_char_p libgst.gst_structure_get_value.argtypes = [ctypes.c_void_p, ctypes.c_char_p] libgst.gst_structure_get_value.restype = ctypes.c_void_p libgst.gst_structure_get_int.argtypes = [ - ctypes.c_void_p, ctypes.c_char_p, ctypes.POINTER(ctypes.c_int)] + ctypes.c_void_p, + ctypes.c_char_p, + ctypes.POINTER(ctypes.c_int), +] libgst.gst_structure_get_int.restype = ctypes.c_int libgst.gst_structure_get_double.argtypes = [ - ctypes.c_void_p, ctypes.c_char_p, ctypes.POINTER(ctypes.c_double)] + ctypes.c_void_p, + ctypes.c_char_p, + ctypes.POINTER(ctypes.c_double), +] libgst.gst_structure_get_double.restype = ctypes.c_int libgst.gst_structure_get_array.argtypes = [ - ctypes.c_void_p, ctypes.c_char_p, ctypes.POINTER(G_VALUE_ARRAY_POINTER)] + ctypes.c_void_p, + ctypes.c_char_p, + ctypes.POINTER(G_VALUE_ARRAY_POINTER), +] libgst.gst_structure_get_array.restype = ctypes.c_bool libgst.gst_structure_n_fields.argtypes = [ctypes.c_void_p] libgst.gst_structure_n_fields.restype = ctypes.c_int @@ -174,13 +196,13 @@ class GstMemory(ctypes.Structure): def is_vaapi_buffer(_buffer): + # pylint: disable=missing-function-docstring if _buffer is None: raise TypeError("Passed buffer is None") mem = libgst.gst_buffer_get_memory(hash(_buffer), 0) if mem is None: return False - res = libgst.gst_memory_is_type( - mem, GST_VAAPI_VIDEO_MEMORY_NAME.encode('utf-8')) + res = libgst.gst_memory_is_type(mem, GST_VAAPI_VIDEO_MEMORY_NAME.encode("utf-8")) # gst_memory_unref mem.contents.mini_object.refcount -= 1 return res @@ -188,6 +210,7 @@ def is_vaapi_buffer(_buffer): @contextmanager def GST_PAD_PROBE_INFO_BUFFER(info): + # pylint: disable=missing-function-docstring _buffer = info.get_buffer() _buffer.mini_object.refcount -= 1 try: @@ -198,6 +221,7 @@ def GST_PAD_PROBE_INFO_BUFFER(info): @contextmanager def TRANSFORM_IP_BUFFER(_buffer): + # pylint: disable=missing-function-docstring _buffer.mini_object.refcount -= 1 try: yield _buffer @@ -207,6 +231,7 @@ def TRANSFORM_IP_BUFFER(_buffer): @contextmanager def gst_buffer_data(_buffer, flags): + # pylint: disable=missing-function-docstring if _buffer is None: raise TypeError("Cannot pass NULL to gst_buffer_map") @@ -234,16 +259,14 @@ def gst_buffer_data(_buffer, flags): class GList(ctypes.Structure): + # pylint: disable=missing-class-docstring,too-few-public-methods pass GLIST_POINTER = ctypes.POINTER(GList) -GList._fields_ = [ - ('data', ctypes.c_void_p), - ('next', GLIST_POINTER), - ('prev', GLIST_POINTER) -] +# pylint: disable=protected-access +GList._fields_ = [("data", ctypes.c_void_p), ("next", GLIST_POINTER), ("prev", GLIST_POINTER)] libgobject.g_type_name.argtypes = [ctypes.c_void_p] @@ -257,12 +280,19 @@ class GList(ctypes.Structure): libgobject.g_value_set_variant.argtypes = [ctypes.c_void_p, ctypes.c_void_p] libgobject.g_value_set_variant.restype = None libgobject.g_variant_get_fixed_array.argtypes = [ - ctypes.c_void_p, ctypes.POINTER(ctypes.c_size_t), ctypes.c_size_t] + ctypes.c_void_p, + ctypes.POINTER(ctypes.c_size_t), + ctypes.c_size_t, +] libgobject.g_variant_get_fixed_array.restype = ctypes.c_void_p libgobject.g_list_remove.argtypes = [GLIST_POINTER, ctypes.c_void_p] libgobject.g_list_remove.restypes = GLIST_POINTER libgobject.g_variant_new_fixed_array.argtypes = [ - ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t, ctypes.c_size_t] + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_size_t, + ctypes.c_size_t, +] libgobject.g_variant_new_fixed_array.restype = ctypes.c_void_p libgobject.g_value_array_new.argtypes = [ctypes.c_size_t] libgobject.g_value_array_new.restype = G_VALUE_ARRAY_POINTER @@ -272,7 +302,7 @@ class GList(ctypes.Structure): libgobject.g_value_set_uint.restype = ctypes.c_void_p libgobject.g_value_set_int.argtypes = [ctypes.c_void_p, ctypes.c_size_t] libgobject.g_value_set_int.restype = ctypes.c_void_p -libgobject.g_value_array_append.argtypes = [G_VALUE_ARRAY_POINTER, ctypes.c_void_p] +libgobject.g_value_array_append.argtypes = [G_VALUE_ARRAY_POINTER, ctypes.c_void_p] libgobject.g_value_array_append.restype = G_VALUE_ARRAY_POINTER libgobject.g_value_array_get_nth.argtypes = [G_VALUE_ARRAY_POINTER, ctypes.c_uint] libgobject.g_value_array_get_nth.restype = G_VALUE_POINTER @@ -289,47 +319,58 @@ class GList(ctypes.Structure): # libgstvideo libgstvideo = ctypes.CDLL("libgstvideo-1.0.so.0") + # VideoRegionOfInterestMeta class VideoRegionOfInterestMeta(ctypes.Structure): + # pylint: disable=missing-class-docstring,too-few-public-methods _fields_ = [ - ('_meta_flags', ctypes.c_int), - ('_info', ctypes.c_void_p), - ('roi_type', ctypes.c_int), - ('id', ctypes.c_int), - ('parent_id', ctypes.c_int), - ('x', ctypes.c_int), - ('y', ctypes.c_int), - ('w', ctypes.c_int), - ('h', ctypes.c_int), - ('_params', GLIST_POINTER) + ("_meta_flags", ctypes.c_int), + ("_info", ctypes.c_void_p), + ("roi_type", ctypes.c_int), + ("id", ctypes.c_int), + ("parent_id", ctypes.c_int), + ("x", ctypes.c_int), + ("y", ctypes.c_int), + ("w", ctypes.c_int), + ("h", ctypes.c_int), + ("_params", GLIST_POINTER), ] VIDEO_REGION_OF_INTEREST_POINTER = ctypes.POINTER(VideoRegionOfInterestMeta) libgstvideo.gst_video_region_of_interest_meta_get_param.argtypes = [ - VIDEO_REGION_OF_INTEREST_POINTER, ctypes.c_char_p] + VIDEO_REGION_OF_INTEREST_POINTER, + ctypes.c_char_p, +] libgstvideo.gst_video_region_of_interest_meta_get_param.restype = ctypes.c_void_p libgstvideo.gst_video_region_of_interest_meta_add_param.argtypes = [ - VIDEO_REGION_OF_INTEREST_POINTER, ctypes.c_void_p] + VIDEO_REGION_OF_INTEREST_POINTER, + ctypes.c_void_p, +] libgstvideo.gst_video_region_of_interest_meta_add_param.restype = None libgstvideo.gst_buffer_get_video_region_of_interest_meta_id.argtypes = [ - ctypes.c_void_p, ctypes.c_uint] + ctypes.c_void_p, + ctypes.c_uint, +] libgstvideo.gst_buffer_get_video_region_of_interest_meta_id.restype = ctypes.c_void_p + # GVATensorMeta class GVATensorMeta(ctypes.Structure): + # pylint: disable=missing-class-docstring,too-few-public-methods _fields_ = [ - ('_meta_flags', ctypes.c_int), - ('_info', ctypes.c_void_p), - ('data', ctypes.c_void_p) + ("_meta_flags", ctypes.c_int), + ("_info", ctypes.c_void_p), + ("data", ctypes.c_void_p), ] @classmethod def add_tensor_meta(cls, buffer): + # pylint: disable=missing-function-docstring try: - tensor_meta_info = libgst.gst_meta_get_info("GstGVATensorMeta".encode('utf-8')) + tensor_meta_info = libgst.gst_meta_get_info("GstGVATensorMeta".encode("utf-8")) value = libgst.gst_buffer_add_meta(hash(buffer), tensor_meta_info, None) - except Exception as error: + except Exception: value = None if not value: @@ -339,55 +380,64 @@ def add_tensor_meta(cls, buffer): class GVAJSONMetaStr(str): + # pylint: disable=missing-class-docstring def __new__(cls, meta, content): return super().__new__(cls, content) def __init__(self, meta, content): + # pylint: disable=unused-argument self.meta = meta super().__init__() # GVAJSONMeta class GVAJSONMeta(ctypes.Structure): - _fields_ = [('_meta_flags', ctypes.c_int), - ('_info', ctypes.c_void_p), - ('_message', ctypes.c_char_p) - ] + # pylint: disable=missing-class-docstring + _fields_ = [ + ("_meta_flags", ctypes.c_int), + ("_info", ctypes.c_void_p), + ("_message", ctypes.c_char_p), + ] def get_message(self): - return GVAJSONMetaStr(self, self._message.decode('utf-8')) + # pylint: disable=missing-function-docstring + return GVAJSONMetaStr(self, self._message.decode("utf-8")) @classmethod def remove_json_meta(cls, buffer, meta): + # pylint: disable=missing-function-docstring return libgst.gst_buffer_remove_meta(hash(buffer), ctypes.byref(meta)) @classmethod def add_json_meta(cls, buffer, message): + # pylint: disable=missing-function-docstring try: - json_meta_info = libgst.gst_meta_get_info("GstGVAJSONMeta".encode('utf-8')) + json_meta_info = libgst.gst_meta_get_info("GstGVAJSONMeta".encode("utf-8")) value = libgst.gst_buffer_add_meta(hash(buffer), json_meta_info, None) - except Exception as error: + except Exception: value = None if value is None: return meta = ctypes.cast(value, ctypes.POINTER(GVAJSONMeta)).contents - meta._message = libglib.g_strdup(message.encode('utf-8')) + meta._message = libglib.g_strdup(message.encode("utf-8")) return meta @classmethod def iterate(cls, buffer): + # pylint: disable=missing-function-docstring try: meta_api = hash(GObject.GType.from_name("GstGVAJSONMetaAPI")) except: return gpointer = ctypes.c_void_p() - while(True): + while True: try: value = libgst.gst_buffer_iterate_meta_filtered( - hash(buffer), ctypes.byref(gpointer), meta_api) - except Exception as error: + hash(buffer), ctypes.byref(gpointer), meta_api + ) + except Exception: value = None if not value: @@ -395,29 +445,33 @@ def iterate(cls, buffer): yield ctypes.cast(value, ctypes.POINTER(GVAJSONMeta)).contents + def _VideoInfoFromCaps(caps): return GstVideo.VideoInfo.new_from_caps(caps) + def _VideoInfoFromCaps_Legacy(caps): video_info = GstVideo.VideoInfo() video_info.from_caps(caps) return video_info + def _AudioInfoFromCaps(caps): return GstAudio.AudioInfo.new_from_caps(caps) + def _AudioInfoFromCaps_Legacy(caps): audio_info = GstAudio.AudioInfo() audio_info.from_caps(caps) return audio_info + # Check for GST 1.20 APIs # pylint: disable=method-hidden VideoInfoFromCaps = _VideoInfoFromCaps_Legacy -if hasattr(GstVideo.VideoInfo, 'new_from_caps'): +if hasattr(GstVideo.VideoInfo, "new_from_caps"): VideoInfoFromCaps = _VideoInfoFromCaps AudioInfoFromCaps = _AudioInfoFromCaps_Legacy -if hasattr(GstAudio.AudioInfo, 'new_from_caps'): +if hasattr(GstAudio.AudioInfo, "new_from_caps"): AudioInfoFromCaps = _AudioInfoFromCaps - diff --git a/libraries/dl-streamer/python/gstgva/video_frame.py b/libraries/dl-streamer/python/gstgva/video_frame.py index c94faab34..1fd2a669d 100644 --- a/libraries/dl-streamer/python/gstgva/video_frame.py +++ b/libraries/dl-streamer/python/gstgva/video_frame.py @@ -234,13 +234,6 @@ def data(self, flag: Gst.MapFlags = Gst.MapFlags.READ) -> numpy.ndarray: requested_size = h * w * bytes_per_pix if mapped_data_size != requested_size: - warn( - "Size of buffer's data: {}, and requested size: {}\n" - "Let to get shape from video meta...".format( - mapped_data_size, requested_size - ), - stacklevel=2, - ) meta = self.video_meta() if meta: h, w = meta.height, meta.width @@ -352,4 +345,4 @@ def __get_label_by_label_id(region_tensor: Gst.Structure, label_id: int) -> str: res = region_tensor.get_array("labels") if res[0] and 0 <= label_id < res[1].n_values: return res[1].get_nth(label_id) - return "" + return "" \ No newline at end of file diff --git a/libraries/dl-streamer/samples/gstreamer/gst_launch/gvapython/face_detection_and_classification/postproc_callbacks/age_gender_classification.py b/libraries/dl-streamer/samples/gstreamer/gst_launch/gvapython/face_detection_and_classification/postproc_callbacks/age_gender_classification.py index 85b71b0b8..d7f8f3d69 100644 --- a/libraries/dl-streamer/samples/gstreamer/gst_launch/gvapython/face_detection_and_classification/postproc_callbacks/age_gender_classification.py +++ b/libraries/dl-streamer/samples/gstreamer/gst_launch/gvapython/face_detection_and_classification/postproc_callbacks/age_gender_classification.py @@ -1,5 +1,5 @@ # ============================================================================== -# Copyright (C) 2018-2021 Intel Corporation +# Copyright (C) 2018-2025 Intel Corporation # # SPDX-License-Identifier: MIT # ============================================================================== @@ -10,19 +10,19 @@ def process_frame(frame: VideoFrame) -> bool: for roi in frame.regions(): for tensor in roi.tensors(): - if tensor.name() == 'detection': + if tensor.name() == "detection": continue layer_name = tensor.layer_name() data = tensor.data() - if 'age_conv3' == layer_name: + if "age_conv3" == layer_name: tensor.set_label(str(int(data[0] * 100))) tensor.set_name("age") continue - if 'prob' == layer_name: + if "prob" == layer_name: tensor.set_label(" M " if data[1] > 0.5 else " F ") tensor.set_name("gender") continue - if 'prob_emotion' == layer_name: + if "prob_emotion" == layer_name: emotions = ["neutral", "happy", "sad", "surprise", "anger"] tensor.set_label(emotions[data.index(max(data))]) tensor.set_name("emotion") diff --git a/libraries/dl-streamer/samples/gstreamer/gst_launch/gvapython/face_detection_and_classification/postproc_callbacks/age_logger.py b/libraries/dl-streamer/samples/gstreamer/gst_launch/gvapython/face_detection_and_classification/postproc_callbacks/age_logger.py index 022f6d56d..653d331c3 100644 --- a/libraries/dl-streamer/samples/gstreamer/gst_launch/gvapython/face_detection_and_classification/postproc_callbacks/age_logger.py +++ b/libraries/dl-streamer/samples/gstreamer/gst_launch/gvapython/face_detection_and_classification/postproc_callbacks/age_logger.py @@ -1,23 +1,27 @@ # ============================================================================== -# Copyright (C) 2018-2021 Intel Corporation +# Copyright (C) 2018-2025 Intel Corporation # # SPDX-License-Identifier: MIT # ============================================================================== -from gstgva import VideoFrame +# pylint: disable=missing-module-docstring +from gstgva import VideoFrame class AgeLogger: + # pylint: disable=missing-class-docstring def __init__(self, log_file_path): - self.log_file = open(log_file_path, "a") + # pylint: disable=consider-using-with + self.log_file = open(log_file_path, "a", encoding="utf-8") def log_age(self, frame: VideoFrame) -> bool: + # pylint: disable=missing-function-docstring for roi in frame.regions(): for tensor in roi.tensors(): - if tensor.name() == 'detection': + if tensor.name() == "detection": continue layer_name = tensor.layer_name() - if 'age_conv3' == layer_name: + if "age_conv3" == layer_name: self.log_file.write(tensor.label() + "\n") continue return True diff --git a/libraries/dl-streamer/samples/gstreamer/gst_launch/gvapython/face_detection_and_classification/postproc_callbacks/ssd_object_detection.py b/libraries/dl-streamer/samples/gstreamer/gst_launch/gvapython/face_detection_and_classification/postproc_callbacks/ssd_object_detection.py index 477462193..8841880e5 100644 --- a/libraries/dl-streamer/samples/gstreamer/gst_launch/gvapython/face_detection_and_classification/postproc_callbacks/ssd_object_detection.py +++ b/libraries/dl-streamer/samples/gstreamer/gst_launch/gvapython/face_detection_and_classification/postproc_callbacks/ssd_object_detection.py @@ -1,22 +1,25 @@ # ============================================================================== -# Copyright (C) 2018-2021 Intel Corporation +# Copyright (C) 2018-2025 Intel Corporation # # SPDX-License-Identifier: MIT # ============================================================================== +# pylint: disable=missing-module-docstring + import sys import gi -gi.require_version('Gst', '1.0') from gi.repository import Gst, GObject - from gstgva import VideoFrame +gi.require_version("Gst", "1.0") + DETECT_THRESHOLD = 0.5 Gst.init(sys.argv) def process_frame(frame: VideoFrame, threshold: float = DETECT_THRESHOLD) -> bool: + # pylint: disable=missing-function-docstring,too-many-locals width = frame.video_info().width height = frame.video_info().height @@ -39,6 +42,7 @@ def process_frame(frame: VideoFrame, threshold: float = DETECT_THRESHOLD) -> boo continue roi = frame.add_region( - x_min, y_min, x_max - x_min, y_max - y_min, str(label_id), confidence) + x_min, y_min, x_max - x_min, y_max - y_min, str(label_id), confidence + ) return True diff --git a/libraries/dl-streamer/samples/gstreamer/python/draw_face_attributes/draw_face_attributes.py b/libraries/dl-streamer/samples/gstreamer/python/draw_face_attributes/draw_face_attributes.py index 474b3bffa..2121f8d64 100755 --- a/libraries/dl-streamer/samples/gstreamer/python/draw_face_attributes/draw_face_attributes.py +++ b/libraries/dl-streamer/samples/gstreamer/python/draw_face_attributes/draw_face_attributes.py @@ -4,42 +4,61 @@ # SPDX-License-Identifier: MIT # ============================================================================== -from gstgva import VideoFrame, util +# pylint: disable=missing-module-docstring + import sys import os +from argparse import ArgumentParser +from gstgva import VideoFrame, util import numpy import cv2 -from argparse import ArgumentParser - import gi -gi.require_version('GObject', '2.0') -gi.require_version('Gst', '1.0') -gi.require_version('GstApp', '1.0') -gi.require_version('GstVideo', '1.0') from gi.repository import Gst, GLib, GstApp, GstVideo +gi.require_version("GObject", "2.0") +gi.require_version("Gst", "1.0") +gi.require_version("GstApp", "1.0") +gi.require_version("GstVideo", "1.0") + parser = ArgumentParser(add_help=False) -_args = parser.add_argument_group('Options') -_args.add_argument("-i", "--input", help="Required. Path to input video file", - required=True, type=str) -_args.add_argument("-d", "--detection_model", help="Required. Path to an .xml file with object detection model", - required=True, type=str) -_args.add_argument("-c1", "--classification_model1", - help="Required. Path to an .xml file with object classification model", - required=True, type=str) -_args.add_argument("-c2", "--classification_model2", - help="Required. Path to an .xml file with object classification model", - required=True, type=str) -_args.add_argument("-c3", "--classification_model3", - help="Required. Path to an .xml file with object classification model", - required=True, type=str) -_args.add_argument("-o", "--output", - help="Required. Output type", - required=True, type=str) +_args = parser.add_argument_group("Options") +_args.add_argument( + "-i", "--input", help="Required. Path to input video file", required=True, type=str +) +_args.add_argument( + "-d", + "--detection_model", + help="Required. Path to an .xml file with object detection model", + required=True, + type=str, +) +_args.add_argument( + "-c1", + "--classification_model1", + help="Required. Path to an .xml file with object classification model", + required=True, + type=str, +) +_args.add_argument( + "-c2", + "--classification_model2", + help="Required. Path to an .xml file with object classification model", + required=True, + type=str, +) +_args.add_argument( + "-c3", + "--classification_model3", + help="Required. Path to an .xml file with object classification model", + required=True, + type=str, +) +_args.add_argument("-o", "--output", help="Required. Output type", required=True, type=str) args = parser.parse_args() def frame_callback(frame: VideoFrame): + # pylint: disable=missing-function-docstring with frame.data() as mat: for roi in frame.regions(): labels = [] @@ -51,8 +70,7 @@ def frame_callback(frame: VideoFrame): for i in range(0, len(data), 2): x = int(rect.x + rect.w * data[i]) y = int(rect.y + rect.h * data[i + 1]) - cv2.circle(mat, (x, y), int( - 1 + 0.02 * rect.w), lm_color, -1) + cv2.circle(mat, (x, y), int(1 + 0.02 * rect.w), lm_color, -1) elif "prob" == tensor.layer_name(): data = tensor.data() if data[1] > 0.5: @@ -70,11 +88,19 @@ def frame_callback(frame: VideoFrame): if labels: label = " ".join(labels) - cv2.putText(mat, label, (rect.x, rect.y + rect.h + 30), - cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) + cv2.putText( + mat, + label, + (rect.x, rect.y + rect.h + 30), + cv2.FONT_HERSHEY_SIMPLEX, + 1, + (0, 0, 255), + 2, + ) def pad_probe_callback(pad, info): + # pylint: disable=missing-function-docstring with util.GST_PAD_PROBE_INFO_BUFFER(info) as buffer: caps = pad.get_current_caps() frame = VideoFrame(buffer, caps=caps) @@ -84,6 +110,7 @@ def pad_probe_callback(pad, info): def create_launch_string(): + # pylint: disable=missing-function-docstring if "/dev/video" in args.input: source = "v4l2src device" elif "://" in args.input: @@ -92,10 +119,12 @@ def create_launch_string(): source = "filesrc location" if args.output == "display": - sink = "gvawatermark name=gvawatermark ! videoconvert n-threads=4 ! gvafpscounter ! autovideosink sync=false" + sink = ("gvawatermark name=gvawatermark ! videoconvert n-threads=4" + + " ! gvafpscounter ! autovideosink sync=false") elif args.output == "display-and-json": - sink = "gvametaconvert ! gvametapublish file-format=json-lines file-path=output.json ! \ - gvawatermark name=gvawatermark ! videoconvert n-threads=4 ! gvafpscounter ! autovideosink sync=false" + sink = ("gvametaconvert ! gvametapublish file-format=json-lines file-path=output.json" + + " ! gvawatermark name=gvawatermark ! videoconvert n-threads=4 ! gvafpscounter" + + " ! autovideosink sync=false") elif args.output == "json": sink = "gvametaconvert ! gvametapublish file-format=json-lines file-path=output.json ! \ gvafpscounter ! fakesink sync=false" @@ -103,16 +132,17 @@ def create_launch_string(): print("Unsupported output type") sys.exit() - return f"{source}={args.input} ! decodebin3 ! \ - videoconvert n-threads=4 ! capsfilter caps=\"video/x-raw,format=BGRx\" ! \ + return f'{source}={args.input} ! decodebin3 ! \ + videoconvert n-threads=4 ! capsfilter caps="video/x-raw,format=BGRx" ! \ gvadetect model={args.detection_model} device=CPU ! queue ! \ gvainference model={args.classification_model1} device=CPU inference-region=roi-list ! queue ! \ gvainference model={args.classification_model2} device=CPU inference-region=roi-list ! queue ! \ gvainference model={args.classification_model3} device=CPU inference-region=roi-list ! queue ! \ - {sink}" + {sink}' def glib_mainloop(): + # pylint: disable=missing-function-docstring mainloop = GLib.MainLoop() try: mainloop.run() @@ -121,6 +151,7 @@ def glib_mainloop(): def bus_call(bus, message, pipeline): + # pylint: disable=missing-function-docstring,redefined-outer-name,unused-argument t = message.type if t == Gst.MessageType.EOS: print("pipeline ended") @@ -128,7 +159,7 @@ def bus_call(bus, message, pipeline): sys.exit() elif t == Gst.MessageType.ERROR: err, debug = message.parse_error() - print("Error:\n{}\nAdditional debug info:\n{}\n".format(err, debug)) + print(f"Error:\n{err}\nAdditional debug info:\n{debug}\n") pipeline.set_state(Gst.State.NULL) sys.exit() else: @@ -137,7 +168,8 @@ def bus_call(bus, message, pipeline): def set_callbacks(pipeline): - if(args.output != "json"): + # pylint: disable=missing-function-docstring,redefined-outer-name + if args.output != "json": gvawatermark = pipeline.get_by_name("gvawatermark") pad = gvawatermark.get_static_pad("src") pad.add_probe(Gst.PadProbeType.BUFFER, pad_probe_callback) @@ -147,7 +179,7 @@ def set_callbacks(pipeline): bus.connect("message", bus_call, pipeline) -if __name__ == '__main__': +if __name__ == "__main__": Gst.init(sys.argv) gst_launch_string = create_launch_string() print(gst_launch_string) diff --git a/libraries/dl-streamer/scripts/optimizer/optimizer.py b/libraries/dl-streamer/scripts/optimizer/optimizer.py index f68e2c3e2..befe0db0c 100644 --- a/libraries/dl-streamer/scripts/optimizer/optimizer.py +++ b/libraries/dl-streamer/scripts/optimizer/optimizer.py @@ -4,6 +4,8 @@ # SPDX-License-Identifier: MIT # ============================================================================== +# pylint: disable=missing-module-docstring + import argparse import time import logging @@ -13,9 +15,11 @@ import subprocess import gi -gi.require_version("Gst", "1.0") from gi.repository import Gst +gi.require_version("Gst", "1.0") + + ####################################### Init ###################################################### Gst.init() @@ -23,14 +27,13 @@ logger = logging.getLogger(__name__) logger.info("GStreamer initialized successfully") gst_version = Gst.version() -logger.info("GStreamer version: %d.%d.%d", - gst_version.major, - gst_version.minor, - gst_version.micro) +logger.info("GStreamer version: %d.%d.%d", gst_version.major, gst_version.minor, gst_version.micro) ####################################### Utils ##################################################### + def parse_element_parameters(element): + # pylint: disable=missing-function-docstring parameters = element.strip().split(" ") del parameters[0] parsed_parameters = {} @@ -40,48 +43,60 @@ def parse_element_parameters(element): return parsed_parameters + def assemble_parameters(parameters): + # pylint: disable=missing-function-docstring result = "" for parameter, value in parameters.items(): result = result + parameter + "=" + value + " " return result + def log_parameters_of_interest(pipeline): + # pylint: disable=missing-function-docstring for element in pipeline: if "gvadetect" in element: parameters = parse_element_parameters(element) - logger.info("Found Gvadetect, device: %s, batch size: %s, nireqs: %s", - parameters.get("device", "not set"), - parameters.get("batch-size", "not set"), - parameters.get("nireq", "not set")) + logger.info( + "Found Gvadetect, device: %s, batch size: %s, nireqs: %s", + parameters.get("device", "not set"), + parameters.get("batch-size", "not set"), + parameters.get("nireq", "not set"), + ) if "gvaclassify" in element: parameters = parse_element_parameters(element) - logger.info("Found Gvaclassify, device: %s, batch size: %s, nireqs: %s", - parameters.get("device", "not set"), - parameters.get("batch-size", "not set"), - parameters.get("nireq", "not set")) + logger.info( + "Found Gvaclassify, device: %s, batch size: %s, nireqs: %s", + parameters.get("device", "not set"), + parameters.get("batch-size", "not set"), + parameters.get("nireq", "not set"), + ) + ###################################### System Scanning ############################################ + def scan_system(): - context = {"GPU": False, - "NPU": False} + # pylint: disable=missing-function-docstring + context = {"GPU": False, "NPU": False} # check for presence of GPU try: - gpu_query = subprocess.run(["dpkg", "-l", "intel-opencl-icd"], - stderr=subprocess.DEVNULL, - stdout=subprocess.DEVNULL, - check=False) + gpu_query = subprocess.run( + ["dpkg", "-l", "intel-opencl-icd"], + stderr=subprocess.DEVNULL, + stdout=subprocess.DEVNULL, + check=False, + ) gpu_dir = os.listdir("/dev/dri") for file in gpu_dir: if "render" in file and gpu_query.returncode == 0: context["GPU"] = True # can happen on missing directory, signifies no GPU support - except Exception: # pylint: disable=broad-exception-caught + except Exception: # pylint: disable=broad-exception-caught pass if context["GPU"]: @@ -91,17 +106,19 @@ def scan_system(): # check for presence of NPU try: - npu_query = subprocess.run(["dpkg", "-l", "intel-driver-compiler-npu"], - stderr=subprocess.DEVNULL, - stdout=subprocess.DEVNULL, - check=False) + npu_query = subprocess.run( + ["dpkg", "-l", "intel-driver-compiler-npu"], + stderr=subprocess.DEVNULL, + stdout=subprocess.DEVNULL, + check=False, + ) npu_dir = os.listdir("/dev/accel/") for file in npu_dir: if "accel" in file and npu_query.returncode == 0: context["NPU"] = True # can happen on missing directory, signifies no NPU support - except Exception: # pylint: disable=broad-exception-caught + except Exception: # pylint: disable=broad-exception-caught pass if context["NPU"]: @@ -111,9 +128,12 @@ def scan_system(): return context + ##################################### Pipeline Running ############################################ + def explore_pipelines(suggestions, base_fps, search_duration, sample_duration): + # pylint: disable=missing-function-docstring start_time = time.time() combinations = itertools.product(*suggestions) # first element is the original pipeline, use it as baseline @@ -139,7 +159,9 @@ def explore_pipelines(suggestions, base_fps, search_duration, sample_duration): return best_pipeline, best_fps + def sample_pipeline(pipeline, sample_duration): + # pylint: disable=missing-function-docstring,too-many-locals pipeline = pipeline.copy() # check if there is an fps counter after the last inference element @@ -158,7 +180,9 @@ def sample_pipeline(pipeline, sample_duration): pipeline = Gst.parse_launch(pipeline) logger.info("Sampling for %s seconds...", str(sample_duration)) - fps_counter = next(filter(lambda element: "gvafpscounter" in element.name, reversed(pipeline.children))) # pylint: disable=line-too-long + fps_counter = next( + filter(lambda element: "gvafpscounter" in element.name, reversed(pipeline.children)) + ) # pylint: disable=line-too-long bus = pipeline.get_bus() @@ -203,6 +227,7 @@ def sample_pipeline(pipeline, sample_duration): logger.debug("Sampled fps: %f.2", fps) return fps + ######################################## Preprocess ############################################### preprocessing_rules = { @@ -215,7 +240,9 @@ def sample_pipeline(pipeline, sample_duration): r"\bdecodebin\b": "decodebin3", } + def preprocess_pipeline(pipeline): + # pylint: disable=missing-function-docstring pipeline = "!".join(pipeline) for pattern, replacement in preprocessing_rules.items(): if re.search(pattern, pipeline): @@ -223,9 +250,12 @@ def preprocess_pipeline(pipeline): pipeline = pipeline.split("!") return pipeline + #################################### Gvadetect & Gvaclassify ###################################### + def add_device_suggestions(suggestions, context): + # pylint: disable=missing-function-docstring for suggestion in suggestions: for element in ["gvadetect", "gvaclassify"]: if element in suggestion[0]: @@ -245,7 +275,9 @@ def add_device_suggestions(suggestions, context): parameters["pre-process-backend"] = "opencv" suggestion.append(f" {element} {assemble_parameters(parameters)}") + def add_batch_suggestions(suggestions, _): + # pylint: disable=missing-function-docstring batches = [1, 2, 4, 8, 16, 32] for suggestion in suggestions: for element in ["gvadetect", "gvaclassify"]: @@ -257,6 +289,7 @@ def add_batch_suggestions(suggestions, _): def add_nireq_suggestions(suggestions, _): + # pylint: disable=missing-function-docstring nireqs = range(1, 9) for suggestion in suggestions: for element in ["gvadetect", "gvaclassify"]: @@ -266,8 +299,10 @@ def add_nireq_suggestions(suggestions, _): parameters["nireq"] = str(nireq) suggestion.append(f" {element} {assemble_parameters(parameters)}") + ####################################### Main Logic ################################################ + # Steps of pipeline optimization: # 1. Measure the baseline pipeline's performace. # 2. Pre-process the pipeline to cover cases where we're certain of the best alternative. @@ -277,7 +312,8 @@ def add_nireq_suggestions(suggestions, _): # and start running the combinations to measure performance. # 6. Any time a better pipeline is found, save it and its performance information. # 7. Return the best discovered pipeline. -def get_optimized_pipeline(pipeline, search_duration = 300, sample_duration = 10): +def get_optimized_pipeline(pipeline, search_duration=300, sample_duration=10): + # pylint: disable=missing-function-docstring context = scan_system() pipeline = pipeline.split("!") @@ -314,7 +350,9 @@ def get_optimized_pipeline(pipeline, search_duration = 300, sample_duration = 10 # Reconstruct the pipeline as a single string and return it. return "!".join(pipeline), fps + def prepare_suggestions(pipeline): + # pylint: disable=missing-function-docstring # Prepare the suggestions structure # Suggestions structure: # [ @@ -330,27 +368,37 @@ def prepare_suggestions(pipeline): def main(): + # pylint: disable=missing-function-docstring parser = argparse.ArgumentParser( prog="DLStreamer Pipeline Optimization Tool", - description="Use this tool to try and find versions of your pipeline that will run with increased performance." # pylint: disable=line-too-long + description=("Use this tool to try and find versions of " + + "your pipeline that will run with increased performance."), ) - parser.add_argument("--search-duration", default=300, - help="Duration of time which should be spent searching for optimized pipelines (default: %(default)ss)") # pylint: disable=line-too-long - parser.add_argument("--sample-duration", default=10, - help="Duration of sampling individual pipelines. Longer duration should offer more stable results (default: %(default)ss)") # pylint: disable=line-too-long - parser.add_argument("pipeline", nargs="+", - help="Pipeline to be analyzed") - args=parser.parse_args() + parser.add_argument( + "--search-duration", + default=300, + help=("Duration of time which should be spent searching " + + "for optimized pipelines (default: %(default)ss)"), + ) # pylint: disable=line-too-long + parser.add_argument( + "--sample-duration", + default=10, + help=("Duration of sampling individual pipelines. Longer duration should" + + "offer more stable results (default: %(default)ss)"), + ) # pylint: disable=line-too-long + parser.add_argument("pipeline", nargs="+", help="Pipeline to be analyzed") + args = parser.parse_args() pipeline = " ".join(args.pipeline) try: - best_pipeline, best_fps = get_optimized_pipeline(pipeline, - args.search_duration, - args.sample_duration) + best_pipeline, best_fps = get_optimized_pipeline( + pipeline, args.search_duration, args.sample_duration + ) logger.info("\nBest found pipeline: %s \nwith fps: %f.2", best_pipeline, best_fps) - except Exception as e: # pylint: disable=broad-exception-caught + except Exception as e: # pylint: disable=broad-exception-caught logger.error("Failed to optimize pipeline: %s", e) + if __name__ == "__main__": main() diff --git a/libraries/dl-streamer/src/gst/python/inference_openvino.py b/libraries/dl-streamer/src/gst/python/inference_openvino.py index 7b813a34e..75c44ba21 100644 --- a/libraries/dl-streamer/src/gst/python/inference_openvino.py +++ b/libraries/dl-streamer/src/gst/python/inference_openvino.py @@ -1,15 +1,16 @@ #!/usr/bin/python3 # ============================================================================== -# Copyright (C) 2022 Intel Corporation +# Copyright (C) 2022-2025 Intel Corporation # # SPDX-License-Identifier: MIT # ============================================================================== import gi -gi.require_version('Gst', '1.0') -gi.require_version('GstBase', '1.0') -gi.require_version('GstVideo', '1.0') + +gi.require_version("Gst", "1.0") +gi.require_version("GstBase", "1.0") +gi.require_version("GstVideo", "1.0") from gi.repository import Gst, GObject, GLib, GstBase, GstVideo import numpy as np @@ -23,16 +24,42 @@ class InferenceOpenVINO(GstBase.BaseTransform): - __gstmetadata__ = ('OpenVINO inference', 'Transform', - 'OpenVINO™ toolkit inference element', 'dkl') - - __gsttemplates__ = (Gst.PadTemplate.new("sink", Gst.PadDirection.SINK, Gst.PadPresence.ALWAYS, TENSORS_CAPS), - Gst.PadTemplate.new("src", Gst.PadDirection.SRC, Gst.PadPresence.ALWAYS, TENSORS_CAPS)) + __gstmetadata__ = ( + "OpenVINO inference", + "Transform", + "OpenVINO™ toolkit inference element", + "dkl", + ) + + __gsttemplates__ = ( + Gst.PadTemplate.new("sink", Gst.PadDirection.SINK, Gst.PadPresence.ALWAYS, TENSORS_CAPS), + Gst.PadTemplate.new("src", Gst.PadDirection.SRC, Gst.PadPresence.ALWAYS, TENSORS_CAPS), + ) __gproperties__ = { - "model": (GObject.TYPE_STRING, "model", "OpenVINO™ toolkit model path", "", GObject.ParamFlags.READWRITE), - "device": (GObject.TYPE_STRING, "device", "Inference device", "CPU", GObject.ParamFlags.READWRITE), - "nireq": (GObject.TYPE_INT64, "nireq", "Number inference requests", 0, GLib.MAXINT, 0, GObject.ParamFlags.READWRITE), + "model": ( + GObject.TYPE_STRING, + "model", + "OpenVINO™ toolkit model path", + "", + GObject.ParamFlags.READWRITE, + ), + "device": ( + GObject.TYPE_STRING, + "device", + "Inference device", + "CPU", + GObject.ParamFlags.READWRITE, + ), + "nireq": ( + GObject.TYPE_INT64, + "nireq", + "Number inference requests", + 0, + GLib.MAXINT, + 0, + GObject.ParamFlags.READWRITE, + ), } def __init__(self, gproperties=__gproperties__): @@ -40,8 +67,11 @@ def __init__(self, gproperties=__gproperties__): self.property = {} # default values for key, value in gproperties.items(): - self.property[key] = value[3] if value[0] in ( - bool, str, GObject.TYPE_STRING, GObject.TYPE_BOOLEAN) else value[5] + self.property[key] = ( + value[3] + if value[0] in (bool, str, GObject.TYPE_STRING, GObject.TYPE_BOOLEAN) + else value[5] + ) self.core = Core() self.model = None @@ -56,29 +86,29 @@ def do_get_property(self, prop: GObject.GParamSpec): def read_model(self): if not self.model: - model = self.core.read_model(self.property['model']) + model = self.core.read_model(self.property["model"]) ppp = PrePostProcessor(model) - ppp.input().tensor().set_layout(Layout('NHWC')).set_element_type(Type.u8) + ppp.input().tensor().set_layout(Layout("NHWC")).set_element_type(Type.u8) self.model = ppp.build() def compile_model(self): if not self.compiled_model: - self.compiled_model = self.core.compile_model( - self.model, self.property['device']) - if self.property['nireq'] != 1: - self.infer_queue = AsyncInferQueue( - self.compiled_model, self.property['nireq']) + self.compiled_model = self.core.compile_model(self.model, self.property["device"]) + if self.property["nireq"] != 1: + self.infer_queue = AsyncInferQueue(self.compiled_model, self.property["nireq"]) self.infer_queue.set_callback(self.completion_callback) def do_transform_caps(self, direction, caps, filter): self.read_model() infos = self.model.inputs if direction == Gst.PadDirection.SRC else self.model.outputs - shapes = [":".join(str(d) for d in np.array(info.shape)[::-1]) - for info in infos] # dims in reverse order - types = [self.TYPE_NAME[info.element_type.get_type_name()] - for info in infos] - caps_str = 'other/tensors,num_tensors=(uint){num},types={types},dimensions={shapes}'.format( - num=len(infos), types=",".join(types), shapes=",".join(shapes)) + shapes = [ + ":".join(str(d) for d in np.array(info.shape)[::-1]) for info in infos + ] # dims in reverse order + types = [self.TYPE_NAME[info.element_type.get_type_name()] for info in infos] + num = len(infos) + types = ",".join(types) + shapes = ",".join(shapes) + caps_str = f"other/tensors,num_tensors=(uint){num},types={types},dimensions={shapes}" my_caps = Gst.Caps.from_string(caps_str) if filter: my_caps = my_caps.intersect(filter) @@ -95,8 +125,10 @@ def do_generate_output(self): # Map all Gst.Memory to numpy arrays mems = [src.get_memory(i) for i in range(src.n_memory())] maps = [mem.map(Gst.MapFlags.READ)[1] for mem in mems] - tensors = [np.ndarray(shape=info.shape, buffer=map.data, dtype=np.uint8) - for map, info in zip(maps, self.model.inputs)] + tensors = [ + np.ndarray(shape=info.shape, buffer=map.data, dtype=np.uint8) + for map, info in zip(maps, self.model.inputs) + ] # Submit async inference request or run inference synchronously if self.infer_queue: @@ -120,8 +152,7 @@ def push_results(self, src, mems, maps, tensors): # Wrap output tensors into Gst.Memory and attach to Gst.Buffer dst = Gst.Buffer.new() for tensor in tensors: - mem = Gst.Memory.new_wrapped( - 0, tensor.tobytes(), tensor.nbytes, 0, None, None) + mem = Gst.Memory.new_wrapped(0, tensor.tobytes(), tensor.nbytes, 0, None, None) dst.append_memory(mem) # Copy timestamps from input buffer @@ -131,7 +162,7 @@ def push_results(self, src, mems, maps, tensors): self.srcpad.push(dst) def do_sink_event(self, event): - if (event.type == Gst.EventType.EOS or event.type == Gst.EventType.FLUSH_STOP) and self.infer_queue: + if event.type in (Gst.EventType.EOS, Gst.EventType.FLUSH_STOP) and self.infer_queue: self.infer_queue.wait_all() return GstBase.BaseTransform.do_sink_event(self, event) @@ -140,13 +171,9 @@ def do_stop(self): self.infer_queue.wait_all() return True - TYPE_NAME = { - "u8": "uint8", - "f32": "float32" - } + TYPE_NAME = {"u8": "uint8", "f32": "float32"} GObject.type_register(InferenceOpenVINO) -__gstelementfactory__ = ("inference_openvino", - Gst.Rank.NONE, InferenceOpenVINO) +__gstelementfactory__ = ("inference_openvino", Gst.Rank.NONE, InferenceOpenVINO) diff --git a/libraries/dl-streamer/src/gst/python/python_object_association.py b/libraries/dl-streamer/src/gst/python/python_object_association.py index abe8db4e1..b8c722444 100644 --- a/libraries/dl-streamer/src/gst/python/python_object_association.py +++ b/libraries/dl-streamer/src/gst/python/python_object_association.py @@ -1,15 +1,16 @@ #!/usr/bin/python3 # ============================================================================== -# Copyright (C) 2023 Intel Corporation +# Copyright (C) 2023-2025 Intel Corporation # # SPDX-License-Identifier: MIT # ============================================================================== import gi -gi.require_version('Gst', '1.0') -gi.require_version('GstBase', '1.0') -gi.require_version('GstVideo', '1.0') + +gi.require_version("Gst", "1.0") +gi.require_version("GstBase", "1.0") +gi.require_version("GstVideo", "1.0") from gi.repository import Gst, GObject, GstBase, GLib from gstgva import VideoFrame @@ -24,7 +25,8 @@ Gst.init(None) VIDEO_CAPS = Gst.Caps.from_string( - "video/x-raw; video/x-raw(memory:DMABuf); video/x-raw(memory:VASurface)") + "video/x-raw; video/x-raw(memory:DMABuf); video/x-raw(memory:VASurface)" +) OBJECT_CLASS_DEFAULT = "" @@ -55,52 +57,80 @@ def iou(bbox_1: list, bbox_2: list) -> float: class Identifier(GstBase.BaseTransform): - __gstmetadata__ = ('ID assignment tracking algorithm', 'Transform', - "ID assignment SORT type tracking algorithm which require embedding from each ROI to cosine comparison.", - 'Intel Corporation') + __gstmetadata__ = ( + "ID assignment tracking algorithm", + "Transform", + ("ID assignment SORT type tracking algorithm which require " + + "embedding from each ROI to cosine comparison."), + "Intel Corporation", + ) - __gsttemplates__ = (Gst.PadTemplate.new("sink", Gst.PadDirection.SINK, Gst.PadPresence.ALWAYS, VIDEO_CAPS), - Gst.PadTemplate.new("src", Gst.PadDirection.SRC, Gst.PadPresence.ALWAYS, VIDEO_CAPS)) + __gsttemplates__ = ( + Gst.PadTemplate.new("sink", Gst.PadDirection.SINK, Gst.PadPresence.ALWAYS, VIDEO_CAPS), + Gst.PadTemplate.new("src", Gst.PadDirection.SRC, Gst.PadPresence.ALWAYS, VIDEO_CAPS), + ) __gproperties__ = { "object-class": ( - str, "object-class", + str, + "object-class", "Filter for Region of Interest class label on this element input.", - OBJECT_CLASS_DEFAULT, GObject.ParamFlags.READWRITE + OBJECT_CLASS_DEFAULT, + GObject.ParamFlags.READWRITE, ), "overwrite-roi": ( - bool, "overwrite-roi", + bool, + "overwrite-roi", "If True, input ROIs will be overwritten with tracker's output.", - REWRITE_ROI_DEFAULT, GObject.ParamFlags.READWRITE + REWRITE_ROI_DEFAULT, + GObject.ParamFlags.READWRITE, ), "save-object-class-label": ( - bool, "save-object-class-label", + bool, + "save-object-class-label", """If true, the label from `object-class` will be saved during ROI overwriting.""", - SAVE_LABEL_DEFAULT, GObject.ParamFlags.READWRITE + SAVE_LABEL_DEFAULT, + GObject.ParamFlags.READWRITE, ), "n-init": ( - int, "n-init", + int, + "n-init", """Number of consecutive detections before the track is confirmed. The \t\ttrack state is set to `Deleted` if a miss occurs within the first `n-init` frames.""", - 1, GLib.MAXINT, N_INIT_DEFAULT, GObject.ParamFlags.READWRITE + 1, + GLib.MAXINT, + N_INIT_DEFAULT, + GObject.ParamFlags.READWRITE, ), "max-age": ( - int, "max-age", + int, + "max-age", "Maximum number of missed misses before a track is deleted.", - 0, GLib.MAXINT, MAX_AGE_DEFAULT, GObject.ParamFlags.READWRITE + 0, + GLib.MAXINT, + MAX_AGE_DEFAULT, + GObject.ParamFlags.READWRITE, ), "max-iou-distance": ( - float, "max-iou-distance", + float, + "max-iou-distance", """The matching IoU threshold. Samples with larger distance are considered \t\tan invalid match.""", - 0., 1., MAX_IOU_DISTANCE_DEFAULT, GObject.ParamFlags.READWRITE + 0.0, + 1.0, + MAX_IOU_DISTANCE_DEFAULT, + GObject.ParamFlags.READWRITE, ), "nn-budget": ( - int, "nn-budget", + int, + "nn-budget", """Fix samples per class to at most this number. Removes \t\tthe oldest samples when the budget is reached.""", - 0, GLib.MAXINT, NN_BUDGET_DEFAULT, GObject.ParamFlags.READWRITE - ) + 0, + GLib.MAXINT, + NN_BUDGET_DEFAULT, + GObject.ParamFlags.READWRITE, + ), } def __init__(self, gproperties=__gproperties__): @@ -108,39 +138,49 @@ def __init__(self, gproperties=__gproperties__): self.property = {} # default values for key, value in gproperties.items(): - self.property[key] = value[3] if value[0] in ( - bool, str) else value[5] + self.property[key] = value[3] if value[0] in (bool, str) else value[5] + + self._object_class = None + self._rewrite_roi = None + self._save_label = None + self._nn_budget = None + self._max_iou_distance = None + self._max_age = None + self._n_init = None + self.__write_result = None def __get_properties(self): - self._object_class = self.property['object-class'] - self._rewrite_roi = self.property['overwrite-roi'] - self._save_label = self.property['save-object-class-label'] - self._nn_budget = self.property['nn-budget'] - self._max_iou_distance = self.property['max-iou-distance'] - self._max_age = self.property['max-age'] - self._n_init = self.property['n-init'] + self._object_class = self.property["object-class"] + self._rewrite_roi = self.property["overwrite-roi"] + self._save_label = self.property["save-object-class-label"] + self._nn_budget = self.property["nn-budget"] + self._max_iou_distance = self.property["max-iou-distance"] + self._max_age = self.property["max-age"] + self._n_init = self.property["n-init"] def __init_on_start(self): self.__get_properties() - metric = NearestNeighborDistanceMetric( - "cosine", self._max_iou_distance, self._nn_budget - ) + metric = NearestNeighborDistanceMetric("cosine", self._max_iou_distance, self._nn_budget) self._tracker = Tracker( metric, max_iou_distance=self._max_iou_distance, max_age=self._max_age, - n_init=self._n_init + n_init=self._n_init, ) - self.__write_result = self.__rewrite_regions_with_tracks if self._rewrite_roi else self.__write_ids_to_regions + self.__write_result = ( + self.__rewrite_regions_with_tracks if self._rewrite_roi else self.__write_ids_to_regions + ) if self._save_label and not self._rewrite_roi: Gst.warning( - "`save-object-class-label` property is true while `overwrite-roi` is False.") + "`save-object-class-label` property is true while `overwrite-roi` is False." + ) if self._save_label and not self._object_class: Gst.warning( - "`save-object-class-label` property is true while `object-class` is not defined.") + "`save-object-class-label` property is true while `object-class` is not defined." + ) self._save_label = self._object_class and self._rewrite_roi and self._save_label self._label_to_save = self._object_class if self._save_label else "" @@ -162,7 +202,9 @@ def __get_detections(self, regions): if len(tensors) > 2: # TODO: create special label for embedding Gst.warning( - f"Limitation: must be only 1 tensor meta per ROI which is embedding, except detection meta.") + "Limitation: must be only 1 tensor meta per ROI which " + + "is embedding, except detection meta." + ) continue embedding = None @@ -175,8 +217,7 @@ def __get_detections(self, regions): bounding_box = list(region.rect()) confidence = region.confidence() - detections.append( - Detection(bounding_box, confidence, embedding)) + detections.append(Detection(bounding_box, confidence, embedding)) return detections @@ -185,7 +226,8 @@ def __get_tracks(self, detections): self._tracker.update(detections) confirmed_tracks = [ - track for track in self._tracker.tracks + track + for track in self._tracker.tracks if track.is_confirmed() and track.time_since_update <= 1 ] @@ -197,8 +239,7 @@ def __rewrite_regions_with_tracks(self, dst_vf, regions, tracks): with warnings.catch_warnings(): warnings.simplefilter("ignore") for track in tracks: - region = dst_vf.add_region( - *track.to_tlwh(), label=self._label_to_save) + region = dst_vf.add_region(*track.to_tlwh(), label=self._label_to_save) region.set_object_id(int(track.track_id)) def __write_ids_to_regions(self, dst_vf, regions, tracks): @@ -212,9 +253,11 @@ def do_transform_ip(self, in_buffer: Gst.Buffer): try: dst_vf = VideoFrame(in_buffer) - regions = [r for r in dst_vf.regions() - if self._object_class and r.label() == self._object_class - or not self._object_class] + regions = [ + r + for r in dst_vf.regions() + if self._object_class and r.label() == self._object_class or not self._object_class + ] detections = self.__get_detections(regions) @@ -231,5 +274,4 @@ def do_transform_ip(self, in_buffer: Gst.Buffer): GObject.type_register(Identifier) -__gstelementfactory__ = ("python_object_association", - Gst.Rank.NONE, Identifier) +__gstelementfactory__ = ("python_object_association", Gst.Rank.NONE, Identifier) diff --git a/libraries/dl-streamer/src/gst/python/pytorch_tensor_inference.py b/libraries/dl-streamer/src/gst/python/pytorch_tensor_inference.py index 88cdb1c6f..fdacd7ab1 100644 --- a/libraries/dl-streamer/src/gst/python/pytorch_tensor_inference.py +++ b/libraries/dl-streamer/src/gst/python/pytorch_tensor_inference.py @@ -1,15 +1,16 @@ #!/usr/bin/python3 # ============================================================================== -# Copyright (C) 2022-2024 Intel Corporation +# Copyright (C) 2022-2025 Intel Corporation # # SPDX-License-Identifier: MIT # ============================================================================== import gi -gi.require_version('Gst', '1.0') -gi.require_version('GstBase', '1.0') -gi.require_version('GstVideo', '1.0') + +gi.require_version("Gst", "1.0") +gi.require_version("GstBase", "1.0") +gi.require_version("GstVideo", "1.0") from gi.repository import Gst, GObject, GstBase @@ -49,8 +50,7 @@ def str_to_datatype(data_type: str): if data_type == "int32": return np.int32 - raise RuntimeError( - "Unknown data type. Can't convert it to numpy data type") + raise RuntimeError("Unknown data type. Can't convert it to numpy data type") def datatype_to_str(data_type) -> str: @@ -70,7 +70,7 @@ def str_to_list(arr: str) -> list: if not arr: return list() - res = map(lambda x: int(x), arr.split(':')) + res = map(lambda x: int(x), arr.split(":")) return list(res) @@ -99,14 +99,14 @@ def gst_caps_to_tensor_info(caps: Gst.Caps, caps_index: int) -> List[TensorInfo] if not strides_str: strides_str = "" - types_array = types_str.split(',') - shapes_array = shapes_str.split(',') if shapes_str else list() - strides_array = strides_str.split(',') if strides_str else list() + types_array = types_str.split(",") + shapes_array = shapes_str.split(",") if shapes_str else [] + strides_array = strides_str.split(",") if strides_str else [] for i in range(num_tensors): data_type = str_to_datatype(types_array[i]) - shape = str_to_list(shapes_array[i]) if shapes_array else list() - stride = str_to_list(strides_array[i]) if strides_array else list() + shape = str_to_list(shapes_array[i]) if shapes_array else [] + stride = str_to_list(strides_array[i]) if strides_array else [] # reverse order shape.reverse() @@ -121,11 +121,12 @@ def tensor_info_to_gst_caps(tensors_info: List[TensorInfo]) -> Gst.Caps: if not tensors_info: return Gst.Caps.new_any() - dtypes_str = ",".join(datatype_to_str(tensor_info.data_type) - for tensor_info in tensors_info) - shapes_str = ",".join(":".join( - str(d) for d in tensor_info.shape[::-1]) for tensor_info in tensors_info) - caps_str = f"other/tensors,num_tensors=(uint){len(tensors_info)},types=(string)\"{dtypes_str}\",dimensions=(string)\"{shapes_str}\"" + dtypes_str = ",".join(datatype_to_str(tensor_info.data_type) for tensor_info in tensors_info) + shapes_str = ",".join( + ":".join(str(d) for d in tensor_info.shape[::-1]) for tensor_info in tensors_info + ) + caps_str = f'other/tensors,num_tensors=(uint){len(tensors_info)}' + caps_str += f',types=(string)"{dtypes_str}",dimensions=(string)"{shapes_str}"' return Gst.Caps.from_string(caps_str) @@ -139,17 +140,38 @@ def is_pytorch_model(model_str: str) -> bool: class InferencePyTorch(GstBase.BaseTransform): - __gstmetadata__ = ('PyTorch inference', 'Transform', - 'PyTorch inference element', 'dkl') + __gstmetadata__ = ("PyTorch inference", "Transform", "PyTorch inference element", "dkl") - __gsttemplates__ = (Gst.PadTemplate.new("sink", Gst.PadDirection.SINK, Gst.PadPresence.ALWAYS, TENSORS_CAPS), - Gst.PadTemplate.new("src", Gst.PadDirection.SRC, Gst.PadPresence.ALWAYS, TENSORS_CAPS)) + __gsttemplates__ = ( + Gst.PadTemplate.new("sink", Gst.PadDirection.SINK, Gst.PadPresence.ALWAYS, TENSORS_CAPS), + Gst.PadTemplate.new("src", Gst.PadDirection.SRC, Gst.PadPresence.ALWAYS, TENSORS_CAPS), + ) # TODO: support batching __gproperties__ = { - "model": (GObject.TYPE_STRING, "model", "The full module name of the PyTorch model to be imported from torchvision or model path. Ex. 'torchvision.models.resnet50' or '/path/to/model.pth'", "", GObject.ParamFlags.READWRITE), - "model-weights": (GObject.TYPE_STRING, "model_weights", "PyTorch model weights path. If model-weights is empty, the default weights will be used", "", GObject.ParamFlags.READWRITE), - "device": (GObject.TYPE_STRING, "device", "Inference device", "cpu", GObject.ParamFlags.READWRITE) + "model": ( + GObject.TYPE_STRING, + "model", + ("The full module name of the PyTorch model to be imported from torchvision " + + "or model path. Ex. 'torchvision.models.resnet50' or '/path/to/model.pth'"), + "", + GObject.ParamFlags.READWRITE, + ), + "model-weights": ( + GObject.TYPE_STRING, + "model_weights", + ("PyTorch model weights path. If model-weights is empty, the default " + + "weights will be used"), + "", + GObject.ParamFlags.READWRITE, + ), + "device": ( + GObject.TYPE_STRING, + "device", + "Inference device", + "cpu", + GObject.ParamFlags.READWRITE, + ), } def __init__(self, gproperties=__gproperties__): @@ -157,8 +179,11 @@ def __init__(self, gproperties=__gproperties__): self.property = {} # default values for key, value in gproperties.items(): - self.property[key] = value[3] if value[0] in ( - bool, str, GObject.TYPE_STRING, GObject.TYPE_BOOLEAN) else value[5] + self.property[key] = ( + value[3] + if value[0] in (bool, str, GObject.TYPE_STRING, GObject.TYPE_BOOLEAN) + else value[5] + ) self.device = torch.device(self.property["device"]) self.model = None @@ -178,7 +203,9 @@ def init_pytorch_model(self): model_name_arr = model_str.split(".") if len(model_name_arr) < 2: raise AttributeError( - f"Invalid module name in property 'model'. It must include at least the name of the import module and the name of the model. Got: {model_str}") + "Invalid module name in property 'model'. It must include at least " + + f"the name of the import module and the name of the model. Got: {model_str}" + ) model_name = model_name_arr[-1] import_module = ".".join(module for module in model_name_arr[:-1]) @@ -187,8 +214,7 @@ def init_pytorch_model(self): if self.property["model-weights"]: self.model = creator() - self.model.load_state_dict( - torch.load(self.property["model-weights"])) + self.model.load_state_dict(torch.load(self.property["model-weights"])) else: weights_class = None for attr in dir(module): @@ -202,7 +228,9 @@ def init_pytorch_model(self): model_args["weights"] = weights_class.DEFAULT else: Gst.warning( - "No suitable class with weights was found in the module. No pre-trained weights are used") + "No suitable class with weights was found in the module. " + + "No pre-trained weights are used" + ) self.model = creator(**model_args) else: @@ -235,8 +263,7 @@ def do_transform_caps(self, direction, caps, filter): if not self.output_tensors_info: for i in range(caps.get_size()): input_tensors_info = gst_caps_to_tensor_info(caps, i) - output_tensors_info = self.get_output_tensors_info( - input_tensors_info) + output_tensors_info = self.get_output_tensors_info(input_tensors_info) if output_tensors_info: self.input_tensors_info = input_tensors_info self.output_tensors_info = output_tensors_info @@ -246,7 +273,8 @@ def do_transform_caps(self, direction, caps, filter): else: if not self.input_tensors_info: self.input_tensors_info = self.get_input_tensor_info_from_model() - # Input shapes must be specified with capsfilter before the tensor_convert element if preprocessing information could not be obtained from the model + # Input shapes must be specified with capsfilter before the tensor_convert + # element if preprocessing information could not be obtained from the model my_caps = tensor_info_to_gst_caps(self.input_tensors_info) if filter: @@ -258,9 +286,13 @@ def do_transform_caps(self, direction, caps, filter): return Gst.Caps.new_empty() def get_output_tensors_info(self, input_tensors_info: List[TensorInfo]) -> List[TensorInfo]: - if len(input_tensors_info) != 1: # TODO: remove limitation. Support models with multiple inputs + if ( + len(input_tensors_info) != 1 + ): raise RuntimeError( - f"Models with one layer only are supported now. Got tensors array from caps size of: {len(input_tensors_info)}") + "Models with one layer only are supported now. Got tensors array " + + f"from caps size of: {len(input_tensors_info)}" + ) output_tensors_info = list() input_tensor_info = input_tensors_info[0] @@ -273,22 +305,20 @@ def get_output_tensors_info(self, input_tensors_info: List[TensorInfo]) -> List[ self.model.to(self.device) # load model to device try: - # The forward function can contain arbitrary python code. Forward dummy tensor to see the output + # The forward function can contain arbitrary python code. + # Forward dummy tensor to see the output x = torch.randn(input_tensor_info.shape, device=self.device) x = x.unsqueeze(0) # add batch dimension output = self.model(x)[0] # TODO: support batching except Exception as model_exc: - Gst.debug( - f"Model inferencing failed at caps transform stage: {str(model_exc)}") + Gst.debug(f"Model inferencing failed at caps transform stage: {str(model_exc)}") return output_tensors_info # wait for the next input tensor shape if isinstance(output, torch.Tensor): - output_tensors_info.append( - TensorInfo(output.shape, output.dtype, [])) + output_tensors_info.append(TensorInfo(output.shape, output.dtype, [])) elif isinstance(output, dict): for tensor in output.values(): - output_tensors_info.append( - TensorInfo(tensor.shape, tensor.dtype, [])) + output_tensors_info.append(TensorInfo(tensor.shape, tensor.dtype, [])) else: raise RuntimeError("Unsupported model output") @@ -305,14 +335,16 @@ def get_input_tensor_info_from_model(self) -> List[TensorInfo]: if not isinstance(preproc, ImageClassification): return input_tensors_info - # TODO: Parse the remaining preprocessing information and pass it to the preprocessing sub-pipeline resize_size = preproc.resize_size if len(resize_size) != 1: Gst.warning( - "Unsupported resize size. Unable to parse preprocessing info from weights. Default values from caps will be used") + "Unsupported resize size. Unable to parse preprocessing info from weights. " + + "Default values from caps will be used" + ) else: - input_tensors_info.append(TensorInfo( - [3, resize_size[0], resize_size[0]], torch.float32, [])) + input_tensors_info.append( + TensorInfo([3, resize_size[0], resize_size[0]], torch.float32, []) + ) return input_tensors_info @@ -339,7 +371,7 @@ def add_model_info(self, buf): input_shapes = "" input_types = "" for i, tensor_info in enumerate(self.input_tensors_info): - if (i): + if i: input_shapes += "," input_types += "," @@ -375,17 +407,19 @@ def do_generate_output(self): input_tensor_info = self.input_tensors_info[0] if not input_tensor_info.shape: - raise RuntimeError( - "Input shape is empty. Unable to create tensor") + raise RuntimeError("Input shape is empty. Unable to create tensor") - nd_arr = np.ndarray(shape=input_tensor_info.shape, - buffer=map.data, dtype=input_tensor_info.data_type) - tensor = torch.Tensor(nd_arr, device=self.device).float( - ).unsqueeze(0) # FIXME: support batching + nd_arr = np.ndarray( + shape=input_tensor_info.shape, + buffer=map.data, + dtype=input_tensor_info.data_type, + ) + tensor = ( + torch.Tensor(nd_arr, device=self.device).float().unsqueeze(0) + ) with torch.no_grad(): - output_tensor = self.model.forward( - tensor)[0] # FIXME: support batching + output_tensor = self.model.forward(tensor)[0] # Unmap input Gst.Memory mem.unmap(map) @@ -397,7 +431,8 @@ def do_generate_output(self): self.append_tensor_to_buffer(dst, output_tensor) else: raise RuntimeError( - f"Unsupported inference output type: '{type(output_tensor)}'") + f"Unsupported inference output type: '{type(output_tensor)}'" + ) # Copy timestamps from input buffer dst.copy_into(src, Gst.BufferCopyFlags.TIMESTAMPS, 0, 0) @@ -415,14 +450,15 @@ def append_tensor_to_buffer(self, buf: Gst.Buffer, tensor: torch.Tensor): mem = self.gst_alloc.alloc(tensor_nd_arr.nbytes) if not mem: - raise RuntimeError( - "Unable to allocate memory using default gst allocator") + raise RuntimeError("Unable to allocate memory using default gst allocator") res, map = mem.map(Gst.MapFlags.WRITE) if not res: raise RuntimeError("Unable to map gst memory to write") - np.copyto(np.ndarray(shape=tensor_nd_arr.shape, - buffer=map.data, dtype=tensor_nd_arr.dtype), tensor_nd_arr) + np.copyto( + np.ndarray(shape=tensor_nd_arr.shape, buffer=map.data, dtype=tensor_nd_arr.dtype), + tensor_nd_arr, + ) mem.unmap(map) buf.append_memory(mem) @@ -430,5 +466,4 @@ def append_tensor_to_buffer(self, buf: Gst.Buffer, tensor: torch.Tensor): GObject.type_register(InferencePyTorch) -__gstelementfactory__ = ("pytorch_tensor_inference", - Gst.Rank.NONE, InferencePyTorch) +__gstelementfactory__ = ("pytorch_tensor_inference", Gst.Rank.NONE, InferencePyTorch) diff --git a/libraries/dl-streamer/tests/scripts/unit_test_results.py b/libraries/dl-streamer/tests/scripts/unit_test_results.py index cce5982d9..e6974ab6e 100644 --- a/libraries/dl-streamer/tests/scripts/unit_test_results.py +++ b/libraries/dl-streamer/tests/scripts/unit_test_results.py @@ -7,7 +7,7 @@ import xml.etree.ElementTree as ET import sys -#usage: python unit_test_results.py path/to/your/results +# usage: python unit_test_results.py path/to/your/results results_path = sys.argv[1] @@ -16,51 +16,57 @@ summary_file = f"{results_path}/unit_test_summary.txt" + def extract_test_results(xml_file, test_type): tree = ET.parse(xml_file) root = tree.getroot() failed_tests = [] -#for pytests; attributes are in which is a child of - if test_type == 'pytest' and root.tag == 'testsuites': - testsuite = root.find('testsuite') + # for pytests; attributes are in which is a child of + if test_type == "pytest" and root.tag == "testsuites": + testsuite = root.find("testsuite") else: testsuite = root - total = int(testsuite.attrib.get('tests', 0)) - failed = int(testsuite.attrib.get('failures', 0)) - errors = int(testsuite.attrib.get('errors', 0)) - skipped = int(testsuite.attrib.get('skipped', 0)) + total = int(testsuite.attrib.get("tests", 0)) + failed = int(testsuite.attrib.get("failures", 0)) + errors = int(testsuite.attrib.get("errors", 0)) + skipped = int(testsuite.attrib.get("skipped", 0)) - for testcase in testsuite.findall('testcase'): - if test_type == 'ctest': - if testcase.get('status') == 'fail': - failed_tests.append(testcase.attrib['name']) - elif test_type == 'pytest': - failure = testcase.find('failure') + for testcase in testsuite.findall("testcase"): + if test_type == "ctest": + if testcase.get("status") == "fail": + failed_tests.append(testcase.attrib["name"]) + elif test_type == "pytest": + failure = testcase.find("failure") if failure is not None: - failed_tests.append(testcase.attrib['name']) + failed_tests.append(testcase.attrib["name"]) passed = total - failed - errors - skipped return total, passed, failed, errors, skipped, failed_tests + def save_summary(test_type, results): - with open(summary_file, 'a') as f: - f.write(f"{test_type}: Total: {results[0]}, Passed: {results[1]}, " - f"Failed: {results[2]}, Errors: {results[3]}, Skipped: {results[4]}\n") + with open(summary_file, "a", encoding="utf-8") as f: + f.write( + f"{test_type}: Total: {results[0]}, Passed: {results[1]}, " + f"Failed: {results[2]}, Errors: {results[3]}, Skipped: {results[4]}\n" + ) if results[2] > 0: f.write(f"Failed tests ({test_type}):\n") for test_name in results[5]: f.write(f" - {test_name}\n") -#ctests + + +# ctests try: - ctest_results = extract_test_results(ctest_result_xml, 'ctest') + ctest_results = extract_test_results(ctest_result_xml, "ctest") save_summary("CTest", ctest_results) except FileNotFoundError: print(f"File not found {ctest_result_xml}") -#pytests +# pytests try: - pytest_results = extract_test_results(pytest_result_xml, 'pytest') + pytest_results = extract_test_results(pytest_result_xml, "pytest") save_summary("Pytest", pytest_results) except FileNotFoundError: print(f"File not found {pytest_result_xml}") diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/pipeline_runner.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/pipeline_runner.py index db62afb37..fa5e5860d 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/pipeline_runner.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/pipeline_runner.py @@ -11,9 +11,10 @@ import unittest import gi -gi.require_version('Gst', '1.0') + +gi.require_version("Gst", "1.0") gi.require_version("GLib", "2.0") -gi.require_version('GstApp', '1.0') +gi.require_version("GstApp", "1.0") gi.require_version("GstVideo", "1.0") from gi.repository import GLib, Gst, GstApp, GstVideo # noqa import gstgva as va # noqa @@ -32,7 +33,7 @@ def set_pipeline(self, pipeline): self._bus = self._pipeline.get_bus() self._bus.add_signal_watch() - self._bus.connect('message', self.on_message) + self._bus.connect("message", self.on_message) def run_pipeline(self): self._state = self._pipeline.set_state(Gst.State.PLAYING) @@ -65,9 +66,19 @@ def on_message(self, bus, msg): class TestPipelineRunner(TestGenericPipelineRunner): - def set_pipeline(self, pipeline, image_path, ground_truth, - check_only_bbox_number=False, check_additional_info=True, check_frame_data=True, - ground_truth_per_frame=False, image_repeat_num=7, check_first_skip=0, check_format=True): + def set_pipeline( + self, + pipeline, + image_path, + ground_truth, + check_only_bbox_number=False, + check_additional_info=True, + check_frame_data=True, + ground_truth_per_frame=False, + image_repeat_num=7, + check_first_skip=0, + check_format=True, + ): self.exceptions = [] self._ground_truth = ground_truth self._check_only_bbox_number = check_only_bbox_number @@ -84,10 +95,10 @@ def set_pipeline(self, pipeline, image_path, ground_truth, self._bus = self._pipeline.get_bus() self._bus.add_signal_watch() - self._bus.connect('message', self.on_message) + self._bus.connect("message", self.on_message) self._mysink = self._pipeline.get_by_name("mysink") - self._mysink.connect('new-sample', self.on_new_buffer) + self._mysink.connect("new-sample", self.on_new_buffer) self._mysrc = self._pipeline.get_by_name("mysrc") self._mysrc.connect("need-data", self.need_data) @@ -95,8 +106,7 @@ def set_pipeline(self, pipeline, image_path, ground_truth, self._image_paths_to_src = [] if isdir(image_path): for i, file_name in enumerate(listdir(image_path)): - self._image_paths_to_src.append( - join(image_path, file_name)) + self._image_paths_to_src.append(join(image_path, file_name)) elif isfile(image_path): self._image_paths_to_src.append(image_path) self._image_paths_to_src *= image_repeat_num @@ -114,7 +124,7 @@ def need_data(self, app_src, size): with open(image_path, "rb") as f: image_data = bytearray(f.read()) # Check for GST 1.20 API - if hasattr(Gst.Buffer, 'new_memdup'): + if hasattr(Gst.Buffer, "new_memdup"): buff = Gst.Buffer.new_memdup(image_data) else: buff = Gst.Buffer.new_allocate(None, len(image_data), None) @@ -152,43 +162,56 @@ def on_new_buffer(self, appsink): try: for region in frame.regions(): detection_tensor = region.detection() - bbox = BBox(detection_tensor['x_min'], - detection_tensor['y_min'], - detection_tensor['x_max'], - detection_tensor['y_max'], - list(), tracker_id=region.object_id(), class_id=region.label_id()) + bbox = BBox( + detection_tensor["x_min"], + detection_tensor["y_min"], + detection_tensor["x_max"], + detection_tensor["y_max"], + [], + tracker_id=region.object_id(), + class_id=region.label_id(), + ) for tensor in region.get_gst_roi_params(): if tensor.is_detection(): continue else: - bbox.additional_info.append({ - 'label': tensor.label(), - 'layer_name': tensor.layer_name(), - 'data': tensor.data(), - 'name': tensor.name(), - 'format': tensor.format(), - 'keypoints_data': tensor['keypoints_data'] - }) + bbox.additional_info.append( + { + "label": tensor.label(), + "layer_name": tensor.layer_name(), + "data": tensor.data(), + "name": tensor.name(), + "format": tensor.format(), + "keypoints_data": tensor["keypoints_data"], + } + ) regions.append(bbox) for tensor in frame.tensors(): - # TODO: add 'is_classification' check for the Tensor using the 'type' field of this tensor bbox = BBox(0, 0, 1, 1, list()) - bbox.additional_info.append({ - 'label': tensor.label(), - 'layer_name': tensor.layer_name(), - 'data': tensor.data(), - 'name': tensor.name(), - 'format': tensor.format() - }) + bbox.additional_info.append( + { + "label": tensor.label(), + "layer_name": tensor.layer_name(), + "data": tensor.data(), + "name": tensor.name(), + "format": tensor.format(), + } + ) regions.append(bbox) except Exception as e: self.exceptions.append(e) try: - gt = self._ground_truth[:] if not self._ground_truth_per_frame else self._ground_truth[self._current_frame - 1] - self.assertTrue(BBox.bboxes_is_equal( - regions[:], gt, - self._check_only_bbox_number, self._check_additional_info)) + gt = ( + self._ground_truth[:] + if not self._ground_truth_per_frame + else self._ground_truth[self._current_frame - 1] + ) + self.assertTrue( + BBox.bboxes_is_equal( + regions[:], gt, self._check_only_bbox_number, self._check_additional_info + ) + ) except Exception as e: self.exceptions.append(e) diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/run_tests.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/run_tests.py index 0853e01d2..dbb110aba 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/run_tests.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/run_tests.py @@ -28,35 +28,32 @@ import test_pipeline_human_pose_estimation import test_pipeline_action_recognition -if __name__ == '__main__': +if __name__ == "__main__": loader = unittest.TestLoader() suite_gstgva = unittest.TestSuite() suite_gstgva.addTests(loader.loadTestsFromModule(test_region_of_interest)) suite_gstgva.addTests(loader.loadTestsFromModule(test_tensor)) suite_gstgva.addTests(loader.loadTestsFromModule(test_video_frame)) - suite_gstgva.addTests(loader.loadTestsFromModule( - test_pipeline_color_formats)) - suite_gstgva.addTests(loader.loadTestsFromModule( - test_pipeline_face_detection_and_classification)) - suite_gstgva.addTests(loader.loadTestsFromModule( - test_pipeline_face_detection_and_classification_emotion_ferplus_onnx)) - suite_gstgva.addTests(loader.loadTestsFromModule( - test_pipeline_vehicle_pedestrian_tracker)) - suite_gstgva.addTests(loader.loadTestsFromModule( - test_pipeline_classification_mobilenet_v2_onnx)) - suite_gstgva.addTests(loader.loadTestsFromModule( - test_audio_event)) - suite_gstgva.addTests(loader.loadTestsFromModule( - test_audio_frame)) - suite_gstgva.addTests(loader.loadTestsFromModule( - test_pipeline_gvapython)) - suite_gstgva.addTests(loader.loadTestsFromModule( - test_pipeline_gvapython_vaapi)) - suite_gstgva.addTests(loader.loadTestsFromModule( - test_pipeline_action_recognition)) - suite_gstgva.addTests(loader.loadTestsFromModule( - test_pipeline_human_pose_estimation)) + suite_gstgva.addTests(loader.loadTestsFromModule(test_pipeline_color_formats)) + suite_gstgva.addTests( + loader.loadTestsFromModule(test_pipeline_face_detection_and_classification) + ) + suite_gstgva.addTests( + loader.loadTestsFromModule( + test_pipeline_face_detection_and_classification_emotion_ferplus_onnx + ) + ) + suite_gstgva.addTests(loader.loadTestsFromModule(test_pipeline_vehicle_pedestrian_tracker)) + suite_gstgva.addTests( + loader.loadTestsFromModule(test_pipeline_classification_mobilenet_v2_onnx) + ) + suite_gstgva.addTests(loader.loadTestsFromModule(test_audio_event)) + suite_gstgva.addTests(loader.loadTestsFromModule(test_audio_frame)) + suite_gstgva.addTests(loader.loadTestsFromModule(test_pipeline_gvapython)) + suite_gstgva.addTests(loader.loadTestsFromModule(test_pipeline_gvapython_vaapi)) + suite_gstgva.addTests(loader.loadTestsFromModule(test_pipeline_action_recognition)) + suite_gstgva.addTests(loader.loadTestsFromModule(test_pipeline_human_pose_estimation)) runner = unittest.TextTestRunner(verbosity=3) result = runner.run(suite_gstgva) diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_audio_event.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_audio_event.py index cffa7bec5..8b9f947e0 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_audio_event.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_audio_event.py @@ -7,21 +7,24 @@ import ctypes import unittest import gi -gi.require_version('GLib', '2.0') + +gi.require_version("GLib", "2.0") from gi.repository import GLib from gstgva.util import GList, libgst, GLIST_POINTER from gstgva.tensor import Tensor from gstgva.audio.audio_event import AudioEvent from gstgva.audio.audio_event_meta import AudioEventMeta + class TestAudioEvent(unittest.TestCase): tensors_count = 2 confidence_value = 1 label_id = 9 + def setUp(self): - classification_structure = libgst.gst_structure_new_empty('classification'.encode("utf-8")) - detection_structure = libgst.gst_structure_new_empty('detection'.encode("utf-8")) + classification_structure = libgst.gst_structure_new_empty("classification".encode("utf-8")) + detection_structure = libgst.gst_structure_new_empty("detection".encode("utf-8")) tensor = Tensor(detection_structure) tensor.__setitem__("confidence", self.confidence_value) tensor.__setitem__("label_id", self.label_id) @@ -63,7 +66,7 @@ def test_audio_event_label(self): def test_tensors(self): tensors_count = 0 for tensor in self.audio_event.tensors(): - tensors_count+=1 + tensors_count += 1 self.assertEqual(tensors_count, self.tensors_count) def test_audio_event_label_id(self): @@ -92,5 +95,6 @@ def test_audio_event_meta(self): def tearDown(self): pass -if __name__ == '__main__': + +if __name__ == "__main__": unittest.main() diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_audio_frame.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_audio_frame.py index 297a30021..c264f5739 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_audio_frame.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_audio_frame.py @@ -10,8 +10,8 @@ import gi import numpy as np -gi.require_version('Gst', '1.0') -gi.require_version('GstAudio', '1.0') +gi.require_version("Gst", "1.0") +gi.require_version("GstAudio", "1.0") from gi.repository import Gst, GstAudio from gstgva.audio.audio_frame import AudioFrame @@ -25,7 +25,7 @@ class TestAudioFrame(unittest.TestCase): def setUp(self): register_metadata() - + self.buffer = Gst.Buffer.new_allocate(None, 0, None) self.meta = AudioEventMeta() @@ -48,7 +48,7 @@ def testAlternateConstructor(self): caps = self.audio_info.to_caps() new_audio_frame = AudioFrame(Gst.Buffer.new_allocate(None, 0, None), None, caps) # Check for GST 1.20 API - if hasattr(GstAudio.AudioInfo, 'new_from_caps'): + if hasattr(GstAudio.AudioInfo, "new_from_caps"): audio_info = GstAudio.AudioInfo.new_from_caps(caps) else: audio_info = new_audio_frame.audio_info() @@ -79,8 +79,8 @@ def test_tensors(self): def test_data(self): - data=np.array([1, 2, 3]) - buffer= Gst.Buffer.new_wrapped(data) + data = np.array([1, 2, 3]) + buffer = Gst.Buffer.new_wrapped(data) frame_from_info = AudioFrame(buffer, self.audio_info) self.assertNotEqual(frame_from_info.data().any(), None) @@ -93,5 +93,6 @@ def test_data(self): with self.assertRaises(RuntimeError): AudioFrame(buffer) -if __name__ == '__main__': + +if __name__ == "__main__": unittest.main() diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_files/instance_segmentation_0002_postproc.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_files/instance_segmentation_0002_postproc.py index 308b86cfc..fa2954175 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_files/instance_segmentation_0002_postproc.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_files/instance_segmentation_0002_postproc.py @@ -8,16 +8,97 @@ import gi import numpy as np -gi.require_version('Gst', '1.0') +gi.require_version("Gst", "1.0") from gi.repository import GLib, Gst, GObject from gstgva import VideoFrame, Tensor, RegionOfInterest + Gst.init(sys.argv) DETECTION_CONFEDENCE_THRESHOLD = 0.9 -LABELS = ["person", "bicycle", "car", "motorbike", "aeroplane", "bus", "train", "truck", "boat", "traffic light", "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket", - "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "sofa", "pottedplant", "bed", "diningtable", "toilet", "tvmonitor", "laptop", "mouse", "remote", "keyboard", "cell phone", "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear", "hair drier", "toothbrush"] +LABELS = [ + "person", + "bicycle", + "car", + "motorbike", + "aeroplane", + "bus", + "train", + "truck", + "boat", + "traffic light", + "fire hydrant", + "stop sign", + "parking meter", + "bench", + "bird", + "cat", + "dog", + "horse", + "sheep", + "cow", + "elephant", + "bear", + "zebra", + "giraffe", + "backpack", + "umbrella", + "handbag", + "tie", + "suitcase", + "frisbee", + "skis", + "snowboard", + "sports ball", + "kite", + "baseball bat", + "baseball glove", + "skateboard", + "surfboard", + "tennis racket", + "bottle", + "wine glass", + "cup", + "fork", + "knife", + "spoon", + "bowl", + "banana", + "apple", + "sandwich", + "orange", + "broccoli", + "carrot", + "hot dog", + "pizza", + "donut", + "cake", + "chair", + "sofa", + "pottedplant", + "bed", + "diningtable", + "toilet", + "tvmonitor", + "laptop", + "mouse", + "remote", + "keyboard", + "cell phone", + "microwave", + "oven", + "toaster", + "sink", + "refrigerator", + "book", + "clock", + "vase", + "scissors", + "teddy bear", + "hair drier", + "toothbrush", +] # n c h w INPUT_SHAPE = (1, 3, 768, 1024) @@ -31,7 +112,8 @@ def __init__(self, top_left_x, top_left_y, bottom_right_x, bottom_right_y, confi self.confidence = confidence def __repr__(self) -> str: - return f"{self.top_left_x}, {self.top_left_y}, {self.bottom_right_x}, {self.bottom_right_y}, {self.confidence}" + return (f"{self.top_left_x}, {self.top_left_y}, {self.bottom_right_x}, " + + f"{self.bottom_right_y}, {self.confidence}") def process_labels(tensor): @@ -71,11 +153,11 @@ def process_frame(frame: VideoFrame) -> bool: for tensor in frame.tensors(): layer_name = tensor.layer_name() - if layer_name == 'labels': + if layer_name == "labels": labels_out = tensor - if layer_name == 'boxes': + if layer_name == "boxes": boxes_out = tensor - if layer_name == 'masks': + if layer_name == "masks": masks_out = tensor labels = list() @@ -90,7 +172,14 @@ def process_frame(frame: VideoFrame) -> bool: for bbox, label, mask in zip(bboxes, labels, masks): if bbox.confidence > DETECTION_CONFEDENCE_THRESHOLD: - frame.add_region(bbox.top_left_x, bbox.top_left_y, bbox.bottom_right_x - bbox.top_left_x, - bbox.bottom_right_y - bbox.top_left_y, label=label, confidence=bbox.confidence, normalized=True) + frame.add_region( + bbox.top_left_x, + bbox.top_left_y, + bbox.bottom_right_x - bbox.top_left_x, + bbox.bottom_right_y - bbox.top_left_y, + label=label, + confidence=bbox.confidence, + normalized=True, + ) return True diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_files/test_module.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_files/test_module.py index a6dfe5c93..f967420d9 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_files/test_module.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_files/test_module.py @@ -4,9 +4,11 @@ # SPDX-License-Identifier: MIT # ============================================================================== import gi -gi.require_version('Gst', '1.0') + +gi.require_version("Gst", "1.0") from gi.repository import Gst + class MyClass: def __init__(self): print("MyClass.__init__") @@ -35,14 +37,12 @@ def __init__(self): def read_frame_data(self, frame): print("MyClassVaapi.read_frame_data") with frame.data() as mat: - print( - f"MyClassVaapi.read_frame_data: Get frame.data() size {mat.nbytes}") + print(f"MyClassVaapi.read_frame_data: Get frame.data() size {mat.nbytes}") def write_frame_data(self, frame): print("MyClassVaapi.write_frame_data") with frame.data(Gst.MapFlags.WRITE) as mat: - print( - f"MyClassVaapi.write_frame_data: Get frame.data() size {mat.nbytes}") + print(f"MyClassVaapi.write_frame_data: Get frame.data() size {mat.nbytes}") def process_frame(frame): diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_color_formats.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_color_formats.py index 72675407d..a77b28667 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_color_formats.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_color_formats.py @@ -25,15 +25,25 @@ ! appsink name=mysink emit-signals=true sync=false """ GOLD_TRUE = [ - BBox(0.16715965520083387, 0.22123040141508574, 0.7384700885187101, 0.7272685343116798, - [], class_id=1 - ), - BBox(0.17164345043366325, 0.38195868355967616, 0.40469565994584045, 0.939372365266666, - [], class_id=16 - ), - BBox(0.6076358885710818, 0.129305732686903, 0.9001748219158472, 0.295689319506625, - [], class_id=2 - ) + BBox( + 0.16715965520083387, + 0.22123040141508574, + 0.7384700885187101, + 0.7272685343116798, + [], + class_id=1, + ), + BBox( + 0.17164345043366325, + 0.38195868355967616, + 0.40469565994584045, + 0.939372365266666, + [], + class_id=16, + ), + BBox( + 0.6076358885710818, 0.129305732686903, 0.9001748219158472, 0.295689319506625, [], class_id=2 + ), ] @@ -41,18 +51,15 @@ class TestColorFormatsPipeline(unittest.TestCase): def test_color_formats_pipeline(self): pipeline_runner = TestPipelineRunner() for color_format in color_formats: - pipeline = PIPELINE_STR.format( - color_format, d_model_path) - pipeline_runner.set_pipeline(pipeline, - IMAGE_PATH, - GOLD_TRUE) + pipeline = PIPELINE_STR.format(color_format, d_model_path) + pipeline_runner.set_pipeline(pipeline, IMAGE_PATH, GOLD_TRUE) pipeline_runner.run_pipeline() for e in pipeline_runner.exceptions: print(e) - pipeline_runner.assertEqual(len(pipeline_runner.exceptions), 0, - "Exceptions have been caught.") + pipeline_runner.assertEqual( + len(pipeline_runner.exceptions), 0, "Exceptions have been caught." + ) if __name__ == "__main__": unittest.main() - diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_custom_preproc.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_custom_preproc.py index 14e3ad4d4..992990cc2 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_custom_preproc.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_custom_preproc.py @@ -18,7 +18,7 @@ D_OPENCV_PIPELINE_STR = f""" appsrc name=mysrc -! jpegparse ! jpegdec +! decodebin3 ! queue ! gvadetect pre-process-backend=opencv device=CPU model={D_MODEL_PATH} threshold=0.9 ! appsink name=mysink emit-signals=true sync=false """ @@ -38,18 +38,25 @@ """ D_GOLD_TRUE = [ - BBox(0.582991799458739, 0.3142750898057349, 0.9671368743052611, 0.710030757159208, [], class_id=41, tracker_id=None) + BBox( + 0.582991799458739, + 0.3142750898057349, + 0.9671368743052611, + 0.710030757159208, + [], + class_id=41, + tracker_id=None, + ) ] C_MODEL_NAME = "resnest-50-pytorch" C_MODEL_PATH = get_model_path(C_MODEL_NAME) -C_MODEL_PROC_PATH = os.path.join( - SCRIPT_DIR, "test_files", "imagenet_custom_pre_proc_resnet.json") +C_MODEL_PROC_PATH = os.path.join(SCRIPT_DIR, "test_files", "imagenet_custom_pre_proc_resnet.json") C_OPENCV_PIPELINE_STR = f""" appsrc name=mysrc -! jpegparse ! jpegdec +! decodebin3 ! queue ! gvaclassify inference-region=full-frame pre-process-backend=opencv device=CPU model={C_MODEL_PATH} model-proc={C_MODEL_PROC_PATH} ! appsink name=mysink emit-signals=true sync=false """ @@ -68,79 +75,70 @@ ! appsink name=mysink emit-signals=true sync=false """ -C_GOLD_TRUE = [BBox(0, 0, 1, 1, - [ - { - 'label': "espresso", - 'layer_name': "prob", - 'name': "ANY" - } - ] - ) - ] +C_GOLD_TRUE = [BBox(0, 0, 1, 1, [{"label": "espresso", "layer_name": "prob", "name": "ANY"}])] class TestCustomPreProcPipeline(unittest.TestCase): def test_custom_opencv_yolo_11_pipeline(self): pipeline_runner = TestPipelineRunner() - pipeline_runner.set_pipeline( - D_OPENCV_PIPELINE_STR, IMAGE_PATH, D_GOLD_TRUE) + pipeline_runner.set_pipeline(D_OPENCV_PIPELINE_STR, IMAGE_PATH, D_GOLD_TRUE) pipeline_runner.run_pipeline() for e in pipeline_runner.exceptions: print(e) - pipeline_runner.assertEqual(len(pipeline_runner.exceptions), 0, - "Exceptions have been caught.") + pipeline_runner.assertEqual( + len(pipeline_runner.exceptions), 0, "Exceptions have been caught." + ) def test_custom_vaapi_yolo_11_pipeline(self): pipeline_runner = TestPipelineRunner() - pipeline_runner.set_pipeline( - D_VAAPI_PIPELINE_STR, IMAGE_PATH, D_GOLD_TRUE) + pipeline_runner.set_pipeline(D_VAAPI_PIPELINE_STR, IMAGE_PATH, D_GOLD_TRUE) pipeline_runner.run_pipeline() for e in pipeline_runner.exceptions: print(e) - pipeline_runner.assertEqual(len(pipeline_runner.exceptions), 0, - "Exceptions have been caught.") + pipeline_runner.assertEqual( + len(pipeline_runner.exceptions), 0, "Exceptions have been caught." + ) def test_custom_vaapi_surface_sharing_yolo_11_pipeline(self): pipeline_runner = TestPipelineRunner() - pipeline_runner.set_pipeline( - D_VAAPI_SURFACE_SHARING_PIPELINE_STR, IMAGE_PATH, D_GOLD_TRUE) + pipeline_runner.set_pipeline(D_VAAPI_SURFACE_SHARING_PIPELINE_STR, IMAGE_PATH, D_GOLD_TRUE) pipeline_runner.run_pipeline() for e in pipeline_runner.exceptions: print(e) - pipeline_runner.assertEqual(len(pipeline_runner.exceptions), 0, - "Exceptions have been caught.") + pipeline_runner.assertEqual( + len(pipeline_runner.exceptions), 0, "Exceptions have been caught." + ) def test_custom_opencv_resnet_pipeline(self): pipeline_runner = TestPipelineRunner() - pipeline_runner.set_pipeline( - C_OPENCV_PIPELINE_STR, IMAGE_PATH, C_GOLD_TRUE) + pipeline_runner.set_pipeline(C_OPENCV_PIPELINE_STR, IMAGE_PATH, C_GOLD_TRUE) pipeline_runner.run_pipeline() for e in pipeline_runner.exceptions: print(e) - pipeline_runner.assertEqual(len(pipeline_runner.exceptions), 0, - "Exceptions have been caught.") + pipeline_runner.assertEqual( + len(pipeline_runner.exceptions), 0, "Exceptions have been caught." + ) def test_custom_vaapi_resnet_pipeline(self): pipeline_runner = TestPipelineRunner() - pipeline_runner.set_pipeline( - C_VAAPI_PIPELINE_STR, IMAGE_PATH, C_GOLD_TRUE) + pipeline_runner.set_pipeline(C_VAAPI_PIPELINE_STR, IMAGE_PATH, C_GOLD_TRUE) pipeline_runner.run_pipeline() for e in pipeline_runner.exceptions: print(e) - pipeline_runner.assertEqual(len(pipeline_runner.exceptions), 0, - "Exceptions have been caught.") + pipeline_runner.assertEqual( + len(pipeline_runner.exceptions), 0, "Exceptions have been caught." + ) def test_custom_vaapi_surface_sharing_resnet_pipeline(self): pipeline_runner = TestPipelineRunner() - pipeline_runner.set_pipeline( - C_VAAPI_SURFACE_SHARING_PIPELINE_STR, IMAGE_PATH, C_GOLD_TRUE) + pipeline_runner.set_pipeline(C_VAAPI_SURFACE_SHARING_PIPELINE_STR, IMAGE_PATH, C_GOLD_TRUE) pipeline_runner.run_pipeline() for e in pipeline_runner.exceptions: print(e) - pipeline_runner.assertEqual(len(pipeline_runner.exceptions), 0, - "Exceptions have been caught.") + pipeline_runner.assertEqual( + len(pipeline_runner.exceptions), 0, "Exceptions have been caught." + ) + if __name__ == "__main__": unittest.main() - diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_detection_atss.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_detection_atss.py index c3b041db6..b1f6f0f21 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_detection_atss.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_detection_atss.py @@ -14,8 +14,7 @@ IMAGE_PATH = os.path.join(SCRIPT_DIR, "test_files", "car_detection.png") d_model_name = "person-vehicle-bike-detection-2004" -d_model_path, d_model_proc_path = get_model_path( - d_model_name), get_model_proc_path(d_model_name) +d_model_path, d_model_proc_path = get_model_path(d_model_name), get_model_proc_path(d_model_name) PIPELINE_STR = f"""appsrc name=mysrc \ @@ -25,29 +24,43 @@ ! appsink name=mysink emit-signals=true sync=false """ GOLD_TRUE = [ - BBox(0.10468322783708572, 0.19903349876403809, 0.32950497418642044, 0.9529740810394287, - [], class_id=0 - ), - BBox(0.4107516407966614, 0.28523483872413635, 0.6255635023117065, 0.9386073648929596, - [], class_id=0 - ), - BBox(0.40668997168540955, 0.2672349214553833, 0.6080639958381653, 0.5492938756942749, - [], class_id=0) - + BBox( + 0.10468322783708572, + 0.19903349876403809, + 0.32950497418642044, + 0.9529740810394287, + [], + class_id=0, + ), + BBox( + 0.4107516407966614, + 0.28523483872413635, + 0.6255635023117065, + 0.9386073648929596, + [], + class_id=0, + ), + BBox( + 0.40668997168540955, + 0.2672349214553833, + 0.6080639958381653, + 0.5492938756942749, + [], + class_id=0, + ), ] class TestDetectionATSSPipeline(unittest.TestCase): def test_detection_atss_pipeline(self): pipeline_runner = TestPipelineRunner() - pipeline_runner.set_pipeline(PIPELINE_STR, - IMAGE_PATH, - GOLD_TRUE) + pipeline_runner.set_pipeline(PIPELINE_STR, IMAGE_PATH, GOLD_TRUE) pipeline_runner.run_pipeline() for e in pipeline_runner.exceptions: print(e) - pipeline_runner.assertEqual(len(pipeline_runner.exceptions), 0, - "Exceptions have been caught.") + pipeline_runner.assertEqual( + len(pipeline_runner.exceptions), 0, "Exceptions have been caught." + ) if __name__ == "__main__": diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_detection_yolo_11s.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_detection_yolo_11s.py index 9963bd418..71e72ba79 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_detection_yolo_11s.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_detection_yolo_11s.py @@ -13,31 +13,70 @@ SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) IMAGE_PATH = os.path.join(SCRIPT_DIR, "test_files", "dog_bike_car.jpg") + def make_pipeline_str(model_name): PIPELINE_STR = """appsrc name=mysrc \ ! decodebin ! videoconvert ! video/x-raw,format=BGRA \ ! gvadetect pre-process-backend=ie model={} \ ! gvawatermark \ -! appsink name=mysink emit-signals=true sync=false """.format(get_model_path(model_name)) +! appsink name=mysink emit-signals=true sync=false """.format( + get_model_path(model_name) + ) return PIPELINE_STR GOLD_TRUE = [ - BBox(0.16600936461207816, 0.38890058405662487, - 0.4078545726244531, 0.9406926827498019, [], class_id=16), - BBox(0.6055093107665357, 0.13401658383886872, - 0.8919420810698284, 0.2956839696427691, [], class_id=7), - BBox(0.1501398097734139, 0.21889342922873212, - 0.7452847887655665, 0.7433104570456628, [], class_id=1) + BBox( + 0.16600936461207816, + 0.38890058405662487, + 0.4078545726244531, + 0.9406926827498019, + [], + class_id=16, + ), + BBox( + 0.6055093107665357, + 0.13401658383886872, + 0.8919420810698284, + 0.2956839696427691, + [], + class_id=7, + ), + BBox( + 0.1501398097734139, + 0.21889342922873212, + 0.7452847887655665, + 0.7433104570456628, + [], + class_id=1, + ), ] GOLD_TRUE_SEG = [ - BBox(0.17104654567013, 0.37789393034419305, - 0.40481482155345105, 0.939848055539251, [], class_id=16), - BBox(0.1644484544463225, 0.22790937763317487, - 0.7408722987901015, 0.728528415091759, [], class_id=1), - BBox(0.6058582396188115, 0.12965262129385202, - 0.9041038647905566, 0.2973447724781151, [], class_id=2) + BBox( + 0.17104654567013, + 0.37789393034419305, + 0.40481482155345105, + 0.939848055539251, + [], + class_id=16, + ), + BBox( + 0.1644484544463225, + 0.22790937763317487, + 0.7408722987901015, + 0.728528415091759, + [], + class_id=1, + ), + BBox( + 0.6058582396188115, + 0.12965262129385202, + 0.9041038647905566, + 0.2973447724781151, + [], + class_id=2, + ), ] EMPTY_GOLD_TRUE = [] @@ -50,8 +89,9 @@ def test_detection_yolo_v11s_pipeline(self): pipeline_runner.run_pipeline() for e in pipeline_runner.exceptions: print(e) - pipeline_runner.assertEqual(len(pipeline_runner.exceptions), 0, - "Exceptions have been caught.") + pipeline_runner.assertEqual( + len(pipeline_runner.exceptions), 0, "Exceptions have been caught." + ) def test_detection_yolo_v11s_obb_pipeline(self): pipeline_runner = TestPipelineRunner() @@ -59,8 +99,9 @@ def test_detection_yolo_v11s_obb_pipeline(self): pipeline_runner.run_pipeline() for e in pipeline_runner.exceptions: print(e) - pipeline_runner.assertEqual(len(pipeline_runner.exceptions), 0, - "Exceptions have been caught.") + pipeline_runner.assertEqual( + len(pipeline_runner.exceptions), 0, "Exceptions have been caught." + ) def test_detection_yolo_v11s_pose_pipeline(self): pipeline_runner = TestPipelineRunner() @@ -68,8 +109,9 @@ def test_detection_yolo_v11s_pose_pipeline(self): pipeline_runner.run_pipeline() for e in pipeline_runner.exceptions: print(e) - pipeline_runner.assertEqual(len(pipeline_runner.exceptions), 0, - "Exceptions have been caught.") + pipeline_runner.assertEqual( + len(pipeline_runner.exceptions), 0, "Exceptions have been caught." + ) def test_detection_yolo_v11s_seg_pipeline(self): pipeline_runner = TestPipelineRunner() @@ -77,11 +119,10 @@ def test_detection_yolo_v11s_seg_pipeline(self): pipeline_runner.run_pipeline() for e in pipeline_runner.exceptions: print(e) - pipeline_runner.assertEqual(len(pipeline_runner.exceptions), 0, - "Exceptions have been caught.") + pipeline_runner.assertEqual( + len(pipeline_runner.exceptions), 0, "Exceptions have been caught." + ) if __name__ == "__main__": unittest.main() - - diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_detection_yolo_v10s.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_detection_yolo_v10s.py index 820197c47..ace3174ac 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_detection_yolo_v10s.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_detection_yolo_v10s.py @@ -21,16 +21,36 @@ ! decodebin ! videoconvert ! video/x-raw,format=BGRA \ ! gvadetect pre-process-backend=ie model={} \ ! gvawatermark \ -! appsink name=mysink emit-signals=true sync=false """.format(D_MODEL_PATH) +! appsink name=mysink emit-signals=true sync=false """.format( + D_MODEL_PATH +) GOLD_TRUE = [ - BBox(0.16600936461207816, 0.38890058405662487, - 0.4078545726244531, 0.9406926827498019, [], class_id=16), - BBox(0.6055093107665357, 0.13401658383886872, - 0.8919420810698284, 0.2956839696427691, [], class_id=7), - BBox(0.1501398097734139, 0.21889342922873212, - 0.7452847887655665, 0.7433104570456628, [], class_id=1) + BBox( + 0.16600936461207816, + 0.38890058405662487, + 0.4078545726244531, + 0.9406926827498019, + [], + class_id=16, + ), + BBox( + 0.6055093107665357, + 0.13401658383886872, + 0.8919420810698284, + 0.2956839696427691, + [], + class_id=7, + ), + BBox( + 0.1501398097734139, + 0.21889342922873212, + 0.7452847887655665, + 0.7433104570456628, + [], + class_id=1, + ), ] @@ -41,10 +61,10 @@ def test_detection_yolo_v10s_pipeline(self): pipeline_runner.run_pipeline() for e in pipeline_runner.exceptions: print(e) - pipeline_runner.assertEqual(len(pipeline_runner.exceptions), 0, - "Exceptions have been caught.") + pipeline_runner.assertEqual( + len(pipeline_runner.exceptions), 0, "Exceptions have been caught." + ) if __name__ == "__main__": unittest.main() - diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_face_detection_and_classification.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_face_detection_and_classification.py index ccec93037..af809b4e2 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_face_detection_and_classification.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_face_detection_and_classification.py @@ -16,14 +16,17 @@ D_MODEL_PATH = get_model_path("face-detection-adas-0001") C1_MODEL_NAME = "age-gender-recognition-retail-0013" -C1_MODEL_PATH, C1_MODEL_PROC_PATH = get_model_path( - C1_MODEL_NAME), get_model_proc_path(C1_MODEL_NAME) +C1_MODEL_PATH, C1_MODEL_PROC_PATH = get_model_path(C1_MODEL_NAME), get_model_proc_path( + C1_MODEL_NAME +) C2_MODEL_NAME = "emotions-recognition-retail-0003" -C2_MODEL_PATH, C2_MODEL_PROC_PATH = get_model_path( - C2_MODEL_NAME), get_model_proc_path(C2_MODEL_NAME) +C2_MODEL_PATH, C2_MODEL_PROC_PATH = get_model_path(C2_MODEL_NAME), get_model_proc_path( + C2_MODEL_NAME +) C3_MODEL_NAME = "landmarks-regression-retail-0009" -C3_MODEL_PATH, C3_MODEL_PROC_PATH = get_model_path( - C3_MODEL_NAME), get_model_proc_path(C3_MODEL_NAME) +C3_MODEL_PATH, C3_MODEL_PROC_PATH = get_model_path(C3_MODEL_NAME), get_model_proc_path( + C3_MODEL_NAME +) # Previously the color format was BGRA but due to know issue CVS-97946 it has been changed to BGR # Can be reverted back once issue is resolved @@ -38,163 +41,146 @@ def set_of_pipelines(): - preprocessors = ['ie', 'opencv'] + preprocessors = ["ie", "opencv"] for preproc in preprocessors: - pipeline_str = PIPELINE_STR_TEMPLATE.format(D_MODEL_PATH, preproc, - C1_MODEL_PATH, C1_MODEL_PROC_PATH, preproc, - C2_MODEL_PATH, C2_MODEL_PROC_PATH, preproc, - C3_MODEL_PATH, C3_MODEL_PROC_PATH, preproc, FILE_PATH, - ) - yield(pipeline_str) + pipeline_str = PIPELINE_STR_TEMPLATE.format( + D_MODEL_PATH, + preproc, + C1_MODEL_PATH, + C1_MODEL_PROC_PATH, + preproc, + C2_MODEL_PATH, + C2_MODEL_PROC_PATH, + preproc, + C3_MODEL_PATH, + C3_MODEL_PROC_PATH, + preproc, + FILE_PATH, + ) + yield pipeline_str GROUND_TRUTH_CV = [ - BBox(0.692409336566925, 0.1818923056125641, 0.8225383162498474, 0.5060393810272217, - [ - { - 'label': "21", - 'layer_name': "age_conv3", - 'name': "age" - }, - { - 'label': "Male", - 'layer_name': "prob", - 'name': "gender" - }, - { - 'label': "surprise", - 'layer_name': "prob_emotion", - 'name': "emotion" - }, - { - 'data': [ - 0.38138410449028015, - 0.3854252099990845, - 0.8030526041984558, - 0.3897205889225006, - 0.6947423219680786, - 0.543339192867279, - 0.4235397279262543, - 0.731324315071106, - 0.79606693983078, - 0.7303038835525513 - ], - 'format': "landmark_points", - 'layer_name': "95", - 'name': "UNKNOWN" - } - ], class_id=0 - ), - BBox(0.18316425383090973, 0.19858068227767944, 0.30258169770240784, 0.5096779465675354, - [ - { - 'label': "Female", - 'layer_name': "prob", - 'name': "gender" - }, - { - 'label': "happy", - 'layer_name': "prob_emotion", - 'name': "emotion" - }, - { - 'label': "25", - 'layer_name': "age_conv3", - 'name': "age" - }, - { - 'data': [ - 0.2102919965982437, - 0.36596113443374634, - 0.6744474172592163, - 0.37297171354293823, - 0.36115342378616333, - 0.5115487575531006, - 0.19850215315818787, - 0.7386893033981323, - 0.6249252557754517, - 0.7444547414779663 - ], - 'format': "landmark_points", - 'layer_name': "95", - 'name': "UNKNOWN" - } - ], class_id=0, - )] + BBox( + 0.692409336566925, + 0.1818923056125641, + 0.8225383162498474, + 0.5060393810272217, + [ + {"label": "21", "layer_name": "age_conv3", "name": "age"}, + {"label": "Male", "layer_name": "prob", "name": "gender"}, + {"label": "surprise", "layer_name": "prob_emotion", "name": "emotion"}, + { + "data": [ + 0.38138410449028015, + 0.3854252099990845, + 0.8030526041984558, + 0.3897205889225006, + 0.6947423219680786, + 0.543339192867279, + 0.4235397279262543, + 0.731324315071106, + 0.79606693983078, + 0.7303038835525513, + ], + "format": "landmark_points", + "layer_name": "95", + "name": "UNKNOWN", + }, + ], + class_id=0, + ), + BBox( + 0.18316425383090973, + 0.19858068227767944, + 0.30258169770240784, + 0.5096779465675354, + [ + {"label": "Female", "layer_name": "prob", "name": "gender"}, + {"label": "happy", "layer_name": "prob_emotion", "name": "emotion"}, + {"label": "25", "layer_name": "age_conv3", "name": "age"}, + { + "data": [ + 0.2102919965982437, + 0.36596113443374634, + 0.6744474172592163, + 0.37297171354293823, + 0.36115342378616333, + 0.5115487575531006, + 0.19850215315818787, + 0.7386893033981323, + 0.6249252557754517, + 0.7444547414779663, + ], + "format": "landmark_points", + "layer_name": "95", + "name": "UNKNOWN", + }, + ], + class_id=0, + ), +] GROUND_TRUTH_IE = [ - BBox(0.692409336566925, 0.1818923056125641, 0.8225383162498474, 0.5060393810272217, - [ - { - 'label': "21", - 'layer_name': "age_conv3", - 'name': "age" - }, - { - 'label': "Male", - 'layer_name': "prob", - 'name': "gender" - }, - { - 'label': "surprise", - 'layer_name': "prob_emotion", - 'name': "emotion" - }, - { - 'data': [ - 0.38138410449028015, - 0.3854252099990845, - 0.8030526041984558, - 0.3897205889225006, - 0.6947423219680786, - 0.543339192867279, - 0.4235397279262543, - 0.731324315071106, - 0.79606693983078, - 0.7303038835525513 - ], - 'format': "landmark_points", - 'layer_name': "95", - 'name': "UNKNOWN" - } - ], class_id=0 - ), - BBox(0.18316425383090973, 0.19858068227767944, 0.30258169770240784, 0.5096779465675354, - [ - { - 'label': "Female", - 'layer_name': "prob", - 'name': "gender" - }, - { - 'label': "happy", - 'layer_name': "prob_emotion", - 'name': "emotion" - }, - { - 'label': "26", - 'layer_name': "age_conv3", - 'name': "age" - }, - { - 'data': [ - 0.2102919965982437, - 0.36596113443374634, - 0.6744474172592163, - 0.37297171354293823, - 0.36115342378616333, - 0.5115487575531006, - 0.19850215315818787, - 0.7386893033981323, - 0.6249252557754517, - 0.7444547414779663 - ], - 'format': "landmark_points", - 'layer_name': "95", - 'name': "UNKNOWN" - } - ], class_id=0, - )] + BBox( + 0.692409336566925, + 0.1818923056125641, + 0.8225383162498474, + 0.5060393810272217, + [ + {"label": "21", "layer_name": "age_conv3", "name": "age"}, + {"label": "Male", "layer_name": "prob", "name": "gender"}, + {"label": "surprise", "layer_name": "prob_emotion", "name": "emotion"}, + { + "data": [ + 0.38138410449028015, + 0.3854252099990845, + 0.8030526041984558, + 0.3897205889225006, + 0.6947423219680786, + 0.543339192867279, + 0.4235397279262543, + 0.731324315071106, + 0.79606693983078, + 0.7303038835525513, + ], + "format": "landmark_points", + "layer_name": "95", + "name": "UNKNOWN", + }, + ], + class_id=0, + ), + BBox( + 0.18316425383090973, + 0.19858068227767944, + 0.30258169770240784, + 0.5096779465675354, + [ + {"label": "Female", "layer_name": "prob", "name": "gender"}, + {"label": "happy", "layer_name": "prob_emotion", "name": "emotion"}, + {"label": "26", "layer_name": "age_conv3", "name": "age"}, + { + "data": [ + 0.2102919965982437, + 0.36596113443374634, + 0.6744474172592163, + 0.37297171354293823, + 0.36115342378616333, + 0.5115487575531006, + 0.19850215315818787, + 0.7386893033981323, + 0.6249252557754517, + 0.7444547414779663, + ], + "format": "landmark_points", + "layer_name": "95", + "name": "UNKNOWN", + }, + ], + class_id=0, + ), +] class TestFaceDetectionAndClassification(unittest.TestCase): @@ -213,8 +199,9 @@ def test_face_detection_and_classification_pipeline(self): for e in pipeline_runner.exceptions: print(e) - pipeline_runner.assertEqual(len(pipeline_runner.exceptions), 0, - "Exceptions have been caught.") + pipeline_runner.assertEqual( + len(pipeline_runner.exceptions), 0, "Exceptions have been caught." + ) if __name__ == "__main__": diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_face_detection_and_emotions-recognition-retail-0003.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_face_detection_and_emotions-recognition-retail-0003.py index 916902714..b45f801de 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_face_detection_and_emotions-recognition-retail-0003.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_face_detection_and_emotions-recognition-retail-0003.py @@ -26,41 +26,40 @@ ! gvadetect model={} ! queue \ ! gvaclassify model={} model-proc={} pre-process-backend=opencv \ ! gvawatermark \ -! appsink name=mysink emit-signals=true sync=false """.format(d_model_path, c_model_path, c_model_proc_path) +! appsink name=mysink emit-signals=true sync=false """.format( + d_model_path, c_model_path, c_model_proc_path +) GOLD_TRUE = [ - BBox(0.6926184892654419, 0.18179790675640106, 0.822385311126709, 0.5055984705686569, - [ - { - 'label': "surprise", - 'layer_name': "prob_emotion", - 'name': "detection" - } - ], class_id=0 - ), - BBox(0.18315134942531586, 0.19866728782653809, 0.30272287130355835, 0.5095890760421753, - [ - { - 'label': "happy", - 'layer_name': "prob_emotion", - 'name': "emotion" - } - ], class_id=0 - ) + BBox( + 0.6926184892654419, + 0.18179790675640106, + 0.822385311126709, + 0.5055984705686569, + [{"label": "surprise", "layer_name": "prob_emotion", "name": "detection"}], + class_id=0, + ), + BBox( + 0.18315134942531586, + 0.19866728782653809, + 0.30272287130355835, + 0.5095890760421753, + [{"label": "happy", "layer_name": "prob_emotion", "name": "emotion"}], + class_id=0, + ), ] class TestDetectionClassificationPipeline(unittest.TestCase): def test_pipeline_face_detection_and_emotions_recognition_retail_0003(self): pipeline_runner = TestPipelineRunner() - pipeline_runner.set_pipeline(PIPELINE_STR, - IMAGE_PATH, - GOLD_TRUE) + pipeline_runner.set_pipeline(PIPELINE_STR, IMAGE_PATH, GOLD_TRUE) pipeline_runner.run_pipeline() for e in pipeline_runner.exceptions: print(e) - pipeline_runner.assertEqual(len(pipeline_runner.exceptions), 0, - "Exceptions have been caught.") + pipeline_runner.assertEqual( + len(pipeline_runner.exceptions), 0, "Exceptions have been caught." + ) if __name__ == "__main__": diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_gvainference_gvapython.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_gvainference_gvapython.py index 0b31e5827..47489b18e 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_gvainference_gvapython.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_gvainference_gvapython.py @@ -12,10 +12,8 @@ SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) IMAGE_PATH = os.path.join(SCRIPT_DIR, "test_files", "dog_bike_car.jpg") -MODULE_PATH = os.path.join(SCRIPT_DIR, "test_files", - "instance_segmentation_0002_postproc.py") -MODEL_PROC_PATH = os.path.join( - SCRIPT_DIR, "test_files", "instance-segmentation-security-0002.json") +MODULE_PATH = os.path.join(SCRIPT_DIR, "test_files", "instance_segmentation_0002_postproc.py") +MODEL_PROC_PATH = os.path.join(SCRIPT_DIR, "test_files", "instance-segmentation-security-0002.json") MODEL_NAME = "instance-segmentation-security-0002" MODEL_PATH = get_model_path(MODEL_NAME, precision="FP16-INT8") @@ -28,22 +26,21 @@ ! appsink name=mysink emit-signals=true sync=false""" -GOLD_TRUE = [ - BBox(0, 0, 1, 1), - BBox(0, 0, 1, 1) -] +GOLD_TRUE = [BBox(0, 0, 1, 1), BBox(0, 0, 1, 1)] class TestInferencePythonPipeline(unittest.TestCase): def test_gvainference_gvapython_pipeline(self): pipeline_runner = TestPipelineRunner() pipeline_runner.set_pipeline( - PIPELINE_STR, IMAGE_PATH, GOLD_TRUE, check_additional_info=False) + PIPELINE_STR, IMAGE_PATH, GOLD_TRUE, check_additional_info=False + ) pipeline_runner.run_pipeline() for e in pipeline_runner.exceptions: print(e) - pipeline_runner.assertEqual(len(pipeline_runner.exceptions), 0, - "Exceptions have been caught.") + pipeline_runner.assertEqual( + len(pipeline_runner.exceptions), 0, "Exceptions have been caught." + ) if __name__ == "__main__": diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_gvapython.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_gvapython.py index bd6c06153..e34aeb696 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_gvapython.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_gvapython.py @@ -16,17 +16,18 @@ PIPELINE_TEMPLATE = "filesrc location={} ! jpegdec ! gvapython module={} {} ! fakesink" + class TestGvaPythonParameters(unittest.TestCase): def generate_pipelines(self): additional_args = [ [""], ["class=MyClass"], - ["class=MyClass", "function=\"my_function\""], + ["class=MyClass", 'function="my_function"'], ["class=MyClassWithArgs", "arg=[]", "kwarg=[]"], ["class=MyClassWithArgs", "arg=[]"], - ["class=MyClass", "function=\"my_functions\""], - ["function=\"my_func\""], - ["class=MyClass", "arg=[\"foo\"]"] + ["class=MyClass", 'function="my_functions"'], + ['function="my_func"'], + ["class=MyClass", 'arg=["foo"]'], ] pipelines = [] for args in additional_args: @@ -48,5 +49,6 @@ def test_gvapython_parameters_pipeline(self): actual_result.append(False) pipeline_runner.assertEqual(expected_result, actual_result) + if __name__ == "__main__": unittest.main() diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_gvapython_vaapi.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_gvapython_vaapi.py index 6894dc3ad..cb720df7b 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_gvapython_vaapi.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_gvapython_vaapi.py @@ -12,7 +12,9 @@ IMAGE_PATH = os.path.join(SCRIPT_DIR, "test_files", "cup.jpg") MODULE_PATH = os.path.join(SCRIPT_DIR, "test_files", "test_module.py") -PIPELINE_TEMPLATE = "filesrc location={} ! jpegparse ! vaapijpegdec ! vaapipostproc ! video/x-raw(memory:VASurface),format={} ! gvapython module={} class=MyClassVaapi function={} ! {} fakesink sync=false" +PIPELINE_TEMPLATE = ("filesrc location={} ! jpegparse ! vaapijpegdec ! vaapipostproc ! " + + "video/x-raw(memory:VASurface),format={} ! gvapython module={} " + + "class=MyClassVaapi function={} ! {} fakesink sync=false") ENCODERS = ["", "vaapipostproc ! vaapijpegenc !"] FORMATS = ["NV12", "I420"] READ_FUNC = "read_frame_data" @@ -26,16 +28,22 @@ def test_gvapython_vaapi_map(self): for func_exception in [(READ_FUNC, False), (WRITE_FUNC, True)]: (func, expect_exception) = func_exception pipeline_str = PIPELINE_TEMPLATE.format( - IMAGE_PATH, caps_format, MODULE_PATH, func, enc) + IMAGE_PATH, caps_format, MODULE_PATH, func, enc + ) pipeline_runner = TestGenericPipelineRunner() pipeline_runner.set_pipeline(pipeline_str) pipeline_runner.run_pipeline() if expect_exception: pipeline_runner.assertGreater( - len(pipeline_runner.exceptions), 0, "No exception when mapping VAAPI buffer for writing. Expected at least one.") + len(pipeline_runner.exceptions), + 0, + ("No exception when mapping VAAPI buffer for writing. " + + "Expected at least one."), + ) else: pipeline_runner.assertEqual( - len(pipeline_runner.exceptions), 0, "Exceptions have been caught.") + len(pipeline_runner.exceptions), 0, "Exceptions have been caught." + ) if __name__ == "__main__": diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_multi_human_pose_estimation.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_multi_human_pose_estimation.py index e64bd90c4..1d8df830b 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_multi_human_pose_estimation.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_multi_human_pose_estimation.py @@ -23,50 +23,119 @@ ! appsink name=mysink emit-signals=true sync=false """ GOLD_TRUE = [ - BBox(0, 0, 1, 1, - [ - {'format': 'keypoints', - 'layer_name': 'Mconv7_stage2_L2\\Mconv7_stage2_L1', - 'data': [0.79256946, 0.3625, 0.7645139, 0.45416668, 0.79256946, - 0.47916666, 0.7972454, 0.6041667, 0.80659723, 0.6958333, - 0.7411343, 0.42916667, 0.7785417, 0.3125, 0.8159491, - 0.24583334, 0.77386576, 0.67083335, 0.77386576, 0.8208333, - 0.75048614, 0.95416665, 0.73645836, 0.6625, 0.73178244, - 0.79583335, 0.7224305, 0.9291667, 0.7785417, 0.3375, - -1., -1., 0.76918983, 0.35416666, -1., - -1.] - } - ] - ), - BBox(0, 0, 1, 1, - [ - {'format': 'keypoints', - 'layer_name': 'Mconv7_stage2_L2\\Mconv7_stage2_L1', - 'data': [0.57747686, 0.32083333, 0.6195602, 0.4125, 0.6382639, - 0.39583334, 0.57280093, 0.4625, 0.52136576, 0.47916666, - 0.6008565, 0.42916667, 0.5868287, 0.5625, 0.57280093, - 0.65416664, 0.64761573, 0.62916666, 0.6382639, 0.77916664, - 0.6382639, 0.90416664, 0.61488426, 0.6375, 0.6055324, - 0.79583335, 0.6055324, 0.9291667, -1., -1., - 0.5821528, 0.3125, -1., -1., 0.6008565, - 0.3125] - } - ] - ) + BBox( + 0, + 0, + 1, + 1, + [ + { + "format": "keypoints", + "layer_name": "Mconv7_stage2_L2\\Mconv7_stage2_L1", + "data": [ + 0.79256946, + 0.3625, + 0.7645139, + 0.45416668, + 0.79256946, + 0.47916666, + 0.7972454, + 0.6041667, + 0.80659723, + 0.6958333, + 0.7411343, + 0.42916667, + 0.7785417, + 0.3125, + 0.8159491, + 0.24583334, + 0.77386576, + 0.67083335, + 0.77386576, + 0.8208333, + 0.75048614, + 0.95416665, + 0.73645836, + 0.6625, + 0.73178244, + 0.79583335, + 0.7224305, + 0.9291667, + 0.7785417, + 0.3375, + -1.0, + -1.0, + 0.76918983, + 0.35416666, + -1.0, + -1.0, + ], + } + ], + ), + BBox( + 0, + 0, + 1, + 1, + [ + { + "format": "keypoints", + "layer_name": "Mconv7_stage2_L2\\Mconv7_stage2_L1", + "data": [ + 0.57747686, + 0.32083333, + 0.6195602, + 0.4125, + 0.6382639, + 0.39583334, + 0.57280093, + 0.4625, + 0.52136576, + 0.47916666, + 0.6008565, + 0.42916667, + 0.5868287, + 0.5625, + 0.57280093, + 0.65416664, + 0.64761573, + 0.62916666, + 0.6382639, + 0.77916664, + 0.6382639, + 0.90416664, + 0.61488426, + 0.6375, + 0.6055324, + 0.79583335, + 0.6055324, + 0.9291667, + -1.0, + -1.0, + 0.5821528, + 0.3125, + -1.0, + -1.0, + 0.6008565, + 0.3125, + ], + } + ], + ), ] class TestMultiHumanPoseEstimation(unittest.TestCase): def test_multi_human_pose_estimation(self): pipeline_runner = TestPipelineRunner() - pipeline_runner.set_pipeline(PIPELINE_STR, - IMAGE_PATH, - GOLD_TRUE) + pipeline_runner.set_pipeline(PIPELINE_STR, IMAGE_PATH, GOLD_TRUE) pipeline_runner.run_pipeline() for e in pipeline_runner.exceptions: print(e) - pipeline_runner.assertEqual(len(pipeline_runner.exceptions), 0, - "Exceptions have been caught.") + pipeline_runner.assertEqual( + len(pipeline_runner.exceptions), 0, "Exceptions have been caught." + ) if __name__ == "__main__": diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_single_human_pose_estimation.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_single_human_pose_estimation.py index e81818dcf..7b733d889 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_single_human_pose_estimation.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_single_human_pose_estimation.py @@ -24,57 +24,117 @@ ! appsink name=mysink emit-signals=true sync=false """ GOLD_TRUE = [ - BBox(0.7052448987960815, 0.3016299605369568, - 0.8172802925109863, 0.9893561005592346, - [ - {'format': 'keypoints', - 'layer_name': 'heatmaps', - 'data': [ - 0.72745574, 0.06521739, 0.65284485, 0.06521739, 0.65284485, - 0.04347826, 0.3544015, 0.10869565, 0.578234, 0.08695652, - 0.27979067, 0.2173913, 0.72745574, 0.26086956, 0.20517981, - 0.3478261, 0.80206656, 0.45652175, 0.27979067, 0.47826087, - 0.9512882, 0.6086956, 0.27979067, 0.5217391, 0.65284485, - 0.54347825, 0.20517981, 0.7173913, 0.578234, 0.76086956, - 0.20517981, 0.9130435, 0.42901236, 0.95652175 - ] - } - ], - class_id=0 - ), - BBox(0.4834686815738678, 0.24317866563796997, - 0.667809247970581, 0.9917208552360535, - [ - { - 'format': 'keypoints', - 'layer_name': 'heatmaps', - 'data': [ - 0.49979568, 0.13043478, 0.5491582, 0.10869565, 0.49979568, - 0.08695652, 0.6478833, 0.10869565, 0.7466084, 0.10869565, - 0.59852076, 0.26086956, 0.84533346, 0.19565217, 0.5491582, - 0.4347826, 0.49979568, 0.2826087, 0.49979568, 0.5869565, - 0.20362046, 0.3043478, 0.69724584, 0.54347825, 0.894696, - 0.5217391, 0.69724584, 0.73913044, 0.84533346, 0.7173913, - 0.7466084, 0.9130435, 0.84533346, 0.8913044 - ] - } - ], - class_id=0 - ), + BBox( + 0.7052448987960815, + 0.3016299605369568, + 0.8172802925109863, + 0.9893561005592346, + [ + { + "format": "keypoints", + "layer_name": "heatmaps", + "data": [ + 0.72745574, + 0.06521739, + 0.65284485, + 0.06521739, + 0.65284485, + 0.04347826, + 0.3544015, + 0.10869565, + 0.578234, + 0.08695652, + 0.27979067, + 0.2173913, + 0.72745574, + 0.26086956, + 0.20517981, + 0.3478261, + 0.80206656, + 0.45652175, + 0.27979067, + 0.47826087, + 0.9512882, + 0.6086956, + 0.27979067, + 0.5217391, + 0.65284485, + 0.54347825, + 0.20517981, + 0.7173913, + 0.578234, + 0.76086956, + 0.20517981, + 0.9130435, + 0.42901236, + 0.95652175, + ], + } + ], + class_id=0, + ), + BBox( + 0.4834686815738678, + 0.24317866563796997, + 0.667809247970581, + 0.9917208552360535, + [ + { + "format": "keypoints", + "layer_name": "heatmaps", + "data": [ + 0.49979568, + 0.13043478, + 0.5491582, + 0.10869565, + 0.49979568, + 0.08695652, + 0.6478833, + 0.10869565, + 0.7466084, + 0.10869565, + 0.59852076, + 0.26086956, + 0.84533346, + 0.19565217, + 0.5491582, + 0.4347826, + 0.49979568, + 0.2826087, + 0.49979568, + 0.5869565, + 0.20362046, + 0.3043478, + 0.69724584, + 0.54347825, + 0.894696, + 0.5217391, + 0.69724584, + 0.73913044, + 0.84533346, + 0.7173913, + 0.7466084, + 0.9130435, + 0.84533346, + 0.8913044, + ], + } + ], + class_id=0, + ), ] class TestSingleHumanPoseEstimation(unittest.TestCase): def test_single_human_pose_estimation(self): pipeline_runner = TestPipelineRunner() - pipeline_runner.set_pipeline(PIPELINE_STR, - IMAGE_PATH, - GOLD_TRUE) + pipeline_runner.set_pipeline(PIPELINE_STR, IMAGE_PATH, GOLD_TRUE) pipeline_runner.run_pipeline() for e in pipeline_runner.exceptions: print(e) - pipeline_runner.assertEqual(len(pipeline_runner.exceptions), 0, - "Exceptions have been caught.") + pipeline_runner.assertEqual( + len(pipeline_runner.exceptions), 0, "Exceptions have been caught." + ) if __name__ == "__main__": diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_vehicle_pedestrian_tracker.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_vehicle_pedestrian_tracker.py index 4d1d79019..97f7b89b5 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_vehicle_pedestrian_tracker.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_pipeline_vehicle_pedestrian_tracker.py @@ -11,20 +11,20 @@ from utils import BBox, get_model_path, get_model_proc_path SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) -PEOPLE_IMAGE_PATH = os.path.join( - SCRIPT_DIR, "test_files", "people_detection.png") +PEOPLE_IMAGE_PATH = os.path.join(SCRIPT_DIR, "test_files", "people_detection.png") CAR_IMAGE_PATH = os.path.join(SCRIPT_DIR, "test_files", "car_detection.png") FILE_PATH = os.path.join(SCRIPT_DIR, "meta_vpt.json") D_MODEL_NAME = "person-vehicle-bike-detection-crossroad-0078" -D_MODEL_PATH, D_MODEL_PROC_PATH = get_model_path( - D_MODEL_NAME), get_model_proc_path(D_MODEL_NAME) +D_MODEL_PATH, D_MODEL_PROC_PATH = get_model_path(D_MODEL_NAME), get_model_proc_path(D_MODEL_NAME) C1_MODEL_NAME = "person-attributes-recognition-crossroad-0230" -C1_MODEL_PATH, C1_MODEL_PROC_PATH = get_model_path( - C1_MODEL_NAME), get_model_proc_path(C1_MODEL_NAME) +C1_MODEL_PATH, C1_MODEL_PROC_PATH = get_model_path(C1_MODEL_NAME), get_model_proc_path( + C1_MODEL_NAME +) C2_MODEL_NAME = "vehicle-attributes-recognition-barrier-0039" -C2_MODEL_PATH, C2_MODEL_PROC_PATH = get_model_path( - C2_MODEL_NAME), get_model_proc_path(C2_MODEL_NAME) +C2_MODEL_PATH, C2_MODEL_PROC_PATH = get_model_path(C2_MODEL_NAME), get_model_proc_path( + C2_MODEL_NAME +) PIPELINE_STR_TEMPLATE = """appsrc name=mysrc ! \ @@ -39,77 +39,78 @@ def set_of_pipelines(): - tracker_types = ['short-term-imageless', 'zero-term'] + tracker_types = ["short-term-imageless", "zero-term"] inference_intervals = [4, 1] for tracker_type, interval in zip(tracker_types, inference_intervals): - pipeline_str = PIPELINE_STR_TEMPLATE.format(D_MODEL_PATH, D_MODEL_PROC_PATH, - interval, tracker_type, - C1_MODEL_PATH, C1_MODEL_PROC_PATH, - C2_MODEL_PATH, C2_MODEL_PROC_PATH, FILE_PATH - ) + pipeline_str = PIPELINE_STR_TEMPLATE.format( + D_MODEL_PATH, + D_MODEL_PROC_PATH, + interval, + tracker_type, + C1_MODEL_PATH, + C1_MODEL_PROC_PATH, + C2_MODEL_PATH, + C2_MODEL_PROC_PATH, + FILE_PATH, + ) print(pipeline_str) - yield(pipeline_str) + yield pipeline_str PEOPLE_GOLD_TRUE = [ - BBox(0.4875, 0.21782178217821782, 0.6875, 0.9851485148514851, - [ - { - 'label': "M: has_longpants ", - 'layer_name': "453", - 'name': "person-attributes" - } - ], tracker_id=1, class_id=1 - ), - BBox(0.7055555555555556, 0.29207920792079206, 0.8305555555555556, 1.0, - [ - { - "label": "F: has_bag has_longhair ", - "layer_name": "453", - "name": "person-attributes" - } - ], tracker_id=2, class_id=1 - )] + BBox( + 0.4875, + 0.21782178217821782, + 0.6875, + 0.9851485148514851, + [{"label": "M: has_longpants ", "layer_name": "453", "name": "person-attributes"}], + tracker_id=1, + class_id=1, + ), + BBox( + 0.7055555555555556, + 0.29207920792079206, + 0.8305555555555556, + 1.0, + [{"label": "F: has_bag has_longhair ", "layer_name": "453", "name": "person-attributes"}], + tracker_id=2, + class_id=1, + ), +] CAR_GOLD_TRUE = [ - BBox(0.10026041666666667, 0.19907407407407407, 0.32421875, 1.0, - [ - { - "label": "white", - "layer_name": "color", - "name": "color" - }, - { - "label": "car", - "layer_name": "type", - "name": "type" - } - - ], tracker_id=1, class_id=2 - ), - BBox(0.4127604166666667, 0.2523148148148148, 0.6184895833333334, 0.9467592592592593, - [ - { - "label": "red", - "layer_name": "color", - "name": "color" - }, - { - "label": "car", - "layer_name": "type", - "name": "type" - } - - ], tracker_id=2, class_id=2 - )] + BBox( + 0.10026041666666667, + 0.19907407407407407, + 0.32421875, + 1.0, + [ + {"label": "white", "layer_name": "color", "name": "color"}, + {"label": "car", "layer_name": "type", "name": "type"}, + ], + tracker_id=1, + class_id=2, + ), + BBox( + 0.4127604166666667, + 0.2523148148148148, + 0.6184895833333334, + 0.9467592592592593, + [ + {"label": "red", "layer_name": "color", "name": "color"}, + {"label": "car", "layer_name": "type", "name": "type"}, + ], + tracker_id=2, + class_id=2, + ), +] class TestVehiclePedestrianTracker(unittest.TestCase): def test_pedestrian_tracker_pipeline(self): pipeline_runner = TestPipelineRunner() for pipeline_str in set_of_pipelines(): - pipeline_runner.set_pipeline( - pipeline_str, PEOPLE_IMAGE_PATH, PEOPLE_GOLD_TRUE, True) + pipeline_runner.set_pipeline(pipeline_str, PEOPLE_IMAGE_PATH, PEOPLE_GOLD_TRUE, True) pipeline_runner.run_pipeline() if os.path.isfile(FILE_PATH): @@ -117,14 +118,14 @@ def test_pedestrian_tracker_pipeline(self): for e in pipeline_runner.exceptions: print(e) - pipeline_runner.assertEqual(len(pipeline_runner.exceptions), 0, - "Exceptions have been caught.") + pipeline_runner.assertEqual( + len(pipeline_runner.exceptions), 0, "Exceptions have been caught." + ) def test_vehicle_tracker_pipeline(self): pipeline_runner = TestPipelineRunner() for pipeline_str in set_of_pipelines(): - pipeline_runner.set_pipeline( - pipeline_str, CAR_IMAGE_PATH, CAR_GOLD_TRUE, True) + pipeline_runner.set_pipeline(pipeline_str, CAR_IMAGE_PATH, CAR_GOLD_TRUE, True) pipeline_runner.run_pipeline() if os.path.isfile(FILE_PATH): @@ -132,8 +133,9 @@ def test_vehicle_tracker_pipeline(self): for e in pipeline_runner.exceptions: print(e) - pipeline_runner.assertEqual(len(pipeline_runner.exceptions), 0, - "Exceptions have been caught.") + pipeline_runner.assertEqual( + len(pipeline_runner.exceptions), 0, "Exceptions have been caught." + ) if __name__ == "__main__": diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_region_of_interest.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_region_of_interest.py index 7b2a567a1..59f988237 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_region_of_interest.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_region_of_interest.py @@ -9,9 +9,10 @@ import time import gi -gi.require_version('GstVideo', '1.0') -gi.require_version('GLib', '2.0') -gi.require_version('Gst', '1.0') + +gi.require_version("GstVideo", "1.0") +gi.require_version("GLib", "2.0") +gi.require_version("Gst", "1.0") from gstgva.region_of_interest import RegionOfInterest, Tensor from gstgva.util import VideoRegionOfInterestMeta, libgst @@ -29,8 +30,7 @@ def setUp(self): video_info.set_format(GstVideo.VideoFormat.NV12, 1920, 1080) # FullHD vf = VideoFrame(self.buffer, video_info=video_info) - self.roi = vf.add_region( - 0.0, 0.0, 0.3, 0.6, "label", 0.77, normalized=True) + self.roi = vf.add_region(0.0, 0.0, 0.3, 0.6, "label", 0.77, normalized=True) def test_add_tensor(self): self.assertAlmostEqual(self.roi.confidence(), 0.77) @@ -38,9 +38,7 @@ def test_add_tensor(self): tensors_num = 10 for i in range(0, tensors_num): - gst_structure = libgst.gst_structure_new_empty( - f"tensor_{i}".encode("utf-8") - ) + gst_structure = libgst.gst_structure_new_empty(f"tensor_{i}".encode("utf-8")) tensor = Tensor(gst_structure) tensor["confidence"] = i / 10 self.roi.add_tensor(tensor) @@ -48,18 +46,15 @@ def test_add_tensor(self): self.assertEqual(len(list(self.roi.tensors())), tensors_num + 1) delta = 0.0000001 self.assertAlmostEqual(self.roi.confidence(), 0.77, delta=delta) - self.assertAlmostEqual((list(self.roi.tensors()))[ - 5].confidence(), 0.4, delta=delta) + self.assertAlmostEqual((list(self.roi.tensors()))[5].confidence(), 0.4, delta=delta) confidence = 0.0 for it_tensor in self.roi.tensors(): if not it_tensor.is_detection(): - self.assertAlmostEqual( - it_tensor.confidence(), confidence, delta=delta) + self.assertAlmostEqual(it_tensor.confidence(), confidence, delta=delta) confidence += 0.1 else: - self.assertAlmostEqual( - it_tensor.confidence(), 0.77, delta=delta) + self.assertAlmostEqual(it_tensor.confidence(), 0.77, delta=delta) def test_add_object_id_set_get(self): self.assertIsNone(self.roi.object_id()) @@ -76,5 +71,5 @@ def tearDown(self): pass -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_tensor.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_tensor.py index 59755267a..8807f0bed 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_tensor.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_tensor.py @@ -7,7 +7,8 @@ import unittest import gi -gi.require_version('Gst', '1.0') + +gi.require_version("Gst", "1.0") gi.require_version("GstVideo", "1.0") gi.require_version("GLib", "2.0") from gi.repository import GstVideo, GLib, Gst, GObject @@ -15,6 +16,7 @@ from gstgva.util import libgst from gstgva.tensor import Tensor + class TensorTestCase(unittest.TestCase): def setUp(self): pass @@ -24,7 +26,7 @@ def test_tensor(self): test_label_id = 2 test_confidence = 0.5 - structure = libgst.gst_structure_new_empty('classification'.encode("utf-8")) + structure = libgst.gst_structure_new_empty("classification".encode("utf-8")) tensor = Tensor(structure) self.assertEqual(tensor.name(), "classification") @@ -72,8 +74,7 @@ def test_tensor(self): tensor["precision"] = Tensor.PRECISION.U8.value self.assertEqual(tensor.has_field("precision"), True) - self.assertEqual((Tensor.PRECISION)( - tensor.__getitem__("precision")), tensor.precision()) + self.assertEqual((Tensor.PRECISION)(tensor.__getitem__("precision")), tensor.precision()) tensor["layout"] = Tensor.LAYOUT.NCHW.value self.assertEqual(tensor.has_field("layout"), True) @@ -86,19 +87,9 @@ def test_tensor(self): self.assertEqual(tensor.layout_as_string(), "NCHW") self.assertEqual(tensor.precision_as_string(), "U8") - # Currently Tensor.__setitem__ for list -> GValueArray of GstStructure is not implemented (technical issues) - # dims = [1, 2, 3] - # tensor["dims"] = dims - # idx=0 - # dims = tensor.dims() - # print(dims) - # for i in dims: - # self.assertEqual(i, libgobject.g_value_get_int(libgobject.g_value_array_get_nth(test_array, ctypes.c_uint(idx))) - # idx += 1 - def tearDown(self): pass -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_video_frame.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_video_frame.py index e02d1e48d..06889e690 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_video_frame.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/test_video_frame.py @@ -9,7 +9,8 @@ import numpy as np import gi -gi.require_version('Gst', '1.0') + +gi.require_version("Gst", "1.0") gi.require_version("GstVideo", "1.0") gi.require_version("GLib", "2.0") from gi.repository import Gst, GstVideo, GLib @@ -27,23 +28,19 @@ def setUp(self): self.buffer = Gst.Buffer.new_allocate(None, 0, None) self.video_info_nv12 = GstVideo.VideoInfo.new() - self.video_info_nv12.set_format( - GstVideo.VideoFormat.NV12, 1920, 1080) # FullHD + self.video_info_nv12.set_format(GstVideo.VideoFormat.NV12, 1920, 1080) # FullHD self.video_frame_nv12 = va.VideoFrame(self.buffer, self.video_info_nv12) self.video_info_i420 = GstVideo.VideoInfo.new() - self.video_info_i420.set_format( - GstVideo.VideoFormat.I420, 1920, 1080) # FullHD + self.video_info_i420.set_format(GstVideo.VideoFormat.I420, 1920, 1080) # FullHD self.video_frame_i420 = va.VideoFrame(self.buffer, self.video_info_i420) self.video_info_bgrx = GstVideo.VideoInfo.new() - self.video_info_bgrx.set_format( - GstVideo.VideoFormat.BGRX, 1920, 1080) # FullHD + self.video_info_bgrx.set_format(GstVideo.VideoFormat.BGRX, 1920, 1080) # FullHD self.video_frame_bgrx = va.VideoFrame(self.buffer, self.video_info_bgrx) - def tearDown(self): pass @@ -79,9 +76,7 @@ def test_regions(self): counter += 1 self.assertEqual(counter, rois_num) - self.video_frame_nv12.add_region( - 0.0, 0.0, 0.3, 0.6, "label", 0.8, normalized=True - ) + self.video_frame_nv12.add_region(0.0, 0.0, 0.3, 0.6, "label", 0.8, normalized=True) self.assertEqual(len(list(self.video_frame_nv12.regions())), rois_num + 1) self.assertEqual(len(regions), rois_num) @@ -101,8 +96,9 @@ def test_tensors(self): for ind in range(tensor_meta_size): test_model = model_name + str(ind) - tensor_ind = next(i for i, tensor in enumerate(tensors) - if tensor.model_name() == test_model) + tensor_ind = next( + i for i, tensor in enumerate(tensors) if tensor.model_name() == test_model + ) del tensors[tensor_ind] self.assertEqual(len(tensors), 0) @@ -118,8 +114,9 @@ def test_messages(self): self.assertEqual(len(messages), messages_num) for ind in range(messages_num): - message_ind = next(i for i, message in enumerate(messages) - if message == test_message + str(ind)) + message_ind = next( + i for i, message in enumerate(messages) if message == test_message + str(ind) + ) messages.pop(message_ind) pass self.assertEqual(len(messages), 0) @@ -157,5 +154,5 @@ def test_data(self): self.assertRaises(Exception, frame_from_buf.data()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main(verbosity=3) diff --git a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/utils.py b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/utils.py index 4381dc09b..a10bf742d 100644 --- a/libraries/dl-streamer/tests/unit_tests/tests_gstgva/utils.py +++ b/libraries/dl-streamer/tests/unit_tests/tests_gstgva/utils.py @@ -12,7 +12,7 @@ def env_var_value(env_var): try: - env_var_values = os.environ[env_var].split(':') + env_var_values = os.environ[env_var].split(":") except KeyError: env_var_values = None return env_var_values @@ -21,29 +21,33 @@ def env_var_value(env_var): def get_model_path(model_name, type="ir", precision="FP32"): if os.path.isfile(model_name) and model_name.endswith(".xml"): return model_name - models_path_list = env_var_value('MODELS_PATH') + models_path_list = env_var_value("MODELS_PATH") # new models location - path/PR/name.xml, path/name.onnx for models_path in models_path_list: for path, subdirs, files in os.walk(models_path): for name in files: if type == "ir": - if ((precision.lower() in path.lower() and name == (model_name + ".xml")) or - name == "{}-{}.xml".format(model_name, precision.lower())): - return (os.path.join(path, name)) + precision_lower = precision.lower() + if ( + precision.lower() in path.lower() and name == (model_name + ".xml") + ) or name == f"{model_name}-{precision_lower}.xml": + return os.path.join(path, name) if type == "onnx": - if (name == model_name + '.onnx'): - return (os.path.join(path, name)) + if name == model_name + ".onnx": + return os.path.join(path, name) # old models location - path/name-pr.xml for models_path in models_path_list: for path, subdirs, files in os.walk(models_path): for name in files: - if (precision == "FP32" and name == model_name + '.xml'): - return (os.path.join(path, name)) + if precision == "FP32" and name == model_name + ".xml": + return os.path.join(path, name) - raise ValueError("Model was not found. Check your MODELS_PATH={} environment variable or model's name ({}) & precision ({})".format( - models_path_list, model_name, precision)) + raise ValueError( + f"Model was not found. Check your MODELS_PATH={models_path_list} " + + f"environment variable or model's name ({model_name}) & precision ({precision})" + ) def get_model_proc_path(model_name): @@ -54,22 +58,23 @@ def get_model_proc_path(model_name): for model_proc_path in models_procs_path: for path, subdirs, files in os.walk(model_proc_path): for name in files: - if f'{model_name}.json' == name: - return (os.path.join(path, name)) + if f"{model_name}.json" == name: + return os.path.join(path, name) else: pwd = env_var_value("PWD")[0] - gst_va_path = pwd[:pwd.find( - "gst-video-analytics") + len("gst-video-analytics")] + gst_va_path = pwd[: pwd.find("gst-video-analytics") + len("gst-video-analytics")] samples_path = gst_va_path + "/samples" for path, subdirs, files in os.walk(samples_path): for name in files: - if f'{model_name}.json' == name: - return (os.path.join(path, name)) + if f"{model_name}.json" == name: + return os.path.join(path, name) return None class BBox: - def __init__(self, x_min, y_min, x_max, y_max, additional_info=None, class_id=0, tracker_id=None): + def __init__( + self, x_min, y_min, x_max, y_max, additional_info=None, class_id=0, tracker_id=None + ): self.x_min, self.y_min, self.x_max, self.y_max = x_min, y_min, x_max, y_max self.additional_info = additional_info self.class_id = class_id @@ -79,14 +84,18 @@ def __repr__(self): return f"BBox({str(self)})" def __str__(self): - return f"<({self.x_min}, {self.y_min}, {self.x_max}, {self.y_max}), {self.additional_info}, class_id={self.class_id}, tracker_id={self.tracker_id}>" + return (f"<({self.x_min}, {self.y_min}, {self.x_max}, {self.y_max}), " + + f"{self.additional_info}, class_id={self.class_id}, " + + f"tracker_id={self.tracker_id}>") - @ staticmethod + @staticmethod def IoU(bbox_1, bbox_2): - if (bbox_1.x_max < bbox_2.x_min or - bbox_2.x_max < bbox_1.x_min or - bbox_1.y_max < bbox_2.y_min or - bbox_2.y_max < bbox_1.y_min): + if ( + bbox_1.x_max < bbox_2.x_min + or bbox_2.x_max < bbox_1.x_min + or bbox_1.y_max < bbox_2.y_min + or bbox_2.y_max < bbox_1.y_min + ): return 0 i_x_min = max(bbox_1.x_min, bbox_2.x_min) @@ -95,67 +104,83 @@ def IoU(bbox_1, bbox_2): i_y_max = min(bbox_1.y_max, bbox_2.y_max) intersection_area = (i_x_max - i_x_min) * (i_y_max - i_y_min) - bbox_1_area = (bbox_1.x_max - bbox_1.x_min) * \ - (bbox_1.y_max - bbox_1.y_min) - bbox_2_area = (bbox_2.x_max - bbox_2.x_min) * \ - (bbox_2.y_max - bbox_2.y_min) + bbox_1_area = (bbox_1.x_max - bbox_1.x_min) * (bbox_1.y_max - bbox_1.y_min) + bbox_2_area = (bbox_2.x_max - bbox_2.x_min) * (bbox_2.y_max - bbox_2.y_min) union_area = bbox_1_area + bbox_2_area - intersection_area - return (intersection_area / union_area) + return intersection_area / union_area - @ staticmethod + @staticmethod def additional_info_is_equal(pr_info, gt_info): if pr_info == gt_info == None: return True truncated_pr_info = list() for gt_info_item in gt_info: - layer_name = gt_info_item['layer_name'] + layer_name = gt_info_item["layer_name"] for pr_info_item in pr_info: - if layer_name == pr_info_item['layer_name']: + if layer_name == pr_info_item["layer_name"]: truncated_pr_info.append(pr_info_item) pr_info = truncated_pr_info if len(pr_info) != len(gt_info): print(len(pr_info), len(gt_info)) return False - pr_info = sorted(pr_info, key=lambda i: i['layer_name']) - gt_info = sorted(gt_info, key=lambda i: i['layer_name']) + pr_info = sorted(pr_info, key=lambda i: i["layer_name"]) + gt_info = sorted(gt_info, key=lambda i: i["layer_name"]) if pr_info == gt_info: return True for pr_info_item, gt_info_item in zip(pr_info, gt_info): - if 'format' in pr_info_item and 'format' in gt_info_item: - if pr_info_item['format'] == gt_info_item['format'] == "landmark_points": - for i, (pr_data, gt_data) in enumerate(zip(pr_info_item['data'], gt_info_item['data'])): + if "format" in pr_info_item and "format" in gt_info_item: + if pr_info_item["format"] == gt_info_item["format"] == "landmark_points": + for i, (pr_data, gt_data) in enumerate( + zip(pr_info_item["data"], gt_info_item["data"]) + ): if abs(pr_data - gt_data) > 0.01: - print("landmark_points[{}]: ".format( - i), pr_data, gt_data) + print(f"landmark_points[{i}]: ", pr_data, gt_data) return False - if pr_info_item['format'] == gt_info_item['format'] == 'keypoints': - for i, (pr_data, gt_data) in enumerate(zip(pr_info_item['data'], gt_info_item['data'])): + if pr_info_item["format"] == gt_info_item["format"] == "keypoints": + for i, (pr_data, gt_data) in enumerate( + zip(pr_info_item["data"], gt_info_item["data"]) + ): if abs(pr_data - gt_data) > 0.01: - print("keypoints[{}]: ".format( - i), pr_data, gt_data) + print(f"keypoints[{i}]: ", pr_data, gt_data) return False - if 'name' in pr_info_item and 'name' in gt_info_item: - supported_names = ["emotion", "gender", "age", - "person-attributes", "type", "color", "action"] - pr_name = pr_info_item['name'] - if pr_name == gt_info_item['name'] and pr_name in supported_names and pr_info_item['label'] != gt_info_item['label']: + if "name" in pr_info_item and "name" in gt_info_item: + supported_names = [ + "emotion", + "gender", + "age", + "person-attributes", + "type", + "color", + "action", + ] + pr_name = pr_info_item["name"] + if ( + pr_name == gt_info_item["name"] + and pr_name in supported_names + and pr_info_item["label"] != gt_info_item["label"] + ): print( - f"Labels aren't equal for '{pr_name}': pr - '{pr_info_item['label']}'; gt - '{gt_info_item['label']}'") + f"Labels aren't equal for '{pr_name}': pr - '{pr_info_item['label']}'" + + f"; gt - '{gt_info_item['label']}'" + ) return False return True - @ staticmethod - def bboxes_is_equal(pr_bboxes: list, gt_bboxes: list, only_number=False, check_additional_info=True): + @staticmethod + def bboxes_is_equal( + pr_bboxes: list, gt_bboxes: list, only_number=False, check_additional_info=True + ): correspondence_matrix = dict() if len(pr_bboxes) == len(gt_bboxes): if only_number: return True else: - print("Number of bboxes is not equal: pr: {}, gt: {}".format(len(pr_bboxes), - len(gt_bboxes))) + len_pr_bboxes = len(pr_bboxes) + len_gt_bboxes = len(gt_bboxes) + print(f"Number of bboxes is not equal: pr: {len_pr_bboxes}, gt: {len_gt_bboxes}") print("Predicted bboxes:", pr_bboxes) return False @@ -165,9 +190,15 @@ def bboxes_is_equal(pr_bboxes: list, gt_bboxes: list, only_number=False, check_a max_iou_index = None for i, gt_bbox in enumerate(gt_bboxes): iou = BBox.IoU(pr_bbox, gt_bbox) - # Different components (OpenVINO™ Toolkit and its plugins, VAS OT, etc.) can change between releases. To track exact accuracy we have Regression Tests. + # Different components (OpenVINO™ Toolkit and its plugins, VAS OT, etc.) + # can change between releases. To track exact accuracy we have Regression Tests. # This IoU check is just sanity check to find out if things really got bad - if (iou > 0.7 and iou <= 1 and iou > max_iou and gt_bbox.class_id == pr_bbox.class_id and gt_bbox.tracker_id == pr_bbox.tracker_id): + if ( + 1 >= iou > 0.7 + and iou > max_iou + and gt_bbox.class_id == pr_bbox.class_id + and gt_bbox.tracker_id == pr_bbox.tracker_id + ): max_corresponde_gt_bbox = gt_bbox max_iou = iou max_iou_index = i @@ -180,7 +211,8 @@ def bboxes_is_equal(pr_bboxes: list, gt_bboxes: list, only_number=False, check_a if check_additional_info: for pr_bbox, gt_bbox in correspondence_matrix.items(): if not BBox.additional_info_is_equal( - pr_bbox.additional_info[:], gt_bbox.additional_info[:]): + pr_bbox.additional_info[:], gt_bbox.additional_info[:] + ): return False return True