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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions .github/workflows/create-sae-release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: Create SAE helm release

on:
push:
workflow_dispatch:
inputs:
versionChoice:
type: choice
required: true
description: Version Change
options:
- patch
- minor
- major

permissions:
contents: write

env:
VERSION_CHOICE: ${{ github.event.inputs.versionChoice }}
CHART_NAME: sae
DOCKERHUB_USERNAME: starwit
DOCKERHUB_ORG: starwitorg

jobs:
publish-helm:
name: Publish helm chart
runs-on: [self-hosted, linux, X64]

steps:
- name: Install Helm
uses: azure/setup-helm@v4

- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22

- name: Install GH CLI
uses: dev-hanz-ops/install-gh-cli-action@v0.2.1
with:
gh-cli-version: 2.78.0

- name: Login to Helm registry
run: helm registry login registry-1.docker.io -u $DOCKERHUB_USERNAME -p ${{ secrets.DOCKERHUB_TOKEN }}

- name: Run Helm update
working-directory: helm/sae
run: helm dep update

- name: Bump version and commit
working-directory: helm/sae
run: |
CURRENT_VERSION=$(grep version: Chart.yaml | head -1 | awk '{print $2}')
echo "RELEASE_VERSION=$(npx semver $CURRENT_VERSION -i ${{ env.VERSION_CHOICE }})" >> $GITHUB_ENV

sed -i -r "s/^version: [0-9]+\.[0-9]+\.[0-9]+$/version: ${{ env.RELEASE_VERSION }}/" Chart.yaml

# git add Chart.yaml
# git commit -m "Bump version to ${{ env.RELEASE_VERSION }}"
# git tag ${{ env.RELEASE_VERSION }}
# git push
# - name: Create Github release
# run: gh release create ${{ env.RELEASE_VERSION }} --generate-notes
# env:
# GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# - name: Do Helm release
# working-directory: helm/sae
# run: |
# rm sae-*.tgz
# helm dependency build
# helm package .
# helm push sae-*.tgz oci://registry-1.docker.io/$DOCKERHUB_ORG



23 changes: 12 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,18 @@ Please note, that regardless of deployment method - SAE works in all of them wit

## Repositories
The components of the vision pipeline can be found in the following repositories:
| Component | Repository / URI |
| ---------------- | ---------------------------------------------------------- |
| Video Source | https://github.com/starwit/video-source-py |
| Object Detector | https://github.com/starwit/object-detector |
| Object Tracker | https://github.com/starwit/object-tracker |
| Geo Mapper | https://github.com/starwit/geo-mapper |
| Position Source | https://github.com/starwit/sae-position-source |
| Redis Writer | https://github.com/starwit/sae-redis-writer |
| Database Writer | https://github.com/starwit/vision-api-jms-client |
| vision-api | https://github.com/starwit/vision-api |
| vision-lib | https://github.com/starwit/vision-lib |
| Component | Repository / URI |
| -------------------- | ---------------------------------------------------------- |
| Video Source | https://github.com/starwit/sae-video-source |
| Position Source | https://github.com/starwit/sae-position-source |
| Object Detector | https://github.com/starwit/sae-object-detector |
| Object Tracker | https://github.com/starwit/sae-object-tracker |
| Geo Mapper | https://github.com/starwit/sae-geo-mapper |
| Detection Aggregator | https://github.com/starwit/detection-aggregator |
| Redis Writer | https://github.com/starwit/sae-redis-writer |
| Database Writer | https://github.com/starwit/sae-database-writer |
| vision-api | https://github.com/starwit/vision-api |
| vision-lib | https://github.com/starwit/vision-lib |

## Content Overview
- [`/doc`](doc/README.md) - Documentation of the architecture and some details of the technical setup
Expand Down
2 changes: 1 addition & 1 deletion doc/installation/Installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Please note, that regardless of deployment method - SAE works in all of them wit

