Browse Source

Fix typos, CI and README

tags/v0.3.6-rc0
Hennzau haixuanTao 1 year ago
parent
commit
0b0e9aeeff
9 changed files with 73 additions and 75 deletions
  1. +3
    -3
      examples/python-dataflow/dataflow.yml
  2. +3
    -3
      examples/python-dataflow/dataflow_dynamic.yml
  3. +4
    -6
      examples/python-dataflow/dataflow_yolo.yml
  4. +23
    -25
      node-hub/opencv-plot/README.md
  5. +29
    -31
      node-hub/opencv-plot/main.py
  6. +2
    -2
      node-hub/opencv-video-capture/README.md
  7. +5
    -1
      node-hub/opencv-video-capture/main.py
  8. +3
    -3
      node-hub/ultralytics-yolo/README.md
  9. +1
    -1
      node-hub/ultralytics-yolo/main.py

+ 3
- 3
examples/python-dataflow/dataflow.yml View File

@@ -3,7 +3,8 @@ nodes:
build: pip install ../../node-hub/opencv-video-capture
path: opencv-video-capture
inputs:
tick: plot/tick
tick: dora/timer/millis/16
stop: plot/end
outputs:
- image
- text
@@ -17,7 +18,6 @@ nodes:
path: opencv-plot
inputs:
image: camera/image
tick: dora/timer/millis/16 # this node display a window, so it's better to deflect the timer, so when the window is closed, the ticks are not sent anymore in the graph
text: camera/text
outputs:
- tick
- end

+ 3
- 3
examples/python-dataflow/dataflow_dynamic.yml View File

@@ -3,7 +3,8 @@ nodes:
build: pip install ../../node-hub/opencv-video-capture
path: opencv-video-capture
inputs:
tick: plot/tick
tick: dora/timer/millis/16
stop: plot/end
outputs:
- image
env:
@@ -16,6 +17,5 @@ nodes:
path: dynamic
inputs:
image: camera/image
tick: dora/timer/millis/16 # this node display a window, so it's better to deflect the timer, so when the window is closed, the ticks are not sent anymore in the graph
outputs:
- tick
- end

+ 4
- 6
examples/python-dataflow/dataflow_yolo.yml View File

@@ -3,7 +3,8 @@ nodes:
build: pip install ../../node-hub/opencv-video-capture
path: opencv-video-capture
inputs:
tick: plot/tick
tick: dora/timer/millis/16
stop: plot/end
outputs:
- image
env:
@@ -21,7 +22,7 @@ nodes:
outputs:
- bbox
env:
MODEL: yolov5n.pt
MODEL: yolov8n.pt

- id: plot
build: pip install ../../node-hub/opencv-plot
@@ -31,8 +32,5 @@ nodes:
source: camera/image
queue_size: 1
bbox: object-detection/bbox
tick:
source: dora/timer/millis/16 # this node display a window, so it's better to deflect the timer, so when the window is closed, the ticks are not sent anymore in the graph
queue_size: 1
outputs:
- tick
- end

+ 23
- 25
node-hub/opencv-plot/README.md View File

