Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
Upload sensAI-Generic-Object-Detection with upload_repo.py
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +2 -0
- Dockerfile +25 -0
- README.md +65 -10
- app.py +335 -0
- download_models.py +46 -0
- install_eve.py +104 -0
- requirements.txt +8 -0
- shared/assets/EULA.md +21 -0
- shared/ctypes_enum.py +10 -0
- shared/env_utils.py +49 -0
- shared/eula_tab.py +47 -0
- shared/eve_app_tabs.py +276 -0
- shared/eve_inference_handlers.py +485 -0
- shared/eve_messages.py +231 -0
- shared/eve_python/eve_sdk.py +297 -0
- shared/eve_python/eve_sdk_structs.py +48 -0
- shared/eve_python/structs/CAlgorithms.py +27 -0
- shared/eve_python/structs/CBasicStructs.py +86 -0
- shared/eve_python/structs/CCameraStructs.py +48 -0
- shared/eve_python/structs/CDetectionStructs.py +38 -0
- shared/eve_python/structs/CFaceData.py +55 -0
- shared/eve_python/structs/CFaceIdStructs.py +68 -0
- shared/eve_python/structs/CFpgaData.py +350 -0
- shared/eve_python/structs/CHandGesture.py +144 -0
- shared/eve_python/structs/CImageManipulation.py +12 -0
- shared/eve_python/structs/CKarolinska.py +57 -0
- shared/eve_python/structs/CLandmarkMaps.py +40 -0
- shared/eve_python/structs/CROIStructs.py +29 -0
- shared/eve_python/structs/CScreenLocation.py +10 -0
- shared/eve_python/structs/CVisualSpeechStructs.py +18 -0
- shared/eve_python/structs/EveAlgorithm.py +5 -0
- shared/eve_python/structs/EveAlgorithmStructs.py +14 -0
- shared/eve_python/structs/EveCallbackReturnData.py +13 -0
- shared/eve_python/structs/EveCamera.py +5 -0
- shared/eve_python/structs/EveCameraStructs.py +27 -0
- shared/eve_python/structs/EveConfigurationParameters.py +36 -0
- shared/eve_python/structs/EveControlInterface.py +9 -0
- shared/eve_python/structs/EveControlOption.py +8 -0
- shared/eve_python/structs/EveErrors.py +22 -0
- shared/eve_python/structs/EveFaceId.py +5 -0
- shared/eve_python/structs/EveFaceIdStructs.py +31 -0
- shared/eve_python/structs/EveFaceTracker.py +5 -0
- shared/eve_python/structs/EveFaceTrackerStructs.py +40 -0
- shared/eve_python/structs/EveFpga.py +7 -0
- shared/eve_python/structs/EveFpgaStructs.py +24 -0
- shared/eve_python/structs/EveHandGesture.py +5 -0
- shared/eve_python/structs/EveHandGestureStructs.py +48 -0
- shared/eve_python/structs/EveImage.py +5 -0
- shared/eve_python/structs/EveImageManipulation.py +5 -0
- shared/eve_python/structs/EveImageManipulationStructs.py +12 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
*.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
*.deb filter=lfs diff=lfs merge=lfs -text
|
Dockerfile
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# syntax=docker/dockerfile:1
|
| 2 |
+
FROM python:3.11
|
| 3 |
+
|
| 4 |
+
RUN apt-get update && apt-get install -y ffmpeg libopenblas-dev libopencv-dev qt6-base-dev qt6-multimedia-dev libssl-dev mesa-opencl-icd libboost-all-dev libturbojpeg0-dev ocl-icd-opencl-dev clinfo ocl-icd-libopencl1 && rm -rf /var/lib/apt/lists
|
| 5 |
+
|
| 6 |
+
ARG HF_TOKEN=""
|
| 7 |
+
|
| 8 |
+
RUN pip install --no-cache-dir huggingface-hub
|
| 9 |
+
COPY install_eve.py /tmp/install_eve.py
|
| 10 |
+
RUN --mount=type=secret,id=MODEL_ACCESS_TOKEN \
|
| 11 |
+
HF_TOKEN="$HF_TOKEN" python /tmp/install_eve.py && rm /tmp/install_eve.py
|
| 12 |
+
|
| 13 |
+
RUN useradd -m -u 1000 user
|
| 14 |
+
USER user
|
| 15 |
+
ENV PATH="/home/user/.local/bin:$PATH"
|
| 16 |
+
|
| 17 |
+
WORKDIR /app
|
| 18 |
+
|
| 19 |
+
COPY --chown=user ./requirements.txt requirements.txt
|
| 20 |
+
RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
| 21 |
+
|
| 22 |
+
RUN mkdir -p /home/user/.config
|
| 23 |
+
|
| 24 |
+
COPY --chown=user . /app
|
| 25 |
+
CMD ["python", "app.py"]
|
README.md
CHANGED
|
@@ -1,10 +1,65 @@
|
|
| 1 |
-
---
|
| 2 |
-
title:
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: Lattice sensAI Generic Object Detection
|
| 3 |
+
slug: sensAI-Generic-Object-Detection
|
| 4 |
+
short_description: Object detection — GMOD-80 / AMOD-8 / OMOD on the EVE SDK
|
| 5 |
+
emoji: 📦
|
| 6 |
+
colorFrom: blue
|
| 7 |
+
colorTo: indigo
|
| 8 |
+
sdk: docker
|
| 9 |
+
pinned: false
|
| 10 |
+
tags:
|
| 11 |
+
- computer-vision
|
| 12 |
+
- real-time
|
| 13 |
+
- edge-ai
|
| 14 |
+
- on-device
|
| 15 |
+
- embedded
|
| 16 |
+
- low-power
|
| 17 |
+
- object-detection
|
| 18 |
+
- gmod
|
| 19 |
+
- amod
|
| 20 |
+
- omod
|
| 21 |
+
- npu
|
| 22 |
+
- soc
|
| 23 |
+
---
|
| 24 |
+
|
| 25 |
+
The Lattice sensAI Generic Object Detection demo runs the EVE SDK's MOD
|
| 26 |
+
(Multi-Object Detection) subsystem against a frame from an uploaded image,
|
| 27 |
+
an uploaded video, or a live webcam feed. Pick exactly one of three models:
|
| 28 |
+
|
| 29 |
+
| Model | Description |
|
| 30 |
+
| --- | --- |
|
| 31 |
+
| **GMOD-80** | Generic 80-class object detector (active baseline) |
|
| 32 |
+
| **AMOD-8** | 8-class automotive object detector — person, bicycle, car, motorcycle, bus, truck, traffic light, stop sign *(preview — placeholder)* |
|
| 33 |
+
| **OMOD** | Many-class office-objects detector *(preview — placeholder)* |
|
| 34 |
+
|
| 35 |
+
> **Preview note.** AMOD and OMOD currently fall back to GMOD-80 weights —
|
| 36 |
+
> the EVE C SDK ships a single hardcoded MOD model and does not yet expose a
|
| 37 |
+
> runtime model-switch entry point. Once the SDK gains
|
| 38 |
+
> `EveLoadObjectDetectionModel(...)` (or equivalent), the placeholders go
|
| 39 |
+
> live without any UI changes — only the EVE wrapper and
|
| 40 |
+
> `download_models.py` need updates.
|
| 41 |
+
|
| 42 |
+
To preview the demo, use the tabs:
|
| 43 |
+
|
| 44 |
+
- <u>Live Inference</u> — webcam → annotated frames in real time.
|
| 45 |
+
- <u>Offline Inference</u> — upload an image **or** a video; mutually
|
| 46 |
+
exclusive accordions keep the UI focused on one input at a time.
|
| 47 |
+
|
| 48 |
+
> Note: For demo purposes, the AI pipeline and image-draw operations run on
|
| 49 |
+
> a Hugging Face CPU server. Performance varies with concurrent users.
|
| 50 |
+
|
| 51 |
+
For SDK access, fill the form on
|
| 52 |
+
[this page](https://huggingface.co/LatticeSemi/sensAI-Edge-Vision-Engine-SDK-Packages)
|
| 53 |
+
and follow the download instructions. Support: evehelp@latticesemi.com.
|
| 54 |
+
|
| 55 |
+
## About
|
| 56 |
+
|
| 57 |
+
This demo is maintained by **Lattice Semiconductor** (LatticeSemi).
|
| 58 |
+
|
| 59 |
+
## License
|
| 60 |
+
|
| 61 |
+
Proprietary - Lattice Semiconductor Corporation. All rights reserved.
|
| 62 |
+
|
| 63 |
+
## Need a Longer or Commercial License?
|
| 64 |
+
|
| 65 |
+
- **Email**: evehelp@latticesemi.com
|
app.py
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import atexit
|
| 2 |
+
import os
|
| 3 |
+
import sys
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
|
| 6 |
+
import gradio as gr
|
| 7 |
+
|
| 8 |
+
sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent / "shared"))
|
| 9 |
+
sys.path.insert(0, str(Path(__file__).resolve().parent / "shared"))
|
| 10 |
+
|
| 11 |
+
from env_utils import load_dotenv_if_present, require_secrets
|
| 12 |
+
from eula_tab import build_eula_tab
|
| 13 |
+
from eve_app_tabs import build_image_or_video_offline_tab, build_live_inference_tab
|
| 14 |
+
from eve_inference_handlers import EveAppHandlers, patch_video_for_external_urls
|
| 15 |
+
from eve_worker_pool import EveWorkerPool
|
| 16 |
+
from live_inference import (
|
| 17 |
+
TAB_SWITCH_AUTO_STOP_JS,
|
| 18 |
+
RtcConfigProvider,
|
| 19 |
+
patch_aioice_stun_transaction,
|
| 20 |
+
patch_aiortc_h264_nvenc,
|
| 21 |
+
patch_fastrtc_frame_queue,
|
| 22 |
+
patch_fastrtc_yuv420p_output,
|
| 23 |
+
)
|
| 24 |
+
from live_stream_manager import LiveStreamManager
|
| 25 |
+
from log_utils import log_cpu_info, setup_logger
|
| 26 |
+
from session_tracker import SessionTracker
|
| 27 |
+
from usage_analytics import UsageTracker
|
| 28 |
+
from video_processing import VideoLimits
|
| 29 |
+
|
| 30 |
+
MOD_MODELS = ["GMOD-80", "AMOD-8", "OMOD"]
|
| 31 |
+
DEFAULT_MOD_MODEL = "GMOD-80"
|
| 32 |
+
|
| 33 |
+
_IMAGE_EXTS = (".jpg", ".jpeg", ".png", ".bmp", ".webp")
|
| 34 |
+
_VIDEO_EXTS = (".mp4", ".avi", ".mov", ".mkv", ".webm")
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def _build_feature_radio(hint: str = "") -> gr.Radio:
|
| 38 |
+
"""Build the model-selection radio — exactly one MOD model active at a time."""
|
| 39 |
+
label = "Object Detection Model"
|
| 40 |
+
if hint:
|
| 41 |
+
label += f" — {hint}"
|
| 42 |
+
return gr.Radio(
|
| 43 |
+
choices=MOD_MODELS,
|
| 44 |
+
value=DEFAULT_MOD_MODEL,
|
| 45 |
+
label=label,
|
| 46 |
+
info="Only GMOD-80 is active. AMOD-8 / OMOD are placeholders pending an "
|
| 47 |
+
"EVE SDK update that adds runtime model switching.",
|
| 48 |
+
interactive=False,
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def _scan_examples(folder: Path, exts: tuple[str, ...]) -> list[list[str]]:
|
| 53 |
+
"""Scan ``folder`` for files with any extension in ``exts``."""
|
| 54 |
+
if not folder.is_dir():
|
| 55 |
+
return []
|
| 56 |
+
return [[str(p)] for p in sorted(folder.iterdir()) if p.suffix.lower() in exts]
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
if __name__ == "__main__":
|
| 60 |
+
patch_fastrtc_frame_queue()
|
| 61 |
+
patch_fastrtc_yuv420p_output()
|
| 62 |
+
patch_aioice_stun_transaction()
|
| 63 |
+
patch_aiortc_h264_nvenc()
|
| 64 |
+
|
| 65 |
+
load_dotenv_if_present()
|
| 66 |
+
logger = setup_logger(name="app")
|
| 67 |
+
log_cpu_info(logger)
|
| 68 |
+
require_secrets("MODEL_ACCESS_TOKEN")
|
| 69 |
+
|
| 70 |
+
tracker = UsageTracker(
|
| 71 |
+
repo_id=os.environ.get("ANALYTICS_REPO_ID", "LatticeSemi/PRIVATE-Demo-Analytics-v1.0"),
|
| 72 |
+
)
|
| 73 |
+
tracker.log("server", "server_start")
|
| 74 |
+
|
| 75 |
+
max_workers = int(os.environ.get("MAX_WORKERS", os.cpu_count()))
|
| 76 |
+
max_ram_gb = float(os.environ.get("MAX_RAM_GB", 32))
|
| 77 |
+
pool = EveWorkerPool(max_workers=max_workers, max_ram_gb=max_ram_gb, ram_headroom_gb=2.0)
|
| 78 |
+
|
| 79 |
+
max_fps_raw = float(os.environ.get("MAX_TARGET_FPS", "24"))
|
| 80 |
+
min_fps_raw = float(os.environ.get("MIN_TARGET_FPS", "15"))
|
| 81 |
+
max_fps: float | None = max_fps_raw if max_fps_raw > 0 else None
|
| 82 |
+
min_fps: float | None = min_fps_raw if min_fps_raw > 0 else None
|
| 83 |
+
|
| 84 |
+
camera_width = int(os.environ.get("CAMERA_WIDTH", 640))
|
| 85 |
+
camera_height = int(os.environ.get("CAMERA_HEIGHT", 360))
|
| 86 |
+
|
| 87 |
+
stream_manager = LiveStreamManager(
|
| 88 |
+
pool,
|
| 89 |
+
session_lifetime_seconds=60 * 4,
|
| 90 |
+
max_fps=max_fps,
|
| 91 |
+
min_fps=min_fps,
|
| 92 |
+
tracker=tracker,
|
| 93 |
+
)
|
| 94 |
+
|
| 95 |
+
session_tracker = SessionTracker(pool=pool, tracker=tracker, logger=logger)
|
| 96 |
+
|
| 97 |
+
handlers = EveAppHandlers(
|
| 98 |
+
pool=pool,
|
| 99 |
+
stream_manager=stream_manager,
|
| 100 |
+
sessions=session_tracker,
|
| 101 |
+
logger=logger,
|
| 102 |
+
max_fps=max_fps,
|
| 103 |
+
min_fps=min_fps,
|
| 104 |
+
)
|
| 105 |
+
|
| 106 |
+
def _shutdown() -> None:
|
| 107 |
+
session_tracker.shutdown()
|
| 108 |
+
stream_manager.shutdown()
|
| 109 |
+
tracker.log("server", "server_stop")
|
| 110 |
+
tracker.shutdown()
|
| 111 |
+
|
| 112 |
+
atexit.register(_shutdown)
|
| 113 |
+
|
| 114 |
+
examples_dir = Path(__file__).resolve().parent / "examples"
|
| 115 |
+
image_examples = _scan_examples(examples_dir, _IMAGE_EXTS)
|
| 116 |
+
video_examples = _scan_examples(examples_dir, _VIDEO_EXTS)
|
| 117 |
+
video_limits = VideoLimits()
|
| 118 |
+
rtc_config_provider = RtcConfigProvider()
|
| 119 |
+
|
| 120 |
+
with gr.Blocks(
|
| 121 |
+
title="GMOD / AMOD / OMOD Object Detection Demo",
|
| 122 |
+
theme=gr.themes.Default(
|
| 123 |
+
text_size=gr.themes.sizes.text_lg,
|
| 124 |
+
primary_hue=gr.themes.colors.yellow,
|
| 125 |
+
),
|
| 126 |
+
css=(
|
| 127 |
+
f"#webrtc-stream-col {{ max-width: {camera_width}px !important; margin: 0 auto; }}"
|
| 128 |
+
" .gradio-container h1, .gradio-container .md h1 { font-size: 2.25rem !important; }"
|
| 129 |
+
" .gradio-container h2, .gradio-container .md h2 { font-size: 1.75rem !important; }"
|
| 130 |
+
" .gradio-container h3, .gradio-container .md h3 { font-size: 1.4rem !important; }"
|
| 131 |
+
" .gradio-container button[role='tab'],"
|
| 132 |
+
" .gradio-container button[role='tab'] *"
|
| 133 |
+
" { text-decoration: underline !important; }"
|
| 134 |
+
" .gradio-container .tab-container {"
|
| 135 |
+
" height: auto !important;"
|
| 136 |
+
" overflow: visible !important;"
|
| 137 |
+
" gap: 4px !important;"
|
| 138 |
+
" border-bottom: 2px solid var(--border-color-primary) !important; }"
|
| 139 |
+
" .gradio-container .tab-container::after { display: none !important; }"
|
| 140 |
+
" .gradio-container button[role='tab'] {"
|
| 141 |
+
" height: auto !important;"
|
| 142 |
+
" padding: 10px 20px !important;"
|
| 143 |
+
" border: 1px solid var(--border-color-primary) !important;"
|
| 144 |
+
" border-bottom: none !important;"
|
| 145 |
+
" border-radius: 8px 8px 0 0 !important;"
|
| 146 |
+
" background: var(--background-fill-secondary) !important;"
|
| 147 |
+
" margin-bottom: -2px !important; }"
|
| 148 |
+
" .gradio-container button[role='tab'].selected {"
|
| 149 |
+
" background: var(--primary-500) !important;"
|
| 150 |
+
" color: var(--neutral-950) !important;"
|
| 151 |
+
" border-color: var(--primary-500) !important;"
|
| 152 |
+
" font-weight: 600 !important; }"
|
| 153 |
+
" .gradio-container button[role='tab'].selected::after { display: none !important; }"
|
| 154 |
+
),
|
| 155 |
+
head=TAB_SWITCH_AUTO_STOP_JS,
|
| 156 |
+
) as demo:
|
| 157 |
+
gr.Markdown("# Lattice sensAI — Generic Object Detection")
|
| 158 |
+
gr.Markdown(
|
| 159 |
+
"Run object detection on images, videos, or a live camera feed using "
|
| 160 |
+
"one of three EVE SDK models:\n\n"
|
| 161 |
+
"- **GMOD-80** — generic 80-class detector (active baseline)\n"
|
| 162 |
+
"- **AMOD-8** — 8-class automotive object detector "
|
| 163 |
+
"(person, bicycle, car, motorcycle, bus, truck, traffic light, "
|
| 164 |
+
"stop sign) *(preview)*\n"
|
| 165 |
+
"- **OMOD** — many-class office-objects detector *(preview)*\n\n"
|
| 166 |
+
"Only one model is active at a time. Pick the model with the radio "
|
| 167 |
+
"in each tab.\n\n"
|
| 168 |
+
"> **Preview note:** AMOD and OMOD slots currently fall back to GMOD-80 "
|
| 169 |
+
"weights — pending an EVE SDK update that adds runtime model switching."
|
| 170 |
+
)
|
| 171 |
+
|
| 172 |
+
# Required by EveAppHandlers signatures (Face ID gallery state). Empty
|
| 173 |
+
# for this demo — Face ID is not exposed.
|
| 174 |
+
session_registry = gr.State(value={})
|
| 175 |
+
session_hash_state = gr.State(value="unknown")
|
| 176 |
+
# Constant False states for the four Face/Person/FaceID/Hand flags
|
| 177 |
+
# that EveAppHandlers expects but this demo does not expose.
|
| 178 |
+
false_state = gr.State(value=False)
|
| 179 |
+
|
| 180 |
+
with gr.Tabs() as tabs:
|
| 181 |
+
(live_tab, webrtc_stream, live_radio) = build_live_inference_tab(
|
| 182 |
+
rtc_configuration=lambda: rtc_config_provider.get(),
|
| 183 |
+
feature_checkbox_builder=_build_feature_radio,
|
| 184 |
+
max_fps=int(max_fps) if max_fps else 30,
|
| 185 |
+
width=camera_width,
|
| 186 |
+
height=camera_height,
|
| 187 |
+
)
|
| 188 |
+
|
| 189 |
+
offline = build_image_or_video_offline_tab(
|
| 190 |
+
feature_checkbox_builder=_build_feature_radio,
|
| 191 |
+
image_examples=image_examples,
|
| 192 |
+
video_examples=video_examples,
|
| 193 |
+
video_limits=video_limits,
|
| 194 |
+
)
|
| 195 |
+
patch_video_for_external_urls(offline.video_output)
|
| 196 |
+
offline_radio = offline.checkboxes # gr.Radio in this demo
|
| 197 |
+
|
| 198 |
+
build_eula_tab()
|
| 199 |
+
|
| 200 |
+
# --- Mutually exclusive accordions on the offline tab ---
|
| 201 |
+
offline.image_accordion.expand(
|
| 202 |
+
fn=lambda: gr.update(open=False),
|
| 203 |
+
outputs=[offline.video_accordion],
|
| 204 |
+
)
|
| 205 |
+
offline.video_accordion.expand(
|
| 206 |
+
fn=lambda: gr.update(open=False),
|
| 207 |
+
outputs=[offline.image_accordion],
|
| 208 |
+
)
|
| 209 |
+
|
| 210 |
+
# --- Examples wire-up: clicking a sample loads it into the matching input ---
|
| 211 |
+
if offline.image_example_dataset is not None:
|
| 212 |
+
offline.image_example_dataset.click(
|
| 213 |
+
fn=lambda sample: sample[0],
|
| 214 |
+
inputs=[offline.image_example_dataset],
|
| 215 |
+
outputs=[offline.image_input],
|
| 216 |
+
)
|
| 217 |
+
if offline.video_example_dataset is not None:
|
| 218 |
+
offline.video_example_dataset.click(
|
| 219 |
+
fn=lambda sample: sample[0],
|
| 220 |
+
inputs=[offline.video_example_dataset],
|
| 221 |
+
outputs=[offline.video_input],
|
| 222 |
+
)
|
| 223 |
+
|
| 224 |
+
# --- Process button gating ---
|
| 225 |
+
def _on_input_change(image_path: str | None, video_path: str | None) -> dict:
|
| 226 |
+
return gr.update(interactive=bool(image_path) or bool(video_path))
|
| 227 |
+
|
| 228 |
+
for src in (offline.image_input, offline.video_input):
|
| 229 |
+
src.change(
|
| 230 |
+
fn=_on_input_change,
|
| 231 |
+
inputs=[offline.image_input, offline.video_input],
|
| 232 |
+
outputs=[offline.process_btn],
|
| 233 |
+
)
|
| 234 |
+
|
| 235 |
+
# --- Process dispatcher: image vs video ---
|
| 236 |
+
def _process_dispatch(
|
| 237 |
+
image_path: str | None,
|
| 238 |
+
video_path: str | None,
|
| 239 |
+
mod_model: str,
|
| 240 |
+
registry: dict,
|
| 241 |
+
request: gr.Request,
|
| 242 |
+
progress: gr.Progress = gr.Progress(),
|
| 243 |
+
):
|
| 244 |
+
if image_path:
|
| 245 |
+
annotated, registry = handlers.run_eve_image_inference(
|
| 246 |
+
image_path,
|
| 247 |
+
False,
|
| 248 |
+
False,
|
| 249 |
+
False,
|
| 250 |
+
False,
|
| 251 |
+
registry,
|
| 252 |
+
mod_model,
|
| 253 |
+
request,
|
| 254 |
+
progress,
|
| 255 |
+
)
|
| 256 |
+
return (
|
| 257 |
+
gr.update(value=annotated, visible=True),
|
| 258 |
+
gr.update(value=None, visible=False),
|
| 259 |
+
registry,
|
| 260 |
+
)
|
| 261 |
+
if video_path:
|
| 262 |
+
output_path, registry = handlers.run_eve_inference(
|
| 263 |
+
video_path,
|
| 264 |
+
False,
|
| 265 |
+
False,
|
| 266 |
+
False,
|
| 267 |
+
False,
|
| 268 |
+
registry,
|
| 269 |
+
mod_model,
|
| 270 |
+
request,
|
| 271 |
+
progress,
|
| 272 |
+
)
|
| 273 |
+
return (
|
| 274 |
+
gr.update(value=None, visible=False),
|
| 275 |
+
gr.update(value=output_path, visible=True),
|
| 276 |
+
registry,
|
| 277 |
+
)
|
| 278 |
+
raise gr.Error("Please upload an image or video.")
|
| 279 |
+
|
| 280 |
+
offline.process_btn.click(
|
| 281 |
+
fn=_process_dispatch,
|
| 282 |
+
inputs=[
|
| 283 |
+
offline.image_input,
|
| 284 |
+
offline.video_input,
|
| 285 |
+
offline_radio,
|
| 286 |
+
session_registry,
|
| 287 |
+
],
|
| 288 |
+
outputs=[
|
| 289 |
+
offline.image_output,
|
| 290 |
+
offline.video_output,
|
| 291 |
+
session_registry,
|
| 292 |
+
],
|
| 293 |
+
concurrency_limit=pool.worker_count,
|
| 294 |
+
)
|
| 295 |
+
|
| 296 |
+
# --- Live feature change tracking ---
|
| 297 |
+
live_radio.change(
|
| 298 |
+
fn=handlers.on_live_feature_change,
|
| 299 |
+
inputs=[false_state, false_state, false_state, false_state, live_radio],
|
| 300 |
+
outputs=[],
|
| 301 |
+
)
|
| 302 |
+
|
| 303 |
+
# --- Live inference wiring ---
|
| 304 |
+
webrtc_stream.stream(
|
| 305 |
+
fn=handlers.process_live_frame,
|
| 306 |
+
inputs=[
|
| 307 |
+
webrtc_stream,
|
| 308 |
+
false_state,
|
| 309 |
+
false_state,
|
| 310 |
+
false_state,
|
| 311 |
+
false_state,
|
| 312 |
+
session_registry,
|
| 313 |
+
session_hash_state,
|
| 314 |
+
live_radio,
|
| 315 |
+
],
|
| 316 |
+
outputs=[webrtc_stream],
|
| 317 |
+
concurrency_limit=pool.worker_count + 8,
|
| 318 |
+
)
|
| 319 |
+
|
| 320 |
+
# --- Tab switching analytics ---
|
| 321 |
+
tabs.select(fn=session_tracker.on_tab_switch, inputs=[], outputs=[])
|
| 322 |
+
|
| 323 |
+
# --- Session lifecycle ---
|
| 324 |
+
demo.load(session_tracker.on_load, outputs=[session_hash_state])
|
| 325 |
+
demo.unload(handlers.cleanup_session)
|
| 326 |
+
|
| 327 |
+
if tracker.enabled:
|
| 328 |
+
gr.HTML(
|
| 329 |
+
"<p style='font-size:0.8em;color:#888;text-align:center;margin-top:1em'>"
|
| 330 |
+
"This demo collects anonymous usage data (session activity, feature usage) "
|
| 331 |
+
"to improve the experience. No personal information is stored.</p>"
|
| 332 |
+
)
|
| 333 |
+
|
| 334 |
+
demo.queue()
|
| 335 |
+
demo.launch(server_name="0.0.0.0", server_port=7860, share=False)
|
download_models.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Placeholder downloader for GMOD / AMOD / OMOD .h5 model artifacts.
|
| 2 |
+
|
| 3 |
+
The EVE C SDK currently ships a single hardcoded MOD model (see
|
| 4 |
+
``EveEthosNpu/Models.h`` -> ``ObjectDetection = "gmod-cpu-...dat"``) and has
|
| 5 |
+
no runtime model-switch entry point. Until that lands, this script is a
|
| 6 |
+
**stub** — it does nothing at runtime, but documents the URLs we plan to
|
| 7 |
+
fetch so the wiring is obvious when the SDK gains the switch API.
|
| 8 |
+
|
| 9 |
+
When the EVE SDK gains a model-load function:
|
| 10 |
+
|
| 11 |
+
1. Fill in the real URLs below (likely a public GitHub release, possibly a
|
| 12 |
+
gated ``LatticeSemi/PRIVATE-*`` HF repo).
|
| 13 |
+
2. Have the Dockerfile invoke this script after ``install_eve.py`` so the
|
| 14 |
+
``.h5`` files land in ``/opt/eve_models/`` (or wherever the SDK looks).
|
| 15 |
+
3. Hand-add a binding for the new SDK function in
|
| 16 |
+
``src/shared/eve_python/eve_sdk.py`` and update
|
| 17 |
+
``eve_wrapper.enable_object_detection`` to call it.
|
| 18 |
+
"""
|
| 19 |
+
|
| 20 |
+
from __future__ import annotations
|
| 21 |
+
|
| 22 |
+
import sys
|
| 23 |
+
|
| 24 |
+
# TODO: replace with real download URLs (GitHub Releases or
|
| 25 |
+
# LatticeSemi/PRIVATE-* HF repo) once available.
|
| 26 |
+
MODELS: dict[str, str] = {
|
| 27 |
+
# "GMOD-80": "https://github.com/<org>/<repo>/releases/download/<tag>/gmod-80.h5",
|
| 28 |
+
# "AMOD-8": "https://github.com/<org>/<repo>/releases/download/<tag>/amod-8.h5",
|
| 29 |
+
# "OMOD": "https://github.com/<org>/<repo>/releases/download/<tag>/omod.h5",
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def main() -> int:
|
| 34 |
+
if not MODELS:
|
| 35 |
+
print(
|
| 36 |
+
"download_models.py: nothing to do — model URLs not yet wired up. "
|
| 37 |
+
"EVE SDK currently uses its bundled MOD model.",
|
| 38 |
+
file=sys.stderr,
|
| 39 |
+
)
|
| 40 |
+
return 0
|
| 41 |
+
# When wired up: download each entry to a known target directory.
|
| 42 |
+
raise NotImplementedError("Fill in the download loop once URLs are known.")
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
if __name__ == "__main__":
|
| 46 |
+
sys.exit(main())
|
install_eve.py
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Download and install the Eve SDK .deb package from HuggingFace Hub.
|
| 2 |
+
|
| 3 |
+
Called during Docker build. Tries authentication in order:
|
| 4 |
+
|
| 5 |
+
1. Docker BuildKit secret ``MODEL_ACCESS_TOKEN`` (HF Spaces — automatic)
|
| 6 |
+
2. ``HF_TOKEN`` build arg (local builds)
|
| 7 |
+
3. No token (public repos only)
|
| 8 |
+
|
| 9 |
+
Local usage::
|
| 10 |
+
|
| 11 |
+
docker build --build-arg HF_TOKEN=$(cat ~/.cache/huggingface/token) \
|
| 12 |
+
-t eve ./src/demos/eve_hmi
|
| 13 |
+
"""
|
| 14 |
+
|
| 15 |
+
import os
|
| 16 |
+
import re
|
| 17 |
+
import shutil
|
| 18 |
+
import subprocess
|
| 19 |
+
import sys
|
| 20 |
+
|
| 21 |
+
from huggingface_hub import hf_hub_download
|
| 22 |
+
|
| 23 |
+
EVE_REPO = "LatticeSemi/PRIVATE-Edge-Vision-Engine-EVE-v7.0"
|
| 24 |
+
EVE_DEB = "LINUX_X86-8-7.0-eve-huggingface_7.0.8~git20260408.4a1a3f1_amd64.deb"
|
| 25 |
+
EVE_LICENSE_REPO = "LatticeSemi/PRIVATE-Edge-Vision-Engine-EVE-v7.0-License"
|
| 26 |
+
EVE_LICENSE = "libEveDevLicense.so"
|
| 27 |
+
SECRET_PATH = "/run/secrets/MODEL_ACCESS_TOKEN"
|
| 28 |
+
DOWNLOAD_DIR = "/tmp/eve"
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def get_token():
|
| 32 |
+
"""Return an HF token from the first available source, or None."""
|
| 33 |
+
# 1. Docker BuildKit secret (HF Spaces injects MODEL_ACCESS_TOKEN automatically)
|
| 34 |
+
if os.path.isfile(SECRET_PATH):
|
| 35 |
+
with open(SECRET_PATH) as f:
|
| 36 |
+
token = f.read().strip()
|
| 37 |
+
if token:
|
| 38 |
+
return token, "build secret (MODEL_ACCESS_TOKEN)"
|
| 39 |
+
|
| 40 |
+
# 2. HF_TOKEN build arg forwarded as env var
|
| 41 |
+
token = os.environ.get("HF_TOKEN", "").strip()
|
| 42 |
+
if token:
|
| 43 |
+
return token, "build arg (HF_TOKEN)"
|
| 44 |
+
|
| 45 |
+
# 3. No token — will only work for public repos
|
| 46 |
+
return None, "no auth (will fail for private repos)"
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def get_license_destination_path() -> str:
|
| 50 |
+
"""Parse the .deb package of EVE to extract the version."""
|
| 51 |
+
# Alright so regexes are fun, what we want here is to extract the version
|
| 52 |
+
# of EVE's package since we need to copy the license into EVE's install
|
| 53 |
+
# folder which is /opt/EVE-version-Source/lib.
|
| 54 |
+
# For example, in LINUX_X86-531-dev-eve-development_7.0.531~git20260309.c5f1ee6_amd64.deb,
|
| 55 |
+
# we want the version extracted to be 7.0.531.
|
| 56 |
+
match = re.search(r"(?<=_)\d+(?:\.\d+)+(?=~)", EVE_DEB)
|
| 57 |
+
if not match:
|
| 58 |
+
raise RuntimeError("Could not parse EVE's package version.")
|
| 59 |
+
|
| 60 |
+
version = match.group()
|
| 61 |
+
|
| 62 |
+
return f"/opt/EVE-{version}-Source/lib"
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def main():
|
| 66 |
+
token, auth_source = get_token()
|
| 67 |
+
|
| 68 |
+
if token is None and "PRIVATE" in EVE_REPO:
|
| 69 |
+
print(
|
| 70 |
+
f"ERROR: No authentication token found.\n"
|
| 71 |
+
f" Repo '{EVE_REPO}' is private and requires a token.\n"
|
| 72 |
+
f" On HF Spaces: set MODEL_ACCESS_TOKEN as a Space secret.\n"
|
| 73 |
+
f" Locally: docker build --build-arg HF_TOKEN=$(cat ~/.cache/huggingface/token) ...",
|
| 74 |
+
file=sys.stderr,
|
| 75 |
+
)
|
| 76 |
+
sys.exit(1)
|
| 77 |
+
|
| 78 |
+
print(f"Downloading Eve SDK from {EVE_REPO} using {auth_source}...")
|
| 79 |
+
|
| 80 |
+
deb_path = hf_hub_download(
|
| 81 |
+
repo_id=EVE_REPO,
|
| 82 |
+
filename=EVE_DEB,
|
| 83 |
+
local_dir=DOWNLOAD_DIR,
|
| 84 |
+
token=token,
|
| 85 |
+
)
|
| 86 |
+
|
| 87 |
+
print(f"Installing {deb_path}...")
|
| 88 |
+
subprocess.run(["apt-get", "install", "-y", deb_path], check=True)
|
| 89 |
+
|
| 90 |
+
license_path = hf_hub_download(
|
| 91 |
+
repo_id=EVE_LICENSE_REPO, filename=EVE_LICENSE, local_dir=DOWNLOAD_DIR, token=token
|
| 92 |
+
)
|
| 93 |
+
|
| 94 |
+
destination_path = get_license_destination_path()
|
| 95 |
+
|
| 96 |
+
print(f"Installing {license_path}...")
|
| 97 |
+
subprocess.run(["mv", license_path, destination_path], check=True)
|
| 98 |
+
|
| 99 |
+
shutil.rmtree(DOWNLOAD_DIR, ignore_errors=True)
|
| 100 |
+
print("Eve SDK installed successfully.")
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
if __name__ == "__main__":
|
| 104 |
+
main()
|
requirements.txt
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
av
|
| 2 |
+
gradio==5.50.0
|
| 3 |
+
fastrtc==0.0.34
|
| 4 |
+
huggingface-hub==1.5.0
|
| 5 |
+
opencv-python
|
| 6 |
+
dotenv
|
| 7 |
+
twilio
|
| 8 |
+
psutil
|
shared/assets/EULA.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# DEMO EVALUATION END USER LICENSE AGREEMENT
|
| 2 |
+
|
| 3 |
+
IMPORTANT: BY DOWNLOADING, INSTALLING, ACTIVATING, ACCESSING, OR USING THE SOFTWARE, YOU AGREE TO THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT USE THE SOFTWARE.
|
| 4 |
+
|
| 5 |
+
This Demo Evaluation End User License Agreement ("Agreement") is between Lattice Semiconductor Corporation ("Lattice") and the person or entity using the Software ("Licensee"). The individual accepting this Agreement represents and warrants that they have authority to bind Licensee.
|
| 6 |
+
|
| 7 |
+
**1. Software.** "Software" means the demo version of the software, in object code form only, together with related documentation, materials, updates, license keys, and any output or data generated by the Software, provided by Lattice.
|
| 8 |
+
|
| 9 |
+
**2. License Grant.** Subject to this Agreement, Lattice grants Licensee a limited, non-exclusive, non-transferable, non-sublicensable, revocable license to use the Software solely for Licensee's internal, non-commercial evaluation and demonstration purposes, only to assess the Software and determine whether to request a longer-term testing license from Lattice. The Software may be used only by Licensee's employees at a single site. No other rights are granted by implication, estoppel, or otherwise.
|
| 10 |
+
|
| 11 |
+
**3. License Key; Revocation.** Use of the Software is controlled by a license key or similar activation mechanism. Lattice may revoke, suspend, disable, or refuse to renew any license key at any time, with or without cause, and without notice or liability. Upon expiration, revocation, suspension, or disablement of the license key, Licensee's right to use the Software immediately terminates and Licensee must comply with Section 8(b).
|
| 12 |
+
|
| 13 |
+
**4. Restrictions.** Licensee may not, and may not permit or enable any third party to: (a) use the Software for production, commercial, or revenue-generating purposes; (b) sell, license, sublicense, rent, lease, lend, distribute, transfer, or disclose the Software or any portion thereof to any third party; (c) copy, modify, adapt, translate, or create derivative works of the Software; (d) reverse engineer, decompile, disassemble, or otherwise attempt to discover the source code, algorithms, data structures, or underlying ideas of the Software, except to the limited extent such restriction is expressly prohibited by applicable law; (e) remove, alter, or obscure any proprietary, copyright, trademark, or other notices; (f) use the Software or any information derived from it to develop, improve, train, or benchmark any competing product, service, or technology; (g) publish or disclose any benchmark, test, performance, or evaluation results related to the Software without Lattice's prior written consent; (h) use the Software in violation of any applicable law or regulation; or (i) circumvent or attempt to circumvent any technical protection measures in the Software.
|
| 14 |
+
|
| 15 |
+
**5. Ownership; Confidentiality; Feedback.** The Software is licensed, not sold. Lattice and its licensors retain all right, title, and interest in and to the Software, all derivatives and improvements thereof, and all related intellectual property rights worldwide. No license or right is granted to any Lattice patent, trade secret, or trademark. The Software, its features, performance characteristics, and all information relating thereto constitute confidential and proprietary trade secrets of Lattice. Licensee will protect the Software using at least the same degree of care it uses for its own confidential information, but no less than reasonable care, and will not disclose or provide access to the Software except to employees or contractors with a need to know who are bound by written confidentiality obligations no less protective than this Agreement. Any suggestions, ideas, feedback, evaluation results, or other input provided by Licensee regarding the Software ("Feedback") are assigned to Lattice and may be used by Lattice for any purpose without restriction, compensation, or obligation. To the extent such assignment is not enforceable, Licensee grants Lattice a perpetual, irrevocable, worldwide, royalty-free, fully sublicensable license to use and exploit the Feedback.
|
| 16 |
+
|
| 17 |
+
**6. Disclaimer.** THE SOFTWARE IS PROVIDED "AS IS" AND "AS AVAILABLE," WITHOUT WARRANTY OF ANY KIND. TO THE MAXIMUM EXTENT PERMITTED BY LAW, LATTICE DISCLAIMS ALL EXPRESS, IMPLIED, STATUTORY, AND OTHER WARRANTIES, INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, NON-INFRINGEMENT, AND ACCURACY. LATTICE DOES NOT WARRANT THAT THE SOFTWARE WILL BE ERROR-FREE, UNINTERRUPTED, SECURE, OR FREE OF HARMFUL COMPONENTS.
|
| 18 |
+
|
| 19 |
+
**7. Limitation of Liability.** TO THE MAXIMUM EXTENT PERMITTED BY LAW, LATTICE AND ITS LICENSORS, DIRECTORS, OFFICERS, AND EMPLOYEES WILL NOT BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, EXEMPLARY, OR PUNITIVE DAMAGES, OR FOR ANY LOSS OF PROFITS, REVENUE, DATA, BUSINESS, GOODWILL, OR USE, ARISING OUT OF OR RELATED TO THIS AGREEMENT OR THE SOFTWARE, REGARDLESS OF THE THEORY OF LIABILITY AND EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. LATTICE'S TOTAL AGGREGATE LIABILITY ARISING OUT OF OR RELATED TO THIS AGREEMENT OR THE SOFTWARE WILL NOT EXCEED US$100. THESE LIMITATIONS APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
|
| 20 |
+
|
| 21 |
+
**8. Termination.** (a) This Agreement begins upon first use of the Software and terminates automatically upon breach by Licensee, expiration or revocation of the license key, or upon thirty (30) days' notice by Lattice. Lattice may terminate immediately if Licensee breaches Sections 4 or 5. (b) Upon termination, Licensee must immediately cease all use of the Software, permanently delete or destroy all copies (including backups), and certify such destruction in writing to Lattice within five (5) business days.
|
shared/ctypes_enum.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from enum import IntEnum
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
# Taken from https://v4.chriskrycho.com/2015/ctypes-structures-and-dll-exports.html
|
| 5 |
+
class CtypesEnum(IntEnum):
|
| 6 |
+
"""A ctypes-compatible IntEnum superclass."""
|
| 7 |
+
|
| 8 |
+
@classmethod
|
| 9 |
+
def from_param(cls, obj):
|
| 10 |
+
return int(obj)
|
shared/env_utils.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
|
| 5 |
+
from dotenv import load_dotenv # type: ignore
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def load_dotenv_if_present(dotenv_path: str | os.PathLike = ".env.local") -> bool:
|
| 9 |
+
"""
|
| 10 |
+
Optional convenience for local dev: loads .env if python-dotenv is installed.
|
| 11 |
+
If python-dotenv is not installed or file doesn't exist, this is a no-op.
|
| 12 |
+
|
| 13 |
+
Returns True if a .env was loaded, else False.
|
| 14 |
+
"""
|
| 15 |
+
p = Path(dotenv_path)
|
| 16 |
+
if not p.exists():
|
| 17 |
+
return False
|
| 18 |
+
|
| 19 |
+
load_dotenv(dotenv_path=p)
|
| 20 |
+
return True
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def require_secrets(*names: str) -> None:
|
| 24 |
+
"""Verify that required HF Space secrets are set, or exit with a clear message.
|
| 25 |
+
|
| 26 |
+
Only enforced when ``SPACE_ID`` is present in the environment (i.e. the app
|
| 27 |
+
is running on Hugging Face Spaces). Locally, developers authenticate via
|
| 28 |
+
``hf auth login`` so secrets like ``MODEL_ACCESS_TOKEN`` are not needed.
|
| 29 |
+
|
| 30 |
+
Args:
|
| 31 |
+
*names: Environment variable names that must be non-empty.
|
| 32 |
+
|
| 33 |
+
Raises:
|
| 34 |
+
SystemExit: If any secret is missing while running on HF Spaces.
|
| 35 |
+
"""
|
| 36 |
+
space_id = os.environ.get("SPACE_ID", "")
|
| 37 |
+
if not space_id or not names:
|
| 38 |
+
return
|
| 39 |
+
|
| 40 |
+
missing = [n for n in names if not os.environ.get(n, "").strip()]
|
| 41 |
+
if not missing:
|
| 42 |
+
return
|
| 43 |
+
|
| 44 |
+
settings_url = f"https://huggingface.co/spaces/{space_id}/settings"
|
| 45 |
+
print(
|
| 46 |
+
f"ERROR: Missing required secrets: {', '.join(missing)}\n" f"Set them at: {settings_url}",
|
| 47 |
+
file=sys.stderr,
|
| 48 |
+
)
|
| 49 |
+
sys.exit(1)
|
shared/eula_tab.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""EULA tab for Gradio demos.
|
| 2 |
+
|
| 3 |
+
Displays the End User License Agreement as a read-only Markdown tab.
|
| 4 |
+
The EULA text is loaded from ``shared/assets/EULA.md`` so it can be
|
| 5 |
+
updated without changing any Python code.
|
| 6 |
+
|
| 7 |
+
Usage::
|
| 8 |
+
|
| 9 |
+
with gr.Blocks() as demo:
|
| 10 |
+
with gr.Tabs():
|
| 11 |
+
build_eula_tab()
|
| 12 |
+
"""
|
| 13 |
+
|
| 14 |
+
from pathlib import Path
|
| 15 |
+
|
| 16 |
+
import gradio as gr
|
| 17 |
+
|
| 18 |
+
_ASSETS_DIR = Path(__file__).resolve().parent / "assets"
|
| 19 |
+
_DEFAULT_EULA_PATH = _ASSETS_DIR / "EULA.md"
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def build_eula_tab(
|
| 23 |
+
eula_path: str | Path | None = None,
|
| 24 |
+
tab_label: str = "EULA",
|
| 25 |
+
) -> gr.TabItem:
|
| 26 |
+
"""Create a tab displaying the EULA as Markdown.
|
| 27 |
+
|
| 28 |
+
Must be called inside a ``gr.Tabs()`` context.
|
| 29 |
+
|
| 30 |
+
Args:
|
| 31 |
+
eula_path: Path to a Markdown file. Defaults to ``shared/assets/EULA.md``.
|
| 32 |
+
tab_label: Label shown on the tab. Defaults to ``"EULA"``.
|
| 33 |
+
|
| 34 |
+
Returns:
|
| 35 |
+
The ``gr.TabItem`` component.
|
| 36 |
+
"""
|
| 37 |
+
path = Path(eula_path) if eula_path is not None else _DEFAULT_EULA_PATH
|
| 38 |
+
|
| 39 |
+
if path.is_file():
|
| 40 |
+
content = path.read_text(encoding="utf-8")
|
| 41 |
+
else:
|
| 42 |
+
content = f"_EULA file not found. Expected location:_ `{path}`"
|
| 43 |
+
|
| 44 |
+
with gr.TabItem(tab_label) as tab:
|
| 45 |
+
gr.Markdown(content)
|
| 46 |
+
|
| 47 |
+
return tab
|
shared/eve_app_tabs.py
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Tab builders for EVE-based Gradio demos.
|
| 2 |
+
|
| 3 |
+
Both tabs (Offline Inference, Live Inference) follow the same pattern:
|
| 4 |
+
|
| 5 |
+
- Outer ``gr.TabItem`` with the demo-supplied label.
|
| 6 |
+
- Demo-specific feature checkboxes built via a caller-provided callable so
|
| 7 |
+
each demo defines its own feature set (Face Detection / Person /
|
| 8 |
+
Hand Detection / Face ID / …).
|
| 9 |
+
- Optional ``extras_builder`` hook for demo-specific extras inside the tab
|
| 10 |
+
(e.g. eve_hmi's Face ID summary thumbnails).
|
| 11 |
+
|
| 12 |
+
The tab builders return the underlying components so the caller can wire
|
| 13 |
+
events (``process_btn.click``, ``webrtc_stream.stream``, etc.) outside.
|
| 14 |
+
"""
|
| 15 |
+
|
| 16 |
+
from __future__ import annotations
|
| 17 |
+
|
| 18 |
+
from dataclasses import dataclass
|
| 19 |
+
from typing import Callable, TypeVar
|
| 20 |
+
|
| 21 |
+
import gradio as gr
|
| 22 |
+
|
| 23 |
+
from live_inference import RtcConfigurationInput, build_webrtc_stream
|
| 24 |
+
from video_processing import VideoLimits, build_video_constraints_accordion
|
| 25 |
+
|
| 26 |
+
# The exact tuple of Checkbox components is demo-specific. We let the
|
| 27 |
+
# caller's checkbox-builder define the shape and return it transparently.
|
| 28 |
+
TCheckboxes = TypeVar("TCheckboxes")
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def build_offline_inference_tab(
|
| 32 |
+
*,
|
| 33 |
+
feature_checkbox_builder: Callable[..., TCheckboxes],
|
| 34 |
+
example_videos: list,
|
| 35 |
+
video_limits: VideoLimits,
|
| 36 |
+
extras_builder: Callable[[], None] | None = None,
|
| 37 |
+
tab_label: str = "Offline Inference",
|
| 38 |
+
feature_hint: str = "applied when processing starts",
|
| 39 |
+
) -> tuple[
|
| 40 |
+
gr.TabItem,
|
| 41 |
+
gr.Video,
|
| 42 |
+
gr.Video,
|
| 43 |
+
TCheckboxes,
|
| 44 |
+
gr.Button,
|
| 45 |
+
gr.Dataset,
|
| 46 |
+
]:
|
| 47 |
+
"""Build the Offline Inference tab. Must be called inside a ``gr.Tabs`` context.
|
| 48 |
+
|
| 49 |
+
Args:
|
| 50 |
+
feature_checkbox_builder: Callable that builds the demo's feature
|
| 51 |
+
checkboxes inside the tab. Receives the keyword ``hint`` (a
|
| 52 |
+
short string shown next to the "Features" heading). Returns a
|
| 53 |
+
tuple of ``gr.Checkbox`` instances — the same tuple is returned
|
| 54 |
+
unchanged so the caller can wire events.
|
| 55 |
+
example_videos: Pre-loaded example videos (list of ``[path]`` rows).
|
| 56 |
+
video_limits: Upload constraints rendered in the accordion.
|
| 57 |
+
extras_builder: Optional callable invoked after the input/output
|
| 58 |
+
video columns to add demo-specific widgets (e.g. a Face ID
|
| 59 |
+
summary). Called inside the same row, so it shares horizontal
|
| 60 |
+
space with the videos.
|
| 61 |
+
tab_label: Tab label text (default ``"Offline Inference"``).
|
| 62 |
+
feature_hint: Short hint shown next to the Features heading.
|
| 63 |
+
|
| 64 |
+
Returns:
|
| 65 |
+
``(tab, input_video, output_video, checkboxes, process_btn, example_dataset)``.
|
| 66 |
+
``checkboxes`` is exactly what ``feature_checkbox_builder`` returned.
|
| 67 |
+
"""
|
| 68 |
+
with gr.TabItem(tab_label) as video_tab:
|
| 69 |
+
with gr.Accordion("Instructions", open=False):
|
| 70 |
+
gr.Markdown(
|
| 71 |
+
"1. Select the features that will be processed on the video\n"
|
| 72 |
+
"2. Select a video (or upload your own in the Input Video frame)\n"
|
| 73 |
+
"3. Press the **Process Video** button\n\n"
|
| 74 |
+
"Once the video has been processed, you can play the video in the "
|
| 75 |
+
"Output Video frame"
|
| 76 |
+
)
|
| 77 |
+
|
| 78 |
+
checkboxes = feature_checkbox_builder(hint=feature_hint)
|
| 79 |
+
|
| 80 |
+
with gr.Accordion("Video Examples", open=True):
|
| 81 |
+
example_dataset = gr.Dataset(
|
| 82 |
+
components=[gr.Video(visible=False)],
|
| 83 |
+
samples=example_videos,
|
| 84 |
+
show_label=False,
|
| 85 |
+
)
|
| 86 |
+
|
| 87 |
+
process_btn = gr.Button("Process Video", variant="primary", interactive=False)
|
| 88 |
+
|
| 89 |
+
build_video_constraints_accordion(video_limits)
|
| 90 |
+
|
| 91 |
+
with gr.Row(equal_height=True):
|
| 92 |
+
with gr.Column(scale=5):
|
| 93 |
+
input_video = gr.Video(label="Input Video", sources=["upload", "webcam"])
|
| 94 |
+
with gr.Column(scale=5):
|
| 95 |
+
output_video = gr.Video(label="Output Video")
|
| 96 |
+
if extras_builder is not None:
|
| 97 |
+
extras_builder()
|
| 98 |
+
|
| 99 |
+
return video_tab, input_video, output_video, checkboxes, process_btn, example_dataset
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
@dataclass
|
| 103 |
+
class ImageOrVideoOfflineTab:
|
| 104 |
+
"""Components returned by :func:`build_image_or_video_offline_tab`.
|
| 105 |
+
|
| 106 |
+
The image/video accordions are exposed so the caller can wire mutual
|
| 107 |
+
exclusion (expanding one collapses the other) — same pattern as
|
| 108 |
+
:class:`face_id_tab.FaceIdTab`.
|
| 109 |
+
"""
|
| 110 |
+
|
| 111 |
+
tab: gr.TabItem
|
| 112 |
+
image_input: gr.Image
|
| 113 |
+
video_input: gr.Video
|
| 114 |
+
image_output: gr.Image
|
| 115 |
+
video_output: gr.Video
|
| 116 |
+
checkboxes: object # demo-specific (radio, checkbox tuple, etc.)
|
| 117 |
+
process_btn: gr.Button
|
| 118 |
+
image_example_dataset: gr.Dataset | None
|
| 119 |
+
video_example_dataset: gr.Dataset | None
|
| 120 |
+
image_accordion: gr.Accordion
|
| 121 |
+
video_accordion: gr.Accordion
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
def build_image_or_video_offline_tab(
|
| 125 |
+
*,
|
| 126 |
+
feature_checkbox_builder: Callable[..., TCheckboxes],
|
| 127 |
+
image_examples: list | None,
|
| 128 |
+
video_examples: list | None,
|
| 129 |
+
video_limits: VideoLimits,
|
| 130 |
+
tab_label: str = "Offline Inference",
|
| 131 |
+
feature_hint: str = "applied when processing starts",
|
| 132 |
+
) -> ImageOrVideoOfflineTab:
|
| 133 |
+
"""Build an Offline Inference tab that accepts image OR video.
|
| 134 |
+
|
| 135 |
+
Pattern: two mutually-exclusive accordions on the input side ("Input
|
| 136 |
+
from an Image" / "Input from a Video"), one Process button, two
|
| 137 |
+
output components (image + video) shown side-by-side. Caller is
|
| 138 |
+
responsible for:
|
| 139 |
+
|
| 140 |
+
- Wiring ``image_accordion`` / ``video_accordion`` mutual exclusion
|
| 141 |
+
(one-liner per side, see ``face_id_tab.FaceIdTab.wire``).
|
| 142 |
+
- Routing ``process_btn.click`` to a handler that dispatches by
|
| 143 |
+
which input is populated.
|
| 144 |
+
- Toggling output visibility based on which branch ran.
|
| 145 |
+
|
| 146 |
+
Args:
|
| 147 |
+
feature_checkbox_builder: Callable that builds the demo's feature
|
| 148 |
+
checkboxes/radio inside the tab. Called with keyword
|
| 149 |
+
``hint=feature_hint``.
|
| 150 |
+
image_examples: Pre-loaded image examples (list of ``[path]``
|
| 151 |
+
rows) or ``None`` to skip the examples accordion.
|
| 152 |
+
video_examples: Same for videos.
|
| 153 |
+
video_limits: Upload constraints rendered inside the video
|
| 154 |
+
accordion.
|
| 155 |
+
tab_label: Tab label text.
|
| 156 |
+
feature_hint: Short hint shown next to the Features heading.
|
| 157 |
+
"""
|
| 158 |
+
with gr.TabItem(tab_label) as tab:
|
| 159 |
+
with gr.Accordion("Instructions", open=False):
|
| 160 |
+
gr.Markdown(
|
| 161 |
+
"1. Select the model that will be used for object detection\n"
|
| 162 |
+
"2. Choose between processing an **Image** or a **Video**:\n"
|
| 163 |
+
" - For an image: select an example or upload your own, then press "
|
| 164 |
+
"**Process**.\n"
|
| 165 |
+
" - For a video: expand the video section, select an example or "
|
| 166 |
+
"upload your own, then press **Process**.\n\n"
|
| 167 |
+
"Once processing is complete, the annotated result appears on the "
|
| 168 |
+
"right (image or video, depending on the input)."
|
| 169 |
+
)
|
| 170 |
+
|
| 171 |
+
checkboxes = feature_checkbox_builder(hint=feature_hint)
|
| 172 |
+
|
| 173 |
+
with gr.Row():
|
| 174 |
+
# --- Left column: input ---
|
| 175 |
+
with gr.Column(scale=5):
|
| 176 |
+
image_example_dataset: gr.Dataset | None = None
|
| 177 |
+
video_example_dataset: gr.Dataset | None = None
|
| 178 |
+
|
| 179 |
+
with gr.Accordion(
|
| 180 |
+
"Input from an Image", open=True
|
| 181 |
+
) as image_accordion:
|
| 182 |
+
if image_examples:
|
| 183 |
+
with gr.Accordion("Image Examples", open=True):
|
| 184 |
+
image_example_dataset = gr.Dataset(
|
| 185 |
+
components=[gr.Image(visible=False)],
|
| 186 |
+
samples=image_examples,
|
| 187 |
+
show_label=False,
|
| 188 |
+
)
|
| 189 |
+
image_input = gr.Image(
|
| 190 |
+
label="Input Image",
|
| 191 |
+
sources=["upload", "webcam"],
|
| 192 |
+
type="filepath",
|
| 193 |
+
)
|
| 194 |
+
|
| 195 |
+
with gr.Accordion(
|
| 196 |
+
"Input from a Video", open=False
|
| 197 |
+
) as video_accordion:
|
| 198 |
+
if video_examples:
|
| 199 |
+
with gr.Accordion("Video Examples", open=True):
|
| 200 |
+
video_example_dataset = gr.Dataset(
|
| 201 |
+
components=[gr.Video(visible=False)],
|
| 202 |
+
samples=video_examples,
|
| 203 |
+
show_label=False,
|
| 204 |
+
)
|
| 205 |
+
build_video_constraints_accordion(video_limits)
|
| 206 |
+
video_input = gr.Video(
|
| 207 |
+
label="Input Video", sources=["upload", "webcam"]
|
| 208 |
+
)
|
| 209 |
+
|
| 210 |
+
process_btn = gr.Button(
|
| 211 |
+
"Process", variant="primary", interactive=False
|
| 212 |
+
)
|
| 213 |
+
|
| 214 |
+
# --- Right column: output (image OR video, toggled by handler) ---
|
| 215 |
+
with gr.Column(scale=5):
|
| 216 |
+
image_output = gr.Image(label="Output Image", visible=True)
|
| 217 |
+
video_output = gr.Video(label="Output Video", visible=False)
|
| 218 |
+
|
| 219 |
+
return ImageOrVideoOfflineTab(
|
| 220 |
+
tab=tab,
|
| 221 |
+
image_input=image_input,
|
| 222 |
+
video_input=video_input,
|
| 223 |
+
image_output=image_output,
|
| 224 |
+
video_output=video_output,
|
| 225 |
+
checkboxes=checkboxes,
|
| 226 |
+
process_btn=process_btn,
|
| 227 |
+
image_example_dataset=image_example_dataset,
|
| 228 |
+
video_example_dataset=video_example_dataset,
|
| 229 |
+
image_accordion=image_accordion,
|
| 230 |
+
video_accordion=video_accordion,
|
| 231 |
+
)
|
| 232 |
+
|
| 233 |
+
|
| 234 |
+
def build_live_inference_tab(
|
| 235 |
+
*,
|
| 236 |
+
rtc_configuration: RtcConfigurationInput,
|
| 237 |
+
feature_checkbox_builder: Callable[..., TCheckboxes],
|
| 238 |
+
extras_builder: Callable[[], None] | None = None,
|
| 239 |
+
max_fps: int = 15,
|
| 240 |
+
width: int = 640,
|
| 241 |
+
height: int = 360,
|
| 242 |
+
tab_label: str = "Live Inference",
|
| 243 |
+
description_html: str = (
|
| 244 |
+
"<p>Use your webcam for real-time inference. "
|
| 245 |
+
"Select features below, then grant camera access when prompted.</p>"
|
| 246 |
+
),
|
| 247 |
+
) -> tuple[gr.TabItem, object, TCheckboxes]:
|
| 248 |
+
"""Build the Live Inference tab with feature checkboxes + WebRTC stream.
|
| 249 |
+
|
| 250 |
+
Args:
|
| 251 |
+
rtc_configuration: ICE configuration dict, callable that returns
|
| 252 |
+
one, or ``None`` for direct connection. A callable is invoked
|
| 253 |
+
per-connection by FastRTC, allowing credential refresh.
|
| 254 |
+
feature_checkbox_builder: Callable that builds the demo's feature
|
| 255 |
+
checkboxes (same shape as in the offline tab).
|
| 256 |
+
extras_builder: Optional callable invoked after the WebRTC stream
|
| 257 |
+
for demo-specific widgets (e.g. Face ID summary).
|
| 258 |
+
max_fps: Maximum frame rate requested from the browser camera.
|
| 259 |
+
width / height: Camera frame dimensions in pixels.
|
| 260 |
+
tab_label: Tab label text.
|
| 261 |
+
description_html: Optional HTML shown above the stream.
|
| 262 |
+
|
| 263 |
+
Returns:
|
| 264 |
+
``(tab, webrtc_stream, checkboxes)``.
|
| 265 |
+
"""
|
| 266 |
+
with gr.TabItem(tab_label) as tab:
|
| 267 |
+
if description_html:
|
| 268 |
+
gr.HTML(description_html)
|
| 269 |
+
checkboxes = feature_checkbox_builder()
|
| 270 |
+
webrtc_stream = build_webrtc_stream(
|
| 271 |
+
rtc_configuration, max_fps=max_fps, width=width, height=height
|
| 272 |
+
)
|
| 273 |
+
if extras_builder is not None:
|
| 274 |
+
extras_builder()
|
| 275 |
+
|
| 276 |
+
return tab, webrtc_stream, checkboxes
|
shared/eve_inference_handlers.py
ADDED
|
@@ -0,0 +1,485 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Offline + live inference handlers shared by EVE-based Gradio demos.
|
| 2 |
+
|
| 3 |
+
The two main handlers (``run_eve_inference`` for the Offline Inference tab,
|
| 4 |
+
``process_live_frame`` for the Live Inference tab) used to live in
|
| 5 |
+
``eve_hmi/app.py``. They are bundled on an ``EveAppHandlers`` instance so
|
| 6 |
+
demos can wire them with one ``handlers = EveAppHandlers(...)`` line and
|
| 7 |
+
re-use them as Gradio callbacks.
|
| 8 |
+
|
| 9 |
+
Face ID is opt-in: pass an empty / ``None`` ``registry`` and Face ID
|
| 10 |
+
behaviour is bypassed (gallery restore is skipped, the ``face_id`` flag
|
| 11 |
+
still travels through ``FeatureFlags`` so the EVE SDK can act on it).
|
| 12 |
+
"""
|
| 13 |
+
|
| 14 |
+
from __future__ import annotations
|
| 15 |
+
|
| 16 |
+
import logging
|
| 17 |
+
import os
|
| 18 |
+
import shutil
|
| 19 |
+
import tempfile
|
| 20 |
+
import threading
|
| 21 |
+
import time
|
| 22 |
+
import uuid
|
| 23 |
+
from typing import TYPE_CHECKING
|
| 24 |
+
|
| 25 |
+
import cv2
|
| 26 |
+
import gradio as gr
|
| 27 |
+
import numpy as np
|
| 28 |
+
|
| 29 |
+
from eve_messages import FeatureFlags
|
| 30 |
+
from eve_worker_pool import log_worker_activity
|
| 31 |
+
from face_id_tab import FaceEntry # runtime import: Gradio resolves type hints at wire time
|
| 32 |
+
from frame_drawing import draw_countdown_banner, draw_overlay, draw_session_timer
|
| 33 |
+
|
| 34 |
+
if TYPE_CHECKING:
|
| 35 |
+
from eve_worker_pool import EveWorkerPool
|
| 36 |
+
from live_stream_manager import LiveStreamManager
|
| 37 |
+
from session_tracker import SessionTracker
|
| 38 |
+
from video_file_server import VideoFileServer
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def patch_video_for_external_urls(video_component: gr.Video) -> None:
|
| 42 |
+
"""Patch a ``gr.Video`` so HTTP(S) URLs bypass Gradio's safehttpx download.
|
| 43 |
+
|
| 44 |
+
Gradio's default postprocessing fetches HTTP URLs via ``safehttpx``,
|
| 45 |
+
which refuses localhost / private IPs. Setting both ``FileData.path``
|
| 46 |
+
and ``FileData.url`` short-circuits the cache logic in
|
| 47 |
+
``async_move_files_to_cache`` so the browser plays the URL directly.
|
| 48 |
+
"""
|
| 49 |
+
from gradio.components.video import VideoData
|
| 50 |
+
from gradio.data_classes import FileData
|
| 51 |
+
|
| 52 |
+
original = video_component.postprocess
|
| 53 |
+
|
| 54 |
+
def _postprocess(value): # type: ignore[no-untyped-def]
|
| 55 |
+
if isinstance(value, str) and value.startswith(("http://", "https://")):
|
| 56 |
+
return VideoData(video=FileData(path=value, url=value))
|
| 57 |
+
return original(value)
|
| 58 |
+
|
| 59 |
+
video_component.postprocess = _postprocess # type: ignore[assignment]
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
class EveAppHandlers:
|
| 63 |
+
"""Gradio-callable handlers for EVE offline + live inference.
|
| 64 |
+
|
| 65 |
+
Args:
|
| 66 |
+
pool: The shared worker pool.
|
| 67 |
+
stream_manager: ``LiveStreamManager`` driving WebRTC streams.
|
| 68 |
+
sessions: ``SessionTracker`` for analytics + idle reaping.
|
| 69 |
+
logger: Logger used for per-session log lines.
|
| 70 |
+
max_fps / min_fps: FPS bounds forwarded to ``send_process_video``
|
| 71 |
+
(controls the worker-side encoding rate).
|
| 72 |
+
video_server: Optional local HTTP server for processed videos.
|
| 73 |
+
When set, processed clips are returned as URLs instead of raw
|
| 74 |
+
paths so Chrome's per-origin connection limit doesn't block
|
| 75 |
+
playback while SSE is open.
|
| 76 |
+
"""
|
| 77 |
+
|
| 78 |
+
def __init__(
|
| 79 |
+
self,
|
| 80 |
+
pool: EveWorkerPool,
|
| 81 |
+
stream_manager: LiveStreamManager,
|
| 82 |
+
sessions: SessionTracker,
|
| 83 |
+
logger: logging.Logger,
|
| 84 |
+
max_fps: float | None,
|
| 85 |
+
min_fps: float | None,
|
| 86 |
+
video_server: VideoFileServer | None = None,
|
| 87 |
+
) -> None:
|
| 88 |
+
self._pool = pool
|
| 89 |
+
self._stream = stream_manager
|
| 90 |
+
self._sessions = sessions
|
| 91 |
+
self._logger = logger
|
| 92 |
+
self._max_fps = max_fps
|
| 93 |
+
self._min_fps = min_fps
|
| 94 |
+
self._video_server = video_server
|
| 95 |
+
self._live_logged: set[str] = set()
|
| 96 |
+
self._live_logged_lock = threading.Lock()
|
| 97 |
+
|
| 98 |
+
# ----- offline inference -------------------------------------------------
|
| 99 |
+
|
| 100 |
+
def run_eve_inference(
|
| 101 |
+
self,
|
| 102 |
+
input_video: str,
|
| 103 |
+
face_detection: bool,
|
| 104 |
+
person_detection: bool,
|
| 105 |
+
face_id: bool,
|
| 106 |
+
hand_gesture: bool,
|
| 107 |
+
registry: dict[int, FaceEntry] | None,
|
| 108 |
+
mod_model: str | None = None,
|
| 109 |
+
request: gr.Request | None = None,
|
| 110 |
+
progress: gr.Progress = gr.Progress(),
|
| 111 |
+
) -> tuple[str | None, dict[int, FaceEntry]]:
|
| 112 |
+
"""Process an uploaded video through one EVE worker, end-to-end.
|
| 113 |
+
|
| 114 |
+
The whole read → infer → encode → write loop happens inside the
|
| 115 |
+
worker process so the asyncio event loop stays free for SSE
|
| 116 |
+
delivery. The main thread only forwards the path/config and
|
| 117 |
+
relays small progress dicts.
|
| 118 |
+
|
| 119 |
+
Returns ``(output_url_or_path, registry)``. ``registry`` is
|
| 120 |
+
returned unchanged when Face ID is disabled, or with ``sdk_id``
|
| 121 |
+
fields refreshed from the worker's gallery-restore results.
|
| 122 |
+
"""
|
| 123 |
+
registry = registry or {}
|
| 124 |
+
session = request.session_hash[:8]
|
| 125 |
+
self._sessions.track(
|
| 126 |
+
request.session_hash,
|
| 127 |
+
"video_process",
|
| 128 |
+
face_detection=face_detection,
|
| 129 |
+
person_detection=person_detection,
|
| 130 |
+
face_id=face_id,
|
| 131 |
+
hand_gesture=hand_gesture,
|
| 132 |
+
mod_model=mod_model,
|
| 133 |
+
)
|
| 134 |
+
|
| 135 |
+
fps, width, height, total_frames = _read_video_metadata(input_video)
|
| 136 |
+
if total_frames <= 0:
|
| 137 |
+
raise gr.Error("Could not read any frames from the video.")
|
| 138 |
+
|
| 139 |
+
features = FeatureFlags(
|
| 140 |
+
face_detection=face_detection,
|
| 141 |
+
person_detection=person_detection,
|
| 142 |
+
face_id=face_id,
|
| 143 |
+
hand_gesture=hand_gesture,
|
| 144 |
+
mod_model=mod_model,
|
| 145 |
+
)
|
| 146 |
+
|
| 147 |
+
gallery_paths: list[str] = []
|
| 148 |
+
remove_all_users = False
|
| 149 |
+
if face_id and registry:
|
| 150 |
+
gallery_paths = [entry.path for entry in registry.values()]
|
| 151 |
+
elif face_id:
|
| 152 |
+
remove_all_users = True
|
| 153 |
+
|
| 154 |
+
# Write directly into Gradio's cache so postprocessing skips the
|
| 155 |
+
# expensive hash_file + shutil.copy2 that would block the asyncio
|
| 156 |
+
# event loop.
|
| 157 |
+
gradio_cache = os.path.join(tempfile.gettempdir(), "gradio")
|
| 158 |
+
session_out = os.path.join(gradio_cache, f"eve_{request.session_hash}")
|
| 159 |
+
os.makedirs(session_out, exist_ok=True)
|
| 160 |
+
output_path = os.path.join(session_out, f"output_{uuid.uuid4().hex[:8]}.mp4")
|
| 161 |
+
|
| 162 |
+
self._logger.info(f"[{session}] run_eve_inference: waiting for worker...")
|
| 163 |
+
# Only emit queue events when we actually have to wait — matches the
|
| 164 |
+
# live queue behaviour so dashboards don't show phantom peaks.
|
| 165 |
+
will_wait = self._pool.idle_count == 0
|
| 166 |
+
if will_wait:
|
| 167 |
+
self._sessions.track(request.session_hash, "offline_queue_enter")
|
| 168 |
+
t0 = time.monotonic()
|
| 169 |
+
worker = self._pool.acquire(
|
| 170 |
+
request.session_hash,
|
| 171 |
+
timeout=300.0,
|
| 172 |
+
progress=progress,
|
| 173 |
+
eta_fn=self._stream.estimated_wait,
|
| 174 |
+
)
|
| 175 |
+
if will_wait:
|
| 176 |
+
self._sessions.track(
|
| 177 |
+
request.session_hash,
|
| 178 |
+
"offline_queue_exit",
|
| 179 |
+
wait_seconds=round(time.monotonic() - t0, 1),
|
| 180 |
+
)
|
| 181 |
+
log_worker_activity(
|
| 182 |
+
self._logger, "acquired", "video-processing", self._pool, worker.worker_id
|
| 183 |
+
)
|
| 184 |
+
try:
|
| 185 |
+
frames_processed, gallery_results = worker.send_process_video(
|
| 186 |
+
input_path=input_video,
|
| 187 |
+
output_path=output_path,
|
| 188 |
+
features=features,
|
| 189 |
+
gallery_paths=gallery_paths,
|
| 190 |
+
remove_all_users=remove_all_users,
|
| 191 |
+
fps=fps,
|
| 192 |
+
width=width,
|
| 193 |
+
height=height,
|
| 194 |
+
total_frames=total_frames,
|
| 195 |
+
progress=progress,
|
| 196 |
+
max_fps=self._max_fps,
|
| 197 |
+
min_fps=self._min_fps,
|
| 198 |
+
)
|
| 199 |
+
self._logger.info(
|
| 200 |
+
f"[{session}] run_eve_inference: done, {frames_processed} frames processed"
|
| 201 |
+
)
|
| 202 |
+
finally:
|
| 203 |
+
self._pool.release(worker)
|
| 204 |
+
log_worker_activity(
|
| 205 |
+
self._logger, "released", "video-processing", self._pool, worker.worker_id
|
| 206 |
+
)
|
| 207 |
+
self._sessions.track(
|
| 208 |
+
request.session_hash,
|
| 209 |
+
"video_process_complete",
|
| 210 |
+
duration_seconds=round(time.monotonic() - t0, 1),
|
| 211 |
+
)
|
| 212 |
+
|
| 213 |
+
if gallery_results:
|
| 214 |
+
for entry, r in zip(registry.values(), gallery_results):
|
| 215 |
+
entry.sdk_id = r.user_id if r.success else None
|
| 216 |
+
|
| 217 |
+
if self._video_server is not None:
|
| 218 |
+
rel_path = os.path.relpath(output_path, gradio_cache)
|
| 219 |
+
video_result: str | None = self._video_server.build_url(rel_path, request)
|
| 220 |
+
else:
|
| 221 |
+
video_result = output_path
|
| 222 |
+
|
| 223 |
+
return video_result, registry
|
| 224 |
+
|
| 225 |
+
# ----- offline image inference -------------------------------------------
|
| 226 |
+
|
| 227 |
+
def run_eve_image_inference(
|
| 228 |
+
self,
|
| 229 |
+
input_image: str | None,
|
| 230 |
+
face_detection: bool,
|
| 231 |
+
person_detection: bool,
|
| 232 |
+
face_id: bool,
|
| 233 |
+
hand_gesture: bool,
|
| 234 |
+
registry: dict[int, FaceEntry] | None,
|
| 235 |
+
mod_model: str | None = None,
|
| 236 |
+
request: gr.Request | None = None,
|
| 237 |
+
progress: gr.Progress = gr.Progress(),
|
| 238 |
+
) -> tuple[np.ndarray | None, dict[int, FaceEntry]]:
|
| 239 |
+
"""Run a single image through one EVE worker, end-to-end.
|
| 240 |
+
|
| 241 |
+
Single-frame variant of :meth:`run_eve_inference`. Loads the image
|
| 242 |
+
as BGR, sends one ``InferenceCmd`` to the worker (the same path
|
| 243 |
+
that powers live inference), and returns the annotated result as
|
| 244 |
+
an RGB ``np.ndarray`` ready for ``gr.Image``.
|
| 245 |
+
|
| 246 |
+
Returns ``(annotated_image_rgb_or_None, registry)``. Registry is
|
| 247 |
+
returned unchanged — single-image inference does not refresh
|
| 248 |
+
Face ID gallery state.
|
| 249 |
+
"""
|
| 250 |
+
if not input_image:
|
| 251 |
+
raise gr.Error("Please upload an image.")
|
| 252 |
+
|
| 253 |
+
registry = registry or {}
|
| 254 |
+
session = request.session_hash[:8] if request is not None else "?"
|
| 255 |
+
if request is not None:
|
| 256 |
+
self._sessions.track(
|
| 257 |
+
request.session_hash,
|
| 258 |
+
"image_process",
|
| 259 |
+
face_detection=face_detection,
|
| 260 |
+
person_detection=person_detection,
|
| 261 |
+
face_id=face_id,
|
| 262 |
+
hand_gesture=hand_gesture,
|
| 263 |
+
mod_model=mod_model,
|
| 264 |
+
)
|
| 265 |
+
|
| 266 |
+
frame = cv2.imread(input_image)
|
| 267 |
+
if frame is None:
|
| 268 |
+
raise gr.Error(f"Could not read image: {input_image}")
|
| 269 |
+
|
| 270 |
+
features = FeatureFlags(
|
| 271 |
+
face_detection=face_detection,
|
| 272 |
+
person_detection=person_detection,
|
| 273 |
+
face_id=face_id,
|
| 274 |
+
hand_gesture=hand_gesture,
|
| 275 |
+
mod_model=mod_model,
|
| 276 |
+
)
|
| 277 |
+
|
| 278 |
+
self._logger.info(f"[{session}] run_eve_image_inference: waiting for worker...")
|
| 279 |
+
will_wait = self._pool.idle_count == 0
|
| 280 |
+
if will_wait and request is not None:
|
| 281 |
+
self._sessions.track(request.session_hash, "offline_queue_enter")
|
| 282 |
+
t0 = time.monotonic()
|
| 283 |
+
worker = self._pool.acquire(
|
| 284 |
+
request.session_hash if request is not None else "image",
|
| 285 |
+
timeout=300.0,
|
| 286 |
+
progress=progress,
|
| 287 |
+
eta_fn=self._stream.estimated_wait,
|
| 288 |
+
)
|
| 289 |
+
if will_wait and request is not None:
|
| 290 |
+
self._sessions.track(
|
| 291 |
+
request.session_hash,
|
| 292 |
+
"offline_queue_exit",
|
| 293 |
+
wait_seconds=round(time.monotonic() - t0, 1),
|
| 294 |
+
)
|
| 295 |
+
log_worker_activity(
|
| 296 |
+
self._logger, "acquired", "image-processing", self._pool, worker.worker_id
|
| 297 |
+
)
|
| 298 |
+
try:
|
| 299 |
+
result = worker.send_inference(frame, features)
|
| 300 |
+
self._logger.info(f"[{session}] run_eve_image_inference: done")
|
| 301 |
+
finally:
|
| 302 |
+
self._pool.release(worker)
|
| 303 |
+
log_worker_activity(
|
| 304 |
+
self._logger, "released", "image-processing", self._pool, worker.worker_id
|
| 305 |
+
)
|
| 306 |
+
if request is not None:
|
| 307 |
+
self._sessions.track(
|
| 308 |
+
request.session_hash,
|
| 309 |
+
"image_process_complete",
|
| 310 |
+
duration_seconds=round(time.monotonic() - t0, 1),
|
| 311 |
+
)
|
| 312 |
+
|
| 313 |
+
# Worker returns BGR (matches live-inference frame format); Gradio's
|
| 314 |
+
# gr.Image expects RGB.
|
| 315 |
+
result_rgb = cv2.cvtColor(result, cv2.COLOR_BGR2RGB)
|
| 316 |
+
return result_rgb, registry
|
| 317 |
+
|
| 318 |
+
# ----- live inference ----------------------------------------------------
|
| 319 |
+
|
| 320 |
+
def process_live_frame(
|
| 321 |
+
self,
|
| 322 |
+
frame: np.ndarray,
|
| 323 |
+
face_detection: bool,
|
| 324 |
+
person_detection: bool,
|
| 325 |
+
face_id: bool,
|
| 326 |
+
hand_gesture: bool,
|
| 327 |
+
registry: dict[int, FaceEntry] | None,
|
| 328 |
+
session_hash: str,
|
| 329 |
+
mod_model: str | None = None,
|
| 330 |
+
):
|
| 331 |
+
# Return type intentionally unannotated: actual return is
|
| 332 |
+
# ``np.ndarray | fastrtc.CloseStream | None`` but ``CloseStream`` is
|
| 333 |
+
# only imported lazily inside the function (avoids pulling fastrtc
|
| 334 |
+
# into module scope), and Gradio/FastRTC may run ``get_type_hints``
|
| 335 |
+
# on bound handlers — a forward-ref string would break that.
|
| 336 |
+
"""Run a single WebRTC frame through an EVE worker.
|
| 337 |
+
|
| 338 |
+
A worker is acquired on the first frame and held for the lifetime of
|
| 339 |
+
the stream. Returns the frame with an overlay while waiting for a
|
| 340 |
+
worker, or a ``CloseStream`` when the session ends so the UI can
|
| 341 |
+
reset to ``Start Inference``.
|
| 342 |
+
|
| 343 |
+
``gr.Request`` is not available inside FastRTC stream handlers, so
|
| 344 |
+
the Gradio session hash is passed through ``gr.State``. FastRTC's
|
| 345 |
+
per-connection ``webrtc_id`` is still pulled from
|
| 346 |
+
``current_context`` to track worker assignment per peer.
|
| 347 |
+
"""
|
| 348 |
+
if frame is None:
|
| 349 |
+
return None
|
| 350 |
+
|
| 351 |
+
from fastrtc.utils import current_context
|
| 352 |
+
|
| 353 |
+
connection_id = current_context.get().webrtc_id
|
| 354 |
+
worker, reason = self._stream.get_or_acquire(connection_id, session_hash, registry or {})
|
| 355 |
+
if worker is None:
|
| 356 |
+
if reason == "waiting":
|
| 357 |
+
pos, total = self._stream.waiting_position(connection_id)
|
| 358 |
+
eta = self._stream.estimated_wait(pos)
|
| 359 |
+
eta_text = ""
|
| 360 |
+
if eta is not None:
|
| 361 |
+
eta_mins = max(0.5, round(eta / 30) * 0.5)
|
| 362 |
+
eta_text = f"\nest. wait ~{eta_mins:g} minutes"
|
| 363 |
+
if total > 1:
|
| 364 |
+
return draw_overlay(frame, f"In queue {eta_text}")
|
| 365 |
+
return draw_overlay(frame, f"Waiting for available worker...{eta_text}")
|
| 366 |
+
with self._live_logged_lock:
|
| 367 |
+
self._live_logged.discard(connection_id)
|
| 368 |
+
from fastrtc import CloseStream
|
| 369 |
+
|
| 370 |
+
return CloseStream(reason or "Stream ended")
|
| 371 |
+
|
| 372 |
+
bridge = self._stream.get_bridge(connection_id)
|
| 373 |
+
if bridge is None or not bridge.is_alive:
|
| 374 |
+
self._stream.release(connection_id)
|
| 375 |
+
return draw_overlay(frame, "Inference error - retrying...")
|
| 376 |
+
|
| 377 |
+
with self._live_logged_lock:
|
| 378 |
+
first_frame = connection_id not in self._live_logged
|
| 379 |
+
if first_frame:
|
| 380 |
+
self._live_logged.add(connection_id)
|
| 381 |
+
if first_frame:
|
| 382 |
+
self._sessions.track(
|
| 383 |
+
session_hash,
|
| 384 |
+
"live_start",
|
| 385 |
+
face_detection=face_detection,
|
| 386 |
+
person_detection=person_detection,
|
| 387 |
+
face_id=face_id,
|
| 388 |
+
hand_gesture=hand_gesture,
|
| 389 |
+
mod_model=mod_model,
|
| 390 |
+
)
|
| 391 |
+
|
| 392 |
+
features = FeatureFlags(
|
| 393 |
+
face_detection=face_detection,
|
| 394 |
+
person_detection=person_detection,
|
| 395 |
+
face_id=face_id,
|
| 396 |
+
hand_gesture=hand_gesture,
|
| 397 |
+
mod_model=mod_model,
|
| 398 |
+
)
|
| 399 |
+
try:
|
| 400 |
+
result = bridge.submit_and_get_latest(frame, features)
|
| 401 |
+
if result is None:
|
| 402 |
+
# First frame — no inference result yet, show camera feed
|
| 403 |
+
return frame
|
| 404 |
+
|
| 405 |
+
remaining = self._stream.countdown_remaining(connection_id)
|
| 406 |
+
if remaining is not None:
|
| 407 |
+
secs = int(remaining) + 1
|
| 408 |
+
result = draw_countdown_banner(result, f"Other users waiting - stopping in {secs}s")
|
| 409 |
+
|
| 410 |
+
session_left = self._stream.session_remaining(connection_id)
|
| 411 |
+
if session_left is not None:
|
| 412 |
+
result = draw_session_timer(result, session_left)
|
| 413 |
+
|
| 414 |
+
return result
|
| 415 |
+
except (BrokenPipeError, EOFError, OSError):
|
| 416 |
+
# Worker pipe is gone (shutdown or crash) — release quietly
|
| 417 |
+
self._stream.release(connection_id)
|
| 418 |
+
return None
|
| 419 |
+
except Exception as exc:
|
| 420 |
+
self._logger.error(f"Live inference error: {exc}")
|
| 421 |
+
self._stream.release(connection_id)
|
| 422 |
+
return draw_overlay(frame, "Inference error - retrying...")
|
| 423 |
+
|
| 424 |
+
def on_live_feature_change(
|
| 425 |
+
self,
|
| 426 |
+
face_detection: bool,
|
| 427 |
+
person_detection: bool,
|
| 428 |
+
face_id: bool,
|
| 429 |
+
hand_gesture: bool,
|
| 430 |
+
mod_model: str | None = None,
|
| 431 |
+
request: gr.Request | None = None,
|
| 432 |
+
) -> None:
|
| 433 |
+
"""Track changes to the Live tab's feature checkboxes."""
|
| 434 |
+
self._sessions.track(
|
| 435 |
+
request.session_hash,
|
| 436 |
+
"live_feature_change",
|
| 437 |
+
face_detection=face_detection,
|
| 438 |
+
person_detection=person_detection,
|
| 439 |
+
face_id=face_id,
|
| 440 |
+
hand_gesture=hand_gesture,
|
| 441 |
+
mod_model=mod_model,
|
| 442 |
+
)
|
| 443 |
+
|
| 444 |
+
# ----- session cleanup ---------------------------------------------------
|
| 445 |
+
|
| 446 |
+
def cleanup_session(self, request: gr.Request) -> None:
|
| 447 |
+
"""Gradio ``demo.unload`` handler — close the session + delete cache."""
|
| 448 |
+
self._sessions.on_unload(request)
|
| 449 |
+
|
| 450 |
+
gradio_cache = os.path.join(tempfile.gettempdir(), "gradio")
|
| 451 |
+
session_out = os.path.join(gradio_cache, f"eve_{request.session_hash}")
|
| 452 |
+
if os.path.isdir(session_out):
|
| 453 |
+
shutil.rmtree(session_out, ignore_errors=True)
|
| 454 |
+
self._logger.debug(f"Session cleanup: removed {session_out}")
|
| 455 |
+
|
| 456 |
+
|
| 457 |
+
def _read_video_metadata(path: str) -> tuple[float, int, int, int]:
|
| 458 |
+
"""Return ``(fps, width, height, total_frames)`` for a video file.
|
| 459 |
+
|
| 460 |
+
Webcam-recorded WebM blobs frequently lie in their headers (fps=0,
|
| 461 |
+
fps=1000 from ms timestamps, or no frame count) so we fall back to a
|
| 462 |
+
full decode pass when the headers look implausible.
|
| 463 |
+
"""
|
| 464 |
+
cap = cv2.VideoCapture(path)
|
| 465 |
+
fps = cap.get(cv2.CAP_PROP_FPS)
|
| 466 |
+
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
| 467 |
+
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
| 468 |
+
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
| 469 |
+
|
| 470 |
+
if fps <= 0 or fps > 240 or total_frames <= 0 or width <= 0 or height <= 0:
|
| 471 |
+
frame_count = 0
|
| 472 |
+
duration_ms = 0.0
|
| 473 |
+
while True:
|
| 474 |
+
ret, frame = cap.read()
|
| 475 |
+
if not ret:
|
| 476 |
+
break
|
| 477 |
+
if frame_count == 0:
|
| 478 |
+
height, width = frame.shape[:2]
|
| 479 |
+
frame_count += 1
|
| 480 |
+
duration_ms = cap.get(cv2.CAP_PROP_POS_MSEC)
|
| 481 |
+
total_frames = frame_count
|
| 482 |
+
if fps <= 0 or fps > 240:
|
| 483 |
+
fps = total_frames / (duration_ms / 1000.0) if duration_ms > 0 else 30.0
|
| 484 |
+
cap.release()
|
| 485 |
+
return fps, width, height, total_frames
|
shared/eve_messages.py
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""IPC message dataclasses for the Eve worker pool.
|
| 2 |
+
|
| 3 |
+
All types are picklable and sent over ``multiprocessing.Pipe`` between the
|
| 4 |
+
main Gradio process and Eve SDK worker processes.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
from dataclasses import dataclass
|
| 8 |
+
|
| 9 |
+
# ---------------------------------------------------------------------------
|
| 10 |
+
# Shared data types
|
| 11 |
+
# ---------------------------------------------------------------------------
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
@dataclass
|
| 15 |
+
class CalibrationResultMsg:
|
| 16 |
+
"""Picklable mirror of ``eve_wrapper.CalibrationResult``."""
|
| 17 |
+
|
| 18 |
+
success: bool
|
| 19 |
+
user_id: int
|
| 20 |
+
message: str
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
@dataclass
|
| 24 |
+
class FeatureFlags:
|
| 25 |
+
"""Feature toggle bundle sent with inference / configure commands."""
|
| 26 |
+
|
| 27 |
+
face_detection: bool = True
|
| 28 |
+
person_detection: bool = True
|
| 29 |
+
face_id: bool = False
|
| 30 |
+
hand_gesture: bool = False
|
| 31 |
+
# None = MOD off. Otherwise a model-name string (e.g. "GMOD-80",
|
| 32 |
+
# "AMOD-8", "OMOD") that the worker resolves to the EVE SDK MOD model.
|
| 33 |
+
# Defaulted so existing demos keep their pickle shape unchanged.
|
| 34 |
+
mod_model: str | None = None
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
@dataclass
|
| 38 |
+
class SerializedFrame:
|
| 39 |
+
"""Picklable representation of a numpy ndarray frame."""
|
| 40 |
+
|
| 41 |
+
data: bytes
|
| 42 |
+
shape: tuple[int, ...]
|
| 43 |
+
dtype: str
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
# ---------------------------------------------------------------------------
|
| 47 |
+
# Commands (main process → worker process)
|
| 48 |
+
# ---------------------------------------------------------------------------
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
@dataclass
|
| 52 |
+
class InferenceCmd:
|
| 53 |
+
frame_bytes: bytes
|
| 54 |
+
shape: tuple[int, ...]
|
| 55 |
+
dtype: str
|
| 56 |
+
features: FeatureFlags
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
@dataclass
|
| 60 |
+
class ConfigureFeaturesCmd:
|
| 61 |
+
features: FeatureFlags
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
@dataclass
|
| 65 |
+
class CalibrateNewUserCmd:
|
| 66 |
+
frames_data: list[SerializedFrame]
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
@dataclass
|
| 70 |
+
class RemoveAllUsersCmd:
|
| 71 |
+
pass
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
@dataclass
|
| 75 |
+
class RestoreGalleryCmd:
|
| 76 |
+
frames_per_user_data: list[list[SerializedFrame]]
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
@dataclass
|
| 80 |
+
class EnableFaceIdCmd:
|
| 81 |
+
enabled: bool
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
@dataclass
|
| 85 |
+
class ProcessVideoCmd:
|
| 86 |
+
input_path: str
|
| 87 |
+
output_path: str
|
| 88 |
+
features: FeatureFlags
|
| 89 |
+
gallery_paths: list[str]
|
| 90 |
+
remove_all_users: bool
|
| 91 |
+
fps: float
|
| 92 |
+
width: int
|
| 93 |
+
height: int
|
| 94 |
+
total_frames: int
|
| 95 |
+
max_fps: float | None = None
|
| 96 |
+
min_fps: float | None = None
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
@dataclass
|
| 100 |
+
class ShutdownCmd:
|
| 101 |
+
pass
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
@dataclass
|
| 105 |
+
class StartProfilingCmd:
|
| 106 |
+
pass
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
@dataclass
|
| 110 |
+
class StopProfilingCmd:
|
| 111 |
+
pass
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
@dataclass
|
| 115 |
+
class GetProfileStatsCmd:
|
| 116 |
+
pass
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
@dataclass
|
| 120 |
+
class GetTimingStatsCmd:
|
| 121 |
+
reset: bool = True
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
WorkerCmd = (
|
| 125 |
+
InferenceCmd
|
| 126 |
+
| ConfigureFeaturesCmd
|
| 127 |
+
| CalibrateNewUserCmd
|
| 128 |
+
| RemoveAllUsersCmd
|
| 129 |
+
| RestoreGalleryCmd
|
| 130 |
+
| EnableFaceIdCmd
|
| 131 |
+
| ProcessVideoCmd
|
| 132 |
+
| ShutdownCmd
|
| 133 |
+
| StartProfilingCmd
|
| 134 |
+
| StopProfilingCmd
|
| 135 |
+
| GetProfileStatsCmd
|
| 136 |
+
| GetTimingStatsCmd
|
| 137 |
+
)
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
# ---------------------------------------------------------------------------
|
| 141 |
+
# Responses (worker process → main process)
|
| 142 |
+
# ---------------------------------------------------------------------------
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
@dataclass
|
| 146 |
+
class ReadyResponse:
|
| 147 |
+
pid: int
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
@dataclass
|
| 151 |
+
class ErrorResponse:
|
| 152 |
+
error: str
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
@dataclass
|
| 156 |
+
class HeartbeatResponse:
|
| 157 |
+
pass
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
@dataclass
|
| 161 |
+
class OkResponse:
|
| 162 |
+
pass
|
| 163 |
+
|
| 164 |
+
|
| 165 |
+
@dataclass
|
| 166 |
+
class InferenceResponse:
|
| 167 |
+
frame_bytes: bytes
|
| 168 |
+
shape: tuple[int, ...]
|
| 169 |
+
dtype: str
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
@dataclass
|
| 173 |
+
class CalibrateOkResponse:
|
| 174 |
+
result: CalibrationResultMsg
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
@dataclass
|
| 178 |
+
class RemoveUsersOkResponse:
|
| 179 |
+
result: bool
|
| 180 |
+
|
| 181 |
+
|
| 182 |
+
@dataclass
|
| 183 |
+
class RestoreGalleryOkResponse:
|
| 184 |
+
results: list[CalibrationResultMsg]
|
| 185 |
+
|
| 186 |
+
|
| 187 |
+
@dataclass
|
| 188 |
+
class GalleryRestoredResponse:
|
| 189 |
+
results: list[CalibrationResultMsg]
|
| 190 |
+
|
| 191 |
+
|
| 192 |
+
@dataclass
|
| 193 |
+
class ProgressResponse:
|
| 194 |
+
current: int
|
| 195 |
+
total: int
|
| 196 |
+
|
| 197 |
+
|
| 198 |
+
@dataclass
|
| 199 |
+
class VideoProcessingDoneResponse:
|
| 200 |
+
frames_processed: int
|
| 201 |
+
gallery_results: list[CalibrationResultMsg]
|
| 202 |
+
recycle: bool
|
| 203 |
+
|
| 204 |
+
|
| 205 |
+
@dataclass
|
| 206 |
+
class ProfileStatsResponse:
|
| 207 |
+
stats_data: bytes # marshalled pstats data
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
@dataclass
|
| 211 |
+
class TimingStatsResponse:
|
| 212 |
+
"""Per-SDK-call timing data from EveWrapper."""
|
| 213 |
+
|
| 214 |
+
stats: dict[str, tuple[int, float]] # {name: (call_count, total_seconds)}
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
WorkerResponse = (
|
| 218 |
+
ReadyResponse
|
| 219 |
+
| ErrorResponse
|
| 220 |
+
| HeartbeatResponse
|
| 221 |
+
| OkResponse
|
| 222 |
+
| InferenceResponse
|
| 223 |
+
| CalibrateOkResponse
|
| 224 |
+
| RemoveUsersOkResponse
|
| 225 |
+
| RestoreGalleryOkResponse
|
| 226 |
+
| GalleryRestoredResponse
|
| 227 |
+
| ProgressResponse
|
| 228 |
+
| VideoProcessingDoneResponse
|
| 229 |
+
| ProfileStatsResponse
|
| 230 |
+
| TimingStatsResponse
|
| 231 |
+
)
|
shared/eve_python/eve_sdk.py
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from . import eve_sdk_structs as structs
|
| 3 |
+
|
| 4 |
+
EveProcessingCallbackFn = ctypes.CFUNCTYPE(None, ctypes.POINTER(structs.EveProcessingCallbackReturnData))
|
| 5 |
+
|
| 6 |
+
class EveSDK:
|
| 7 |
+
def __init__(self, dll_path: str):
|
| 8 |
+
self.cdll = ctypes.CDLL(dll_path)
|
| 9 |
+
# EveCameraApi.h
|
| 10 |
+
self.cdll.EveGetFormats.restype = structs.EveCameraFormats
|
| 11 |
+
self.cdll.EveGetFormats.argtypes = [ctypes.c_uint, structs.CCameraFormat]
|
| 12 |
+
self.cdll.EveGetCamera.restype = structs.EveCamera
|
| 13 |
+
self.cdll.EveGetCamera.argtypes = [ctypes.c_uint]
|
| 14 |
+
self.cdll.EveSetCamera.restype = structs.EveError
|
| 15 |
+
self.cdll.EveSetCamera.argtypes = [ctypes.c_uint, structs.CCameraFormat]
|
| 16 |
+
# EveControlInterface.h
|
| 17 |
+
self.cdll.CreateEve.restype = structs.EveError
|
| 18 |
+
self.cdll.CreateEve.argtypes = [structs.EveStartupParameters]
|
| 19 |
+
self.cdll.EveRegisterDataCallback.restype = structs.EveError
|
| 20 |
+
self.cdll.EveRegisterDataCallback.argtypes = [EveProcessingCallbackFn]
|
| 21 |
+
self.cdll.StartEve.restype = structs.EveError
|
| 22 |
+
self.cdll.StartEve.argtypes = []
|
| 23 |
+
self.cdll.StartEveWithParameters.restype = structs.EveError
|
| 24 |
+
self.cdll.StartEveWithParameters.argtypes = [structs.EveProcessingParameters]
|
| 25 |
+
self.cdll.EveSendImageForProcessing.restype = structs.EveError
|
| 26 |
+
self.cdll.EveSendImageForProcessing.argtypes = [structs.EveInputImage]
|
| 27 |
+
self.cdll.EveSendImageForProcessingWithParams.restype = structs.EveError
|
| 28 |
+
self.cdll.EveSendImageForProcessingWithParams.argtypes = [structs.EveInputImage, structs.CCameraParameters]
|
| 29 |
+
self.cdll.ShutdownEve.restype = structs.EveError
|
| 30 |
+
self.cdll.ShutdownEve.argtypes = []
|
| 31 |
+
|
| 32 |
+
# EveKarolinska.h
|
| 33 |
+
self.cdll.EveConfigureKarolinska.restype = structs.EveKarolinskaOptions
|
| 34 |
+
self.cdll.EveConfigureKarolinska.argtypes = [structs.EveKarolinskaOptions]
|
| 35 |
+
|
| 36 |
+
self.cdll.EveGetKarolinskaData.restype = structs.EveKarolinskaData
|
| 37 |
+
self.cdll.EveGetKarolinskaData.argtypes = []
|
| 38 |
+
|
| 39 |
+
# EveFaceId.h
|
| 40 |
+
self.cdll.EveConfigureFaceId.restype = structs.EveFaceIdOptions
|
| 41 |
+
self.cdll.EveConfigureFaceId.argtypes = [structs.EveFaceIdOptions]
|
| 42 |
+
self.cdll.EveFaceIdCalibrateCurrent.restype = structs.EveError
|
| 43 |
+
self.cdll.EveFaceIdCalibrateCurrent.argtypes = []
|
| 44 |
+
self.cdll.EveFaceIdCalibrateNew.restype = structs.EveError
|
| 45 |
+
self.cdll.EveFaceIdCalibrateNew.argtypes = []
|
| 46 |
+
self.cdll.EveFaceIdForceIdentify.restype = structs.EveError
|
| 47 |
+
self.cdll.EveFaceIdForceIdentify.argtypes = []
|
| 48 |
+
self.cdll.EveFaceIdRemoveCurrent.restype = structs.EveError
|
| 49 |
+
self.cdll.EveFaceIdRemoveCurrent.argtypes = []
|
| 50 |
+
self.cdll.EveFaceIdRemoveAll.restype = structs.EveError
|
| 51 |
+
self.cdll.EveFaceIdRemoveAll.argtypes = []
|
| 52 |
+
self.cdll.EveFaceIdReloadGallery.restype = structs.EveError
|
| 53 |
+
self.cdll.EveFaceIdReloadGallery.argtypes = []
|
| 54 |
+
self.cdll.EveFaceIdCommandWaiting.restype = ctypes.c_uint
|
| 55 |
+
self.cdll.EveFaceIdCommandWaiting.argtypes = []
|
| 56 |
+
self.cdll.EveGetFaceIdData.restype = structs.EveFaceIdData
|
| 57 |
+
self.cdll.EveGetFaceIdData.argtypes = []
|
| 58 |
+
self.cdll.EveSendFaceIdCommand.restype = structs.EveFaceIdCommandStruct
|
| 59 |
+
self.cdll.EveSendFaceIdCommand.argtypes = [structs.EveFaceIdCommandStruct]
|
| 60 |
+
# EveFaceTracker.h
|
| 61 |
+
self.cdll.EveConfigureFaceTracker.restype = structs.EveFaceTrackerOptions
|
| 62 |
+
self.cdll.EveConfigureFaceTracker.argtypes = [structs.EveFaceTrackerOptions]
|
| 63 |
+
self.cdll.EveGetAllFaceData.restype = structs.EveAllFacesData
|
| 64 |
+
self.cdll.EveGetAllFaceData.argtypes = []
|
| 65 |
+
# EveFpga.h
|
| 66 |
+
self.cdll.EveConfigureFpga.restype = structs.EveFpgaOptions
|
| 67 |
+
self.cdll.EveConfigureFpga.argtypes = [structs.EveFpgaOptions]
|
| 68 |
+
self.cdll.EveConfigureFpgaDebug.restype = structs.EveFpgaDebugOptions
|
| 69 |
+
self.cdll.EveConfigureFpgaDebug.argtypes = [structs.EveFpgaDebugOptions]
|
| 70 |
+
self.cdll.QueryFpgaSetting.restype = structs.EveError
|
| 71 |
+
self.cdll.QueryFpgaSetting.argtypes = [structs.pipeline_config_t, ctypes.c_bool]
|
| 72 |
+
self.cdll.QueryFpgaSettings.restype = structs.EveError
|
| 73 |
+
self.cdll.QueryFpgaSettings.argtypes = [ctypes.c_uint16, ctypes.c_uint32, ctypes.c_bool]
|
| 74 |
+
self.cdll.SendSetSetting.restype = structs.EveError
|
| 75 |
+
self.cdll.SendSetSetting.argtypes = [structs.pipeline_config_t]
|
| 76 |
+
self.cdll.PopQueuedSetting.restype = structs.CFpgaGetSetting
|
| 77 |
+
self.cdll.PopQueuedSetting.argtypes = []
|
| 78 |
+
self.cdll.EveGetFpgaData.restype = structs.EveFpgaData
|
| 79 |
+
self.cdll.EveGetFpgaData.argtypes = []
|
| 80 |
+
self.cdll.FpgaReadJson.restype = structs.EveFpgaJsonMetadata
|
| 81 |
+
self.cdll.FpgaReadJson.argtypes = []
|
| 82 |
+
self.cdll.EveSendImageForProcessingWithFpgaData.restype = structs.EveError
|
| 83 |
+
self.cdll.EveSendImageForProcessingWithFpgaData.argtypes = [structs.EveInputImage, structs.EveFpgaManualData]
|
| 84 |
+
|
| 85 |
+
# EveImageManipulation.h
|
| 86 |
+
self.cdll.EveConfigureImageManipulation.restype = structs.EveImageManipulationOptions
|
| 87 |
+
self.cdll.EveConfigureImageManipulation.argtypes = [structs.EveImageManipulationOptions]
|
| 88 |
+
|
| 89 |
+
# EveImage.h
|
| 90 |
+
self.cdll.EveGetProcessedImage.restype = structs.EveProcessedImage
|
| 91 |
+
self.cdll.EveGetProcessedImage.argtypes = []
|
| 92 |
+
self.cdll.EveGetProcessedFrameTime.restype = structs.EveProcessedFrameTime
|
| 93 |
+
self.cdll.EveGetProcessedFrameTime.argtypes = []
|
| 94 |
+
self.cdll.EveConfigureProcessedImage.restype = structs.EveImageFormatRequest
|
| 95 |
+
self.cdll.EveConfigureProcessedImage.argtypes = [structs.EveImageFormatRequest]
|
| 96 |
+
|
| 97 |
+
# EveObjectDetection.h
|
| 98 |
+
self.cdll.EveConfigureObjectDetection.restype = structs.EveObjectDetectionOptions
|
| 99 |
+
self.cdll.EveConfigureObjectDetection.argtypes = []
|
| 100 |
+
self.cdll.EveConfigurePersonDetection.restype = structs.EvePersonDetectionOptions
|
| 101 |
+
self.cdll.EveConfigurePersonDetection.argtypes = []
|
| 102 |
+
self.cdll.EveGetObjectDetectionData.restype = structs.EveDetectionData
|
| 103 |
+
self.cdll.EveGetObjectDetectionData.argtypes = []
|
| 104 |
+
self.cdll.EveCopyObjectDetectionData.restype = structs.EveDetectionData
|
| 105 |
+
self.cdll.EveCopyObjectDetectionData.argtypes = []
|
| 106 |
+
self.cdll.EveGetPersonDetectionData.restype = structs.EveDetectionData
|
| 107 |
+
self.cdll.EveGetPersonDetectionData.argtypes = []
|
| 108 |
+
self.cdll.EveCopyPersonDetectionData.restype = structs.EveDetectionData
|
| 109 |
+
self.cdll.EveCopyPersonDetectionData.argtypes = []
|
| 110 |
+
self.cdll.DeleteDetectionData.restype = structs.EveError
|
| 111 |
+
self.cdll.DeleteDetectionData.argtypes = [structs.EveDetectionData]
|
| 112 |
+
# EveROI.h
|
| 113 |
+
self.cdll.EveConfigureROIs.restype = structs.EveROIOptions
|
| 114 |
+
self.cdll.EveConfigureROIs.argtypes = [structs.EveROIOptions]
|
| 115 |
+
self.cdll.EveGetROIScoreData.restype = structs.EveROIScoreData
|
| 116 |
+
self.cdll.EveGetROIScoreData.argtypes = []
|
| 117 |
+
# EveHandGesture.h
|
| 118 |
+
self.cdll.EveConfigureHandGesture.restype = structs.EveHandGestureOptions
|
| 119 |
+
self.cdll.EveConfigureHandGesture.argtypes = [structs.EveHandGestureOptions]
|
| 120 |
+
self.cdll.EveGetHandGestureData.restype = structs.EveHandGestureData
|
| 121 |
+
self.cdll.EveGetHandGestureData.argtypes = []
|
| 122 |
+
self.cdll.EveCopyHandGestureData.restype = structs.EveHandGestureData
|
| 123 |
+
self.cdll.EveCopyHandGestureData.argtypes = []
|
| 124 |
+
self.cdll.EveDeleteHandGestureData.restype = structs.EveError
|
| 125 |
+
self.cdll.EveDeleteHandGestureData.argtypes = [structs.EveHandGestureData]
|
| 126 |
+
self.cdll.EveGetStaticGestureDetections.restype = structs.EveStaticGestureData
|
| 127 |
+
self.cdll.EveGetStaticGestureDetections.argtypes = []
|
| 128 |
+
self.cdll.EveGetDynamicGestureDetections.restype = structs.EveDynamicGestureData
|
| 129 |
+
self.cdll.EveGetDynamicGestureDetections.argtypes = []
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
# EveCamera.h
|
| 133 |
+
def EveGetFormats(self, cameraId: ctypes.c_uint, filter: structs.CCameraFormat) -> structs.EveCameraFormats:
|
| 134 |
+
return self.cdll.EveGetFormats(cameraId, filter)
|
| 135 |
+
|
| 136 |
+
def EveGetCamera(self, cameraId: ctypes.c_uint) -> structs.EveCamera:
|
| 137 |
+
return self.cdll.EveGetCamera(cameraId)
|
| 138 |
+
|
| 139 |
+
def EveSetCamera(self, cameraId: ctypes.c_uint, filter: structs.CCameraFormat) -> structs.EveError:
|
| 140 |
+
return self.cdll.EveSetCamera(cameraId, filter)
|
| 141 |
+
|
| 142 |
+
# EveControlInterface.h
|
| 143 |
+
def CreateEve(self, options: structs.EveStartupParameters) -> structs.EveError:
|
| 144 |
+
return self.cdll.CreateEve(options)
|
| 145 |
+
|
| 146 |
+
def EveRegisterDataCallback(self, callback) -> structs.EveError:
|
| 147 |
+
return self.cdll.EveRegisterDataCallback(callback)
|
| 148 |
+
|
| 149 |
+
def StartEve(self) -> structs.EveError:
|
| 150 |
+
return self.cdll.StartEve()
|
| 151 |
+
|
| 152 |
+
def StartEveWithParameters(self, parameters: structs.EveProcessingParameters) -> structs.EveError:
|
| 153 |
+
return self.cdll.StartEveWithParameters(parameters)
|
| 154 |
+
|
| 155 |
+
def EveSendImageForProcessing(self, image: structs.EveInputImage) -> structs.EveError:
|
| 156 |
+
return self.cdll.EveSendImageForProcessing(image)
|
| 157 |
+
|
| 158 |
+
def EveSendImageForProcessingWithParams(self, image: structs.EveInputImage, params: structs.CCameraParameters) -> structs.EveError:
|
| 159 |
+
return self.cdll.EveSendImageForProcessingWithParams(image, params)
|
| 160 |
+
|
| 161 |
+
def EveSendFpgaDataManually(self, image: structs.EveFpgaManualData) -> structs.EveError:
|
| 162 |
+
return self.cdll.EveSendFpgaDataManually(image)
|
| 163 |
+
|
| 164 |
+
def ShutdownEve(self) -> structs.EveError:
|
| 165 |
+
return self.cdll.ShutdownEve()
|
| 166 |
+
|
| 167 |
+
# EveFaceId.h
|
| 168 |
+
def EveConfigureFaceId(self, options: structs.EveFaceIdOptions) -> structs.EveFaceIdOptions:
|
| 169 |
+
return self.cdll.EveConfigureFaceId(options)
|
| 170 |
+
|
| 171 |
+
def EveFaceIdCalibrateCurrent(self) -> structs.EveError:
|
| 172 |
+
return self.cdll.EveFaceIdCalibrateCurrent()
|
| 173 |
+
|
| 174 |
+
def EveFaceIdCalibrateNew(self) -> structs.EveError:
|
| 175 |
+
return self.cdll.EveFaceIdCalibrateNew()
|
| 176 |
+
|
| 177 |
+
def EveFaceIdForceIdentify(self) -> structs.EveError:
|
| 178 |
+
return self.cdll.EveFaceIdForceIdentify()
|
| 179 |
+
|
| 180 |
+
def EveFaceIdRemoveCurrent(self) -> structs.EveError:
|
| 181 |
+
return self.cdll.EveFaceIdRemoveCurrent()
|
| 182 |
+
|
| 183 |
+
def EveFaceIdRemoveAll(self) -> structs.EveError:
|
| 184 |
+
return self.cdll.EveFaceIdRemoveAll()
|
| 185 |
+
|
| 186 |
+
def EveFaceIdReloadGallery(self) -> structs.EveError:
|
| 187 |
+
return self.cdll.EveFaceIdReloadGallery()
|
| 188 |
+
|
| 189 |
+
def EveFaceIdCommandWaiting(self) -> ctypes.c_uint:
|
| 190 |
+
return self.cdll.EveFaceIdCommandWaiting()
|
| 191 |
+
|
| 192 |
+
def EveGetFaceIdData(self) -> structs.EveFaceIdData:
|
| 193 |
+
return self.cdll.EveGetFaceIdData()
|
| 194 |
+
|
| 195 |
+
def EveSendFaceIdCommand(self, command: structs.EveFaceIdCommandStruct) -> structs.EveFaceIdCommandStruct:
|
| 196 |
+
return self.cdll.EveSendFaceIdCommand(command)
|
| 197 |
+
|
| 198 |
+
# EveFaceTracker.h
|
| 199 |
+
def EveConfigureFaceTracker(self, options: structs.EveFaceTrackerOptions) -> structs.EveFaceTrackerOptions:
|
| 200 |
+
return self.cdll.EveConfigureFaceTracker(options)
|
| 201 |
+
|
| 202 |
+
def EveGetAllFaceData(self) -> structs.EveAllFacesData:
|
| 203 |
+
return self.cdll.EveGetAllFaceData()
|
| 204 |
+
|
| 205 |
+
# EveFpga.h
|
| 206 |
+
def EveGetFpgaData(self) -> structs.EveFpgaData:
|
| 207 |
+
return self.cdll.EveGetFpgaData()
|
| 208 |
+
|
| 209 |
+
def EveConfigureFpga(self, options: structs.EveFpgaOptions) -> structs.EveFpgaOptions:
|
| 210 |
+
return self.cdll.EveConfigureFpga(options)
|
| 211 |
+
|
| 212 |
+
def EveConfigureFpgaDebug(self, options: structs.EveFpgaDebugOptions) -> structs.EveFpgaDebugOptions:
|
| 213 |
+
return self.cdll.EveConfigureFpgaDebug(options)
|
| 214 |
+
|
| 215 |
+
def QueryFpgaSetting(self, command: structs.pipeline_config_t, notify: ctypes.c_bool) -> structs.EveError:
|
| 216 |
+
return self.cdll.QueryFpgaSetting(command, notify)
|
| 217 |
+
|
| 218 |
+
def QueryFpgaSettings(self, typeMask: ctypes.c_uint16, settingsMask: ctypes.c_uint32, notify: ctypes.c_bool) -> structs.EveError:
|
| 219 |
+
return self.cdll.QueryFpgaSettings(typeMask, settingsMask, notify)
|
| 220 |
+
|
| 221 |
+
def SendSetSetting(self, command: structs.pipeline_config_t) -> structs.EveError:
|
| 222 |
+
return self.cdll.SendSetSetting(command)
|
| 223 |
+
|
| 224 |
+
def PopQueuedSetting(self) -> structs.CFpgaGetSetting:
|
| 225 |
+
return self.cdll.PopQueuedSetting()
|
| 226 |
+
|
| 227 |
+
def FpgaReadJson(self) -> structs.EveFpgaJsonMetadata:
|
| 228 |
+
return self.cdll.FpgaReadJson()
|
| 229 |
+
|
| 230 |
+
# EveKarolinksa.h
|
| 231 |
+
def EveConfigureKarolinska(self, parameters: structs.EveKarolinskaOptions) -> structs.EveKarolinskaOptions:
|
| 232 |
+
return self.cdll.EveConfigureKarolinska(parameters)
|
| 233 |
+
|
| 234 |
+
def EveGetKarolinskaData(self) -> structs.EveKarolinskaData:
|
| 235 |
+
return self.cdll.EveGetKarolinskaData()
|
| 236 |
+
|
| 237 |
+
# EveImageManipulation.h
|
| 238 |
+
def EveConfigureImageManipulation(self, options: structs.EveImageManipulationOptions) -> structs.EveImageManipulationOptions:
|
| 239 |
+
return self.cdll.EveConfigureImageManipulation(options)
|
| 240 |
+
|
| 241 |
+
# EveImage.h
|
| 242 |
+
def EveGetProcessedImage(self) -> structs.EveProcessedImage:
|
| 243 |
+
return self.cdll.EveGetProcessedImage()
|
| 244 |
+
|
| 245 |
+
def EveGetProcessedFrameTime(self) -> structs.EveProcessedFrameTime:
|
| 246 |
+
return self.cdll.EveGetProcessedFrameTime()
|
| 247 |
+
|
| 248 |
+
def EveConfigureProcessedImage(self, fmt: structs.EveImageFormatRequest) -> structs.EveProcessedFrameTime:
|
| 249 |
+
return self.cdll.EveConfigureProcessedImage(fmt)
|
| 250 |
+
|
| 251 |
+
# EveObjectDetection.h
|
| 252 |
+
def EveConfigureObjectDetection(self, enabled: structs.EveObjectDetectionOptions) -> structs.EveObjectDetectionOptions:
|
| 253 |
+
return self.cdll.EveConfigureObjectDetection(enabled)
|
| 254 |
+
|
| 255 |
+
def EveConfigurePersonDetection(self, enabled: structs.EvePersonDetectionOptions) -> structs.EvePersonDetectionOptions:
|
| 256 |
+
return self.cdll.EveConfigurePersonDetection(enabled)
|
| 257 |
+
|
| 258 |
+
def EveGetObjectDetectionData(self) -> structs.EveDetectionData:
|
| 259 |
+
return self.cdll.EveGetObjectDetectionData()
|
| 260 |
+
|
| 261 |
+
def EveCopyObjectDetectionData(self) -> structs.EveDetectionData:
|
| 262 |
+
return self.cdll.EveCopyObjectDetectionData()
|
| 263 |
+
|
| 264 |
+
def EveGetPersonDetectionData(self) -> structs.EveDetectionData:
|
| 265 |
+
return self.cdll.EveGetPersonDetectionData()
|
| 266 |
+
|
| 267 |
+
def EveCopyPersonDetectionData(self) -> structs.EveDetectionData:
|
| 268 |
+
return self.cdll.EveCopyPersonDetectionData()
|
| 269 |
+
|
| 270 |
+
def DeleteDetectionData(self, data: structs.EveDetectionData) -> structs.EveError:
|
| 271 |
+
return self.cdll.DeleteDetectionData(data)
|
| 272 |
+
|
| 273 |
+
# EveROI.h
|
| 274 |
+
def EveConfigureROIs(self, options: structs.EveROIOptions) -> structs.EveError:
|
| 275 |
+
return self.cdll.EveConfigureROIs(options)
|
| 276 |
+
|
| 277 |
+
def EveGetROIScoreData(self) -> structs.EveROIScoreData:
|
| 278 |
+
return self.cdll.EveGetROIScoreData()
|
| 279 |
+
|
| 280 |
+
# EveHandGesture.h
|
| 281 |
+
def EveConfigureHandGesture(self, options: structs.EveHandGestureOptions) -> structs.EveHandGestureOptions:
|
| 282 |
+
return self.cdll.EveConfigureHandGesture(options)
|
| 283 |
+
|
| 284 |
+
def EveGetHandGestureData(self) -> structs.EveHandGestureData:
|
| 285 |
+
return self.cdll.EveGetHandGestureData()
|
| 286 |
+
|
| 287 |
+
def EveCopyHandGestureData(self) -> structs.EveHandGestureData:
|
| 288 |
+
return self.cdll.EveGetHandGestureData()
|
| 289 |
+
|
| 290 |
+
def EveDeleteHandGestureData(self, data: structs.EveHandGestureData) -> structs.EveError:
|
| 291 |
+
return self.cdll.EveGetHandGestureData(data)
|
| 292 |
+
|
| 293 |
+
def EveGetStaticGestureDetections(self) -> structs.EveStaticGestureData:
|
| 294 |
+
return self.cdll.EveGetStaticGestureDetections()
|
| 295 |
+
|
| 296 |
+
def EveGetDynamicGestureDetections(self) -> structs.EveDynamicGestureData:
|
| 297 |
+
return self.cdll.EveGetDynamicGestureDetections()
|
shared/eve_python/eve_sdk_structs.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
#If any of the files below are missing, make sure to run PythonCTypesGenerator.py
|
| 4 |
+
from .structs.CAlgorithms import *
|
| 5 |
+
from .structs.CBasicStructs import *
|
| 6 |
+
from .structs.CCameraStructs import *
|
| 7 |
+
from .structs.CDetectionStructs import *
|
| 8 |
+
from .structs.CFaceData import *
|
| 9 |
+
from .structs.CFaceIdStructs import *
|
| 10 |
+
from .structs.CFpgaData import *
|
| 11 |
+
from .structs.CHandGesture import *
|
| 12 |
+
from .structs.CImageManipulation import *
|
| 13 |
+
from .structs.CKarolinska import *
|
| 14 |
+
from .structs.CROIStructs import *
|
| 15 |
+
from .structs.CScreenLocation import *
|
| 16 |
+
from .structs.CVisualSpeechStructs import *
|
| 17 |
+
from .structs.EveProcessingStatus import *
|
| 18 |
+
from .structs.EveAlgorithm import *
|
| 19 |
+
from .structs.EveAlgorithmStructs import *
|
| 20 |
+
from .structs.EveCallbackReturnData import *
|
| 21 |
+
from .structs.EveCamera import *
|
| 22 |
+
from .structs.EveCameraStructs import *
|
| 23 |
+
from .structs.EveConfigurationParameters import *
|
| 24 |
+
from .structs.EveControlInterface import *
|
| 25 |
+
from .structs.EveControlOption import *
|
| 26 |
+
from .structs.EveErrors import *
|
| 27 |
+
from .structs.EveFaceId import *
|
| 28 |
+
from .structs.EveFaceIdStructs import *
|
| 29 |
+
from .structs.EveFaceTracker import *
|
| 30 |
+
from .structs.EveFaceTrackerStructs import *
|
| 31 |
+
from .structs.EveFpga import *
|
| 32 |
+
from .structs.EveFpgaStructs import *
|
| 33 |
+
from .structs.EveHandGesture import *
|
| 34 |
+
from .structs.EveHandGestureStructs import *
|
| 35 |
+
from .structs.EveImage import *
|
| 36 |
+
from .structs.EveImageManipulation import *
|
| 37 |
+
from .structs.EveImageManipulationStructs import *
|
| 38 |
+
from .structs.EveImageStructs import *
|
| 39 |
+
from .structs.EveKarolinska import *
|
| 40 |
+
from .structs.EveKarolinskaStructs import *
|
| 41 |
+
from .structs.EveObjectDetection import *
|
| 42 |
+
from .structs.EveObjectDetectionStructs import *
|
| 43 |
+
from .structs.EveROI import *
|
| 44 |
+
from .structs.EveROIStructs import *
|
| 45 |
+
from .structs.EveScreenLocation import *
|
| 46 |
+
from .structs.EveScreenLocationStructs import *
|
| 47 |
+
from .structs.EveTiming import *
|
| 48 |
+
from .structs.EveTimingStructs import *
|
shared/eve_python/structs/CAlgorithms.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class EveAlgorithms(CtypesEnum):
|
| 6 |
+
EVE_ALGO_NONE = 0
|
| 7 |
+
EVE_ALGO_BACKGROUND_SEGMENTATION = 1
|
| 8 |
+
EVE_ALGO_OBJECT_DETECTION = 2
|
| 9 |
+
EVE_ALGO_PERSON_DETECTION = 3
|
| 10 |
+
EVE_ALGO_HEADPOSE_3D = 4
|
| 11 |
+
EVE_ALGO_HAND_GESTURE = 5
|
| 12 |
+
EVE_ALGO_DEPTH = 6
|
| 13 |
+
EVE_ALGO_EYEWEAR_DETECTION = 7
|
| 14 |
+
EVE_ALGO_KAROLINSKA = 8
|
| 15 |
+
EVE_ALGO_GAZE = 9
|
| 16 |
+
EVE_ALGO_GAZE_SINGLE_OUTPUT = 10
|
| 17 |
+
EVE_ALGO_FACE_ID = 11
|
| 18 |
+
EVE_ALGO_ROI_SELECTION = 12
|
| 19 |
+
EVE_ALGO_FACE_ENHANCEMENT = 13
|
| 20 |
+
EVE_ALGO_VISUAL_SPEECH_DETECTION = 14
|
| 21 |
+
EVE_ALGO_BACKGROUND_BLUR = 15
|
| 22 |
+
EVE_ALGO_BACKGROUND_REPLACEMENT = 16
|
| 23 |
+
EVE_ALGO_USER_HILIGHT = 17
|
| 24 |
+
EVE_ALGO_USER_FRAMING = 18
|
| 25 |
+
EVE_ALGO_MIRROR_IMAGE = 19
|
| 26 |
+
EVE_ALGO_FPGA_DRAWING = 20
|
| 27 |
+
|
shared/eve_python/structs/CBasicStructs.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
|
| 4 |
+
EVE_ENCODING_SIZE = 9
|
| 5 |
+
EVE_LOCATION_SIZE = 2
|
| 6 |
+
|
| 7 |
+
class EveVideoFormat(CtypesEnum):
|
| 8 |
+
EVE_NONE = 0
|
| 9 |
+
EVE_BGRA = 1
|
| 10 |
+
EVE_YUY2 = 2
|
| 11 |
+
EVE_NV12 = 3
|
| 12 |
+
EVE_MJPG = 4
|
| 13 |
+
EVE_BGR = 5
|
| 14 |
+
EVE_GRAYSCALE = 6
|
| 15 |
+
EVE_RGBA = 7
|
| 16 |
+
EVE_RGB = 8
|
| 17 |
+
EVE_ENCODING_SIZE = 9
|
| 18 |
+
|
| 19 |
+
class EveImageLocation(CtypesEnum):
|
| 20 |
+
EVE_CPU = 0
|
| 21 |
+
EVE_GPU = 1
|
| 22 |
+
EVE_LOCATION_SIZE = 2
|
| 23 |
+
|
| 24 |
+
class CPoint2i(ctypes.Structure):
|
| 25 |
+
_fields_ = [
|
| 26 |
+
("x", ctypes.c_int),
|
| 27 |
+
("y", ctypes.c_int),
|
| 28 |
+
]
|
| 29 |
+
|
| 30 |
+
class CPoint2f(ctypes.Structure):
|
| 31 |
+
_fields_ = [
|
| 32 |
+
("x", ctypes.c_float),
|
| 33 |
+
("y", ctypes.c_float),
|
| 34 |
+
]
|
| 35 |
+
|
| 36 |
+
class CPoint3i(ctypes.Structure):
|
| 37 |
+
_fields_ = [
|
| 38 |
+
("x", ctypes.c_int),
|
| 39 |
+
("y", ctypes.c_int),
|
| 40 |
+
("z", ctypes.c_int),
|
| 41 |
+
]
|
| 42 |
+
|
| 43 |
+
class CPoint3f(ctypes.Structure):
|
| 44 |
+
_fields_ = [
|
| 45 |
+
("x", ctypes.c_float),
|
| 46 |
+
("y", ctypes.c_float),
|
| 47 |
+
("z", ctypes.c_float),
|
| 48 |
+
]
|
| 49 |
+
|
| 50 |
+
class CAngles3f(ctypes.Structure):
|
| 51 |
+
_fields_ = [
|
| 52 |
+
("pitch", ctypes.c_float),
|
| 53 |
+
("yaw", ctypes.c_float),
|
| 54 |
+
("roll", ctypes.c_float),
|
| 55 |
+
]
|
| 56 |
+
|
| 57 |
+
class CRect2i(ctypes.Structure):
|
| 58 |
+
_fields_ = [
|
| 59 |
+
("left", ctypes.c_int),
|
| 60 |
+
("top", ctypes.c_int),
|
| 61 |
+
("right", ctypes.c_int),
|
| 62 |
+
("bottom", ctypes.c_int),
|
| 63 |
+
]
|
| 64 |
+
|
| 65 |
+
class CRect2iWH(ctypes.Structure):
|
| 66 |
+
_fields_ = [
|
| 67 |
+
("x", ctypes.c_int),
|
| 68 |
+
("y", ctypes.c_int),
|
| 69 |
+
("width", ctypes.c_int),
|
| 70 |
+
("height", ctypes.c_int),
|
| 71 |
+
]
|
| 72 |
+
|
| 73 |
+
class CRect2fWH(ctypes.Structure):
|
| 74 |
+
_fields_ = [
|
| 75 |
+
("x", ctypes.c_float),
|
| 76 |
+
("y", ctypes.c_float),
|
| 77 |
+
("width", ctypes.c_float),
|
| 78 |
+
("height", ctypes.c_float),
|
| 79 |
+
]
|
| 80 |
+
|
| 81 |
+
class CResolution(ctypes.Structure):
|
| 82 |
+
_fields_ = [
|
| 83 |
+
("width", ctypes.c_uint),
|
| 84 |
+
("height", ctypes.c_uint),
|
| 85 |
+
]
|
| 86 |
+
|
shared/eve_python/structs/CCameraStructs.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .CBasicStructs import *
|
| 4 |
+
|
| 5 |
+
CAMERA_PID_VID_SIZE = 8
|
| 6 |
+
CAMERA_NAME_SIZE = 64
|
| 7 |
+
|
| 8 |
+
class EveCompare(CtypesEnum):
|
| 9 |
+
EVE_EQUAL = 0
|
| 10 |
+
EVE_AT_MOST = 1
|
| 11 |
+
EVE_AT_LEAST = 2
|
| 12 |
+
|
| 13 |
+
class CCameraFormat(ctypes.Structure):
|
| 14 |
+
_fields_ = [
|
| 15 |
+
("resolution", CResolution),
|
| 16 |
+
("format", ctypes.c_int),
|
| 17 |
+
("fps", ctypes.c_float),
|
| 18 |
+
("compareResolution", ctypes.c_int),
|
| 19 |
+
("compareFps", ctypes.c_int),
|
| 20 |
+
]
|
| 21 |
+
|
| 22 |
+
class CCamera(ctypes.Structure):
|
| 23 |
+
_fields_ = [
|
| 24 |
+
("id", ctypes.c_int),
|
| 25 |
+
("pid", ctypes.c_byte * CAMERA_PID_VID_SIZE),
|
| 26 |
+
("vid", ctypes.c_byte * CAMERA_PID_VID_SIZE),
|
| 27 |
+
("name", ctypes.c_byte * CAMERA_NAME_SIZE),
|
| 28 |
+
("isHardwareCamera", ctypes.c_uint),
|
| 29 |
+
("isFpgaCamera", ctypes.c_uint),
|
| 30 |
+
("isIrCamera", ctypes.c_uint),
|
| 31 |
+
]
|
| 32 |
+
|
| 33 |
+
class CCameraParameters(ctypes.Structure):
|
| 34 |
+
_fields_ = [
|
| 35 |
+
("width", ctypes.c_int),
|
| 36 |
+
("height", ctypes.c_int),
|
| 37 |
+
("focalLength", ctypes.c_double),
|
| 38 |
+
("pixelSizeX", ctypes.c_double),
|
| 39 |
+
("pixelSizeY", ctypes.c_double),
|
| 40 |
+
("principalPointX", ctypes.c_double),
|
| 41 |
+
("principalPointY", ctypes.c_double),
|
| 42 |
+
("depthMin", ctypes.c_double),
|
| 43 |
+
("depthMax", ctypes.c_double),
|
| 44 |
+
("screenLocationXinMM", ctypes.c_float),
|
| 45 |
+
("screenLocationYinMM", ctypes.c_float),
|
| 46 |
+
("isInfrared", ctypes.c_uint),
|
| 47 |
+
]
|
| 48 |
+
|
shared/eve_python/structs/CDetectionStructs.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .EveProcessingStatus import *
|
| 4 |
+
|
| 5 |
+
EVE_DETECTIONS_SIZE = 256
|
| 6 |
+
EVE_CLASS_ID_NAME_SIZE = 32
|
| 7 |
+
|
| 8 |
+
class EveActionStatus(CtypesEnum):
|
| 9 |
+
EVE_IDLE = 0
|
| 10 |
+
EVE_INTERPOLATED = 1
|
| 11 |
+
EVE_COMPUTED = 2
|
| 12 |
+
EVE_NO_OUTPUT = 3
|
| 13 |
+
|
| 14 |
+
class FrontalStatus(CtypesEnum):
|
| 15 |
+
UNKNOWN = 0
|
| 16 |
+
FRONTAL = 1
|
| 17 |
+
NON_FRONTAL = 2
|
| 18 |
+
|
| 19 |
+
class CSingleDetectionData(ctypes.Structure):
|
| 20 |
+
_fields_ = [
|
| 21 |
+
("topLeftX", ctypes.c_int),
|
| 22 |
+
("topLeftY", ctypes.c_int),
|
| 23 |
+
("bottomRightX", ctypes.c_int),
|
| 24 |
+
("bottomRightY", ctypes.c_int),
|
| 25 |
+
("classScore", ctypes.c_float),
|
| 26 |
+
("classId", ctypes.c_int),
|
| 27 |
+
("classIdName", ctypes.c_byte * EVE_CLASS_ID_NAME_SIZE),
|
| 28 |
+
("frontalStatus", ctypes.c_int),
|
| 29 |
+
]
|
| 30 |
+
|
| 31 |
+
class CDetectionData(ctypes.Structure):
|
| 32 |
+
_fields_ = [
|
| 33 |
+
("processingStatus", ctypes.c_int),
|
| 34 |
+
("actionStatus", ctypes.c_int),
|
| 35 |
+
("numberOfDetections", ctypes.c_int),
|
| 36 |
+
("detections", CSingleDetectionData * EVE_DETECTIONS_SIZE),
|
| 37 |
+
]
|
| 38 |
+
|
shared/eve_python/structs/CFaceData.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .CBasicStructs import *
|
| 4 |
+
from .CFaceIdStructs import *
|
| 5 |
+
|
| 6 |
+
EVE_MAX_FACES = 10
|
| 7 |
+
EVE_EYE_LANDMARK_SIZE = 14
|
| 8 |
+
EVE_PUPIL_LANDMARK_SIZE = 2
|
| 9 |
+
|
| 10 |
+
class EveEyeLandmark(CtypesEnum):
|
| 11 |
+
EVE_EYE_RIGHT_CORNER_TEMPORAL = 0
|
| 12 |
+
EVE_EYE_RIGHT_EYELID_UPPER_1 = 1
|
| 13 |
+
EVE_EYE_RIGHT_EYELID_UPPER_2 = 2
|
| 14 |
+
EVE_EYE_RIGHT_CORNER_NASAL = 3
|
| 15 |
+
EVE_EYE_RIGHT_EYELID_LOWER_1 = 4
|
| 16 |
+
EVE_EYE_RIGHT_EYELID_LOWER_2 = 5
|
| 17 |
+
EVE_EYE_LEFT_CORNER_NASAL = 6
|
| 18 |
+
EVE_EYE_LEFT_EYELID_UPPER_2 = 7
|
| 19 |
+
EVE_EYE_LEFT_EYELID_UPPER_1 = 8
|
| 20 |
+
EVE_EYE_LEFT_CORNER_TEMPORAL = 9
|
| 21 |
+
EVE_EYE_LEFT_EYELID_LOWER_2 = 10
|
| 22 |
+
EVE_EYE_LEFT_EYELID_LOWER_1 = 11
|
| 23 |
+
EVE_EYE_RIGHT_PUPIL_CENTER = 12
|
| 24 |
+
EVE_EYE_LEFT_PUPIL_CENTER = 13
|
| 25 |
+
EVE_EYE_LANDMARK_SIZE = 14
|
| 26 |
+
|
| 27 |
+
class EvePupilLandmark(CtypesEnum):
|
| 28 |
+
EVE_RIGHT_PUPIL_CENTER = 0
|
| 29 |
+
EVE_LEFT_PUPIL_CENTER = 1
|
| 30 |
+
EVE_PUPIL_LANDMARK_SIZE = 2
|
| 31 |
+
|
| 32 |
+
class CEyeLandmarks(ctypes.Structure):
|
| 33 |
+
_fields_ = [
|
| 34 |
+
("landmarks", CPoint3f * EVE_EYE_LANDMARK_SIZE),
|
| 35 |
+
]
|
| 36 |
+
|
| 37 |
+
class CPupilLandmarks(ctypes.Structure):
|
| 38 |
+
_fields_ = [
|
| 39 |
+
("landmarks", CPoint3f * EVE_PUPIL_LANDMARK_SIZE),
|
| 40 |
+
]
|
| 41 |
+
|
| 42 |
+
class CFaceData(ctypes.Structure):
|
| 43 |
+
_fields_ = [
|
| 44 |
+
("angles", CAngles3f),
|
| 45 |
+
("faceId", CFaceIdentityData),
|
| 46 |
+
("depth", ctypes.c_float),
|
| 47 |
+
("trackNumber", ctypes.c_int),
|
| 48 |
+
]
|
| 49 |
+
|
| 50 |
+
class CAllFaces(ctypes.Structure):
|
| 51 |
+
_fields_ = [
|
| 52 |
+
("detectedFacesCount", ctypes.c_uint),
|
| 53 |
+
("faces", CFaceData * EVE_MAX_FACES),
|
| 54 |
+
]
|
| 55 |
+
|
shared/eve_python/structs/CFaceIdStructs.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .EveProcessingStatus import *
|
| 4 |
+
|
| 5 |
+
EVE_FACE_ID_MAX_MISSING_CALIBRATION_POSES = 5
|
| 6 |
+
|
| 7 |
+
class EveFaceIdActionStatus(CtypesEnum):
|
| 8 |
+
EVE_FACE_ID_ACTION_IDLE = 0
|
| 9 |
+
EVE_FACE_ID_ACTION_CALIBRATING = 1
|
| 10 |
+
EVE_FACE_ID_ACTION_CALIBRATED = 2
|
| 11 |
+
EVE_FACE_ID_ACTION_IDENTIFIED = 3
|
| 12 |
+
|
| 13 |
+
class EveFaceIdCalibrationStatus(CtypesEnum):
|
| 14 |
+
EVE_FACE_ID_CALIB_NONE = 0
|
| 15 |
+
EVE_FACE_ID_CALIB_RUNNING = 1
|
| 16 |
+
EVE_FACE_ID_CALIB_SUCCESS = 2
|
| 17 |
+
EVE_FACE_ID_CALIB_FAILURE_LACK_POSE_MOTION = 3
|
| 18 |
+
EVE_FACE_ID_CALIB_FAILURE_OTHER = 4
|
| 19 |
+
|
| 20 |
+
class EveFaceIdIdentificationStatus(CtypesEnum):
|
| 21 |
+
EVE_FACE_ID_NONE = 0
|
| 22 |
+
EVE_FACE_ID_SUCCESS = 1
|
| 23 |
+
EVE_FACE_ID_FAILURE_VERIFICATION = 2
|
| 24 |
+
EVE_FACE_ID_FAILURE_ANGLE_PITCH = 3
|
| 25 |
+
EVE_FACE_ID_FAILURE_ANGLE_YAW = 4
|
| 26 |
+
EVE_FACE_ID_FAILURE_ANGLE_ROLL = 5
|
| 27 |
+
EVE_FACE_ID_FAILURE_ANGLE_BOTH = 6
|
| 28 |
+
EVE_FACE_ID_FAILURE_NO_GALLERY = 7
|
| 29 |
+
EVE_FACE_ID_FAILURE_EXP_SMILE = 8
|
| 30 |
+
EVE_FACE_ID_FAILURE_EXP_SQUINT = 9
|
| 31 |
+
EVE_FACE_ID_FAILURE_EXP_EYES_CLOSED = 10
|
| 32 |
+
EVE_FACE_ID_FAILURE_DEPTH = 11
|
| 33 |
+
EVE_FACE_ID_FAILURE_OTHER = 12
|
| 34 |
+
|
| 35 |
+
class EveFaceIdPose(CtypesEnum):
|
| 36 |
+
EVE_FACE_ID_POSE_FRONTAL = 0
|
| 37 |
+
EVE_FACE_ID_POSE_LEFT = 1
|
| 38 |
+
EVE_FACE_ID_POSE_RIGHT = 2
|
| 39 |
+
EVE_FACE_ID_POSE_UP = 3
|
| 40 |
+
EVE_FACE_ID_POSE_DOWN = 4
|
| 41 |
+
|
| 42 |
+
class EveFaceIdCommand(CtypesEnum):
|
| 43 |
+
EVE_FACE_ID_COMMAND_NONE = 0
|
| 44 |
+
EVE_FACE_ID_COMMAND_ADD_NEW_USER = 1
|
| 45 |
+
EVE_FACE_ID_COMMAND_CALIBRATE_CURRENT_USER = 2
|
| 46 |
+
EVE_FACE_ID_COMMAND_FORCE_ID = 3
|
| 47 |
+
EVE_FACE_ID_COMMAND_REMOVE_CURRENT_USER = 4
|
| 48 |
+
EVE_FACE_ID_COMMAND_REMOVE_ALL_USERS = 5
|
| 49 |
+
EVE_FACE_ID_COMMAND_RELOAD_GALLERY = 6
|
| 50 |
+
|
| 51 |
+
class CFaceIdentity(ctypes.Structure):
|
| 52 |
+
_fields_ = [
|
| 53 |
+
("id", ctypes.c_longlong),
|
| 54 |
+
("confidence", ctypes.c_float),
|
| 55 |
+
("similarity", ctypes.c_float),
|
| 56 |
+
]
|
| 57 |
+
|
| 58 |
+
class CFaceIdentityData(ctypes.Structure):
|
| 59 |
+
_fields_ = [
|
| 60 |
+
("processingStatus", ctypes.c_int),
|
| 61 |
+
("actionStatus", ctypes.c_int),
|
| 62 |
+
("calibrationStatus", ctypes.c_int),
|
| 63 |
+
("identificationStatus", ctypes.c_int),
|
| 64 |
+
("faceIdentity", CFaceIdentity),
|
| 65 |
+
("missingCalibrationPosesCount", ctypes.c_uint),
|
| 66 |
+
("missingCalibrationPoses", ctypes.c_int * EVE_FACE_ID_MAX_MISSING_CALIBRATION_POSES),
|
| 67 |
+
]
|
| 68 |
+
|
shared/eve_python/structs/CFpgaData.py
ADDED
|
@@ -0,0 +1,350 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .CBasicStructs import *
|
| 4 |
+
|
| 5 |
+
EVE_FPGA_MAX_USERS = 10
|
| 6 |
+
EVE_FPGA_MAX_PERSONS = 5
|
| 7 |
+
EVE_FPGA_MAX_HAND_LANDMARKS = 11
|
| 8 |
+
EVE_FPGA_HAND_LANDMARKS = 10
|
| 9 |
+
EVE_FPGA_MAX_OBJECT_DETECTION = 50
|
| 10 |
+
PT_SIZE = 6
|
| 11 |
+
MT_SIZE = 4
|
| 12 |
+
RT_SIZE = 4
|
| 13 |
+
|
| 14 |
+
class EveFpgaConnectionType(CtypesEnum):
|
| 15 |
+
EVE_FPGA_AUTO_SELECT = 0
|
| 16 |
+
EVE_FPGA_UART = 1
|
| 17 |
+
EVE_FPGA_I2C = 2
|
| 18 |
+
EVE_FPGA_HUB = 3
|
| 19 |
+
EVE_FPGA_MANUAL = 4
|
| 20 |
+
|
| 21 |
+
class EveFpgaConnectionRequest(CtypesEnum):
|
| 22 |
+
EVE_FPGA_STOP = 0
|
| 23 |
+
EVE_FPGA_CONTINUE = 1
|
| 24 |
+
|
| 25 |
+
class pipeline_config_type_t(CtypesEnum):
|
| 26 |
+
PT_FD = 0
|
| 27 |
+
PT_LM_FV = 1
|
| 28 |
+
PT_FID = 2
|
| 29 |
+
PT_PD = 3
|
| 30 |
+
PT_HD = 4
|
| 31 |
+
PT_HLMV = 5
|
| 32 |
+
PT_SIZE = 6
|
| 33 |
+
|
| 34 |
+
class setting_type_t(CtypesEnum):
|
| 35 |
+
CS_ENABLED = 0x00
|
| 36 |
+
CS_IPS = 0x01
|
| 37 |
+
CS_RESERVED_2_7 = 0x02
|
| 38 |
+
CS_COMMAND = 0x08
|
| 39 |
+
CS_CUSTOM = 0x10
|
| 40 |
+
CS_MAX = 0x11
|
| 41 |
+
|
| 42 |
+
class message_type_t(CtypesEnum):
|
| 43 |
+
MT_NONE = 0
|
| 44 |
+
MT_SET = 1
|
| 45 |
+
MT_GET = 2
|
| 46 |
+
MT_GET_BATCH = 3
|
| 47 |
+
MT_SIZE = 4
|
| 48 |
+
|
| 49 |
+
class response_type_t(CtypesEnum):
|
| 50 |
+
RT_NONE = 0
|
| 51 |
+
RT_DATA = 1
|
| 52 |
+
RT_GET = 2
|
| 53 |
+
RT_ACK = 3
|
| 54 |
+
RT_SIZE = 4
|
| 55 |
+
|
| 56 |
+
class EveFpgaSerialStatus(CtypesEnum):
|
| 57 |
+
EVE_FPGA_SUCCESS = 0
|
| 58 |
+
EVE_FPGA_NO_DATA = 1
|
| 59 |
+
EVE_FPGA_READ_START_MARKER_FAILED = 2
|
| 60 |
+
EVE_FPGA_FIND_START_MARKER_FAILED = 3
|
| 61 |
+
EVE_FPGA_READ_DATA_LENGTH_FAILED = 4
|
| 62 |
+
EVE_FPGA_READ_DATA_FAILED = 5
|
| 63 |
+
EVE_FPGA_CORRUPTED_DATA = 6
|
| 64 |
+
EVE_FPGA_UNEXPECTED_RESPONSE_TYPE = 7
|
| 65 |
+
EVE_FPGA_API_ERROR_START = 8
|
| 66 |
+
EVE_FPGA_NO_CALLBACK = 9
|
| 67 |
+
EVE_FPGA_DATA_ACCESSED_OUTSIDE_CALLBACK = 10
|
| 68 |
+
EVE_FPGA_INIT_FAILED = 11
|
| 69 |
+
EVE_FPGA_NOT_INIT = 12
|
| 70 |
+
EVE_FPGA_NOT_IMPLEMENTED = 13
|
| 71 |
+
EVE_FPGA_API_ERROR_END = 14
|
| 72 |
+
|
| 73 |
+
class EveWakeupDetectionType(CtypesEnum):
|
| 74 |
+
EVE_USER_DETECTION = 0
|
| 75 |
+
EVE_STRANGER_DETECTION = 1
|
| 76 |
+
|
| 77 |
+
class EveFpgaPipelineType(CtypesEnum):
|
| 78 |
+
EVE_UNKNOWN_PIPELINE = 0
|
| 79 |
+
EVE_HEAD_POSE_PIPELINE = 1
|
| 80 |
+
EVE_FACE_ID_PIPELINE = 2
|
| 81 |
+
EVE_HAND_GESTURE_PIPELINE = 3
|
| 82 |
+
EVE_COMPACT_HEAD_POSE_PIPELINE = 4
|
| 83 |
+
EVE_HMI_PIPELINE = 5
|
| 84 |
+
EVE_STANDALONE_HAND_GESTURE_PIPELINE = 6
|
| 85 |
+
|
| 86 |
+
class EvePersonBodyPose(CtypesEnum):
|
| 87 |
+
EVE_FRONT = 0
|
| 88 |
+
EVE_NOT_FRONT = 1
|
| 89 |
+
|
| 90 |
+
class EveDistanceFromCamera(CtypesEnum):
|
| 91 |
+
EVE_DISTANCE_CLOSE = 0
|
| 92 |
+
EVE_DISTANCE_MID = 1
|
| 93 |
+
EVE_DISTANCE_FAR = 2
|
| 94 |
+
|
| 95 |
+
class EvePersonRegistrationStatus(CtypesEnum):
|
| 96 |
+
EVE_REGISTERED = 0
|
| 97 |
+
EVE_UNREGISTERED = 1
|
| 98 |
+
EVE_UNKNOWN = 2
|
| 99 |
+
EVE_REQUIREMENTS_UNMET = 3
|
| 100 |
+
EVE_DISABLED = 4
|
| 101 |
+
EVE_NO_GALLERY = 5
|
| 102 |
+
|
| 103 |
+
class EveFpgaHandGesture(CtypesEnum):
|
| 104 |
+
EVE_FPGA_HAND_GESTURE_NO_GESTURE = 0
|
| 105 |
+
EVE_FPGA_HAND_GESTURE_CLOSE = 1
|
| 106 |
+
EVE_FPGA_HAND_GESTURE_OPEN = 2
|
| 107 |
+
EVE_FPGA_HAND_GESTURE_OPEN_LEFT = 3
|
| 108 |
+
EVE_FPGA_HAND_GESTURE_OPEN_RIGHT = 4
|
| 109 |
+
EVE_FPGA_HAND_GESTURE_INDEX_UP = 5
|
| 110 |
+
EVE_FPGA_HAND_GESTURE_INDEX_DOWN = 6
|
| 111 |
+
EVE_FPGA_HAND_GESTURE_TIP_LEFT = 7
|
| 112 |
+
EVE_FPGA_HAND_GESTURE_TIP_RIGHT = 8
|
| 113 |
+
EVE_FPGA_HAND_GESTURE_UNKNOWN = 9
|
| 114 |
+
|
| 115 |
+
class EveFpgaObjectClass(CtypesEnum):
|
| 116 |
+
EVE_FPGA_OBJECT_CLASS_PERSON = 0
|
| 117 |
+
EVE_FPGA_OBJECT_CLASS_BICYCLE = 1
|
| 118 |
+
EVE_FPGA_OBJECT_CLASS_CAR = 2
|
| 119 |
+
EVE_FPGA_OBJECT_CLASS_MOTORCYCLE = 3
|
| 120 |
+
EVE_FPGA_OBJECT_CLASS_BUS = 4
|
| 121 |
+
EVE_FPGA_OBJECT_CLASS_TRUCK = 5
|
| 122 |
+
EVE_FPGA_OBJECT_CLASS_TRAFFIC_LIGHT = 6
|
| 123 |
+
EVE_FPGA_OBJECT_CLASS_STOP_SIGN = 7
|
| 124 |
+
|
| 125 |
+
class pipeline_setting_t(ctypes.Structure):
|
| 126 |
+
_fields_ = [
|
| 127 |
+
("settingType", ctypes.c_int),
|
| 128 |
+
("value", ctypes.c_uint32),
|
| 129 |
+
]
|
| 130 |
+
|
| 131 |
+
class pipeline_config_t(ctypes.Structure):
|
| 132 |
+
_fields_ = [
|
| 133 |
+
("type", ctypes.c_int),
|
| 134 |
+
("setting", pipeline_setting_t),
|
| 135 |
+
]
|
| 136 |
+
|
| 137 |
+
class CFpgaIdealPersonData(ctypes.Structure):
|
| 138 |
+
_fields_ = [
|
| 139 |
+
("valid", ctypes.c_uint),
|
| 140 |
+
("index", ctypes.c_uint),
|
| 141 |
+
("status", ctypes.c_int),
|
| 142 |
+
("faceAngles", CAngles3f),
|
| 143 |
+
("faceLandmarksConfidence", ctypes.c_float),
|
| 144 |
+
("isFaceLandmarksConfidenceValid", ctypes.c_bool),
|
| 145 |
+
]
|
| 146 |
+
|
| 147 |
+
class CFpgaImageDimensions(ctypes.Structure):
|
| 148 |
+
_fields_ = [
|
| 149 |
+
("width", ctypes.c_int),
|
| 150 |
+
("height", ctypes.c_int),
|
| 151 |
+
("cropArea", CRect2i),
|
| 152 |
+
("reserved1", ctypes.c_int),
|
| 153 |
+
("reserved2", ctypes.c_int),
|
| 154 |
+
]
|
| 155 |
+
|
| 156 |
+
class CFpgaDataContent(ctypes.Structure):
|
| 157 |
+
_fields_ = [
|
| 158 |
+
("numberOfUsers", ctypes.c_int16),
|
| 159 |
+
("idealUserIndex", ctypes.c_int16),
|
| 160 |
+
("numberOfDetectedFaces", ctypes.c_int16),
|
| 161 |
+
("numberOfFacesConfidence", ctypes.c_float),
|
| 162 |
+
("numberOfDetectedPersons", ctypes.c_int16),
|
| 163 |
+
("numberOfPersonsConfidence", ctypes.c_float),
|
| 164 |
+
("isIdealUserDataAvailable", ctypes.c_bool),
|
| 165 |
+
("idealUserDetected", ctypes.c_bool),
|
| 166 |
+
("isIdealUserIndexValid", ctypes.c_bool),
|
| 167 |
+
("isNumberOfDetectedFacesAvailable", ctypes.c_bool),
|
| 168 |
+
("isNumberOfFacesConfidenceAvailable", ctypes.c_bool),
|
| 169 |
+
("isNumberOfDetectedPersonsAvailable", ctypes.c_bool),
|
| 170 |
+
("isNumberOfPersonsConfidenceAvailable", ctypes.c_bool),
|
| 171 |
+
("isUsersDataAvilable", ctypes.c_bool),
|
| 172 |
+
("isFaceIdDataAvailable", ctypes.c_bool),
|
| 173 |
+
("isObjectDetectionAvailable", ctypes.c_bool),
|
| 174 |
+
("isCameraStreaming", ctypes.c_bool),
|
| 175 |
+
("isHandGestureDataAvailable", ctypes.c_bool),
|
| 176 |
+
("isDefectDetectionAvailable", ctypes.c_bool),
|
| 177 |
+
]
|
| 178 |
+
|
| 179 |
+
class CFpgaHandData(ctypes.Structure):
|
| 180 |
+
_fields_ = [
|
| 181 |
+
("validationScore", ctypes.c_float),
|
| 182 |
+
("handBox", CRect2i),
|
| 183 |
+
("landmarks", CPoint3f * EVE_FPGA_MAX_HAND_LANDMARKS),
|
| 184 |
+
]
|
| 185 |
+
|
| 186 |
+
class CFpgaHandsData(ctypes.Structure):
|
| 187 |
+
_fields_ = [
|
| 188 |
+
("numberOfHandLandmarkPoints", ctypes.c_int16),
|
| 189 |
+
("handData", CFpgaHandData),
|
| 190 |
+
("gesture", ctypes.c_int),
|
| 191 |
+
("isHandBoxAvailable", ctypes.c_bool),
|
| 192 |
+
("isHandLandmark3D", ctypes.c_bool),
|
| 193 |
+
]
|
| 194 |
+
|
| 195 |
+
class CFpgaDefectData(ctypes.Structure):
|
| 196 |
+
_fields_ = [
|
| 197 |
+
("defectBox", CRect2i),
|
| 198 |
+
("width", ctypes.c_int),
|
| 199 |
+
("height", ctypes.c_int),
|
| 200 |
+
("similarity", ctypes.c_float),
|
| 201 |
+
("isDefective", ctypes.c_bool),
|
| 202 |
+
]
|
| 203 |
+
|
| 204 |
+
class CFpgaFaceData(ctypes.Structure):
|
| 205 |
+
_fields_ = [
|
| 206 |
+
("faceConfidence", ctypes.c_float),
|
| 207 |
+
("faceDistance", ctypes.c_int16),
|
| 208 |
+
("faceCenter", CPoint3i),
|
| 209 |
+
("anglesICS", CAngles3f),
|
| 210 |
+
("anglesCCS", CAngles3f),
|
| 211 |
+
("faceLandmarksConfidence", ctypes.c_float),
|
| 212 |
+
("faceBox", CRect2i),
|
| 213 |
+
("faceIDStatus", ctypes.c_int),
|
| 214 |
+
("faceID", ctypes.c_int16),
|
| 215 |
+
("isFaceConfidenceAvailable", ctypes.c_bool),
|
| 216 |
+
("isFaceDistanceAvailable", ctypes.c_bool),
|
| 217 |
+
("isFacePositionAvailable", ctypes.c_bool),
|
| 218 |
+
("isEulerAnglesIcsAvailable", ctypes.c_bool),
|
| 219 |
+
("isEulerAnglesCcsAvailable", ctypes.c_bool),
|
| 220 |
+
("isFaceLandmark3D", ctypes.c_bool),
|
| 221 |
+
("isFaceLandmarksConfidenceAvailable", ctypes.c_bool),
|
| 222 |
+
("isFaceGeometricBoxAvailable", ctypes.c_bool),
|
| 223 |
+
("isStatusAvailable", ctypes.c_bool),
|
| 224 |
+
]
|
| 225 |
+
|
| 226 |
+
class CFpgaPersonData(ctypes.Structure):
|
| 227 |
+
_fields_ = [
|
| 228 |
+
("personConfidence", ctypes.c_float),
|
| 229 |
+
("personDistance", ctypes.c_int),
|
| 230 |
+
("personPosture", ctypes.c_int),
|
| 231 |
+
("personFrontalPostureConfidence", ctypes.c_float),
|
| 232 |
+
("personNotFrontalPostureConfidence", ctypes.c_float),
|
| 233 |
+
("position", CPoint3i),
|
| 234 |
+
("personBox", CRect2i),
|
| 235 |
+
("isPersonDataAvailable", ctypes.c_bool),
|
| 236 |
+
]
|
| 237 |
+
|
| 238 |
+
class CFpgaObjectDetection(ctypes.Structure):
|
| 239 |
+
_fields_ = [
|
| 240 |
+
("objectClass", ctypes.c_int),
|
| 241 |
+
("objectConfidence", ctypes.c_float),
|
| 242 |
+
("objectBox", CRect2i),
|
| 243 |
+
]
|
| 244 |
+
|
| 245 |
+
class CFpgaObjectData(ctypes.Structure):
|
| 246 |
+
_fields_ = [
|
| 247 |
+
("numberOfObjects", ctypes.c_int16),
|
| 248 |
+
("objects", CFpgaObjectDetection * EVE_FPGA_MAX_OBJECT_DETECTION),
|
| 249 |
+
]
|
| 250 |
+
|
| 251 |
+
class CFpgaUserData(ctypes.Structure):
|
| 252 |
+
_fields_ = [
|
| 253 |
+
("id", ctypes.c_int16),
|
| 254 |
+
("status", ctypes.c_int),
|
| 255 |
+
("scale", ctypes.c_float),
|
| 256 |
+
("faceData", CFpgaFaceData),
|
| 257 |
+
("personData", CFpgaPersonData),
|
| 258 |
+
("isIdealUser", ctypes.c_bool),
|
| 259 |
+
("isIdValid", ctypes.c_bool),
|
| 260 |
+
("isStatusAvailable", ctypes.c_bool),
|
| 261 |
+
("isScaleAvailable", ctypes.c_bool),
|
| 262 |
+
]
|
| 263 |
+
|
| 264 |
+
class CFpgaFaceIdData(ctypes.Structure):
|
| 265 |
+
_fields_ = [
|
| 266 |
+
("command", ctypes.c_int16),
|
| 267 |
+
("userId", ctypes.c_int16),
|
| 268 |
+
("freeEntry", ctypes.c_int16),
|
| 269 |
+
("statusCode", ctypes.c_int16),
|
| 270 |
+
("faceId", ctypes.c_int16),
|
| 271 |
+
("lastRegisteredFaceID", ctypes.c_int16),
|
| 272 |
+
("usersInGallery", ctypes.c_int16),
|
| 273 |
+
("gallerySize", ctypes.c_int16),
|
| 274 |
+
]
|
| 275 |
+
|
| 276 |
+
class CFpgaPipelineData(ctypes.Structure):
|
| 277 |
+
_fields_ = [
|
| 278 |
+
("pipelineType", ctypes.c_int),
|
| 279 |
+
("imageDimensions", CFpgaImageDimensions),
|
| 280 |
+
("dataContent", CFpgaDataContent),
|
| 281 |
+
("userData", CFpgaUserData * EVE_FPGA_MAX_USERS),
|
| 282 |
+
("objectData", CFpgaObjectData),
|
| 283 |
+
("faceId", CFpgaFaceIdData),
|
| 284 |
+
("handsData", CFpgaHandsData),
|
| 285 |
+
("defectData", CFpgaDefectData),
|
| 286 |
+
]
|
| 287 |
+
|
| 288 |
+
class CFpgaMessage(ctypes.Structure):
|
| 289 |
+
_fields_ = [
|
| 290 |
+
("responseType", ctypes.c_int),
|
| 291 |
+
("responseVersion", ctypes.c_uint8),
|
| 292 |
+
("serialStatus", ctypes.c_int),
|
| 293 |
+
("serialReadTimeNano", ctypes.c_longlong),
|
| 294 |
+
]
|
| 295 |
+
|
| 296 |
+
class CFpgaData(ctypes.Structure):
|
| 297 |
+
_fields_ = [
|
| 298 |
+
("message", CFpgaMessage),
|
| 299 |
+
("pipelineData", CFpgaPipelineData),
|
| 300 |
+
]
|
| 301 |
+
|
| 302 |
+
class CFpgaGetSetting(ctypes.Structure):
|
| 303 |
+
_fields_ = [
|
| 304 |
+
("message", CFpgaMessage),
|
| 305 |
+
("type", ctypes.c_int),
|
| 306 |
+
("setting", ctypes.c_int),
|
| 307 |
+
("value", ctypes.c_uint32),
|
| 308 |
+
]
|
| 309 |
+
|
| 310 |
+
class CFpgaParameters(ctypes.Structure):
|
| 311 |
+
_fields_ = [
|
| 312 |
+
("comport", ctypes.c_uint),
|
| 313 |
+
("socWakeupDelay", ctypes.c_uint),
|
| 314 |
+
("wakeupType", ctypes.c_int),
|
| 315 |
+
("forceCameraOn", ctypes.c_ubyte),
|
| 316 |
+
("registerNewFace", ctypes.c_ubyte),
|
| 317 |
+
("clearCurrentFace", ctypes.c_ubyte),
|
| 318 |
+
("enableFaceId", ctypes.c_ubyte),
|
| 319 |
+
("allPipelinesSupported", ctypes.c_ubyte),
|
| 320 |
+
("pipelineVersion", ctypes.c_uint),
|
| 321 |
+
("connection", ctypes.c_int),
|
| 322 |
+
("i2cAdapterNumber", ctypes.c_uint),
|
| 323 |
+
("i2cDeviceNumber", ctypes.c_uint),
|
| 324 |
+
("i2cIRQPin", ctypes.c_uint),
|
| 325 |
+
]
|
| 326 |
+
|
| 327 |
+
class CFpgaCallbackControl(ctypes.Structure):
|
| 328 |
+
_fields_ = [
|
| 329 |
+
("request", ctypes.c_int),
|
| 330 |
+
]
|
| 331 |
+
|
| 332 |
+
class EveFpgaMetadata(ctypes.Structure):
|
| 333 |
+
_fields_ = [
|
| 334 |
+
("data", ctypes.POINTER(CFpgaData)),
|
| 335 |
+
("errorCode", ctypes.c_int),
|
| 336 |
+
]
|
| 337 |
+
|
| 338 |
+
class EveFpgaManualData(ctypes.Structure):
|
| 339 |
+
_fields_ = [
|
| 340 |
+
("data", ctypes.POINTER(ctypes.c_ubyte)),
|
| 341 |
+
("size", ctypes.c_int),
|
| 342 |
+
]
|
| 343 |
+
|
| 344 |
+
class EveFpgaJsonMetadata(ctypes.Structure):
|
| 345 |
+
_fields_ = [
|
| 346 |
+
("textStart", ctypes.POINTER(ctypes.c_byte)),
|
| 347 |
+
("textSize", ctypes.c_uint),
|
| 348 |
+
("errorCode", ctypes.c_int),
|
| 349 |
+
]
|
| 350 |
+
|
shared/eve_python/structs/CHandGesture.py
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .CBasicStructs import *
|
| 4 |
+
from .EveProcessingStatus import *
|
| 5 |
+
|
| 6 |
+
EVE_MAX_HAND_DETECTIONS = 8
|
| 7 |
+
EVE_MAX_DYNAMIC_GESTURE_SEQUENCE = 8
|
| 8 |
+
EVE_MAX_CUSTOM_STATIC_GESTURES = 20
|
| 9 |
+
EVE_MAX_STATIC_GESTURES = 40
|
| 10 |
+
EVE_HAND_LANDMARKS_SIZE = 2
|
| 11 |
+
EVE_HAND_LANDMARK_SIZE = 11
|
| 12 |
+
EVE_STATIC_GESTURE_SIZE = 22
|
| 13 |
+
EVE_DYNAMIC_GESTURE_SIZE = 12
|
| 14 |
+
|
| 15 |
+
class EveRunHandLandmarks(CtypesEnum):
|
| 16 |
+
EVE_HAND_LANDMARKS_ALL_HANDS = 0
|
| 17 |
+
EVE_HAND_LANDMARKS_MAIN_HAND_ONLY = 1
|
| 18 |
+
EVE_HAND_LANDMARKS_SIZE = 2
|
| 19 |
+
|
| 20 |
+
class EveHandLandmark(CtypesEnum):
|
| 21 |
+
EVE_WRIST = 0
|
| 22 |
+
EVE_THUMB_IP = 1
|
| 23 |
+
EVE_THUMB_TIP = 2
|
| 24 |
+
EVE_INDEX_MCP = 3
|
| 25 |
+
EVE_INDEX_TIP = 4
|
| 26 |
+
EVE_MIDDLE_MCP = 5
|
| 27 |
+
EVE_MIDDLE_TIP = 6
|
| 28 |
+
EVE_RING_MCP = 7
|
| 29 |
+
EVE_RING_TIP = 8
|
| 30 |
+
EVE_PINKY_MCP = 9
|
| 31 |
+
EVE_PINKY_TIP = 10
|
| 32 |
+
EVE_HAND_LANDMARK_SIZE = 11
|
| 33 |
+
|
| 34 |
+
class EveGestureQuality(CtypesEnum):
|
| 35 |
+
EVE_POOR_QUALITY_LOW_CONFIDENCE = 0
|
| 36 |
+
EVE_POOR_QUALITY_HAND_OVER_FACE = 1
|
| 37 |
+
EVE_GOOD_QUALITY = 2
|
| 38 |
+
|
| 39 |
+
class EveStaticGestureType(CtypesEnum):
|
| 40 |
+
EVE_STATIC_GESTURE_NONE = 0
|
| 41 |
+
EVE_OPEN_HAND = 1
|
| 42 |
+
EVE_OPEN_HAND_LEFT = 2
|
| 43 |
+
EVE_OPEN_HAND_RIGHT = 3
|
| 44 |
+
EVE_CLOSED_HAND = 4
|
| 45 |
+
EVE_THUMBS_LEFT = 5
|
| 46 |
+
EVE_THUMBS_RIGHT = 6
|
| 47 |
+
EVE_RESERVED_STATIC_GESTURE_1 = 7
|
| 48 |
+
EVE_RESERVED_STATIC_GESTURE_2 = 8
|
| 49 |
+
EVE_RESERVED_STATIC_GESTURE_3 = 9
|
| 50 |
+
EVE_RESERVED_STATIC_GESTURE_4 = 10
|
| 51 |
+
EVE_RESERVED_STATIC_GESTURE_5 = 11
|
| 52 |
+
EVE_CUSTOM_STATIC_GESTURE_1 = 12
|
| 53 |
+
EVE_CUSTOM_STATIC_GESTURE_2 = 13
|
| 54 |
+
EVE_CUSTOM_STATIC_GESTURE_3 = 14
|
| 55 |
+
EVE_CUSTOM_STATIC_GESTURE_4 = 15
|
| 56 |
+
EVE_CUSTOM_STATIC_GESTURE_5 = 16
|
| 57 |
+
EVE_CUSTOM_STATIC_GESTURE_6 = 17
|
| 58 |
+
EVE_CUSTOM_STATIC_GESTURE_7 = 18
|
| 59 |
+
EVE_CUSTOM_STATIC_GESTURE_8 = 19
|
| 60 |
+
EVE_CUSTOM_STATIC_GESTURE_9 = 20
|
| 61 |
+
EVE_CUSTOM_STATIC_GESTURE_10 = 21
|
| 62 |
+
EVE_STATIC_GESTURE_SIZE = 22
|
| 63 |
+
|
| 64 |
+
class EveDynamicGestureType(CtypesEnum):
|
| 65 |
+
EVE_DYNAMIC_GESTURE_NONE = 0
|
| 66 |
+
EVE_GRAB = 1
|
| 67 |
+
EVE_RESERVED_DYNAMIC_GESTURE_1 = 2
|
| 68 |
+
EVE_RESERVED_DYNAMIC_GESTURE_2 = 3
|
| 69 |
+
EVE_RESERVED_DYNAMIC_GESTURE_3 = 4
|
| 70 |
+
EVE_RESERVED_DYNAMIC_GESTURE_4 = 5
|
| 71 |
+
EVE_RESERVED_DYNAMIC_GESTURE_5 = 6
|
| 72 |
+
EVE_CUSTOM_DYNAMIC_GESTURE_1 = 7
|
| 73 |
+
EVE_CUSTOM_DYNAMIC_GESTURE_2 = 8
|
| 74 |
+
EVE_CUSTOM_DYNAMIC_GESTURE_3 = 9
|
| 75 |
+
EVE_CUSTOM_DYNAMIC_GESTURE_4 = 10
|
| 76 |
+
EVE_CUSTOM_DYNAMIC_GESTURE_5 = 11
|
| 77 |
+
EVE_DYNAMIC_GESTURE_SIZE = 12
|
| 78 |
+
|
| 79 |
+
class EveStaticGesture(ctypes.Structure):
|
| 80 |
+
_fields_ = [
|
| 81 |
+
("handId", ctypes.c_int),
|
| 82 |
+
("isMainUserHand", ctypes.c_int),
|
| 83 |
+
("type", ctypes.c_int),
|
| 84 |
+
("confidence", ctypes.c_float),
|
| 85 |
+
("quality", ctypes.c_int),
|
| 86 |
+
]
|
| 87 |
+
|
| 88 |
+
class EveStaticGestures(ctypes.Structure):
|
| 89 |
+
_fields_ = [
|
| 90 |
+
("count", ctypes.c_uint),
|
| 91 |
+
("gestures", EveStaticGesture * EVE_MAX_HAND_DETECTIONS),
|
| 92 |
+
]
|
| 93 |
+
|
| 94 |
+
class EveStaticGestureDefinition(ctypes.Structure):
|
| 95 |
+
_fields_ = [
|
| 96 |
+
("gestureType", ctypes.c_int),
|
| 97 |
+
("id", ctypes.c_uint),
|
| 98 |
+
("landmarksMap", CPoint2f * EVE_HAND_LANDMARK_SIZE),
|
| 99 |
+
]
|
| 100 |
+
|
| 101 |
+
class EveDynamicGesture(ctypes.Structure):
|
| 102 |
+
_fields_ = [
|
| 103 |
+
("handId", ctypes.c_int),
|
| 104 |
+
("isMainUserHand", ctypes.c_int),
|
| 105 |
+
("type", ctypes.c_int),
|
| 106 |
+
("quality", ctypes.c_int),
|
| 107 |
+
]
|
| 108 |
+
|
| 109 |
+
class EveDynamicGestures(ctypes.Structure):
|
| 110 |
+
_fields_ = [
|
| 111 |
+
("count", ctypes.c_uint),
|
| 112 |
+
("gestures", EveDynamicGesture * EVE_MAX_HAND_DETECTIONS),
|
| 113 |
+
]
|
| 114 |
+
|
| 115 |
+
class EveDynamicGestureDefinition(ctypes.Structure):
|
| 116 |
+
_fields_ = [
|
| 117 |
+
("gestureType", ctypes.c_int),
|
| 118 |
+
("sequenceCount", ctypes.c_uint),
|
| 119 |
+
("gestureSequence", ctypes.c_int * EVE_MAX_DYNAMIC_GESTURE_SEQUENCE),
|
| 120 |
+
]
|
| 121 |
+
|
| 122 |
+
class EveSingleHandDetection(ctypes.Structure):
|
| 123 |
+
_fields_ = [
|
| 124 |
+
("id", ctypes.c_int),
|
| 125 |
+
("isHandValid", ctypes.c_int),
|
| 126 |
+
("boundingBox", CRect2iWH),
|
| 127 |
+
("boundingBoxScore", ctypes.c_float),
|
| 128 |
+
("landmarksICS", CPoint2f * EVE_HAND_LANDMARK_SIZE),
|
| 129 |
+
("validationScore", ctypes.c_float),
|
| 130 |
+
("inPlaneAngle", ctypes.c_float),
|
| 131 |
+
("depth", ctypes.c_float),
|
| 132 |
+
("isMainUserHand", ctypes.c_int),
|
| 133 |
+
("isInCurrentFrame", ctypes.c_int),
|
| 134 |
+
]
|
| 135 |
+
|
| 136 |
+
class EveHandDetections(ctypes.Structure):
|
| 137 |
+
_fields_ = [
|
| 138 |
+
("status", ctypes.c_int),
|
| 139 |
+
("hasFaceROI", ctypes.c_int),
|
| 140 |
+
("faceROI", CRect2fWH),
|
| 141 |
+
("detectedHandCount", ctypes.c_uint),
|
| 142 |
+
("hands", EveSingleHandDetection * EVE_MAX_HAND_DETECTIONS),
|
| 143 |
+
]
|
| 144 |
+
|
shared/eve_python/structs/CImageManipulation.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class CImageManipulationSettings(ctypes.Structure):
|
| 6 |
+
_fields_ = [
|
| 7 |
+
("mirrorImage", ctypes.c_uint),
|
| 8 |
+
("reserved1", ctypes.c_uint),
|
| 9 |
+
("reserved2", ctypes.c_uint),
|
| 10 |
+
("reserved3", ctypes.c_uint),
|
| 11 |
+
]
|
| 12 |
+
|
shared/eve_python/structs/CKarolinska.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class EveKarolinskaSleepiness(CtypesEnum):
|
| 6 |
+
EVE_KAROLINSKA_DISABLED = 0
|
| 7 |
+
EVE_KAROLINSKA_1 = 1
|
| 8 |
+
EVE_KAROLINSKA_2 = 2
|
| 9 |
+
EVE_KAROLINSKA_3 = 3
|
| 10 |
+
EVE_KAROLINSKA_4 = 4
|
| 11 |
+
EVE_KAROLINSKA_5 = 5
|
| 12 |
+
EVE_KAROLINSKA_6 = 6
|
| 13 |
+
EVE_KAROLINSKA_7 = 7
|
| 14 |
+
EVE_KAROLINSKA_8 = 8
|
| 15 |
+
EVE_KAROLINSKA_9 = 9
|
| 16 |
+
EVE_KAROLINSKA_MAX = 10
|
| 17 |
+
|
| 18 |
+
class EveEyeClosureState(CtypesEnum):
|
| 19 |
+
EVE_EYE_STATE_UNKNOWN = 0
|
| 20 |
+
EVE_EYE_OPEN = 1
|
| 21 |
+
EVE_EYE_CLOSED = 2
|
| 22 |
+
|
| 23 |
+
class EveKarolinskaStatus(CtypesEnum):
|
| 24 |
+
EVE_KAROLINSKA_OFF = 0
|
| 25 |
+
EVE_KAROLINSKA_NO_FACE = 1
|
| 26 |
+
EVE_KAROLINSKA_BLINKS_ONLY = 2
|
| 27 |
+
EVE_KAROLINSKA_ON = 3
|
| 28 |
+
|
| 29 |
+
class CEyeState(ctypes.Structure):
|
| 30 |
+
_fields_ = [
|
| 31 |
+
("state", ctypes.c_int),
|
| 32 |
+
("closure", ctypes.c_float),
|
| 33 |
+
("confidence", ctypes.c_float),
|
| 34 |
+
("eyelidDistanceMM", ctypes.c_float),
|
| 35 |
+
]
|
| 36 |
+
|
| 37 |
+
class CEyeStates(ctypes.Structure):
|
| 38 |
+
_fields_ = [
|
| 39 |
+
("left", CEyeState),
|
| 40 |
+
("right", CEyeState),
|
| 41 |
+
("fused", CEyeState),
|
| 42 |
+
("blinkCount", ctypes.c_uint),
|
| 43 |
+
]
|
| 44 |
+
|
| 45 |
+
class CKarolinskaData(ctypes.Structure):
|
| 46 |
+
_fields_ = [
|
| 47 |
+
("status", ctypes.c_int),
|
| 48 |
+
("scale", ctypes.c_int),
|
| 49 |
+
("headPitchScale", ctypes.c_int),
|
| 50 |
+
("yawnScale", ctypes.c_int),
|
| 51 |
+
("blinkDurationScale", ctypes.c_int),
|
| 52 |
+
("yawn", ctypes.c_float),
|
| 53 |
+
("yawnConfidence", ctypes.c_float),
|
| 54 |
+
("yawnCount", ctypes.c_uint),
|
| 55 |
+
("eyes", CEyeStates),
|
| 56 |
+
]
|
| 57 |
+
|
shared/eve_python/structs/CLandmarkMaps.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
|
| 4 |
+
EVE_HMI_P_L_SIZE = 23
|
| 5 |
+
EVE_HMI_S_L_SIZE = 5
|
| 6 |
+
|
| 7 |
+
class EveHmiPrimaryLandmarks(CtypesEnum):
|
| 8 |
+
EVE_HMI_P_L_RIGHT_TEMPLE = 0
|
| 9 |
+
EVE_HMI_P_L_RIGHT_JAW = 1
|
| 10 |
+
EVE_HMI_P_L_CENTER_JAW = 2
|
| 11 |
+
EVE_HMI_P_L_LEFT_JAW = 3
|
| 12 |
+
EVE_HMI_P_L_LEFT_TEMPLE = 4
|
| 13 |
+
EVE_HMI_P_L_RIGHT_EYEBROW = 5
|
| 14 |
+
EVE_HMI_P_L_LEFT_EYEBROW = 6
|
| 15 |
+
EVE_HMI_P_L_NOSE_BRIDGE = 7
|
| 16 |
+
EVE_HMI_P_L_NOSE_TIP_HIGH = 8
|
| 17 |
+
EVE_HMI_P_L_NOSE_TIP = 9
|
| 18 |
+
EVE_HMI_P_L_NOSE_TIP_LOW = 10
|
| 19 |
+
EVE_HMI_P_L_RIGHT_EYE_1 = 11
|
| 20 |
+
EVE_HMI_P_L_RIGHT_EYE_2 = 12
|
| 21 |
+
EVE_HMI_P_L_LEFT_EYE_1 = 13
|
| 22 |
+
EVE_HMI_P_L_LEFT_EYE_2 = 14
|
| 23 |
+
EVE_HMI_P_L_MOUTH_RIGHT_CORNER = 15
|
| 24 |
+
EVE_HMI_P_L_MOUTH_UPPER_LIP = 16
|
| 25 |
+
EVE_HMI_P_L_MOUTH_LEFT_CORNER = 17
|
| 26 |
+
EVE_HMI_P_L_MOUTH_LOWER_LIP = 18
|
| 27 |
+
EVE_HMI_P_L_MOUTH_OPEN_TOP = 19
|
| 28 |
+
EVE_HMI_P_L_MOUTH_OPEN_BOTTOM = 20
|
| 29 |
+
EVE_HMI_P_L_RIGHT_PUPIL = 21
|
| 30 |
+
EVE_HMI_P_L_LEFT_PUPIL = 22
|
| 31 |
+
EVE_HMI_P_L_SIZE = 23
|
| 32 |
+
|
| 33 |
+
class EveHmiSecondaryLandmarks(CtypesEnum):
|
| 34 |
+
EVE_HMI_S_L_RIGHT_PUPIL = 0
|
| 35 |
+
EVE_HMI_S_L_LEFT_PUPIL = 1
|
| 36 |
+
EVE_HMI_S_L_NOSE_TIP_LOW = 2
|
| 37 |
+
EVE_HMI_S_L_RIGHT_MOUTH_CORNER = 3
|
| 38 |
+
EVE_HMI_S_L_LEFT_MOUTH_CORNER = 4
|
| 39 |
+
EVE_HMI_S_L_SIZE = 5
|
| 40 |
+
|
shared/eve_python/structs/CROIStructs.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .EveProcessingStatus import *
|
| 4 |
+
|
| 5 |
+
EVE_ROI_MAX_SCORE_COUNT = 20
|
| 6 |
+
|
| 7 |
+
class EveROIState(CtypesEnum):
|
| 8 |
+
EVE_ROI_STATE_INACTIVE = 0
|
| 9 |
+
EVE_ROI_STATE_ENTERING = 1
|
| 10 |
+
EVE_ROI_STATE_LEAVING = 2
|
| 11 |
+
EVE_ROI_STATE_SELECTED = 3
|
| 12 |
+
|
| 13 |
+
class CROIScore(ctypes.Structure):
|
| 14 |
+
_fields_ = [
|
| 15 |
+
("id", ctypes.c_uint),
|
| 16 |
+
("intersectionScore", ctypes.c_double),
|
| 17 |
+
("filteredScore", ctypes.c_double),
|
| 18 |
+
("state", ctypes.c_int),
|
| 19 |
+
]
|
| 20 |
+
|
| 21 |
+
class CROIScoreData(ctypes.Structure):
|
| 22 |
+
_fields_ = [
|
| 23 |
+
("processingStatus", ctypes.c_int),
|
| 24 |
+
("fusedRoiScoresCount", ctypes.c_uint),
|
| 25 |
+
("fusedRoiScores", CROIScore * EVE_ROI_MAX_SCORE_COUNT),
|
| 26 |
+
("faceRoiScoresCount", ctypes.c_uint),
|
| 27 |
+
("faceRoiScores", CROIScore * EVE_ROI_MAX_SCORE_COUNT),
|
| 28 |
+
]
|
| 29 |
+
|
shared/eve_python/structs/CScreenLocation.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class CScreenLocation(ctypes.Structure):
|
| 6 |
+
_fields_ = [
|
| 7 |
+
("topLeftXInMM", ctypes.c_float),
|
| 8 |
+
("topLeftYInMM", ctypes.c_float),
|
| 9 |
+
]
|
| 10 |
+
|
shared/eve_python/structs/CVisualSpeechStructs.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .EveProcessingStatus import *
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
class EveVisualSpeechState(CtypesEnum):
|
| 7 |
+
EVE_NOT_SET = 0
|
| 8 |
+
EVE_NOT_SPEAKING = 1
|
| 9 |
+
EVE_SPEAKING = 2
|
| 10 |
+
|
| 11 |
+
class CVisualSpeechData(ctypes.Structure):
|
| 12 |
+
_fields_ = [
|
| 13 |
+
("processingStatus", ctypes.c_int),
|
| 14 |
+
("speechState", ctypes.c_int),
|
| 15 |
+
("notSpeakingProbability", ctypes.c_double),
|
| 16 |
+
("speakingProbability", ctypes.c_double),
|
| 17 |
+
]
|
| 18 |
+
|
shared/eve_python/structs/EveAlgorithm.py
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .EveAlgorithmStructs import *
|
| 4 |
+
|
| 5 |
+
|
shared/eve_python/structs/EveAlgorithmStructs.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .CAlgorithms import *
|
| 4 |
+
from .EveErrors import *
|
| 5 |
+
|
| 6 |
+
EVE_ALGORITHMS_SIZE = 20
|
| 7 |
+
|
| 8 |
+
class EveSupportedAlgorithms(ctypes.Structure):
|
| 9 |
+
_fields_ = [
|
| 10 |
+
("errorCode", ctypes.c_int),
|
| 11 |
+
("count", ctypes.c_uint),
|
| 12 |
+
("algorithms", ctypes.c_int * EVE_ALGORITHMS_SIZE),
|
| 13 |
+
]
|
| 14 |
+
|
shared/eve_python/structs/EveCallbackReturnData.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class EveRequestedProcessingState(CtypesEnum):
|
| 6 |
+
EVE_REQUESTED_PROCESSING_STATE_CONTINUE = 0
|
| 7 |
+
EVE_REQUESTED_PROCESSING_STATE_STOP = 1
|
| 8 |
+
|
| 9 |
+
class EveProcessingCallbackReturnData(ctypes.Structure):
|
| 10 |
+
_fields_ = [
|
| 11 |
+
("requestedState", ctypes.c_int),
|
| 12 |
+
]
|
| 13 |
+
|
shared/eve_python/structs/EveCamera.py
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .EveCameraStructs import *
|
| 4 |
+
|
| 5 |
+
|
shared/eve_python/structs/EveCameraStructs.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .CCameraStructs import *
|
| 4 |
+
from .EveErrors import *
|
| 5 |
+
|
| 6 |
+
EVE_CAMERA_FORMATS_SIZE = 20
|
| 7 |
+
|
| 8 |
+
class EveCameraFormats(ctypes.Structure):
|
| 9 |
+
_fields_ = [
|
| 10 |
+
("formats", CCameraFormat * EVE_CAMERA_FORMATS_SIZE),
|
| 11 |
+
("formatsCount", ctypes.c_uint),
|
| 12 |
+
("hadMoreFormats", ctypes.c_uint),
|
| 13 |
+
("error", ctypes.c_int),
|
| 14 |
+
]
|
| 15 |
+
|
| 16 |
+
class EveCamera(ctypes.Structure):
|
| 17 |
+
_fields_ = [
|
| 18 |
+
("data", CCamera),
|
| 19 |
+
("error", ctypes.c_int),
|
| 20 |
+
]
|
| 21 |
+
|
| 22 |
+
class EveNumberOfCameras(ctypes.Structure):
|
| 23 |
+
_fields_ = [
|
| 24 |
+
("count", ctypes.c_uint),
|
| 25 |
+
("error", ctypes.c_int),
|
| 26 |
+
]
|
| 27 |
+
|
shared/eve_python/structs/EveConfigurationParameters.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
|
| 4 |
+
EVE_PIPELINE_TYPE_SIZE = 2
|
| 5 |
+
|
| 6 |
+
class EveImageProvider(CtypesEnum):
|
| 7 |
+
EVE_CAMERA = 0
|
| 8 |
+
EVE_CLIENT_PROVIDED = 1
|
| 9 |
+
|
| 10 |
+
class EveGpuPreference(CtypesEnum):
|
| 11 |
+
EVE_GPU_LOW_POWER = 0
|
| 12 |
+
EVE_GPU_HIGH_PERFORMANCE = 1
|
| 13 |
+
EVE_NO_GPU = 2
|
| 14 |
+
|
| 15 |
+
class EveStartupType(CtypesEnum):
|
| 16 |
+
EVE_SYNC = 0
|
| 17 |
+
EVE_ASYNC = 1
|
| 18 |
+
|
| 19 |
+
class EveProcessingPipelineType(CtypesEnum):
|
| 20 |
+
EVE_FULL = 0
|
| 21 |
+
EVE_HMI = 1
|
| 22 |
+
EVE_PIPELINE_TYPE_SIZE = 2
|
| 23 |
+
|
| 24 |
+
class EveStartupParameters(ctypes.Structure):
|
| 25 |
+
_fields_ = [
|
| 26 |
+
("gpuPreference", ctypes.c_int),
|
| 27 |
+
("imageProvider", ctypes.c_int),
|
| 28 |
+
("startupType", ctypes.c_int),
|
| 29 |
+
("pathOverride", ctypes.c_byte * 512),
|
| 30 |
+
]
|
| 31 |
+
|
| 32 |
+
class EveProcessingParameters(ctypes.Structure):
|
| 33 |
+
_fields_ = [
|
| 34 |
+
("type", ctypes.c_int),
|
| 35 |
+
]
|
| 36 |
+
|
shared/eve_python/structs/EveControlInterface.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .CCameraStructs import *
|
| 4 |
+
from .EveCallbackReturnData import *
|
| 5 |
+
from .EveConfigurationParameters import *
|
| 6 |
+
from .EveErrors import *
|
| 7 |
+
from .EveImageStructs import *
|
| 8 |
+
|
| 9 |
+
|
shared/eve_python/structs/EveControlOption.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class EveOptionEnabled(CtypesEnum):
|
| 6 |
+
EVE_OPTION_DISABLED = 0
|
| 7 |
+
EVE_OPTION_ENABLED = 1
|
| 8 |
+
|
shared/eve_python/structs/EveErrors.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class EveError(CtypesEnum):
|
| 6 |
+
EVE_ERROR_NO_ERROR = 0
|
| 7 |
+
EVE_ERROR_NOT_CREATED = 1
|
| 8 |
+
EVE_ERROR_NOT_STARTED = 2
|
| 9 |
+
EVE_ERROR_PIPELINE_NOT_FOUND = 3
|
| 10 |
+
EVE_ERROR_CAMERA_MANAGER_NOT_FOUND = 4
|
| 11 |
+
EVE_ERROR_NO_CALLBACK = 5
|
| 12 |
+
EVE_ERROR_NOT_ACCESSED_FROM_CALLBACK = 6
|
| 13 |
+
EVE_INVALID_IMAGE_ENCODING = 7
|
| 14 |
+
EVE_CALLBACK_WITHOUT_CONNECTING_TO_CAMERA = 8
|
| 15 |
+
EVE_CAMERA_INTERACTION_WITHOUT_CAMERA = 9
|
| 16 |
+
EVE_NO_MORE_DATA = 10
|
| 17 |
+
EVE_INVALID_CAMERA_ID = 11
|
| 18 |
+
EVE_FACE_ID_INVALID_THRESHOLD = 12
|
| 19 |
+
EVE_ERROR_NO_CAMERA_INTERACTION_WITH_CAMERA = 13
|
| 20 |
+
EVE_ERROR_NOT_IMPLEMENTED = 14
|
| 21 |
+
EVE_ERROR_UNSUPPORTED_FORMAT = 15
|
| 22 |
+
|
shared/eve_python/structs/EveFaceId.py
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .EveFaceIdStructs import *
|
| 4 |
+
|
| 5 |
+
|
shared/eve_python/structs/EveFaceIdStructs.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .CFaceIdStructs import *
|
| 4 |
+
from .EveControlOption import *
|
| 5 |
+
from .EveErrors import *
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class EveFaceIdCalibrationPoseMode(CtypesEnum):
|
| 9 |
+
EVE_FACEID_CALIBRATION_FRONTAL_ONLY = 1
|
| 10 |
+
|
| 11 |
+
class EveFaceIdCommandStruct(ctypes.Structure):
|
| 12 |
+
_fields_ = [
|
| 13 |
+
("command", ctypes.c_int),
|
| 14 |
+
("errorCode", ctypes.c_int),
|
| 15 |
+
]
|
| 16 |
+
|
| 17 |
+
class EveFaceIdOptions(ctypes.Structure):
|
| 18 |
+
_fields_ = [
|
| 19 |
+
("enabled", ctypes.c_int),
|
| 20 |
+
("calibrationPoses", ctypes.c_int),
|
| 21 |
+
("galleryPath", ctypes.c_byte * 256),
|
| 22 |
+
("threshold", ctypes.c_float),
|
| 23 |
+
("error", ctypes.c_int),
|
| 24 |
+
]
|
| 25 |
+
|
| 26 |
+
class EveFaceIdData(ctypes.Structure):
|
| 27 |
+
_fields_ = [
|
| 28 |
+
("data", CFaceIdentityData),
|
| 29 |
+
("error", ctypes.c_int),
|
| 30 |
+
]
|
| 31 |
+
|
shared/eve_python/structs/EveFaceTracker.py
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .EveFaceTrackerStructs import *
|
| 4 |
+
|
| 5 |
+
|
shared/eve_python/structs/EveFaceTrackerStructs.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .CFaceData import *
|
| 4 |
+
from .EveErrors import *
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class EveFaceTrackerMinimumMode(CtypesEnum):
|
| 8 |
+
EVE_FACETRACKER_MINIMUM_MODE_OFF = 0
|
| 9 |
+
EVE_FACETRACKER_MINIMUM_MODE_MINIMAL = 1
|
| 10 |
+
EVE_FACETRACKER_MINIMUM_MODE_AVERAGE = 2
|
| 11 |
+
EVE_FACETRACKER_MINIMUM_MODE_MAXIMAL = 3
|
| 12 |
+
|
| 13 |
+
class EveFaceTrackerOptions(ctypes.Structure):
|
| 14 |
+
_fields_ = [
|
| 15 |
+
("faceTrackerMode", ctypes.c_int),
|
| 16 |
+
("enableEyeLandmarks", ctypes.c_uint),
|
| 17 |
+
("enable3DFaceTracking", ctypes.c_uint),
|
| 18 |
+
("enablePersonDetection", ctypes.c_uint),
|
| 19 |
+
("fitSecondaryUsers", ctypes.c_uint),
|
| 20 |
+
("error", ctypes.c_int),
|
| 21 |
+
]
|
| 22 |
+
|
| 23 |
+
class EveEyes(ctypes.Structure):
|
| 24 |
+
_fields_ = [
|
| 25 |
+
("data", CEyeLandmarks),
|
| 26 |
+
("errorCode", ctypes.c_int),
|
| 27 |
+
]
|
| 28 |
+
|
| 29 |
+
class EvePupils(ctypes.Structure):
|
| 30 |
+
_fields_ = [
|
| 31 |
+
("data", CPupilLandmarks),
|
| 32 |
+
("errorCode", ctypes.c_int),
|
| 33 |
+
]
|
| 34 |
+
|
| 35 |
+
class EveAllFacesData(ctypes.Structure):
|
| 36 |
+
_fields_ = [
|
| 37 |
+
("faceData", ctypes.POINTER(CAllFaces)),
|
| 38 |
+
("errorCode", ctypes.c_int),
|
| 39 |
+
]
|
| 40 |
+
|
shared/eve_python/structs/EveFpga.py
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .CFpgaData import *
|
| 4 |
+
from .EveFpgaStructs import *
|
| 5 |
+
from .EveImageStructs import *
|
| 6 |
+
|
| 7 |
+
|
shared/eve_python/structs/EveFpgaStructs.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .CFpgaData import *
|
| 4 |
+
from .EveErrors import *
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class EveFpgaOptions(ctypes.Structure):
|
| 8 |
+
_fields_ = [
|
| 9 |
+
("parameters", CFpgaParameters),
|
| 10 |
+
("error", ctypes.c_int),
|
| 11 |
+
]
|
| 12 |
+
|
| 13 |
+
class EveFpgaDebugOptions(ctypes.Structure):
|
| 14 |
+
_fields_ = [
|
| 15 |
+
("enableDrawingOnImage", ctypes.c_uint),
|
| 16 |
+
("error", ctypes.c_int),
|
| 17 |
+
]
|
| 18 |
+
|
| 19 |
+
class EveFpgaData(ctypes.Structure):
|
| 20 |
+
_fields_ = [
|
| 21 |
+
("data", ctypes.POINTER(CFpgaData)),
|
| 22 |
+
("error", ctypes.c_int),
|
| 23 |
+
]
|
| 24 |
+
|
shared/eve_python/structs/EveHandGesture.py
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .EveHandGestureStructs import *
|
| 4 |
+
|
| 5 |
+
|
shared/eve_python/structs/EveHandGestureStructs.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .CHandGesture import *
|
| 4 |
+
from .EveControlOption import *
|
| 5 |
+
from .EveErrors import *
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class EveHandGestureOptions(ctypes.Structure):
|
| 9 |
+
_fields_ = [
|
| 10 |
+
("enabled", ctypes.c_int),
|
| 11 |
+
("redetectionDelay", ctypes.c_int),
|
| 12 |
+
("async", ctypes.c_int),
|
| 13 |
+
("run", ctypes.c_int),
|
| 14 |
+
("errorCode", ctypes.c_int),
|
| 15 |
+
]
|
| 16 |
+
|
| 17 |
+
class EveHandGestureData(ctypes.Structure):
|
| 18 |
+
_fields_ = [
|
| 19 |
+
("hands", ctypes.POINTER(EveHandDetections)),
|
| 20 |
+
("errorCode", ctypes.c_int),
|
| 21 |
+
]
|
| 22 |
+
|
| 23 |
+
class EveStaticGestureData(ctypes.Structure):
|
| 24 |
+
_fields_ = [
|
| 25 |
+
("gestures", EveStaticGestures),
|
| 26 |
+
("errorCode", ctypes.c_int),
|
| 27 |
+
]
|
| 28 |
+
|
| 29 |
+
class EveDynamicGestureData(ctypes.Structure):
|
| 30 |
+
_fields_ = [
|
| 31 |
+
("gestures", EveDynamicGestures),
|
| 32 |
+
("errorCode", ctypes.c_int),
|
| 33 |
+
]
|
| 34 |
+
|
| 35 |
+
class EveStaticGestureDefinitions(ctypes.Structure):
|
| 36 |
+
_fields_ = [
|
| 37 |
+
("count", ctypes.c_uint),
|
| 38 |
+
("errorCode", ctypes.c_int),
|
| 39 |
+
("definitions", EveStaticGestureDefinition * EVE_MAX_STATIC_GESTURES),
|
| 40 |
+
]
|
| 41 |
+
|
| 42 |
+
class EveDynamicGestureDefinitions(ctypes.Structure):
|
| 43 |
+
_fields_ = [
|
| 44 |
+
("count", ctypes.c_uint),
|
| 45 |
+
("errorCode", ctypes.c_int),
|
| 46 |
+
("definitions", EveDynamicGestureDefinition * EVE_DYNAMIC_GESTURE_SIZE),
|
| 47 |
+
]
|
| 48 |
+
|
shared/eve_python/structs/EveImage.py
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .EveImageStructs import *
|
| 4 |
+
|
| 5 |
+
|
shared/eve_python/structs/EveImageManipulation.py
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .EveImageManipulationStructs import *
|
| 4 |
+
|
| 5 |
+
|
shared/eve_python/structs/EveImageManipulationStructs.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
from ctypes_enum import CtypesEnum
|
| 3 |
+
from .CImageManipulation import *
|
| 4 |
+
from .EveErrors import *
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class EveImageManipulationOptions(ctypes.Structure):
|
| 8 |
+
_fields_ = [
|
| 9 |
+
("settings", CImageManipulationSettings),
|
| 10 |
+
("errorCode", ctypes.c_int),
|
| 11 |
+
]
|
| 12 |
+
|