## Installation on Kubernetes cluster
1. Set up K3s cluster \
- Create K3s config file (adapt the value of `tls-san`)
- Create K3s config file at `/etc/rancher/k3s/config.yaml` (adapt the value of `tls-san`)
```yaml
write-kubeconfig-mode: "0644"
tls-san:
Expand Down
9 changes: 4 additions & 5 deletions docker-compose/.env.template
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
IMAGE_REGISTRY=docker.io/starwitorg
VIDEO_SOURCE_VERSION=2.3.0
OBJECT_DETECTOR_VERSION=3.3.0
VIDEO_SOURCE_VERSION=2.3.1
OBJECT_DETECTOR_VERSION=4.1.0
OBJECT_TRACKER_VERSION=3.3.0
GEO_MAPPER_VERSION=0.9.0
GEO_MERGER_VERSION=0.1.0
GEO_MAPPER_VERSION=0.10.0
DATABASE_WRITER_VERSION=2.0.0
REDIS_WRITER_VERSION=2.0.2
POSITION_SOURCE_VERSION=1.1.1
AGGREGATOR_VERSION=0.2.4
AGGREGATOR_VERSION=0.2.7

VIDEO_PATH=/PATH/TO/VIDEO
10 changes: 9 additions & 1 deletion docker-compose/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,17 @@ services:
depends_on:
redis:
condition: service_healthy

position-source:
image: ${IMAGE_REGISTRY}/sae-position-source:${POSITION_SOURCE_VERSION}
volumes:
- ./position-source/position-source.settings.yaml:/code/settings.yaml
depends_on:
redis:
condition: service_healthy

object-detector:
image: ${IMAGE_REGISTRY}/object-detector:${OBJECT_DETECTOR_VERSION}
image: ${IMAGE_REGISTRY}/sae-object-detector:${OBJECT_DETECTOR_VERSION}
volumes:
- ./object-detector/object-detector.settings.yaml:/code/settings.yaml
depends_on:
Expand Down
3 changes: 3 additions & 0 deletions docker-compose/geo-mapper/geo-mapper.settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ cameras:
abc_distortion_b: 0.345
abc_distortion_c: -0.705

mapping_strategy:
mode: static

log_level: INFO
redis:
host: redis
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
model:
weights_path: waste.pt
device: "cpu"
inference_size: [ 640, 640 ]
#classes: [ 2 ]
inference_size: [ 640, 640 ]
#classes: [ 2 ]
log_level: DEBUG
redis:
input_stream_prefix: videosource
Expand Down
4 changes: 2 additions & 2 deletions docker-compose/object-detector/object-detector.settings.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
model:
weights_path: yolov8n.pt
device: "cpu"
inference_size: [ 640, 640 ]
classes: [ 2 ]
inference_size: [ 640, 640 ]
classes: [ 2 ]
log_level: DEBUG
redis:
host: redis
Expand Down
16 changes: 8 additions & 8 deletions docker-compose/position-source/position-source.settings.yaml
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
#position_source: # static source outputs the same coordinates twice a second
# type: static
# lat: 52
# lon: 10
position_source: # dynamic source tries to read NMEA sentences from given serial device (i.e. USB gps receiver)
type: serial
serial_device: /dev/ttyACM0
position_source: # static source outputs the same coordinates twice a second
type: static
lat: 52
lon: 10
# position_source: # dynamic source tries to read NMEA sentences from given serial device (i.e. USB gps receiver)
# type: serial
# serial_device: /dev/ttyACM0
# position_source: # command source tries to read NMEA sentences from stdout of given command
# type: command
# command: ["gpspipe", "-r"] # this is passed to Popen; if you want to use a bash pipeline do ["bash", "-c", "command | command2"]


log_level: DEBUG
log_level: INFO
redis:
host: redis
port: 6379
Expand Down
6 changes: 2 additions & 4 deletions docker-compose/redis-writer/redis-writer.settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ log_level: DEBUG
redis:
host: redis
port: 6379
input_stream_prefix: geomapper
target_redis:
host: secondary-redis
port: 6379
output_stream_prefix: output
buffer_length: 100
target_stream_maxlen: 100
stream_ids:
- stream1
mapping_config:
- source: geomapper:stream1
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ uri: rtsp://streaming-server:8554/video-stream
reconnect_backoff_time: 1
max_fps: 10
jpeg_encode: True
log_level: DEBUG
log_level: INFO
redis:
host: redis
port: 6379
79 changes: 46 additions & 33 deletions helm/sae/customvalues.template.yaml
Original file line number Diff line number Diff line change
@@ -1,35 +1,58 @@
positionSource:
enabled: false
settingsYaml: # Everything below this is passed as content of the settings.yaml (notice snake_case vs camelCase)
log_level: INFO
position_source: # static source outputs the same coordinates twice a second
type: static
lat: 52
lon: 10
# position_source: # command source tries to read NMEA sentences from stdout of given command (this is recommended)
# type: command
# command: ["gpspipe", "-r"] # this is passed to Popen; if you want to use a bash pipeline do ["bash", "-c", "command | command2"]
# position_source: # dynamic source tries to read NMEA sentences from given serial device (i.e. USB gps receiver)
# type: dynamic
# serial_device: /dev/ttyACM0
gpsdSidecar:
enabled: false # only enable if non-static config above
image:
repository: starwitorg/sae-gpsd
tag: 2025-09-10
hostGpsDevice: /path/to/gpsdevice # the path to a character device gpsd can use (e.g. /dev/ttyACM0) (is passed to hostPath volume mount)
entrypointSh: |
sleep 3600

videoSource:
logLevel: DEBUG # Options: ERROR, WARNING, INFO, DEBUG
configs:
settingsYamls: # Everything below this is passed as content of the settings.yaml (notice snake_case vs camelCase)
- id: stream1 # The name of the video stream. Will be used as Redis stream key and as camera_id in database output.
uri: 'uri' # Where to retrieve the video from. Must be in a format that OpenCV VideoCapture understands. RTSP stream makes the most sense.
max_fps: 5 # Effectively sets a lower bound on the time between to frames. 0 means off. Integer fractions of original frame rate make the most sense (i.e. 15, 10, 5 for a 30fps source).
scale_width: 0 # If > 0, scale the image to the given width (preserving aspect ratio)
jpeg_quality: 80 # JPEG quality 0 - 100 (100 is lossless and big); Reasonable starting points (for image height): 2160 = 80, 1080 = 90, <720 = 95
log_level: INFO # Options: ERROR, WARNING, INFO, DEBUG

objectDetector:
logLevel: DEBUG # Options: ERROR, WARNING, INFO, DEBUG
customWeights:
enabled: false # Whether to inject custom weights from init container (into custom_weights/*)
imageTag: weights-image-tag # Which tag of the starwitorg/sae-object-detector-weights image to use
config:
settingsYaml:
log_level: INFO # Options: ERROR, WARNING, INFO, DEBUG
model:
weights_path: custom_weights/xyz # Which weights to load. yolov8[nsmlx].pt are shipped with the object-detector. For custom weights see above.
device: cpu # Options: cpu, cuda (uses gpu; needs proper setup; see README)
nms_agnostic: false # Whether to use class-agnostic non-maximum suppression (NMS) (for overlapping detections)
inference_size: [ 640, 640 ] # What resolution the image will be downscaled to before object-detection inference (should be square and a multiple of 32)
classes: [ 2 ] # Which object classes to detect (refer to coco object classes)
drop_edge_detections: false # Drop detections touching the frame borders
inference_size: [ 640, 640 ] # What resolution the image will be downscaled to before object-detection inference (should be square and a multiple of 32)
classes: [ 2 ] # Which object classes to detect (refer to coco object classes)
redis:
stream_ids:
- stream1 # On which video streams to detect objects on. Mostly all video source stream ids.

objectTracker:
logLevel: INFO # Options: ERROR, WARNING, INFO, DEBUG
needsGpu: False # Whether the algorithm needs gpu support (needs proper setup; see README)
streamIds: # On which video streams to track objects (the same as object-detector stream ids above)
- stream1
config: # Tracker specific config (see object-tracker repo / Boxmot for details)
settingsYaml: # Tracker specific config (see object-tracker repo / Boxmot for details)
log_level: INFO # Options: ERROR, WARNING, INFO, DEBUG
tracker_algorithm: OCSORT
tracker_config:
det_thresh: 0.2
Expand All @@ -45,7 +68,8 @@ objectTracker:

geoMapper:
enabled: false # If the geomapper should be deployed (by default it reads from "objecttracker:*"" and outputs into "geomapper:*")
config:
settingsYaml:
log_level: INFO # Options: ERROR, WARNING, INFO, DEBUG
cameras: # Parameters have to be specified for each camera (it makes no sense to run this without correct-ish parameters)
- stream_id: stream1 # This must match one of the existing camera streams
passthrough: false # If the stream should be passed through without geo mapping (all other parameters are ignored if true)
Expand All @@ -67,33 +91,22 @@ geoMapper:
]]
remove_unmapped_detections: false # # If unmapped detections should be removed (i.e. detections filtered by mapping_area, see above)

geoMerger:
enabled: false
config:
merging_config:
max_distance_m: 2
merging_window_ms: 1000
target_mps: 10
input_stream_ids:
- stream1
- stream2
output_stream_id: merged

redisWriter:
enabled: false # If the redis-writer should be deployed (off by default)
configs: # One config per target
instances: # One config per target
- name: writer1 # A unique name to identify the instance
redis: # The SAE internal Redis instance
input_stream_prefix: objecttracker # The prefix of the input stream (e.g. objecttracker or geomapper)
target_redis: # The Redis instance to write to
host: redis-host
port: 6379
output_stream_prefix: saeoutput # The prefix of the output stream (e.g. data will be published to saeoutput:<stream_id>)
buffer_length: 10 # How many messages to buffer before discarding
target_stream_maxlen: 100 # How many messages to keep in the output stream (translates to XADD maxlen option)
tls: false
stream_ids: # Which video stream to attach to
- stream1
settingsYaml:
log_level: INFO # Options: ERROR, WARNING, INFO, DEBUG
#remove_frame_data: null # If frame data should be removed (default true; only applies to SAE messages; beware of privacy and bandwidth consequences!)
target_redis: # The Valkey instance to send this to
host: host
port: 6379
buffer_length: 10
target_stream_maxlen: 100
tls: false
mapping_config: # A list of source (i.e. this SAE instance) to target stream (i.e. on target_redis) mappings
- source: geomapper:stream1 # Source stream name (fully-qualified, including stream prefix)
target: geomapper:mysae1 # (optional) Target stream name; Source name is used if omitted

databaseWriter:
enabled: true # If the database-writer should be deployed
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
{{- with .Values.geoMerger }}
{{- with .Values.detectionAggregator }}
{{- if .enabled }}
{{- with .config }}
{{- with .settingsYaml }}
apiVersion: v1
kind: ConfigMap
metadata:
name: geo-merger-config
name: detection-aggregator-config
data:
settings.yaml: |
{{- toYaml . | nindent 4 }}
---
{{- end }}
{{- end }}
{{- end }}
Loading