@@ -13,12 +13,8 @@ This node is used to plot a text and a list of bbox on a base image (ideal for o
# bbox: Arrow array of bbox
# text: Arrow array of size 1 containing the text to be plotted

tick:
source: dora/timer/millis/16 # this node display a window, so it's better to deflect the timer, so when the window is closed, the ticks are not sent anymore in the graph
queue_size: 1

outputs:
- tick
- end

env:
PLOT_WIDTH: 640 # optional, default is image input width
@@ -26,13 +22,11 @@ This node is used to plot a text and a list of bbox on a base image (ideal for o
```

# Inputs
-
- `tick`: empty Arrow array to trigger the capture

- `image`: Arrow array containing the base image

```python
image = {
image: {
"width": np.uint32,
"height": np.uint32,
"channels": np.uint8,
@@ -50,29 +44,33 @@ decoded_image = {

```

- `bbox`: an arrow array containing the bounding boxes, confidence scores, and class names of the detected objects

```Python

bbox: {
"bbox": np.array, # flattened array of bounding boxes
"conf": np.array, # flat array of confidence scores
"names": np.array, # flat array of class names
}

encoded_bbox = pa.array([bbox])

decoded_bbox = {
"bbox": encoded_bbox[0]["bbox"].values.to_numpy().reshape(-1, 3),
"conf": encoded_bbox[0]["conf"].values.to_numpy(),
"names": encoded_bbox[0]["names"].values.to_numpy(zero_copy_only=False),
}
```

- `text`: Arrow array containing the text to be plotted

```python
text = {
"text": str,
"font_scale": np.float32,
"color": (np.uint8, np.uint8, np.uint8),
"thickness": np.uint32,
"position": (np.uint32, np.uint32)
}
text: str

encoded_text = pa.array([text])

decoded_text = {
"text": encoded_text[0]["text"].as_py(),
"font_scale": np.float32(encoded_text[0]["font_scale"].as_py()),
"color": (np.uint8(encoded_text[0]["color"].as_py()[0]),
np.uint8(encoded_text[0]["color"].as_py()[1]),
np.uint8(encoded_text[0]["color"].as_py()[2])),
"thickness": np.uint32(encoded_text[0]["thickness"].as_py()),
"position": (np.uint32(encoded_text[0]["position"].as_py()[0]),
np.uint32(encoded_text[0]["position"].as_py()[1]))
}
decoded_text = encoded_text[0].as_py()
```

## License


+ 29
- 31
node-hub/opencv-plot/main.py View File

@@ -7,6 +7,8 @@ import pyarrow as pa

from dora import Node

RUNNER_CI = True if os.getenv("CI", False) == "true" else False


class Plot:
frame: np.array = np.array([])
@@ -23,7 +25,7 @@ class Plot:
height: np.uint32 = None


def plot_frame(plot, ci_enabled):
def plot_frame(plot):
for bbox in zip(plot.bboxes["bbox"], plot.bboxes["conf"], plot.bboxes["names"]):
[
[min_x, min_y, max_x, max_y],
@@ -63,15 +65,10 @@ def plot_frame(plot, ci_enabled):
if plot.width is not None and plot.height is not None:
plot.frame = cv2.resize(plot.frame, (plot.width, plot.height))

if not ci_enabled:
if not RUNNER_CI:
if len(plot.frame.shape) >= 3:
cv2.imshow("Dora Node: opencv-plot", plot.frame)

if cv2.waitKey(1) & 0xFF == ord('q'):
return True

return False


def main():
# Handle dynamic nodes, ask for the name of the node in the dataflow, and the same values as the ENV variables.
@@ -96,11 +93,6 @@ def main():
if isinstance(plot_height, str) and plot_height.isnumeric():
plot_height = int(plot_height)

# check if the code is running in a CI environment (e.g. GitHub Actions) (parse to bool)
ci_enabled = os.getenv("CI", False)
if ci_enabled == "true":
ci_enabled = True

node = Node(args.name) # provide the name to connect to the dataflow if dynamic node
plot = Plot()

@@ -115,17 +107,7 @@ def main():
if event_type == "INPUT":
event_id = event["id"]

if event_id == "tick":
if ci_enabled:
break

node.send_output(
"tick",
pa.array([]),
event["metadata"]
)

elif event_id == "image":
if event_id == "image":
arrow_image = event["value"][0]
image = {
"width": np.uint32(arrow_image["width"].as_py()),
@@ -136,29 +118,45 @@ def main():

plot.frame = np.reshape(image["data"], (image["height"], image["width"], image["channels"]))

if plot_frame(plot, ci_enabled):
break
plot_frame(plot)
if not RUNNER_CI:
if cv2.waitKey(1) & 0xFF == ord("q"):
break
else:
break # break the loop for CI

elif event_id == "bbox":
arrow_bbox = event["value"][0]
plot.bboxes = {
"bbox": arrow_bbox["bbox"].values.to_numpy().reshape(-1, 4),
"conf": arrow_bbox["conf"].values.to_numpy(),
"names": arrow_bbox["names"].values.to_pylist(),
"names": arrow_bbox["names"].values.to_numpy(zero_copy_only=False),
}

if plot_frame(plot, ci_enabled):
break

plot_frame(plot)
if not RUNNER_CI:
if cv2.waitKey(1) & 0xFF == ord("q"):
break
else:
break # break the loop for CI
elif event_id == "text":
plot.text = event["value"][0].as_py()

if plot_frame(plot, ci_enabled):
break
plot_frame(plot)
if not RUNNER_CI:
if cv2.waitKey(1) & 0xFF == ord("q"):
break
else:
break # break the loop for CI

elif event_type == "ERROR":
raise Exception(event["error"])

node.send_output(
"end",
pa.array([0], type=pa.uint8())
)


if __name__ == "__main__":
main()

+ 2
- 2
node-hub/opencv-video-capture/README.md View File

@@ -10,7 +10,7 @@ This node is used to capture video from a camera using OpenCV.
path: opencv-video-capture
inputs:
tick: dora/timer/millis/16 # try to capture at 60fps
# stop: some stop signal from another node
outputs:
- image: # the captured image

@@ -31,7 +31,7 @@ This node is used to capture video from a camera using OpenCV.

```Python

image = {
image: {
"width": np.uint32,
"height": np.uint32,
"channels": np.uint8,


+ 5
- 1
node-hub/opencv-video-capture/main.py View File

@@ -58,7 +58,7 @@ def main():
frame = np.zeros((480, 640, 3), dtype=np.uint8)
cv2.putText(
frame,
f'Error: Could not read frame from camera at path {video_capture_path}.',
f'Error: no frame for camera at path {video_capture_path}.',
(int(30), int(30)),
cv2.FONT_HERSHEY_SIMPLEX,
0.50,
@@ -84,6 +84,10 @@ def main():
event["metadata"]
)

if event_id == "stop":
video_capture.release()
break

elif event_type == "ERROR":
raise Exception(event["error"])



+ 3
- 3
node-hub/ultralytics-yolo/README.md View File

@@ -22,7 +22,7 @@ This node is used to detect objects in images using YOLOv8.
- `image`: Arrow array containing the base image

```python
image = {
image: {
"width": np.uint32,
"height": np.uint32,
"channels": np.uint8,
@@ -46,7 +46,7 @@ decoded_image = {

```Python

bbox = {
bbox: {
"bbox": np.array, # flattened array of bounding boxes
"conf": np.array, # flat array of confidence scores
"names": np.array, # flat array of class names
@@ -57,7 +57,7 @@ encoded_bbox = pa.array([bbox])
decoded_bbox = {
"bbox": encoded_bbox[0]["bbox"].values.to_numpy().reshape(-1, 3),
"conf": encoded_bbox[0]["conf"].values.to_numpy(),
"names": encoded_bbox[0]["names"].values.to_pylist(),
"names": encoded_bbox[0]["names"].values.to_numpy(zero_copy_only=False),
}
```



+ 1
- 1
node-hub/ultralytics-yolo/main.py View File

@@ -41,7 +41,7 @@ def main():
"data": arrow_image["data"].values.to_numpy().astype(np.uint8)
}

frame = image["data"].reshape((image["height"], image["width"], 3))
frame = image["data"].reshape((image["height"], image["width"], image["channels"]))

frame = frame[:, :, ::-1] # OpenCV image (BGR to RGB)
results = model(frame, verbose=False) # includes NMS


Loading…
Cancel
Save