From 1bbd631e6d8261b70532787ccff09699c84d5a7b Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Tue, 21 Nov 2023 09:44:56 +0000 Subject: [PATCH] move image_inference output to simple log, since it generates labelled images itself. --- docker/Dockerfile.base | 2 +- docs/README-airt.md | 2 +- {gamutrf => docs}/yolo_notes.md | 0 gamutrf/grinference2mqtt.py | 51 +++++++++++++ gamutrf/grscan.py | 13 ++-- gamutrf/grsource.py | 2 +- gamutrf/gryolo.py | 122 -------------------------------- tests/test_grscan.py | 6 ++ torchserve-cuda.yml | 2 +- torchserve.yml | 2 +- 10 files changed, 66 insertions(+), 136 deletions(-) rename {gamutrf => docs}/yolo_notes.md (100%) create mode 100644 gamutrf/grinference2mqtt.py delete mode 100644 gamutrf/gryolo.py diff --git a/docker/Dockerfile.base b/docker/Dockerfile.base index d47a3955..28c54eac 100644 --- a/docker/Dockerfile.base +++ b/docker/Dockerfile.base @@ -87,7 +87,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libvulkan-dev \ python3-numpy WORKDIR /root -RUN git clone https://github.com/iqtlabs/gr-iqtlabs -b 1.0.46 +RUN git clone https://github.com/iqtlabs/gr-iqtlabs -b 1.0.48 COPY --from=iqtlabs/gamutrf-vkfft:latest /root /root/gr-iqtlabs WORKDIR /root/gr-iqtlabs/build COPY --from=sigmf-builder /usr/local /usr/local diff --git a/docs/README-airt.md b/docs/README-airt.md index f6871f29..8a5230ff 100644 --- a/docs/README-airt.md +++ b/docs/README-airt.md @@ -85,7 +85,7 @@ install gr-iqtlabs $ git clone https://github.com/google/flatbuffers -b v23.5.26 $ git clone https://github.com/nlohmann/json -b v3.11.2 $ git clone https://github.com/deepsig/libsigmf -b v1.0.2 -$ git clone https://github.com/iqtlabs/gr-iqtlabs -b 1.0.46 +$ git clone https://github.com/iqtlabs/gr-iqtlabs -b 1.0.48 $ mkdir -p flatbuffers/build && cd flatbuffers/build && cmake -DCMAKE_INSTALL_PREFIX=~/.conda/envs/$CONDA_DEFAULT_ENV .. && make -j $(nproc) && make install && cd ../.. $ mkdir -p json/build && cd json/build && cmake -DCMAKE_INSTALL_PREFIX=~/.conda/envs/$CONDA_DEFAULT_ENV .. && make -j $(nproc) && make install && cd ../.. $ mkdir -p libsigmf/build && cd libsigmf/build && cmake -DUSE_SYSTEM_JSON=ON -DUSE_SYSTEM_FLATBUFFERS=ON -DCMAKE_INSTALL_PREFIX=~/.conda/envs/$CONDA_DEFAULT_ENV -DCMAKE_CXX_FLAGS="-I $HOME/.conda/envs/$CONDA_DEFAULT_ENV/include" .. && make -j $(nproc) && make install && cd ../.. diff --git a/gamutrf/yolo_notes.md b/docs/yolo_notes.md similarity index 100% rename from gamutrf/yolo_notes.md rename to docs/yolo_notes.md diff --git a/gamutrf/grinference2mqtt.py b/gamutrf/grinference2mqtt.py new file mode 100644 index 00000000..f5fe1783 --- /dev/null +++ b/gamutrf/grinference2mqtt.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +import json +import sys +import numpy as np + +try: + from gnuradio import gr # pytype: disable=import-error +except ModuleNotFoundError as err: # pragma: no cover + print( + "Run from outside a supported environment, please run via Docker (https://github.com/IQTLabs/gamutRF#readme): %s" + % err + ) + sys.exit(1) + + +DELIM = "\n\n" + + +class inference2mqtt(gr.sync_block): + def __init__( + self, + ): + self.yaml_buffer = "" + + gr.sync_block.__init__( + self, + name="inference2mqtt", + in_sig=[np.ubyte], + out_sig=None, + ) + + def work(self, input_items, output_items): + n = 0 + for input_item in input_items: + raw_input_item = input_item.tobytes().decode("utf8") + n += len(raw_input_item) + self.yaml_buffer += raw_input_item + while True: + delim_pos = self.yaml_buffer.find(DELIM) + if delim_pos == -1: + break + raw_item = self.yaml_buffer[:delim_pos] + item = json.loads(raw_item) + self.yaml_buffer = self.yaml_buffer[delim_pos + len(DELIM) :] + self.process_item(item) + return n + + def process_item(self, item): + print(item) + return diff --git a/gamutrf/grscan.py b/gamutrf/grscan.py index c223b9e2..d27caccc 100644 --- a/gamutrf/grscan.py +++ b/gamutrf/grscan.py @@ -20,7 +20,7 @@ sys.exit(1) from gamutrf.grsource import get_source -from gamutrf.gryolo import yolo_bbox +from gamutrf.grinference2mqtt import inference2mqtt from gamutrf.utils import endianstr @@ -189,16 +189,14 @@ def __init__( image_vlen = np.prod(image_shape) prediction_shape = (1, 8, 8400) prediction_vlen = np.prod(prediction_shape) - image_dir = Path(inference_output_dir, "images") Path(inference_output_dir).mkdir(parents=True, exist_ok=True) - image_dir.mkdir(parents=True, exist_ok=True) self.inference_blocks = [ self.iqtlabs.image_inference( tag="rx_freq", vlen=nfft, x=x, y=y, - image_dir=str(image_dir), + image_dir=inference_output_dir, convert_alpha=255, norm_alpha=0, norm_beta=1, @@ -209,12 +207,9 @@ def __init__( min_peak_points=inference_min_db, model_server=inference_model_server, model_name=inference_model_name, + confidence=inference_min_confidence, ), - yolo_bbox( - str(Path(inference_output_dir, "predictions")), - inference_min_confidence, - inference_nms_threshold, - ), + inference2mqtt(), ] if pretune: diff --git a/gamutrf/grsource.py b/gamutrf/grsource.py index d3f91073..f029a7aa 100644 --- a/gamutrf/grsource.py +++ b/gamutrf/grsource.py @@ -78,5 +78,5 @@ def get_source( ) if sdr == "SoapyAIRT": workaround_start_hook = airt_workaround_start_hook - + sources[0].set_thread_priority(99) return sources, cmd_port, workaround_start_hook diff --git a/gamutrf/gryolo.py b/gamutrf/gryolo.py deleted file mode 100644 index 723be6ee..00000000 --- a/gamutrf/gryolo.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -import json -import os -import sys -from pathlib import Path -import cv2 -import numpy as np - -try: - from gnuradio import gr # pytype: disable=import-error -except ModuleNotFoundError as err: # pragma: no cover - print( - "Run from outside a supported environment, please run via Docker (https://github.com/IQTLabs/gamutRF#readme): %s" - % err - ) - sys.exit(1) - - -DELIM = "\n\n" - - -class yolo_bbox(gr.sync_block): - def __init__( - self, - output_dir, - confidence_threshold=0.5, - nms_threshold=0.5, - ): - self.output_dir = output_dir - self.confidence_threshold = confidence_threshold - self.nms_threshold = nms_threshold - self.yaml_buffer = "" - - gr.sync_block.__init__( - self, - name="yolo_bbox", - in_sig=[np.ubyte], - out_sig=None, - ) - - def work(self, input_items, output_items): - n = 0 - for input_item in input_items: - raw_input_item = input_item.tobytes().decode("utf8") - n += len(raw_input_item) - self.yaml_buffer += raw_input_item - while True: - delim_pos = self.yaml_buffer.find(DELIM) - if delim_pos == -1: - break - raw_item = self.yaml_buffer[:delim_pos] - item = json.loads(raw_item) - self.yaml_buffer = self.yaml_buffer[delim_pos + len(DELIM) :] - self.process_item(item) - return n - - def draw_bounding_box(self, img, name, confidence, x, y, x_plus_w, y_plus_h): - label = f"{name}: {confidence}" - color = (255, 255, 255) - cv2.rectangle(img, (x, y), (x_plus_w, y_plus_h), color, 2) - cv2.putText( - img, label, (x - 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2 - ) - - def process_item(self, item): - predictions = item.get("predictions", None) - if not predictions: - return - - boxes = [] - scores = [] - detections = [] - - try: - for name, prediction_data in predictions.items(): - for prediction in prediction_data: - conf = prediction["conf"] - if conf < self.confidence_threshold: - continue - xywh = prediction["xywh"] - box = [ - xywh[0] - (0.5 * xywh[2]), - xywh[1] - (0.5 * xywh[3]), - xywh[2], - xywh[3], - ] - detections.append({"box": box, "score": conf, "name": name}) - boxes.append(box) - scores.append(conf) - except TypeError as e: - print(f"invalid predictions from torchserve: {e}, {predictions}") - return - - if not detections: - return - - original_image = cv2.imread(item["image_path"]) - result_boxes = cv2.dnn.NMSBoxes( - boxes, scores, self.confidence_threshold, self.nms_threshold, 0.5, 200 - ) - - # TODO: output to ZMQ - for detection in detections: - self.draw_bounding_box( - original_image, - detection["name"], - detection["score"], - round(box[0]), - round(box[1]), - round(box[0] + box[2]), - round(box[1] + box[3]), - ) - - Path(self.output_dir).mkdir(parents=True, exist_ok=True) - filename = str( - Path( - self.output_dir, - "_".join(["prediction", os.path.basename(item["image_path"])]), - ) - ) - cv2.imwrite(filename, original_image) diff --git a/tests/test_grscan.py b/tests/test_grscan.py index c0d8a083..9ebd9cf8 100644 --- a/tests/test_grscan.py +++ b/tests/test_grscan.py @@ -43,6 +43,9 @@ def set_time_now(self, time_spec, _mb): def get_time_now(self): return self.time_spec + def set_thread_priority(self, _priority): + return + class FakeUHD: def __init__(self): @@ -63,6 +66,9 @@ def set_sample_rate(self, _channel, _sample_rate): def set_bandwidth(self, _channel, _bw): return + def set_thread_priority(self, _priority): + return + class FakeSoapy: def __init__(self): diff --git a/torchserve-cuda.yml b/torchserve-cuda.yml index 8d05984c..90c94d6d 100644 --- a/torchserve-cuda.yml +++ b/torchserve-cuda.yml @@ -10,7 +10,7 @@ services: ports: - '8080:8080' volumes: - - '${VOL_PREFIX}:/model_store' + - '${VOL_PREFIX}/model_store:/model_store' deploy: resources: reservations: diff --git a/torchserve.yml b/torchserve.yml index 87f7279d..483c474e 100644 --- a/torchserve.yml +++ b/torchserve.yml @@ -10,6 +10,6 @@ services: ports: - '8080:8080' volumes: - - '${VOL_PREFIX}:/model_store' + - '${VOL_PREFIX}/model_store:/model_store' command: - --models mini2_snr=mini2_snr.mar