diff --git a/.gitattributes b/.gitattributes index d5df454628f82dcec8320484769dc3036ef90eb0..6918df289b10c92750ed6f252b49b75c75f8f596 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,38 +1,37 @@ -*.7z filter=lfs diff=lfs merge=lfs -text -*.arrow filter=lfs diff=lfs merge=lfs -text -*.bin filter=lfs diff=lfs merge=lfs -text -*.bz2 filter=lfs diff=lfs merge=lfs -text -*.ckpt filter=lfs diff=lfs merge=lfs -text -*.ftz filter=lfs diff=lfs merge=lfs -text -*.gz filter=lfs diff=lfs merge=lfs -text -*.h5 filter=lfs diff=lfs merge=lfs -text -*.joblib filter=lfs diff=lfs merge=lfs -text -*.lfs.* filter=lfs diff=lfs merge=lfs -text -*.mlmodel filter=lfs diff=lfs merge=lfs -text -*.model filter=lfs diff=lfs merge=lfs -text -*.msgpack filter=lfs diff=lfs merge=lfs -text -*.npy filter=lfs diff=lfs merge=lfs -text -*.npz filter=lfs diff=lfs merge=lfs -text -*.onnx filter=lfs diff=lfs merge=lfs -text -*.ot filter=lfs diff=lfs merge=lfs -text -*.parquet filter=lfs diff=lfs merge=lfs -text -*.pb filter=lfs diff=lfs merge=lfs -text -*.pickle filter=lfs diff=lfs merge=lfs -text -*.pkl filter=lfs diff=lfs merge=lfs -text -*.pt filter=lfs diff=lfs merge=lfs -text -*.pth filter=lfs diff=lfs merge=lfs -text -*.rar filter=lfs diff=lfs merge=lfs -text -*.safetensors filter=lfs diff=lfs merge=lfs -text -saved_model/**/* filter=lfs diff=lfs merge=lfs -text -*.tar.* filter=lfs diff=lfs merge=lfs -text -*.tar filter=lfs diff=lfs merge=lfs -text -*.tflite filter=lfs diff=lfs merge=lfs -text -*.tgz filter=lfs diff=lfs merge=lfs -text -*.wasm filter=lfs diff=lfs merge=lfs -text -*.xz filter=lfs diff=lfs merge=lfs -text -*.zip filter=lfs diff=lfs merge=lfs -text -*.zst filter=lfs diff=lfs merge=lfs -text -*tfevents* filter=lfs diff=lfs merge=lfs -text -*.mp4 filter=lfs diff=lfs merge=lfs -text -*.deb filter=lfs diff=lfs merge=lfs -text -examples_fid/example_couple.jpg filter=lfs diff=lfs merge=lfs -text +*.7z filter=lfs diff=lfs merge=lfs -text +*.arrow filter=lfs diff=lfs merge=lfs -text +*.bin filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text +*.ckpt filter=lfs diff=lfs merge=lfs -text +*.ftz filter=lfs diff=lfs merge=lfs -text +*.gz filter=lfs diff=lfs merge=lfs -text +*.h5 filter=lfs diff=lfs merge=lfs -text +*.joblib filter=lfs diff=lfs merge=lfs -text +*.lfs.* filter=lfs diff=lfs merge=lfs -text +*.mlmodel filter=lfs diff=lfs merge=lfs -text +*.model filter=lfs diff=lfs merge=lfs -text +*.msgpack filter=lfs diff=lfs merge=lfs -text +*.npy filter=lfs diff=lfs merge=lfs -text +*.npz filter=lfs diff=lfs merge=lfs -text +*.onnx filter=lfs diff=lfs merge=lfs -text +*.ot filter=lfs diff=lfs merge=lfs -text +*.parquet filter=lfs diff=lfs merge=lfs -text +*.pb filter=lfs diff=lfs merge=lfs -text +*.pickle filter=lfs diff=lfs merge=lfs -text +*.pkl filter=lfs diff=lfs merge=lfs -text +*.pt filter=lfs diff=lfs merge=lfs -text +*.pth filter=lfs diff=lfs merge=lfs -text +*.rar filter=lfs diff=lfs merge=lfs -text +*.safetensors filter=lfs diff=lfs merge=lfs -text +saved_model/**/* filter=lfs diff=lfs merge=lfs -text +*.tar.* filter=lfs diff=lfs merge=lfs -text +*.tar filter=lfs diff=lfs merge=lfs -text +*.tflite filter=lfs diff=lfs merge=lfs -text +*.tgz filter=lfs diff=lfs merge=lfs -text +*.wasm filter=lfs diff=lfs merge=lfs -text +*.xz filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.zst filter=lfs diff=lfs merge=lfs -text +*tfevents* filter=lfs diff=lfs merge=lfs -text +*.mp4 filter=lfs diff=lfs merge=lfs -text +*.deb filter=lfs diff=lfs merge=lfs -text diff --git a/Dockerfile b/Dockerfile index d8c88a3df4116b7e552b183562ecc58582bea378..dbf1d8b72fb6d3241efe615433b0f8dea5b03f8b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,25 +1,27 @@ -# syntax=docker/dockerfile:1 -FROM python:3.11 - -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 - -ARG HF_TOKEN="" - -RUN pip install --no-cache-dir huggingface-hub -COPY install_eve.py /tmp/install_eve.py -RUN --mount=type=secret,id=MODEL_ACCESS_TOKEN \ - HF_TOKEN="$HF_TOKEN" python /tmp/install_eve.py && rm /tmp/install_eve.py - -RUN useradd -m -u 1000 user -USER user -ENV PATH="/home/user/.local/bin:$PATH" - -WORKDIR /app - -COPY --chown=user ./requirements.txt requirements.txt -RUN pip install --no-cache-dir --upgrade -r requirements.txt - -RUN mkdir -p /home/user/.config - -COPY --chown=user . /app -CMD ["python", "app.py"] +# syntax=docker/dockerfile:1 +FROM python:3.11 + +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 + +ARG HF_TOKEN="" + +RUN pip install --no-cache-dir huggingface-hub +COPY install_eve.py /tmp/install_eve.py +RUN --mount=type=secret,id=MODEL_ACCESS_TOKEN \ + HF_TOKEN="$HF_TOKEN" python /tmp/install_eve.py && rm /tmp/install_eve.py + +RUN useradd -m -u 1000 user +USER user +ENV PATH="/home/user/.local/bin:$PATH" + +WORKDIR /app + +COPY --chown=user ./requirements.txt requirements.txt +RUN pip install --no-cache-dir --upgrade -r requirements.txt + +RUN mkdir -p /home/user/.config + +COPY --chown=user . /app +RUN --mount=type=secret,id=MODEL_ACCESS_TOKEN,uid=1000 \ + HF_TOKEN="$HF_TOKEN" python download_examples.py +CMD ["python", "app.py"] diff --git a/app.py b/app.py index 96b6ca0779857db07ea559e112d5859de600c44a..ea32a13698f82082c84db9801d1bb3e1c38742bc 100644 --- a/app.py +++ b/app.py @@ -1,301 +1,302 @@ -import atexit -import os -import sys -from pathlib import Path - -import gradio as gr - -sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent / "shared")) -sys.path.insert(0, str(Path(__file__).resolve().parent / "shared")) - -from env_utils import load_dotenv_if_present, require_secrets -from eula_tab import build_eula_tab -from eve_app_tabs import build_live_inference_tab, build_offline_inference_tab -from eve_inference_handlers import EveAppHandlers, patch_video_for_external_urls -from eve_worker_pool import EveWorkerPool -from face_id_tab import FaceIdTab -from live_inference import ( - TAB_SWITCH_AUTO_STOP_JS, - RtcConfigProvider, - patch_aioice_stun_transaction, - patch_aiortc_h264_nvenc, - patch_fastrtc_frame_queue, - patch_fastrtc_yuv420p_output, -) -from live_stream_manager import LiveStreamManager -from log_utils import log_cpu_info, setup_logger -from session_tracker import SessionTracker -from usage_analytics import UsageTracker -from video_file_server import VideoFileServer -from video_processing import VideoLimits, get_example_videos, wire_video_upload - - -def _build_feature_checkboxes( - hint: str = "", -) -> tuple[gr.Checkbox, gr.Checkbox, gr.Checkbox, gr.Checkbox]: - """Build the EVE feature checkbox group used by both tabs. - - Must be called inside a Gradio layout context. - """ - with gr.Group(): - label = "
Features" - if hint: - label += f" — {hint}" - label += "
" - gr.HTML(label) - cb_face = gr.Checkbox(label="Face Detection", value=True) - cb_person = gr.Checkbox(label="Person Detection", value=True) - cb_face_id = gr.Checkbox(label="Face Identification", value=False) - cb_hand_gesture = gr.Checkbox(label="Hand Detection", value=False) - return cb_face, cb_person, cb_face_id, cb_hand_gesture - - -if __name__ == "__main__": - - patch_fastrtc_frame_queue() - patch_fastrtc_yuv420p_output() - patch_aioice_stun_transaction() - patch_aiortc_h264_nvenc() - - load_dotenv_if_present() - logger = setup_logger(name="app") - log_cpu_info(logger) - require_secrets("MODEL_ACCESS_TOKEN") - - tracker = UsageTracker( - repo_id=os.environ.get("ANALYTICS_REPO_ID", "LatticeSemi/PRIVATE-Demo-Analytics-v1.0"), - ) - tracker.log("server", "server_start") - - max_workers = int(os.environ.get("MAX_WORKERS", os.cpu_count())) - max_ram_gb = float(os.environ.get("MAX_RAM_GB", 32)) - pool = EveWorkerPool(max_workers=max_workers, max_ram_gb=max_ram_gb, ram_headroom_gb=2.0) - - # FPS cap: each live stream runs between MAX_TARGET_FPS (idle) and - # MIN_TARGET_FPS (full load). Set either to 0 to disable the cap. - max_fps_raw = float(os.environ.get("MAX_TARGET_FPS", "24")) - min_fps_raw = float(os.environ.get("MIN_TARGET_FPS", "15")) - max_fps: float | None = max_fps_raw if max_fps_raw > 0 else None - min_fps: float | None = min_fps_raw if min_fps_raw > 0 else None - - camera_width = int(os.environ.get("CAMERA_WIDTH", 640)) - camera_height = int(os.environ.get("CAMERA_HEIGHT", 360)) - - stream_manager = LiveStreamManager( - pool, - session_lifetime_seconds=60 * 4, - max_fps=max_fps, - min_fps=min_fps, - tracker=tracker, - ) - - session_tracker = SessionTracker(pool=pool, tracker=tracker, logger=logger) - - # Separate HTTP server for video output — bypasses Chrome's per-origin - # connection limit that blocks /file= requests while SSE connections are open. - video_server: VideoFileServer | None = None - # TODO: Put that under an env var, for debug purposes, locally, for more than 2 tabs. - """if not os.environ.get("SPACE_ID"): - gradio_cache = os.path.join(tempfile.gettempdir(), "gradio") - os.makedirs(gradio_cache, exist_ok=True) - video_server = VideoFileServer(root_dir=gradio_cache, logger=logger) - video_server.start()""" - - handlers = EveAppHandlers( - pool=pool, - stream_manager=stream_manager, - sessions=session_tracker, - logger=logger, - max_fps=max_fps, - min_fps=min_fps, - video_server=video_server, - ) - - def _shutdown() -> None: - session_tracker.shutdown() - stream_manager.shutdown() - tracker.log("server", "server_stop") - tracker.shutdown() - - atexit.register(_shutdown) - - EXAMPLE_VIDEOS = get_example_videos() - VIDEO_LIMITS = VideoLimits() - rtc_config_provider = RtcConfigProvider() - - face_id_tab = FaceIdTab( - pool, - max_users=2, - examples_dir="./examples_fid", - accept_video=True, - video_limits=VideoLimits(max_file_size_mb=150, max_duration_seconds=60), - tracker=tracker, - ) - - with gr.Blocks( - title="Eve HMI Demo", - theme=gr.themes.Default( - text_size=gr.themes.sizes.text_lg, - primary_hue=gr.themes.colors.yellow, - ), - css=( - f"#webrtc-stream-col {{ max-width: {camera_width}px !important; margin: 0 auto; }}" - " .gradio-container h1, .gradio-container .md h1 { font-size: 2.25rem !important; }" - " .gradio-container h2, .gradio-container .md h2 { font-size: 1.75rem !important; }" - " .gradio-container h3, .gradio-container .md h3 { font-size: 1.4rem !important; }" - " .gradio-container button[role='tab']," - " .gradio-container button[role='tab'] *" - " { text-decoration: underline !important; }" - " .gradio-container .tab-container {" - " height: auto !important;" - " overflow: visible !important;" - " gap: 4px !important;" - " border-bottom: 2px solid var(--border-color-primary) !important; }" - " .gradio-container .tab-container::after { display: none !important; }" - " .gradio-container button[role='tab'] {" - " height: auto !important;" - " padding: 10px 20px !important;" - " border: 1px solid var(--border-color-primary) !important;" - " border-bottom: none !important;" - " border-radius: 8px 8px 0 0 !important;" - " background: var(--background-fill-secondary) !important;" - " margin-bottom: -2px !important; }" - " .gradio-container button[role='tab'].selected {" - " background: var(--primary-500) !important;" - " color: var(--neutral-950) !important;" - " border-color: var(--primary-500) !important;" - " font-weight: 600 !important; }" - " .gradio-container button[role='tab'].selected::after { display: none !important; }" - ), - head=TAB_SWITCH_AUTO_STOP_JS, - ) as demo: - gr.Markdown("# Lattice sensAI Edge Vision Engine SDK") - gr.Markdown( - "Our SDK solves the human sensing challenges by outputting ready-to-use data." - " Our models have a low computation footprint and are ideal for 0.5-2 TOPS devices" - " like FPGAs, SOCs and small NPUs.\n\n" - # TODO: Insert performance summary table - "To access the EVE SDK, fill the form on this [page](https://huggingface.co/LatticeSemi/sensAI-Edge-Vision-Engine-SDK-Packages) and follow the instructions for download." - " For any questions or support, please reach out to us at evehelp@latticesemi.com.\n\n" - "You can also preview the EVE SDK with the following tabs:\n\n" - "- Live Inference to run it live from your webcam\n" - "- Offline Inference to test it with videos you can upload\n" - "- Use the Face ID Registration tab to register face(s) you can use in either Live or Offline Inference to test the Face ID model.\n\n" - "> Note: For demo purposes, execution of the AI pipeline and image draw operations are all performed on a Hugging Face CPU server. Performance may vary based on the number of concurrent users.\n" - "\n\n" - ) - - session_registry = gr.State(value={}) - session_hash_state = gr.State(value="unknown") - - with gr.Tabs() as tabs: - ( - _live_tab, - webrtc_stream, - (live_cb_face, live_cb_person, live_cb_face_id, live_cb_hand_gesture), - ) = build_live_inference_tab( - rtc_configuration=lambda: rtc_config_provider.get(), - feature_checkbox_builder=_build_feature_checkboxes, - extras_builder=lambda: face_id_tab.build_summary(height=80, scale=1), - max_fps=int(max_fps) if max_fps else 30, - width=camera_width, - height=camera_height, - ) - - ( - video_tab, - input_video, - output_video, - (cb_face, cb_person, cb_face_id, cb_hand_gesture), - process_btn, - example_dataset, - ) = build_offline_inference_tab( - feature_checkbox_builder=_build_feature_checkboxes, - example_videos=EXAMPLE_VIDEOS, - video_limits=VIDEO_LIMITS, - extras_builder=lambda: face_id_tab.build_summary(height=80, scale=1), - ) - patch_video_for_external_urls(output_video) - - face_id_tab.build() - - build_eula_tab() - - if os.environ.get("ENABLE_PROFILER", "").strip() not in ("", "0", "false"): - from profiler_tab import build_profiler_tab - - build_profiler_tab(pool) - - # --- Offline Inference wiring --- - wire_video_upload(input_video, output_video, process_btn, example_dataset, VIDEO_LIMITS) - - process_btn.click( - fn=handlers.run_eve_inference, - inputs=[ - input_video, - cb_face, - cb_person, - cb_face_id, - cb_hand_gesture, - session_registry, - ], - outputs=[output_video, session_registry], - concurrency_limit=pool.worker_count, - ).then( - fn=face_id_tab.refresh_all, - inputs=[session_registry], - outputs=face_id_tab.all_slot_components, - ) - - # --- Face ID wiring (self-contained in FaceIdTab) --- - face_id_tab.wire(session_registry) - - # Refresh summary thumbnails when switching to tabs that show them - for tab in (video_tab, _live_tab): - tab.select( - fn=face_id_tab.refresh_summary, - inputs=[session_registry], - outputs=face_id_tab.summary_components, - ) - - # --- Usage analytics --- - tabs.select(fn=session_tracker.on_tab_switch, inputs=[], outputs=[]) - - live_feature_inputs = [live_cb_face, live_cb_person, live_cb_face_id, live_cb_hand_gesture] - for cb in live_feature_inputs: - cb.change(fn=handlers.on_live_feature_change, inputs=live_feature_inputs, outputs=[]) - - # --- Live Inference wiring --- - # FastRTC defaults concurrency_limit to 1 which causes Gradio's queue - # to reject new WebRTC connections with "Too many concurrent connections". - # Since process_live_frame is non-blocking (shows an overlay while - # waiting for a worker), we allow MORE streams than workers so that - # queued users see a "waiting" overlay instead of a connection error. - webrtc_stream.stream( - fn=handlers.process_live_frame, - inputs=[ - webrtc_stream, - live_cb_face, - live_cb_person, - live_cb_face_id, - live_cb_hand_gesture, - session_registry, - session_hash_state, - ], - outputs=[webrtc_stream], - concurrency_limit=pool.worker_count + 8, - ) - - # --- Session tracking --- - demo.load(session_tracker.on_load, outputs=[session_hash_state]) - demo.unload(handlers.cleanup_session) - - if tracker.enabled: - gr.HTML( - "" - "This demo collects anonymous usage data (session activity, feature usage) " - "to improve the experience. No personal information is stored.
" - ) - - demo.queue() - demo.launch(server_name="0.0.0.0", server_port=7860, share=False) +import atexit +import os +import sys +from pathlib import Path + +import gradio as gr + +APP_DIR = Path(__file__).resolve().parent +sys.path.insert(0, str(APP_DIR.parent.parent / "shared")) +sys.path.insert(0, str(APP_DIR / "shared")) + +from env_utils import load_dotenv_if_present, require_secrets +from eula_tab import build_eula_tab +from eve_app_tabs import build_live_inference_tab, build_offline_inference_tab +from eve_inference_handlers import EveAppHandlers, patch_video_for_external_urls +from eve_worker_pool import EveWorkerPool +from face_id_tab import FaceIdTab +from live_inference import ( + TAB_SWITCH_AUTO_STOP_JS, + RtcConfigProvider, + patch_aioice_stun_transaction, + patch_aiortc_h264_nvenc, + patch_fastrtc_frame_queue, + patch_fastrtc_yuv420p_output, +) +from live_stream_manager import LiveStreamManager +from log_utils import log_cpu_info, setup_logger +from session_tracker import SessionTracker +from usage_analytics import UsageTracker +from video_file_server import VideoFileServer +from video_processing import VideoLimits, get_example_videos, wire_video_upload + + +def _build_feature_checkboxes( + hint: str = "", +) -> tuple[gr.Checkbox, gr.Checkbox, gr.Checkbox, gr.Checkbox]: + """Build the EVE feature checkbox group used by both tabs. + + Must be called inside a Gradio layout context. + """ + with gr.Group(): + label = "Features" + if hint: + label += f" — {hint}" + label += "
" + gr.HTML(label) + cb_face = gr.Checkbox(label="Face Detection", value=True) + cb_person = gr.Checkbox(label="Person Detection", value=True) + cb_face_id = gr.Checkbox(label="Face Identification", value=False) + cb_hand_gesture = gr.Checkbox(label="Hand Detection", value=False) + return cb_face, cb_person, cb_face_id, cb_hand_gesture + + +if __name__ == "__main__": + + patch_fastrtc_frame_queue() + patch_fastrtc_yuv420p_output() + patch_aioice_stun_transaction() + patch_aiortc_h264_nvenc() + + load_dotenv_if_present() + logger = setup_logger(name="app") + log_cpu_info(logger) + require_secrets("MODEL_ACCESS_TOKEN") + + tracker = UsageTracker( + repo_id=os.environ.get("ANALYTICS_REPO_ID", "LatticeSemi/PRIVATE-Demo-Analytics-v1.0"), + ) + tracker.log("server", "server_start") + + max_workers = int(os.environ.get("MAX_WORKERS", os.cpu_count())) + max_ram_gb = float(os.environ.get("MAX_RAM_GB", 32)) + pool = EveWorkerPool(max_workers=max_workers, max_ram_gb=max_ram_gb, ram_headroom_gb=2.0) + + # FPS cap: each live stream runs between MAX_TARGET_FPS (idle) and + # MIN_TARGET_FPS (full load). Set either to 0 to disable the cap. + max_fps_raw = float(os.environ.get("MAX_TARGET_FPS", "24")) + min_fps_raw = float(os.environ.get("MIN_TARGET_FPS", "15")) + max_fps: float | None = max_fps_raw if max_fps_raw > 0 else None + min_fps: float | None = min_fps_raw if min_fps_raw > 0 else None + + camera_width = int(os.environ.get("CAMERA_WIDTH", 640)) + camera_height = int(os.environ.get("CAMERA_HEIGHT", 360)) + + stream_manager = LiveStreamManager( + pool, + session_lifetime_seconds=60 * 4, + max_fps=max_fps, + min_fps=min_fps, + tracker=tracker, + ) + + session_tracker = SessionTracker(pool=pool, tracker=tracker, logger=logger) + + # Separate HTTP server for video output — bypasses Chrome's per-origin + # connection limit that blocks /file= requests while SSE connections are open. + video_server: VideoFileServer | None = None + # TODO: Put that under an env var, for debug purposes, locally, for more than 2 tabs. + """if not os.environ.get("SPACE_ID"): + gradio_cache = os.path.join(tempfile.gettempdir(), "gradio") + os.makedirs(gradio_cache, exist_ok=True) + video_server = VideoFileServer(root_dir=gradio_cache, logger=logger) + video_server.start()""" + + handlers = EveAppHandlers( + pool=pool, + stream_manager=stream_manager, + sessions=session_tracker, + logger=logger, + max_fps=max_fps, + min_fps=min_fps, + video_server=video_server, + ) + + def _shutdown() -> None: + session_tracker.shutdown() + stream_manager.shutdown() + tracker.log("server", "server_stop") + tracker.shutdown() + + atexit.register(_shutdown) + + EXAMPLE_VIDEOS = get_example_videos(str(APP_DIR / "examples")) + VIDEO_LIMITS = VideoLimits() + rtc_config_provider = RtcConfigProvider() + + face_id_tab = FaceIdTab( + pool, + max_users=2, + examples_dir=str(APP_DIR / "examples_fid"), + accept_video=True, + video_limits=VideoLimits(max_file_size_mb=150, max_duration_seconds=60), + tracker=tracker, + ) + + with gr.Blocks( + title="Eve HMI Demo", + theme=gr.themes.Default( + text_size=gr.themes.sizes.text_lg, + primary_hue=gr.themes.colors.yellow, + ), + css=( + f"#webrtc-stream-col {{ max-width: {camera_width}px !important; margin: 0 auto; }}" + " .gradio-container h1, .gradio-container .md h1 { font-size: 2.25rem !important; }" + " .gradio-container h2, .gradio-container .md h2 { font-size: 1.75rem !important; }" + " .gradio-container h3, .gradio-container .md h3 { font-size: 1.4rem !important; }" + " .gradio-container button[role='tab']," + " .gradio-container button[role='tab'] *" + " { text-decoration: underline !important; }" + " .gradio-container .tab-container {" + " height: auto !important;" + " overflow: visible !important;" + " gap: 4px !important;" + " border-bottom: 2px solid var(--border-color-primary) !important; }" + " .gradio-container .tab-container::after { display: none !important; }" + " .gradio-container button[role='tab'] {" + " height: auto !important;" + " padding: 10px 20px !important;" + " border: 1px solid var(--border-color-primary) !important;" + " border-bottom: none !important;" + " border-radius: 8px 8px 0 0 !important;" + " background: var(--background-fill-secondary) !important;" + " margin-bottom: -2px !important; }" + " .gradio-container button[role='tab'].selected {" + " background: var(--primary-500) !important;" + " color: var(--neutral-950) !important;" + " border-color: var(--primary-500) !important;" + " font-weight: 600 !important; }" + " .gradio-container button[role='tab'].selected::after { display: none !important; }" + ), + head=TAB_SWITCH_AUTO_STOP_JS, + ) as demo: + gr.Markdown("# Lattice sensAI Edge Vision Engine SDK") + gr.Markdown( + "Our SDK solves the human sensing challenges by outputting ready-to-use data." + " Our models have a low computation footprint and are ideal for 0.5-2 TOPS devices" + " like FPGAs, SOCs and small NPUs.\n\n" + # TODO: Insert performance summary table + "To access the EVE SDK, fill the form on this [page](https://huggingface.co/LatticeSemi/sensAI-Edge-Vision-Engine-SDK-Packages) and follow the instructions for download." + " For any questions or support, please reach out to us at evehelp@latticesemi.com.\n\n" + "You can also preview the EVE SDK with the following tabs:\n\n" + "- Live Inference to run it live from your webcam\n" + "- Offline Inference to test it with videos you can upload\n" + "- Use the Face ID Registration tab to register face(s) you can use in either Live or Offline Inference to test the Face ID model.\n\n" + "> Note: For demo purposes, execution of the AI pipeline and image draw operations are all performed on a Hugging Face CPU server. Performance may vary based on the number of concurrent users.\n" + "\n\n" + ) + + session_registry = gr.State(value={}) + session_hash_state = gr.State(value="unknown") + + with gr.Tabs() as tabs: + ( + _live_tab, + webrtc_stream, + (live_cb_face, live_cb_person, live_cb_face_id, live_cb_hand_gesture), + ) = build_live_inference_tab( + rtc_configuration=lambda: rtc_config_provider.get(), + feature_checkbox_builder=_build_feature_checkboxes, + extras_builder=lambda: face_id_tab.build_summary(height=80, scale=1), + max_fps=int(max_fps) if max_fps else 30, + width=camera_width, + height=camera_height, + ) + + ( + video_tab, + input_video, + output_video, + (cb_face, cb_person, cb_face_id, cb_hand_gesture), + process_btn, + example_dataset, + ) = build_offline_inference_tab( + feature_checkbox_builder=_build_feature_checkboxes, + example_videos=EXAMPLE_VIDEOS, + video_limits=VIDEO_LIMITS, + extras_builder=lambda: face_id_tab.build_summary(height=80, scale=1), + ) + patch_video_for_external_urls(output_video) + + face_id_tab.build() + + build_eula_tab() + + if os.environ.get("ENABLE_PROFILER", "").strip() not in ("", "0", "false"): + from profiler_tab import build_profiler_tab + + build_profiler_tab(pool) + + # --- Offline Inference wiring --- + wire_video_upload(input_video, output_video, process_btn, example_dataset, VIDEO_LIMITS) + + process_btn.click( + fn=handlers.run_eve_inference, + inputs=[ + input_video, + cb_face, + cb_person, + cb_face_id, + cb_hand_gesture, + session_registry, + ], + outputs=[output_video, session_registry], + concurrency_limit=pool.worker_count, + ).then( + fn=face_id_tab.refresh_all, + inputs=[session_registry], + outputs=face_id_tab.all_slot_components, + ) + + # --- Face ID wiring (self-contained in FaceIdTab) --- + face_id_tab.wire(session_registry) + + # Refresh summary thumbnails when switching to tabs that show them + for tab in (video_tab, _live_tab): + tab.select( + fn=face_id_tab.refresh_summary, + inputs=[session_registry], + outputs=face_id_tab.summary_components, + ) + + # --- Usage analytics --- + tabs.select(fn=session_tracker.on_tab_switch, inputs=[], outputs=[]) + + live_feature_inputs = [live_cb_face, live_cb_person, live_cb_face_id, live_cb_hand_gesture] + for cb in live_feature_inputs: + cb.change(fn=handlers.on_live_feature_change, inputs=live_feature_inputs, outputs=[]) + + # --- Live Inference wiring --- + # FastRTC defaults concurrency_limit to 1 which causes Gradio's queue + # to reject new WebRTC connections with "Too many concurrent connections". + # Since process_live_frame is non-blocking (shows an overlay while + # waiting for a worker), we allow MORE streams than workers so that + # queued users see a "waiting" overlay instead of a connection error. + webrtc_stream.stream( + fn=handlers.process_live_frame, + inputs=[ + webrtc_stream, + live_cb_face, + live_cb_person, + live_cb_face_id, + live_cb_hand_gesture, + session_registry, + session_hash_state, + ], + outputs=[webrtc_stream], + concurrency_limit=pool.worker_count + 8, + ) + + # --- Session tracking --- + demo.load(session_tracker.on_load, outputs=[session_hash_state]) + demo.unload(handlers.cleanup_session) + + if tracker.enabled: + gr.HTML( + "" + "This demo collects anonymous usage data (session activity, feature usage) " + "to improve the experience. No personal information is stored.
" + ) + + demo.queue() + demo.launch(server_name="0.0.0.0", server_port=7860, share=False) diff --git a/download_examples.py b/download_examples.py index bb44d8020d9483add30650f3472eb94a9bd30110..9535b9b8706f2d0686993e95e9359df001e45152 100644 --- a/download_examples.py +++ b/download_examples.py @@ -1,124 +1,124 @@ -"""Download example media from the LatticeSemi/Demo-Examples-v1.0 dataset. - -Runs at Docker build time (after ``COPY --chown=user . /app``) to populate the -demo's ``examples*/`` subfolders from the shared HF dataset. Mirrors the -dataset layout: every file under ``Use your webcam for real-time inference. " - "Select features below, then grant camera access when prompted.
" - ), -) -> tuple[gr.TabItem, object, TCheckboxes]: - """Build the Live Inference tab with feature checkboxes + WebRTC stream. - - Args: - rtc_configuration: ICE configuration dict, callable that returns - one, or ``None`` for direct connection. A callable is invoked - per-connection by FastRTC, allowing credential refresh. - feature_checkbox_builder: Callable that builds the demo's feature - checkboxes (same shape as in the offline tab). - extras_builder: Optional callable invoked after the WebRTC stream - for demo-specific widgets (e.g. Face ID summary). - max_fps: Maximum frame rate requested from the browser camera. - width / height: Camera frame dimensions in pixels. - tab_label: Tab label text. - description_html: Optional HTML shown above the stream. - - Returns: - ``(tab, webrtc_stream, checkboxes)``. - """ - with gr.TabItem(tab_label) as tab: - if description_html: - gr.HTML(description_html) - checkboxes = feature_checkbox_builder() - webrtc_stream = build_webrtc_stream( - rtc_configuration, max_fps=max_fps, width=width, height=height - ) - if extras_builder is not None: - extras_builder() - - return tab, webrtc_stream, checkboxes +"""Tab builders for EVE-based Gradio demos. + +Both tabs (Offline Inference, Live Inference) follow the same pattern: + +- Outer ``gr.TabItem`` with the demo-supplied label. +- Demo-specific feature checkboxes built via a caller-provided callable so + each demo defines its own feature set (Face Detection / Person / + Hand Detection / Face ID / …). +- Optional ``extras_builder`` hook for demo-specific extras inside the tab + (e.g. eve_hmi's Face ID summary thumbnails). + +The tab builders return the underlying components so the caller can wire +events (``process_btn.click``, ``webrtc_stream.stream``, etc.) outside. +""" + +from __future__ import annotations + +from dataclasses import dataclass +from typing import Callable, TypeVar + +import gradio as gr + +from live_inference import RtcConfigurationInput, build_webrtc_stream +from video_processing import VideoLimits, build_video_constraints_accordion + +# The exact tuple of Checkbox components is demo-specific. We let the +# caller's checkbox-builder define the shape and return it transparently. +TCheckboxes = TypeVar("TCheckboxes") + + +def build_offline_inference_tab( + *, + feature_checkbox_builder: Callable[..., TCheckboxes], + example_videos: list, + video_limits: VideoLimits, + extras_builder: Callable[[], None] | None = None, + tab_label: str = "Offline Inference", + feature_hint: str = "applied when processing starts", +) -> tuple[ + gr.TabItem, + gr.Video, + gr.Video, + TCheckboxes, + gr.Button, + gr.Dataset, +]: + """Build the Offline Inference tab. Must be called inside a ``gr.Tabs`` context. + + Args: + feature_checkbox_builder: Callable that builds the demo's feature + checkboxes inside the tab. Receives the keyword ``hint`` (a + short string shown next to the "Features" heading). Returns a + tuple of ``gr.Checkbox`` instances — the same tuple is returned + unchanged so the caller can wire events. + example_videos: Pre-loaded example videos (list of ``[path]`` rows). + video_limits: Upload constraints rendered in the accordion. + extras_builder: Optional callable invoked after the input/output + video columns to add demo-specific widgets (e.g. a Face ID + summary). Called inside the same row, so it shares horizontal + space with the videos. + tab_label: Tab label text (default ``"Offline Inference"``). + feature_hint: Short hint shown next to the Features heading. + + Returns: + ``(tab, input_video, output_video, checkboxes, process_btn, example_dataset)``. + ``checkboxes`` is exactly what ``feature_checkbox_builder`` returned. + """ + with gr.TabItem(tab_label) as video_tab: + with gr.Accordion("Instructions", open=False): + gr.Markdown( + "1. Select the features that will be processed on the video\n" + "2. Select a video (or upload your own in the Input Video frame)\n" + "3. Press the **Process Video** button\n\n" + "Once the video has been processed, you can play the video in the " + "Output Video frame" + ) + + checkboxes = feature_checkbox_builder(hint=feature_hint) + + with gr.Accordion("Video Examples", open=True): + example_dataset = gr.Dataset( + components=[gr.Video(visible=False)], + samples=example_videos, + show_label=False, + ) + + process_btn = gr.Button("Process Video", variant="primary", interactive=False) + + build_video_constraints_accordion(video_limits) + + with gr.Row(equal_height=True): + with gr.Column(scale=5): + input_video = gr.Video(label="Input Video", sources=["upload", "webcam"]) + with gr.Column(scale=5): + output_video = gr.Video(label="Output Video") + if extras_builder is not None: + extras_builder() + + return video_tab, input_video, output_video, checkboxes, process_btn, example_dataset + + +@dataclass +class ImageOrVideoOfflineTab: + """Components returned by :func:`build_image_or_video_offline_tab`. + + The image/video accordions are exposed so the caller can wire mutual + exclusion (expanding one collapses the other) — same pattern as + :class:`face_id_tab.FaceIdTab`. + """ + + tab: gr.TabItem + image_input: gr.Image + video_input: gr.Video + image_output: gr.Image + video_output: gr.Video + checkboxes: object # demo-specific (radio, checkbox tuple, etc.) + process_btn: gr.Button + image_example_dataset: gr.Dataset | None + video_example_dataset: gr.Dataset | None + image_accordion: gr.Accordion + video_accordion: gr.Accordion + + +def build_image_or_video_offline_tab( + *, + feature_checkbox_builder: Callable[..., TCheckboxes], + image_examples: list | None, + video_examples: list | None, + video_limits: VideoLimits, + tab_label: str = "Offline Inference", + feature_hint: str = "applied when processing starts", +) -> ImageOrVideoOfflineTab: + """Build an Offline Inference tab that accepts image OR video. + + Pattern: two mutually-exclusive accordions on the input side ("Input + from an Image" / "Input from a Video"), one Process button, two + output components (image + video) shown side-by-side. Caller is + responsible for: + + - Wiring ``image_accordion`` / ``video_accordion`` mutual exclusion + (one-liner per side, see ``face_id_tab.FaceIdTab.wire``). + - Routing ``process_btn.click`` to a handler that dispatches by + which input is populated. + - Toggling output visibility based on which branch ran. + + Args: + feature_checkbox_builder: Callable that builds the demo's feature + checkboxes/radio inside the tab. Called with keyword + ``hint=feature_hint``. + image_examples: Pre-loaded image examples (list of ``[path]`` + rows) or ``None`` to skip the examples accordion. + video_examples: Same for videos. + video_limits: Upload constraints rendered inside the video + accordion. + tab_label: Tab label text. + feature_hint: Short hint shown next to the Features heading. + """ + with gr.TabItem(tab_label) as tab: + with gr.Accordion("Instructions", open=False): + gr.Markdown( + "1. Select the model that will be used for object detection\n" + "2. Choose between processing an **Image** or a **Video**:\n" + " - For an image: select an example or upload your own, then press " + "**Process**.\n" + " - For a video: expand the video section, select an example or " + "upload your own, then press **Process**.\n\n" + "Once processing is complete, the annotated result appears on the " + "right (image or video, depending on the input)." + ) + + checkboxes = feature_checkbox_builder(hint=feature_hint) + + with gr.Row(): + # --- Left column: input --- + with gr.Column(scale=5): + image_example_dataset: gr.Dataset | None = None + video_example_dataset: gr.Dataset | None = None + + with gr.Accordion( + "Input from an Image", open=True + ) as image_accordion: + if image_examples: + with gr.Accordion("Image Examples", open=True): + image_example_dataset = gr.Dataset( + components=[gr.Image(visible=False)], + samples=image_examples, + show_label=False, + ) + image_input = gr.Image( + label="Input Image", + sources=["upload", "webcam"], + type="filepath", + ) + + with gr.Accordion( + "Input from a Video", open=False + ) as video_accordion: + if video_examples: + with gr.Accordion("Video Examples", open=True): + video_example_dataset = gr.Dataset( + components=[gr.Video(visible=False)], + samples=video_examples, + show_label=False, + ) + build_video_constraints_accordion(video_limits) + video_input = gr.Video( + label="Input Video", sources=["upload", "webcam"] + ) + + process_btn = gr.Button( + "Process", variant="primary", interactive=False + ) + + # --- Right column: output (image OR video, toggled by handler) --- + with gr.Column(scale=5): + image_output = gr.Image(label="Output Image", visible=True) + video_output = gr.Video(label="Output Video", visible=False) + + return ImageOrVideoOfflineTab( + tab=tab, + image_input=image_input, + video_input=video_input, + image_output=image_output, + video_output=video_output, + checkboxes=checkboxes, + process_btn=process_btn, + image_example_dataset=image_example_dataset, + video_example_dataset=video_example_dataset, + image_accordion=image_accordion, + video_accordion=video_accordion, + ) + + +def build_live_inference_tab( + *, + rtc_configuration: RtcConfigurationInput, + feature_checkbox_builder: Callable[..., TCheckboxes], + extras_builder: Callable[[], None] | None = None, + max_fps: int = 15, + width: int = 640, + height: int = 360, + tab_label: str = "Live Inference", + description_html: str = ( + "Use your webcam for real-time inference. " + "Select features below, then grant camera access when prompted.
" + ), +) -> tuple[gr.TabItem, object, TCheckboxes]: + """Build the Live Inference tab with feature checkboxes + WebRTC stream. + + Args: + rtc_configuration: ICE configuration dict, callable that returns + one, or ``None`` for direct connection. A callable is invoked + per-connection by FastRTC, allowing credential refresh. + feature_checkbox_builder: Callable that builds the demo's feature + checkboxes (same shape as in the offline tab). + extras_builder: Optional callable invoked after the WebRTC stream + for demo-specific widgets (e.g. Face ID summary). + max_fps: Maximum frame rate requested from the browser camera. + width / height: Camera frame dimensions in pixels. + tab_label: Tab label text. + description_html: Optional HTML shown above the stream. + + Returns: + ``(tab, webrtc_stream, checkboxes)``. + """ + with gr.TabItem(tab_label) as tab: + if description_html: + gr.HTML(description_html) + checkboxes = feature_checkbox_builder() + webrtc_stream = build_webrtc_stream( + rtc_configuration, max_fps=max_fps, width=width, height=height + ) + if extras_builder is not None: + extras_builder() + + return tab, webrtc_stream, checkboxes diff --git a/shared/eve_inference_handlers.py b/shared/eve_inference_handlers.py index 282777c4e4c2c1553242cf5f2eccad342406a451..b0f485286631e9365743706372a84f6ef1f1627a 100644 --- a/shared/eve_inference_handlers.py +++ b/shared/eve_inference_handlers.py @@ -1,485 +1,509 @@ -"""Offline + live inference handlers shared by EVE-based Gradio demos. - -The two main handlers (``run_eve_inference`` for the Offline Inference tab, -``process_live_frame`` for the Live Inference tab) used to live in -``eve_hmi/app.py``. They are bundled on an ``EveAppHandlers`` instance so -demos can wire them with one ``handlers = EveAppHandlers(...)`` line and -re-use them as Gradio callbacks. - -Face ID is opt-in: pass an empty / ``None`` ``registry`` and Face ID -behaviour is bypassed (gallery restore is skipped, the ``face_id`` flag -still travels through ``FeatureFlags`` so the EVE SDK can act on it). -""" - -from __future__ import annotations - -import logging -import os -import shutil -import tempfile -import threading -import time -import uuid -from typing import TYPE_CHECKING - -import cv2 -import gradio as gr -import numpy as np - -from eve_messages import FeatureFlags -from eve_worker_pool import log_worker_activity -from face_id_tab import FaceEntry # runtime import: Gradio resolves type hints at wire time -from frame_drawing import draw_countdown_banner, draw_overlay, draw_session_timer - -if TYPE_CHECKING: - from eve_worker_pool import EveWorkerPool - from live_stream_manager import LiveStreamManager - from session_tracker import SessionTracker - from video_file_server import VideoFileServer - - -def patch_video_for_external_urls(video_component: gr.Video) -> None: - """Patch a ``gr.Video`` so HTTP(S) URLs bypass Gradio's safehttpx download. - - Gradio's default postprocessing fetches HTTP URLs via ``safehttpx``, - which refuses localhost / private IPs. Setting both ``FileData.path`` - and ``FileData.url`` short-circuits the cache logic in - ``async_move_files_to_cache`` so the browser plays the URL directly. - """ - from gradio.components.video import VideoData - from gradio.data_classes import FileData - - original = video_component.postprocess - - def _postprocess(value): # type: ignore[no-untyped-def] - if isinstance(value, str) and value.startswith(("http://", "https://")): - return VideoData(video=FileData(path=value, url=value)) - return original(value) - - video_component.postprocess = _postprocess # type: ignore[assignment] - - -class EveAppHandlers: - """Gradio-callable handlers for EVE offline + live inference. - - Args: - pool: The shared worker pool. - stream_manager: ``LiveStreamManager`` driving WebRTC streams. - sessions: ``SessionTracker`` for analytics + idle reaping. - logger: Logger used for per-session log lines. - max_fps / min_fps: FPS bounds forwarded to ``send_process_video`` - (controls the worker-side encoding rate). - video_server: Optional local HTTP server for processed videos. - When set, processed clips are returned as URLs instead of raw - paths so Chrome's per-origin connection limit doesn't block - playback while SSE is open. - """ - - def __init__( - self, - pool: EveWorkerPool, - stream_manager: LiveStreamManager, - sessions: SessionTracker, - logger: logging.Logger, - max_fps: float | None, - min_fps: float | None, - video_server: VideoFileServer | None = None, - ) -> None: - self._pool = pool - self._stream = stream_manager - self._sessions = sessions - self._logger = logger - self._max_fps = max_fps - self._min_fps = min_fps - self._video_server = video_server - self._live_logged: set[str] = set() - self._live_logged_lock = threading.Lock() - - # ----- offline inference ------------------------------------------------- - - def run_eve_inference( - self, - input_video: str, - face_detection: bool, - person_detection: bool, - face_id: bool, - hand_gesture: bool, - registry: dict[int, FaceEntry] | None, - mod_model: str | None = None, - request: gr.Request | None = None, - progress: gr.Progress = gr.Progress(), - ) -> tuple[str | None, dict[int, FaceEntry]]: - """Process an uploaded video through one EVE worker, end-to-end. - - The whole read → infer → encode → write loop happens inside the - worker process so the asyncio event loop stays free for SSE - delivery. The main thread only forwards the path/config and - relays small progress dicts. - - Returns ``(output_url_or_path, registry)``. ``registry`` is - returned unchanged when Face ID is disabled, or with ``sdk_id`` - fields refreshed from the worker's gallery-restore results. - """ - registry = registry or {} - session = request.session_hash[:8] - self._sessions.track( - request.session_hash, - "video_process", - face_detection=face_detection, - person_detection=person_detection, - face_id=face_id, - hand_gesture=hand_gesture, - mod_model=mod_model, - ) - - fps, width, height, total_frames = _read_video_metadata(input_video) - if total_frames <= 0: - raise gr.Error("Could not read any frames from the video.") - - features = FeatureFlags( - face_detection=face_detection, - person_detection=person_detection, - face_id=face_id, - hand_gesture=hand_gesture, - mod_model=mod_model, - ) - - gallery_paths: list[str] = [] - remove_all_users = False - if face_id and registry: - gallery_paths = [entry.path for entry in registry.values()] - elif face_id: - remove_all_users = True - - # Write directly into Gradio's cache so postprocessing skips the - # expensive hash_file + shutil.copy2 that would block the asyncio - # event loop. - gradio_cache = os.path.join(tempfile.gettempdir(), "gradio") - session_out = os.path.join(gradio_cache, f"eve_{request.session_hash}") - os.makedirs(session_out, exist_ok=True) - output_path = os.path.join(session_out, f"output_{uuid.uuid4().hex[:8]}.mp4") - - self._logger.info(f"[{session}] run_eve_inference: waiting for worker...") - # Only emit queue events when we actually have to wait — matches the - # live queue behaviour so dashboards don't show phantom peaks. - will_wait = self._pool.idle_count == 0 - if will_wait: - self._sessions.track(request.session_hash, "offline_queue_enter") - t0 = time.monotonic() - worker = self._pool.acquire( - request.session_hash, - timeout=300.0, - progress=progress, - eta_fn=self._stream.estimated_wait, - ) - if will_wait: - self._sessions.track( - request.session_hash, - "offline_queue_exit", - wait_seconds=round(time.monotonic() - t0, 1), - ) - log_worker_activity( - self._logger, "acquired", "video-processing", self._pool, worker.worker_id - ) - try: - frames_processed, gallery_results = worker.send_process_video( - input_path=input_video, - output_path=output_path, - features=features, - gallery_paths=gallery_paths, - remove_all_users=remove_all_users, - fps=fps, - width=width, - height=height, - total_frames=total_frames, - progress=progress, - max_fps=self._max_fps, - min_fps=self._min_fps, - ) - self._logger.info( - f"[{session}] run_eve_inference: done, {frames_processed} frames processed" - ) - finally: - self._pool.release(worker) - log_worker_activity( - self._logger, "released", "video-processing", self._pool, worker.worker_id - ) - self._sessions.track( - request.session_hash, - "video_process_complete", - duration_seconds=round(time.monotonic() - t0, 1), - ) - - if gallery_results: - for entry, r in zip(registry.values(), gallery_results): - entry.sdk_id = r.user_id if r.success else None - - if self._video_server is not None: - rel_path = os.path.relpath(output_path, gradio_cache) - video_result: str | None = self._video_server.build_url(rel_path, request) - else: - video_result = output_path - - return video_result, registry - - # ----- offline image inference ------------------------------------------- - - def run_eve_image_inference( - self, - input_image: str | None, - face_detection: bool, - person_detection: bool, - face_id: bool, - hand_gesture: bool, - registry: dict[int, FaceEntry] | None, - mod_model: str | None = None, - request: gr.Request | None = None, - progress: gr.Progress = gr.Progress(), - ) -> tuple[np.ndarray | None, dict[int, FaceEntry]]: - """Run a single image through one EVE worker, end-to-end. - - Single-frame variant of :meth:`run_eve_inference`. Loads the image - as BGR, sends one ``InferenceCmd`` to the worker (the same path - that powers live inference), and returns the annotated result as - an RGB ``np.ndarray`` ready for ``gr.Image``. - - Returns ``(annotated_image_rgb_or_None, registry)``. Registry is - returned unchanged — single-image inference does not refresh - Face ID gallery state. - """ - if not input_image: - raise gr.Error("Please upload an image.") - - registry = registry or {} - session = request.session_hash[:8] if request is not None else "?" - if request is not None: - self._sessions.track( - request.session_hash, - "image_process", - face_detection=face_detection, - person_detection=person_detection, - face_id=face_id, - hand_gesture=hand_gesture, - mod_model=mod_model, - ) - - frame = cv2.imread(input_image) - if frame is None: - raise gr.Error(f"Could not read image: {input_image}") - - features = FeatureFlags( - face_detection=face_detection, - person_detection=person_detection, - face_id=face_id, - hand_gesture=hand_gesture, - mod_model=mod_model, - ) - - self._logger.info(f"[{session}] run_eve_image_inference: waiting for worker...") - will_wait = self._pool.idle_count == 0 - if will_wait and request is not None: - self._sessions.track(request.session_hash, "offline_queue_enter") - t0 = time.monotonic() - worker = self._pool.acquire( - request.session_hash if request is not None else "image", - timeout=300.0, - progress=progress, - eta_fn=self._stream.estimated_wait, - ) - if will_wait and request is not None: - self._sessions.track( - request.session_hash, - "offline_queue_exit", - wait_seconds=round(time.monotonic() - t0, 1), - ) - log_worker_activity( - self._logger, "acquired", "image-processing", self._pool, worker.worker_id - ) - try: - result = worker.send_inference(frame, features) - self._logger.info(f"[{session}] run_eve_image_inference: done") - finally: - self._pool.release(worker) - log_worker_activity( - self._logger, "released", "image-processing", self._pool, worker.worker_id - ) - if request is not None: - self._sessions.track( - request.session_hash, - "image_process_complete", - duration_seconds=round(time.monotonic() - t0, 1), - ) - - # Worker returns BGR (matches live-inference frame format); Gradio's - # gr.Image expects RGB. - result_rgb = cv2.cvtColor(result, cv2.COLOR_BGR2RGB) - return result_rgb, registry - - # ----- live inference ---------------------------------------------------- - - def process_live_frame( - self, - frame: np.ndarray, - face_detection: bool, - person_detection: bool, - face_id: bool, - hand_gesture: bool, - registry: dict[int, FaceEntry] | None, - session_hash: str, - mod_model: str | None = None, - ): - # Return type intentionally unannotated: actual return is - # ``np.ndarray | fastrtc.CloseStream | None`` but ``CloseStream`` is - # only imported lazily inside the function (avoids pulling fastrtc - # into module scope), and Gradio/FastRTC may run ``get_type_hints`` - # on bound handlers — a forward-ref string would break that. - """Run a single WebRTC frame through an EVE worker. - - A worker is acquired on the first frame and held for the lifetime of - the stream. Returns the frame with an overlay while waiting for a - worker, or a ``CloseStream`` when the session ends so the UI can - reset to ``Start Inference``. - - ``gr.Request`` is not available inside FastRTC stream handlers, so - the Gradio session hash is passed through ``gr.State``. FastRTC's - per-connection ``webrtc_id`` is still pulled from - ``current_context`` to track worker assignment per peer. - """ - if frame is None: - return None - - from fastrtc.utils import current_context - - connection_id = current_context.get().webrtc_id - worker, reason = self._stream.get_or_acquire(connection_id, session_hash, registry or {}) - if worker is None: - if reason == "waiting": - pos, total = self._stream.waiting_position(connection_id) - eta = self._stream.estimated_wait(pos) - eta_text = "" - if eta is not None: - eta_mins = max(0.5, round(eta / 30) * 0.5) - eta_text = f"\nest. wait ~{eta_mins:g} minutes" - if total > 1: - return draw_overlay(frame, f"In queue {eta_text}") - return draw_overlay(frame, f"Waiting for available worker...{eta_text}") - with self._live_logged_lock: - self._live_logged.discard(connection_id) - from fastrtc import CloseStream - - return CloseStream(reason or "Stream ended") - - bridge = self._stream.get_bridge(connection_id) - if bridge is None or not bridge.is_alive: - self._stream.release(connection_id) - return draw_overlay(frame, "Inference error - retrying...") - - with self._live_logged_lock: - first_frame = connection_id not in self._live_logged - if first_frame: - self._live_logged.add(connection_id) - if first_frame: - self._sessions.track( - session_hash, - "live_start", - face_detection=face_detection, - person_detection=person_detection, - face_id=face_id, - hand_gesture=hand_gesture, - mod_model=mod_model, - ) - - features = FeatureFlags( - face_detection=face_detection, - person_detection=person_detection, - face_id=face_id, - hand_gesture=hand_gesture, - mod_model=mod_model, - ) - try: - result = bridge.submit_and_get_latest(frame, features) - if result is None: - # First frame — no inference result yet, show camera feed - return frame - - remaining = self._stream.countdown_remaining(connection_id) - if remaining is not None: - secs = int(remaining) + 1 - result = draw_countdown_banner(result, f"Other users waiting - stopping in {secs}s") - - session_left = self._stream.session_remaining(connection_id) - if session_left is not None: - result = draw_session_timer(result, session_left) - - return result - except (BrokenPipeError, EOFError, OSError): - # Worker pipe is gone (shutdown or crash) — release quietly - self._stream.release(connection_id) - return None - except Exception as exc: - self._logger.error(f"Live inference error: {exc}") - self._stream.release(connection_id) - return draw_overlay(frame, "Inference error - retrying...") - - def on_live_feature_change( - self, - face_detection: bool, - person_detection: bool, - face_id: bool, - hand_gesture: bool, - mod_model: str | None = None, - request: gr.Request | None = None, - ) -> None: - """Track changes to the Live tab's feature checkboxes.""" - self._sessions.track( - request.session_hash, - "live_feature_change", - face_detection=face_detection, - person_detection=person_detection, - face_id=face_id, - hand_gesture=hand_gesture, - mod_model=mod_model, - ) - - # ----- session cleanup --------------------------------------------------- - - def cleanup_session(self, request: gr.Request) -> None: - """Gradio ``demo.unload`` handler — close the session + delete cache.""" - self._sessions.on_unload(request) - - gradio_cache = os.path.join(tempfile.gettempdir(), "gradio") - session_out = os.path.join(gradio_cache, f"eve_{request.session_hash}") - if os.path.isdir(session_out): - shutil.rmtree(session_out, ignore_errors=True) - self._logger.debug(f"Session cleanup: removed {session_out}") - - -def _read_video_metadata(path: str) -> tuple[float, int, int, int]: - """Return ``(fps, width, height, total_frames)`` for a video file. - - Webcam-recorded WebM blobs frequently lie in their headers (fps=0, - fps=1000 from ms timestamps, or no frame count) so we fall back to a - full decode pass when the headers look implausible. - """ - cap = cv2.VideoCapture(path) - fps = cap.get(cv2.CAP_PROP_FPS) - width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) - height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) - total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) - - if fps <= 0 or fps > 240 or total_frames <= 0 or width <= 0 or height <= 0: - frame_count = 0 - duration_ms = 0.0 - while True: - ret, frame = cap.read() - if not ret: - break - if frame_count == 0: - height, width = frame.shape[:2] - frame_count += 1 - duration_ms = cap.get(cv2.CAP_PROP_POS_MSEC) - total_frames = frame_count - if fps <= 0 or fps > 240: - fps = total_frames / (duration_ms / 1000.0) if duration_ms > 0 else 30.0 - cap.release() - return fps, width, height, total_frames +"""Offline + live inference handlers shared by EVE-based Gradio demos. + +The two main handlers (``run_eve_inference`` for the Offline Inference tab, +``process_live_frame`` for the Live Inference tab) used to live in +``eve_hmi/app.py``. They are bundled on an ``EveAppHandlers`` instance so +demos can wire them with one ``handlers = EveAppHandlers(...)`` line and +re-use them as Gradio callbacks. + +Face ID is opt-in: pass an empty / ``None`` ``registry`` and Face ID +behaviour is bypassed (gallery restore is skipped, the ``face_id`` flag +still travels through ``FeatureFlags`` so the EVE SDK can act on it). +""" + +from __future__ import annotations + +import logging +import os +import shutil +import tempfile +import threading +import time +import uuid +from collections.abc import Mapping +from typing import TYPE_CHECKING + +import cv2 +import gradio as gr +import numpy as np +from eve_messages import FeatureFlags, ModelConfig +from eve_worker_pool import log_worker_activity +from face_id_tab import ( + FaceEntry, # runtime import: Gradio resolves type hints at wire time +) +from frame_drawing import draw_countdown_banner, draw_overlay, draw_session_timer + +if TYPE_CHECKING: + from eve_worker_pool import EveWorkerPool + from live_stream_manager import LiveStreamManager + from session_tracker import SessionTracker + from video_file_server import VideoFileServer + + +def patch_video_for_external_urls(video_component: gr.Video) -> None: + """Patch a ``gr.Video`` so HTTP(S) URLs bypass Gradio's safehttpx download. + + Gradio's default postprocessing fetches HTTP URLs via ``safehttpx``, + which refuses localhost / private IPs. Setting both ``FileData.path`` + and ``FileData.url`` short-circuits the cache logic in + ``async_move_files_to_cache`` so the browser plays the URL directly. + """ + from gradio.components.video import VideoData + from gradio.data_classes import FileData + + original = video_component.postprocess + + def _postprocess(value): # type: ignore[no-untyped-def] + if isinstance(value, str) and value.startswith(("http://", "https://")): + return VideoData(video=FileData(path=value, url=value)) + return original(value) + + video_component.postprocess = _postprocess # type: ignore[assignment] + + +class EveAppHandlers: + """Gradio-callable handlers for EVE offline + live inference. + + Args: + pool: The shared worker pool. + stream_manager: ``LiveStreamManager`` driving WebRTC streams. + sessions: ``SessionTracker`` for analytics + idle reaping. + logger: Logger used for per-session log lines. + max_fps / min_fps: FPS bounds forwarded to ``send_process_video`` + (controls the worker-side encoding rate). + video_server: Optional local HTTP server for processed videos. + When set, processed clips are returned as URLs instead of raw + paths so Chrome's per-origin connection limit doesn't block + playback while SSE is open. + mod_model_registry: Maps a model-name string (the value carried by a + demo's MOD radio) to the ``ModelConfig`` the worker should load. + Demos that do not use MOD (e.g. eve_hmi) omit it; in that case a + model name resolves to ``None`` and MOD stays off. + """ + + def __init__( + self, + pool: EveWorkerPool, + stream_manager: LiveStreamManager, + sessions: SessionTracker, + logger: logging.Logger, + max_fps: float | None, + min_fps: float | None, + video_server: VideoFileServer | None = None, + mod_model_registry: Mapping[str, ModelConfig] | None = None, + ) -> None: + self._pool = pool + self._stream = stream_manager + self._sessions = sessions + self._logger = logger + self._max_fps = max_fps + self._min_fps = min_fps + self._video_server = video_server + self._mod_model_registry = mod_model_registry or {} + self._live_logged: set[str] = set() + self._live_logged_lock = threading.Lock() + + def _resolve_mod_model(self, mod_model: str | None) -> ModelConfig | None: + """Resolve a MOD radio value to the ``ModelConfig`` the worker loads. + + ``None`` / empty (MOD off, or a demo with no MOD radio) yields + ``None``. An unknown name with no registry entry falls back to a + bare ``ModelConfig`` (no path) so the SDK's bundled default model is + used rather than failing. + """ + if not mod_model: + return None + config = self._mod_model_registry.get(mod_model) + if config is None: + self._logger.warning(f"Unknown MOD model {mod_model!r}; using bundled default") + return ModelConfig(name=mod_model) + return config + + # ----- offline inference ------------------------------------------------- + + def run_eve_inference( + self, + input_video: str, + face_detection: bool, + person_detection: bool, + face_id: bool, + hand_gesture: bool, + registry: dict[int, FaceEntry] | None, + mod_model: str | None = None, + request: gr.Request | None = None, + progress: gr.Progress = gr.Progress(), + ) -> tuple[str | None, dict[int, FaceEntry]]: + """Process an uploaded video through one EVE worker, end-to-end. + + The whole read → infer → encode → write loop happens inside the + worker process so the asyncio event loop stays free for SSE + delivery. The main thread only forwards the path/config and + relays small progress dicts. + + Returns ``(output_url_or_path, registry)``. ``registry`` is + returned unchanged when Face ID is disabled, or with ``sdk_id`` + fields refreshed from the worker's gallery-restore results. + """ + registry = registry or {} + session = request.session_hash[:8] + self._sessions.track( + request.session_hash, + "video_process", + face_detection=face_detection, + person_detection=person_detection, + face_id=face_id, + hand_gesture=hand_gesture, + mod_model=mod_model, + ) + + fps, width, height, total_frames = _read_video_metadata(input_video) + if total_frames <= 0: + raise gr.Error("Could not read any frames from the video.") + + features = FeatureFlags( + face_detection=face_detection, + person_detection=person_detection, + face_id=face_id, + hand_gesture=hand_gesture, + mod_model_config=self._resolve_mod_model(mod_model), + ) + + gallery_paths: list[str] = [] + remove_all_users = False + if face_id and registry: + gallery_paths = [entry.path for entry in registry.values()] + elif face_id: + remove_all_users = True + + # Write directly into Gradio's cache so postprocessing skips the + # expensive hash_file + shutil.copy2 that would block the asyncio + # event loop. + gradio_cache = os.path.join(tempfile.gettempdir(), "gradio") + session_out = os.path.join(gradio_cache, f"eve_{request.session_hash}") + os.makedirs(session_out, exist_ok=True) + output_path = os.path.join(session_out, f"output_{uuid.uuid4().hex[:8]}.mp4") + + self._logger.info(f"[{session}] run_eve_inference: waiting for worker...") + # Only emit queue events when we actually have to wait — matches the + # live queue behaviour so dashboards don't show phantom peaks. + will_wait = self._pool.idle_count == 0 + if will_wait: + self._sessions.track(request.session_hash, "offline_queue_enter") + t0 = time.monotonic() + worker = self._pool.acquire( + request.session_hash, + timeout=300.0, + progress=progress, + eta_fn=self._stream.estimated_wait, + ) + if will_wait: + self._sessions.track( + request.session_hash, + "offline_queue_exit", + wait_seconds=round(time.monotonic() - t0, 1), + ) + log_worker_activity( + self._logger, "acquired", "video-processing", self._pool, worker.worker_id + ) + try: + frames_processed, gallery_results = worker.send_process_video( + input_path=input_video, + output_path=output_path, + features=features, + gallery_paths=gallery_paths, + remove_all_users=remove_all_users, + fps=fps, + width=width, + height=height, + total_frames=total_frames, + progress=progress, + max_fps=self._max_fps, + min_fps=self._min_fps, + ) + self._logger.info( + f"[{session}] run_eve_inference: done, {frames_processed} frames processed" + ) + finally: + self._pool.release(worker) + log_worker_activity( + self._logger, "released", "video-processing", self._pool, worker.worker_id + ) + self._sessions.track( + request.session_hash, + "video_process_complete", + duration_seconds=round(time.monotonic() - t0, 1), + ) + + if gallery_results: + for entry, r in zip(registry.values(), gallery_results): + entry.sdk_id = r.user_id if r.success else None + + if self._video_server is not None: + rel_path = os.path.relpath(output_path, gradio_cache) + video_result: str | None = self._video_server.build_url(rel_path, request) + else: + video_result = output_path + + return video_result, registry + + # ----- offline image inference ------------------------------------------- + + def run_eve_image_inference( + self, + input_image: str | None, + face_detection: bool, + person_detection: bool, + face_id: bool, + hand_gesture: bool, + registry: dict[int, FaceEntry] | None, + mod_model: str | None = None, + request: gr.Request | None = None, + progress: gr.Progress = gr.Progress(), + ) -> tuple[np.ndarray | None, dict[int, FaceEntry]]: + """Run a single image through one EVE worker, end-to-end. + + Single-frame variant of :meth:`run_eve_inference`. Loads the image + as BGR, sends one ``InferenceCmd`` to the worker (the same path + that powers live inference), and returns the annotated result as + an RGB ``np.ndarray`` ready for ``gr.Image``. + + Returns ``(annotated_image_rgb_or_None, registry)``. Registry is + returned unchanged — single-image inference does not refresh + Face ID gallery state. + """ + if not input_image: + raise gr.Error("Please upload an image.") + + registry = registry or {} + session = request.session_hash[:8] if request is not None else "?" + if request is not None: + self._sessions.track( + request.session_hash, + "image_process", + face_detection=face_detection, + person_detection=person_detection, + face_id=face_id, + hand_gesture=hand_gesture, + mod_model=mod_model, + ) + + frame = cv2.imread(input_image) + if frame is None: + raise gr.Error(f"Could not read image: {input_image}") + + features = FeatureFlags( + face_detection=face_detection, + person_detection=person_detection, + face_id=face_id, + hand_gesture=hand_gesture, + mod_model_config=self._resolve_mod_model(mod_model), + ) + + self._logger.info(f"[{session}] run_eve_image_inference: waiting for worker...") + will_wait = self._pool.idle_count == 0 + if will_wait and request is not None: + self._sessions.track(request.session_hash, "offline_queue_enter") + t0 = time.monotonic() + worker = self._pool.acquire( + request.session_hash if request is not None else "image", + timeout=300.0, + progress=progress, + eta_fn=self._stream.estimated_wait, + ) + if will_wait and request is not None: + self._sessions.track( + request.session_hash, + "offline_queue_exit", + wait_seconds=round(time.monotonic() - t0, 1), + ) + log_worker_activity( + self._logger, "acquired", "image-processing", self._pool, worker.worker_id + ) + try: + result = worker.send_inference(frame, features) + self._logger.info(f"[{session}] run_eve_image_inference: done") + finally: + self._pool.release(worker) + log_worker_activity( + self._logger, "released", "image-processing", self._pool, worker.worker_id + ) + if request is not None: + self._sessions.track( + request.session_hash, + "image_process_complete", + duration_seconds=round(time.monotonic() - t0, 1), + ) + + # Worker returns BGR (matches live-inference frame format); Gradio's + # gr.Image expects RGB. + result_rgb = cv2.cvtColor(result, cv2.COLOR_BGR2RGB) + return result_rgb, registry + + # ----- live inference ---------------------------------------------------- + + def process_live_frame( + self, + frame: np.ndarray, + face_detection: bool, + person_detection: bool, + face_id: bool, + hand_gesture: bool, + registry: dict[int, FaceEntry] | None, + session_hash: str, + mod_model: str | None = None, + ): + # Return type intentionally unannotated: actual return is + # ``np.ndarray | fastrtc.CloseStream | None`` but ``CloseStream`` is + # only imported lazily inside the function (avoids pulling fastrtc + # into module scope), and Gradio/FastRTC may run ``get_type_hints`` + # on bound handlers — a forward-ref string would break that. + """Run a single WebRTC frame through an EVE worker. + + A worker is acquired on the first frame and held for the lifetime of + the stream. Returns the frame with an overlay while waiting for a + worker, or a ``CloseStream`` when the session ends so the UI can + reset to ``Start Inference``. + + ``gr.Request`` is not available inside FastRTC stream handlers, so + the Gradio session hash is passed through ``gr.State``. FastRTC's + per-connection ``webrtc_id`` is still pulled from + ``current_context`` to track worker assignment per peer. + """ + if frame is None: + return None + + from fastrtc.utils import current_context + + connection_id = current_context.get().webrtc_id + worker, reason = self._stream.get_or_acquire(connection_id, session_hash, registry or {}) + if worker is None: + if reason == "waiting": + pos, total = self._stream.waiting_position(connection_id) + eta = self._stream.estimated_wait(pos) + eta_text = "" + if eta is not None: + eta_mins = max(0.5, round(eta / 30) * 0.5) + eta_text = f"\nest. wait ~{eta_mins:g} minutes" + if total > 1: + return draw_overlay(frame, f"In queue {eta_text}") + return draw_overlay(frame, f"Waiting for available worker...{eta_text}") + with self._live_logged_lock: + self._live_logged.discard(connection_id) + from fastrtc import CloseStream + + return CloseStream(reason or "Stream ended") + + bridge = self._stream.get_bridge(connection_id) + if bridge is None or not bridge.is_alive: + self._stream.release(connection_id) + return draw_overlay(frame, "Inference error - retrying...") + + with self._live_logged_lock: + first_frame = connection_id not in self._live_logged + if first_frame: + self._live_logged.add(connection_id) + if first_frame: + self._sessions.track( + session_hash, + "live_start", + face_detection=face_detection, + person_detection=person_detection, + face_id=face_id, + hand_gesture=hand_gesture, + mod_model=mod_model, + ) + + features = FeatureFlags( + face_detection=face_detection, + person_detection=person_detection, + face_id=face_id, + hand_gesture=hand_gesture, + mod_model_config=self._resolve_mod_model(mod_model), + ) + try: + result = bridge.submit_and_get_latest(frame, features) + if result is None: + # First frame — no inference result yet, show camera feed + return frame + + remaining = self._stream.countdown_remaining(connection_id) + if remaining is not None: + secs = int(remaining) + 1 + result = draw_countdown_banner(result, f"Other users waiting - stopping in {secs}s") + + session_left = self._stream.session_remaining(connection_id) + if session_left is not None: + result = draw_session_timer(result, session_left) + + return result + except (BrokenPipeError, EOFError, OSError): + # Worker pipe is gone (shutdown or crash) — release quietly + self._stream.release(connection_id) + return None + except Exception as exc: + self._logger.error(f"Live inference error: {exc}") + self._stream.release(connection_id) + return draw_overlay(frame, "Inference error - retrying...") + + def on_live_feature_change( + self, + face_detection: bool, + person_detection: bool, + face_id: bool, + hand_gesture: bool, + mod_model: str | None = None, + request: gr.Request | None = None, + ) -> None: + """Track changes to the Live tab's feature checkboxes.""" + self._sessions.track( + request.session_hash, + "live_feature_change", + face_detection=face_detection, + person_detection=person_detection, + face_id=face_id, + hand_gesture=hand_gesture, + mod_model=mod_model, + ) + + # ----- session cleanup --------------------------------------------------- + + def cleanup_session(self, request: gr.Request) -> None: + """Gradio ``demo.unload`` handler — close the session + delete cache.""" + self._sessions.on_unload(request) + + gradio_cache = os.path.join(tempfile.gettempdir(), "gradio") + session_out = os.path.join(gradio_cache, f"eve_{request.session_hash}") + if os.path.isdir(session_out): + shutil.rmtree(session_out, ignore_errors=True) + self._logger.debug(f"Session cleanup: removed {session_out}") + + +def _read_video_metadata(path: str) -> tuple[float, int, int, int]: + """Return ``(fps, width, height, total_frames)`` for a video file. + + Webcam-recorded WebM blobs frequently lie in their headers (fps=0, + fps=1000 from ms timestamps, or no frame count) so we fall back to a + full decode pass when the headers look implausible. + """ + cap = cv2.VideoCapture(path) + fps = cap.get(cv2.CAP_PROP_FPS) + width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) + + if fps <= 0 or fps > 240 or total_frames <= 0 or width <= 0 or height <= 0: + frame_count = 0 + duration_ms = 0.0 + while True: + ret, frame = cap.read() + if not ret: + break + if frame_count == 0: + height, width = frame.shape[:2] + frame_count += 1 + duration_ms = cap.get(cv2.CAP_PROP_POS_MSEC) + total_frames = frame_count + if fps <= 0 or fps > 240: + fps = total_frames / (duration_ms / 1000.0) if duration_ms > 0 else 30.0 + cap.release() + return fps, width, height, total_frames diff --git a/shared/eve_messages.py b/shared/eve_messages.py index 5525e0da530129675d748b7ba7b7318b2f6d16cb..634eda55efcf07eba46d6fda5682ca30394ae9d0 100644 --- a/shared/eve_messages.py +++ b/shared/eve_messages.py @@ -1,231 +1,257 @@ -"""IPC message dataclasses for the Eve worker pool. - -All types are picklable and sent over ``multiprocessing.Pipe`` between the -main Gradio process and Eve SDK worker processes. -""" - -from dataclasses import dataclass - -# --------------------------------------------------------------------------- -# Shared data types -# --------------------------------------------------------------------------- - - -@dataclass -class CalibrationResultMsg: - """Picklable mirror of ``eve_wrapper.CalibrationResult``.""" - - success: bool - user_id: int - message: str - - -@dataclass -class FeatureFlags: - """Feature toggle bundle sent with inference / configure commands.""" - - face_detection: bool = True - person_detection: bool = True - face_id: bool = False - hand_gesture: bool = False - # None = MOD off. Otherwise a model-name string (e.g. "GMOD-80", - # "AMOD-8", "OMOD") that the worker resolves to the EVE SDK MOD model. - # Defaulted so existing demos keep their pickle shape unchanged. - mod_model: str | None = None - - -@dataclass -class SerializedFrame: - """Picklable representation of a numpy ndarray frame.""" - - data: bytes - shape: tuple[int, ...] - dtype: str - - -# --------------------------------------------------------------------------- -# Commands (main process → worker process) -# --------------------------------------------------------------------------- - - -@dataclass -class InferenceCmd: - frame_bytes: bytes - shape: tuple[int, ...] - dtype: str - features: FeatureFlags - - -@dataclass -class ConfigureFeaturesCmd: - features: FeatureFlags - - -@dataclass -class CalibrateNewUserCmd: - frames_data: list[SerializedFrame] - - -@dataclass -class RemoveAllUsersCmd: - pass - - -@dataclass -class RestoreGalleryCmd: - frames_per_user_data: list[list[SerializedFrame]] - - -@dataclass -class EnableFaceIdCmd: - enabled: bool - - -@dataclass -class ProcessVideoCmd: - input_path: str - output_path: str - features: FeatureFlags - gallery_paths: list[str] - remove_all_users: bool - fps: float - width: int - height: int - total_frames: int - max_fps: float | None = None - min_fps: float | None = None - - -@dataclass -class ShutdownCmd: - pass - - -@dataclass -class StartProfilingCmd: - pass - - -@dataclass -class StopProfilingCmd: - pass - - -@dataclass -class GetProfileStatsCmd: - pass - - -@dataclass -class GetTimingStatsCmd: - reset: bool = True - - -WorkerCmd = ( - InferenceCmd - | ConfigureFeaturesCmd - | CalibrateNewUserCmd - | RemoveAllUsersCmd - | RestoreGalleryCmd - | EnableFaceIdCmd - | ProcessVideoCmd - | ShutdownCmd - | StartProfilingCmd - | StopProfilingCmd - | GetProfileStatsCmd - | GetTimingStatsCmd -) - - -# --------------------------------------------------------------------------- -# Responses (worker process → main process) -# --------------------------------------------------------------------------- - - -@dataclass -class ReadyResponse: - pid: int - - -@dataclass -class ErrorResponse: - error: str - - -@dataclass -class HeartbeatResponse: - pass - - -@dataclass -class OkResponse: - pass - - -@dataclass -class InferenceResponse: - frame_bytes: bytes - shape: tuple[int, ...] - dtype: str - - -@dataclass -class CalibrateOkResponse: - result: CalibrationResultMsg - - -@dataclass -class RemoveUsersOkResponse: - result: bool - - -@dataclass -class RestoreGalleryOkResponse: - results: list[CalibrationResultMsg] - - -@dataclass -class GalleryRestoredResponse: - results: list[CalibrationResultMsg] - - -@dataclass -class ProgressResponse: - current: int - total: int - - -@dataclass -class VideoProcessingDoneResponse: - frames_processed: int - gallery_results: list[CalibrationResultMsg] - recycle: bool - - -@dataclass -class ProfileStatsResponse: - stats_data: bytes # marshalled pstats data - - -@dataclass -class TimingStatsResponse: - """Per-SDK-call timing data from EveWrapper.""" - - stats: dict[str, tuple[int, float]] # {name: (call_count, total_seconds)} - - -WorkerResponse = ( - ReadyResponse - | ErrorResponse - | HeartbeatResponse - | OkResponse - | InferenceResponse - | CalibrateOkResponse - | RemoveUsersOkResponse - | RestoreGalleryOkResponse - | GalleryRestoredResponse - | ProgressResponse - | VideoProcessingDoneResponse - | ProfileStatsResponse - | TimingStatsResponse -) +"""IPC message dataclasses for the Eve worker pool. + +All types are picklable and sent over ``multiprocessing.Pipe`` between the +main Gradio process and Eve SDK worker processes. +""" + +from dataclasses import dataclass + +# --------------------------------------------------------------------------- +# Shared data types +# --------------------------------------------------------------------------- + + +@dataclass +class CalibrationResultMsg: + """Picklable mirror of ``eve_wrapper.CalibrationResult``.""" + + success: bool + user_id: int + message: str + + +@dataclass +class ModelConfig: + """Resolved EVE object-detection (MOD) model description. + + Carries everything ``eve_wrapper.enable_object_detection`` needs to + configure one MOD model. ``model_path`` of ``None`` / ``""`` selects the + EVE SDK's bundled default model (GMOD-80); a path loads that ``.tflite`` + and applies ``class_names``. ``None`` thresholds fall back to the SDK + defaults. Picklable so it can ride inside ``FeatureFlags`` to a worker. + + Attributes: + name: Human-facing model name (e.g. ``"AMOD-8"``); used for logging. + model_path: Absolute path to the model file, or ``None`` for bundled. + class_names: Ordered class labels matching the model's output indices, + or ``None`` to keep the SDK's default class table. + nms_threshold: Optional non-max-suppression score threshold override. + iou_threshold: Optional IoU threshold override. + """ + + name: str + model_path: str | None = None + class_names: tuple[str, ...] | None = None + nms_threshold: float | None = None + iou_threshold: float | None = None + + +@dataclass +class FeatureFlags: + """Feature toggle bundle sent with inference / configure commands.""" + + face_detection: bool = True + person_detection: bool = True + face_id: bool = False + hand_gesture: bool = False + # None = MOD off. Otherwise the resolved MOD model the worker should load. + # Defaulted so demos that don't use MOD (e.g. eve_hmi) keep their pickle + # shape unchanged. + mod_model_config: ModelConfig | None = None + + +@dataclass +class SerializedFrame: + """Picklable representation of a numpy ndarray frame.""" + + data: bytes + shape: tuple[int, ...] + dtype: str + + +# --------------------------------------------------------------------------- +# Commands (main process → worker process) +# --------------------------------------------------------------------------- + + +@dataclass +class InferenceCmd: + frame_bytes: bytes + shape: tuple[int, ...] + dtype: str + features: FeatureFlags + + +@dataclass +class ConfigureFeaturesCmd: + features: FeatureFlags + + +@dataclass +class CalibrateNewUserCmd: + frames_data: list[SerializedFrame] + + +@dataclass +class RemoveAllUsersCmd: + pass + + +@dataclass +class RestoreGalleryCmd: + frames_per_user_data: list[list[SerializedFrame]] + + +@dataclass +class EnableFaceIdCmd: + enabled: bool + + +@dataclass +class ProcessVideoCmd: + input_path: str + output_path: str + features: FeatureFlags + gallery_paths: list[str] + remove_all_users: bool + fps: float + width: int + height: int + total_frames: int + max_fps: float | None = None + min_fps: float | None = None + + +@dataclass +class ShutdownCmd: + pass + + +@dataclass +class StartProfilingCmd: + pass + + +@dataclass +class StopProfilingCmd: + pass + + +@dataclass +class GetProfileStatsCmd: + pass + + +@dataclass +class GetTimingStatsCmd: + reset: bool = True + + +WorkerCmd = ( + InferenceCmd + | ConfigureFeaturesCmd + | CalibrateNewUserCmd + | RemoveAllUsersCmd + | RestoreGalleryCmd + | EnableFaceIdCmd + | ProcessVideoCmd + | ShutdownCmd + | StartProfilingCmd + | StopProfilingCmd + | GetProfileStatsCmd + | GetTimingStatsCmd +) + + +# --------------------------------------------------------------------------- +# Responses (worker process → main process) +# --------------------------------------------------------------------------- + + +@dataclass +class ReadyResponse: + pid: int + + +@dataclass +class ErrorResponse: + error: str + + +@dataclass +class HeartbeatResponse: + pass + + +@dataclass +class OkResponse: + pass + + +@dataclass +class InferenceResponse: + frame_bytes: bytes + shape: tuple[int, ...] + dtype: str + + +@dataclass +class CalibrateOkResponse: + result: CalibrationResultMsg + + +@dataclass +class RemoveUsersOkResponse: + result: bool + + +@dataclass +class RestoreGalleryOkResponse: + results: list[CalibrationResultMsg] + + +@dataclass +class GalleryRestoredResponse: + results: list[CalibrationResultMsg] + + +@dataclass +class ProgressResponse: + current: int + total: int + + +@dataclass +class VideoProcessingDoneResponse: + frames_processed: int + gallery_results: list[CalibrationResultMsg] + recycle: bool + + +@dataclass +class ProfileStatsResponse: + stats_data: bytes # marshalled pstats data + + +@dataclass +class TimingStatsResponse: + """Per-SDK-call timing data from EveWrapper.""" + + stats: dict[str, tuple[int, float]] # {name: (call_count, total_seconds)} + + +WorkerResponse = ( + ReadyResponse + | ErrorResponse + | HeartbeatResponse + | OkResponse + | InferenceResponse + | CalibrateOkResponse + | RemoveUsersOkResponse + | RestoreGalleryOkResponse + | GalleryRestoredResponse + | ProgressResponse + | VideoProcessingDoneResponse + | ProfileStatsResponse + | TimingStatsResponse +) diff --git a/shared/eve_python/ctypes_enum.py b/shared/eve_python/ctypes_enum.py new file mode 100644 index 0000000000000000000000000000000000000000..d764ee18bb82e3f2d1af7b504aaf384be07d7693 --- /dev/null +++ b/shared/eve_python/ctypes_enum.py @@ -0,0 +1,10 @@ +from enum import IntEnum + + +# Taken from https://v4.chriskrycho.com/2015/ctypes-structures-and-dll-exports.html +class CtypesEnum(IntEnum): + """A ctypes-compatible IntEnum superclass.""" + + @classmethod + def from_param(cls, obj): + return int(obj) diff --git a/shared/eve_python/eve_sdk.py b/shared/eve_python/eve_sdk.py index 8cc118a96fc94c95f3e8389cf79cf10a644af8f9..d25a5925e87700a8f75f16b34b6ac90942ec354e 100644 --- a/shared/eve_python/eve_sdk.py +++ b/shared/eve_python/eve_sdk.py @@ -1,297 +1,388 @@ -import ctypes -from . import eve_sdk_structs as structs - -EveProcessingCallbackFn = ctypes.CFUNCTYPE(None, ctypes.POINTER(structs.EveProcessingCallbackReturnData)) - -class EveSDK: - def __init__(self, dll_path: str): - self.cdll = ctypes.CDLL(dll_path) - # EveCameraApi.h - self.cdll.EveGetFormats.restype = structs.EveCameraFormats - self.cdll.EveGetFormats.argtypes = [ctypes.c_uint, structs.CCameraFormat] - self.cdll.EveGetCamera.restype = structs.EveCamera - self.cdll.EveGetCamera.argtypes = [ctypes.c_uint] - self.cdll.EveSetCamera.restype = structs.EveError - self.cdll.EveSetCamera.argtypes = [ctypes.c_uint, structs.CCameraFormat] - # EveControlInterface.h - self.cdll.CreateEve.restype = structs.EveError - self.cdll.CreateEve.argtypes = [structs.EveStartupParameters] - self.cdll.EveRegisterDataCallback.restype = structs.EveError - self.cdll.EveRegisterDataCallback.argtypes = [EveProcessingCallbackFn] - self.cdll.StartEve.restype = structs.EveError - self.cdll.StartEve.argtypes = [] - self.cdll.StartEveWithParameters.restype = structs.EveError - self.cdll.StartEveWithParameters.argtypes = [structs.EveProcessingParameters] - self.cdll.EveSendImageForProcessing.restype = structs.EveError - self.cdll.EveSendImageForProcessing.argtypes = [structs.EveInputImage] - self.cdll.EveSendImageForProcessingWithParams.restype = structs.EveError - self.cdll.EveSendImageForProcessingWithParams.argtypes = [structs.EveInputImage, structs.CCameraParameters] - self.cdll.ShutdownEve.restype = structs.EveError - self.cdll.ShutdownEve.argtypes = [] - - # EveKarolinska.h - self.cdll.EveConfigureKarolinska.restype = structs.EveKarolinskaOptions - self.cdll.EveConfigureKarolinska.argtypes = [structs.EveKarolinskaOptions] - - self.cdll.EveGetKarolinskaData.restype = structs.EveKarolinskaData - self.cdll.EveGetKarolinskaData.argtypes = [] - - # EveFaceId.h - self.cdll.EveConfigureFaceId.restype = structs.EveFaceIdOptions - self.cdll.EveConfigureFaceId.argtypes = [structs.EveFaceIdOptions] - self.cdll.EveFaceIdCalibrateCurrent.restype = structs.EveError - self.cdll.EveFaceIdCalibrateCurrent.argtypes = [] - self.cdll.EveFaceIdCalibrateNew.restype = structs.EveError - self.cdll.EveFaceIdCalibrateNew.argtypes = [] - self.cdll.EveFaceIdForceIdentify.restype = structs.EveError - self.cdll.EveFaceIdForceIdentify.argtypes = [] - self.cdll.EveFaceIdRemoveCurrent.restype = structs.EveError - self.cdll.EveFaceIdRemoveCurrent.argtypes = [] - self.cdll.EveFaceIdRemoveAll.restype = structs.EveError - self.cdll.EveFaceIdRemoveAll.argtypes = [] - self.cdll.EveFaceIdReloadGallery.restype = structs.EveError - self.cdll.EveFaceIdReloadGallery.argtypes = [] - self.cdll.EveFaceIdCommandWaiting.restype = ctypes.c_uint - self.cdll.EveFaceIdCommandWaiting.argtypes = [] - self.cdll.EveGetFaceIdData.restype = structs.EveFaceIdData - self.cdll.EveGetFaceIdData.argtypes = [] - self.cdll.EveSendFaceIdCommand.restype = structs.EveFaceIdCommandStruct - self.cdll.EveSendFaceIdCommand.argtypes = [structs.EveFaceIdCommandStruct] - # EveFaceTracker.h - self.cdll.EveConfigureFaceTracker.restype = structs.EveFaceTrackerOptions - self.cdll.EveConfigureFaceTracker.argtypes = [structs.EveFaceTrackerOptions] - self.cdll.EveGetAllFaceData.restype = structs.EveAllFacesData - self.cdll.EveGetAllFaceData.argtypes = [] - # EveFpga.h - self.cdll.EveConfigureFpga.restype = structs.EveFpgaOptions - self.cdll.EveConfigureFpga.argtypes = [structs.EveFpgaOptions] - self.cdll.EveConfigureFpgaDebug.restype = structs.EveFpgaDebugOptions - self.cdll.EveConfigureFpgaDebug.argtypes = [structs.EveFpgaDebugOptions] - self.cdll.QueryFpgaSetting.restype = structs.EveError - self.cdll.QueryFpgaSetting.argtypes = [structs.pipeline_config_t, ctypes.c_bool] - self.cdll.QueryFpgaSettings.restype = structs.EveError - self.cdll.QueryFpgaSettings.argtypes = [ctypes.c_uint16, ctypes.c_uint32, ctypes.c_bool] - self.cdll.SendSetSetting.restype = structs.EveError - self.cdll.SendSetSetting.argtypes = [structs.pipeline_config_t] - self.cdll.PopQueuedSetting.restype = structs.CFpgaGetSetting - self.cdll.PopQueuedSetting.argtypes = [] - self.cdll.EveGetFpgaData.restype = structs.EveFpgaData - self.cdll.EveGetFpgaData.argtypes = [] - self.cdll.FpgaReadJson.restype = structs.EveFpgaJsonMetadata - self.cdll.FpgaReadJson.argtypes = [] - self.cdll.EveSendImageForProcessingWithFpgaData.restype = structs.EveError - self.cdll.EveSendImageForProcessingWithFpgaData.argtypes = [structs.EveInputImage, structs.EveFpgaManualData] - - # EveImageManipulation.h - self.cdll.EveConfigureImageManipulation.restype = structs.EveImageManipulationOptions - self.cdll.EveConfigureImageManipulation.argtypes = [structs.EveImageManipulationOptions] - - # EveImage.h - self.cdll.EveGetProcessedImage.restype = structs.EveProcessedImage - self.cdll.EveGetProcessedImage.argtypes = [] - self.cdll.EveGetProcessedFrameTime.restype = structs.EveProcessedFrameTime - self.cdll.EveGetProcessedFrameTime.argtypes = [] - self.cdll.EveConfigureProcessedImage.restype = structs.EveImageFormatRequest - self.cdll.EveConfigureProcessedImage.argtypes = [structs.EveImageFormatRequest] - - # EveObjectDetection.h - self.cdll.EveConfigureObjectDetection.restype = structs.EveObjectDetectionOptions - self.cdll.EveConfigureObjectDetection.argtypes = [] - self.cdll.EveConfigurePersonDetection.restype = structs.EvePersonDetectionOptions - self.cdll.EveConfigurePersonDetection.argtypes = [] - self.cdll.EveGetObjectDetectionData.restype = structs.EveDetectionData - self.cdll.EveGetObjectDetectionData.argtypes = [] - self.cdll.EveCopyObjectDetectionData.restype = structs.EveDetectionData - self.cdll.EveCopyObjectDetectionData.argtypes = [] - self.cdll.EveGetPersonDetectionData.restype = structs.EveDetectionData - self.cdll.EveGetPersonDetectionData.argtypes = [] - self.cdll.EveCopyPersonDetectionData.restype = structs.EveDetectionData - self.cdll.EveCopyPersonDetectionData.argtypes = [] - self.cdll.DeleteDetectionData.restype = structs.EveError - self.cdll.DeleteDetectionData.argtypes = [structs.EveDetectionData] - # EveROI.h - self.cdll.EveConfigureROIs.restype = structs.EveROIOptions - self.cdll.EveConfigureROIs.argtypes = [structs.EveROIOptions] - self.cdll.EveGetROIScoreData.restype = structs.EveROIScoreData - self.cdll.EveGetROIScoreData.argtypes = [] - # EveHandGesture.h - self.cdll.EveConfigureHandGesture.restype = structs.EveHandGestureOptions - self.cdll.EveConfigureHandGesture.argtypes = [structs.EveHandGestureOptions] - self.cdll.EveGetHandGestureData.restype = structs.EveHandGestureData - self.cdll.EveGetHandGestureData.argtypes = [] - self.cdll.EveCopyHandGestureData.restype = structs.EveHandGestureData - self.cdll.EveCopyHandGestureData.argtypes = [] - self.cdll.EveDeleteHandGestureData.restype = structs.EveError - self.cdll.EveDeleteHandGestureData.argtypes = [structs.EveHandGestureData] - self.cdll.EveGetStaticGestureDetections.restype = structs.EveStaticGestureData - self.cdll.EveGetStaticGestureDetections.argtypes = [] - self.cdll.EveGetDynamicGestureDetections.restype = structs.EveDynamicGestureData - self.cdll.EveGetDynamicGestureDetections.argtypes = [] - - - # EveCamera.h - def EveGetFormats(self, cameraId: ctypes.c_uint, filter: structs.CCameraFormat) -> structs.EveCameraFormats: - return self.cdll.EveGetFormats(cameraId, filter) - - def EveGetCamera(self, cameraId: ctypes.c_uint) -> structs.EveCamera: - return self.cdll.EveGetCamera(cameraId) - - def EveSetCamera(self, cameraId: ctypes.c_uint, filter: structs.CCameraFormat) -> structs.EveError: - return self.cdll.EveSetCamera(cameraId, filter) - - # EveControlInterface.h - def CreateEve(self, options: structs.EveStartupParameters) -> structs.EveError: - return self.cdll.CreateEve(options) - - def EveRegisterDataCallback(self, callback) -> structs.EveError: - return self.cdll.EveRegisterDataCallback(callback) - - def StartEve(self) -> structs.EveError: - return self.cdll.StartEve() - - def StartEveWithParameters(self, parameters: structs.EveProcessingParameters) -> structs.EveError: - return self.cdll.StartEveWithParameters(parameters) - - def EveSendImageForProcessing(self, image: structs.EveInputImage) -> structs.EveError: - return self.cdll.EveSendImageForProcessing(image) - - def EveSendImageForProcessingWithParams(self, image: structs.EveInputImage, params: structs.CCameraParameters) -> structs.EveError: - return self.cdll.EveSendImageForProcessingWithParams(image, params) - - def EveSendFpgaDataManually(self, image: structs.EveFpgaManualData) -> structs.EveError: - return self.cdll.EveSendFpgaDataManually(image) - - def ShutdownEve(self) -> structs.EveError: - return self.cdll.ShutdownEve() - - # EveFaceId.h - def EveConfigureFaceId(self, options: structs.EveFaceIdOptions) -> structs.EveFaceIdOptions: - return self.cdll.EveConfigureFaceId(options) - - def EveFaceIdCalibrateCurrent(self) -> structs.EveError: - return self.cdll.EveFaceIdCalibrateCurrent() - - def EveFaceIdCalibrateNew(self) -> structs.EveError: - return self.cdll.EveFaceIdCalibrateNew() - - def EveFaceIdForceIdentify(self) -> structs.EveError: - return self.cdll.EveFaceIdForceIdentify() - - def EveFaceIdRemoveCurrent(self) -> structs.EveError: - return self.cdll.EveFaceIdRemoveCurrent() - - def EveFaceIdRemoveAll(self) -> structs.EveError: - return self.cdll.EveFaceIdRemoveAll() - - def EveFaceIdReloadGallery(self) -> structs.EveError: - return self.cdll.EveFaceIdReloadGallery() - - def EveFaceIdCommandWaiting(self) -> ctypes.c_uint: - return self.cdll.EveFaceIdCommandWaiting() - - def EveGetFaceIdData(self) -> structs.EveFaceIdData: - return self.cdll.EveGetFaceIdData() - - def EveSendFaceIdCommand(self, command: structs.EveFaceIdCommandStruct) -> structs.EveFaceIdCommandStruct: - return self.cdll.EveSendFaceIdCommand(command) - - # EveFaceTracker.h - def EveConfigureFaceTracker(self, options: structs.EveFaceTrackerOptions) -> structs.EveFaceTrackerOptions: - return self.cdll.EveConfigureFaceTracker(options) - - def EveGetAllFaceData(self) -> structs.EveAllFacesData: - return self.cdll.EveGetAllFaceData() - - # EveFpga.h - def EveGetFpgaData(self) -> structs.EveFpgaData: - return self.cdll.EveGetFpgaData() - - def EveConfigureFpga(self, options: structs.EveFpgaOptions) -> structs.EveFpgaOptions: - return self.cdll.EveConfigureFpga(options) - - def EveConfigureFpgaDebug(self, options: structs.EveFpgaDebugOptions) -> structs.EveFpgaDebugOptions: - return self.cdll.EveConfigureFpgaDebug(options) - - def QueryFpgaSetting(self, command: structs.pipeline_config_t, notify: ctypes.c_bool) -> structs.EveError: - return self.cdll.QueryFpgaSetting(command, notify) - - def QueryFpgaSettings(self, typeMask: ctypes.c_uint16, settingsMask: ctypes.c_uint32, notify: ctypes.c_bool) -> structs.EveError: - return self.cdll.QueryFpgaSettings(typeMask, settingsMask, notify) - - def SendSetSetting(self, command: structs.pipeline_config_t) -> structs.EveError: - return self.cdll.SendSetSetting(command) - - def PopQueuedSetting(self) -> structs.CFpgaGetSetting: - return self.cdll.PopQueuedSetting() - - def FpgaReadJson(self) -> structs.EveFpgaJsonMetadata: - return self.cdll.FpgaReadJson() - - # EveKarolinksa.h - def EveConfigureKarolinska(self, parameters: structs.EveKarolinskaOptions) -> structs.EveKarolinskaOptions: - return self.cdll.EveConfigureKarolinska(parameters) - - def EveGetKarolinskaData(self) -> structs.EveKarolinskaData: - return self.cdll.EveGetKarolinskaData() - - # EveImageManipulation.h - def EveConfigureImageManipulation(self, options: structs.EveImageManipulationOptions) -> structs.EveImageManipulationOptions: - return self.cdll.EveConfigureImageManipulation(options) - - # EveImage.h - def EveGetProcessedImage(self) -> structs.EveProcessedImage: - return self.cdll.EveGetProcessedImage() - - def EveGetProcessedFrameTime(self) -> structs.EveProcessedFrameTime: - return self.cdll.EveGetProcessedFrameTime() - - def EveConfigureProcessedImage(self, fmt: structs.EveImageFormatRequest) -> structs.EveProcessedFrameTime: - return self.cdll.EveConfigureProcessedImage(fmt) - - # EveObjectDetection.h - def EveConfigureObjectDetection(self, enabled: structs.EveObjectDetectionOptions) -> structs.EveObjectDetectionOptions: - return self.cdll.EveConfigureObjectDetection(enabled) - - def EveConfigurePersonDetection(self, enabled: structs.EvePersonDetectionOptions) -> structs.EvePersonDetectionOptions: - return self.cdll.EveConfigurePersonDetection(enabled) - - def EveGetObjectDetectionData(self) -> structs.EveDetectionData: - return self.cdll.EveGetObjectDetectionData() - - def EveCopyObjectDetectionData(self) -> structs.EveDetectionData: - return self.cdll.EveCopyObjectDetectionData() - - def EveGetPersonDetectionData(self) -> structs.EveDetectionData: - return self.cdll.EveGetPersonDetectionData() - - def EveCopyPersonDetectionData(self) -> structs.EveDetectionData: - return self.cdll.EveCopyPersonDetectionData() - - def DeleteDetectionData(self, data: structs.EveDetectionData) -> structs.EveError: - return self.cdll.DeleteDetectionData(data) - - # EveROI.h - def EveConfigureROIs(self, options: structs.EveROIOptions) -> structs.EveError: - return self.cdll.EveConfigureROIs(options) - - def EveGetROIScoreData(self) -> structs.EveROIScoreData: - return self.cdll.EveGetROIScoreData() - - # EveHandGesture.h - def EveConfigureHandGesture(self, options: structs.EveHandGestureOptions) -> structs.EveHandGestureOptions: - return self.cdll.EveConfigureHandGesture(options) - - def EveGetHandGestureData(self) -> structs.EveHandGestureData: - return self.cdll.EveGetHandGestureData() - - def EveCopyHandGestureData(self) -> structs.EveHandGestureData: - return self.cdll.EveGetHandGestureData() - - def EveDeleteHandGestureData(self, data: structs.EveHandGestureData) -> structs.EveError: - return self.cdll.EveGetHandGestureData(data) - - def EveGetStaticGestureDetections(self) -> structs.EveStaticGestureData: - return self.cdll.EveGetStaticGestureDetections() - - def EveGetDynamicGestureDetections(self) -> structs.EveDynamicGestureData: - return self.cdll.EveGetDynamicGestureDetections() \ No newline at end of file +import ctypes + +from . import eve_sdk_structs as structs + +EveProcessingCallbackFn = ctypes.CFUNCTYPE(None, ctypes.POINTER(structs.EveProcessingCallbackReturnData)) + +class EveSDK: + def __init__(self, dll_path: str): + self.cdll = ctypes.CDLL(dll_path) + # EveCamera.h + self.cdll.EveGetFormats.restype = structs.EveCameraFormats + self.cdll.EveGetFormats.argtypes = [ctypes.c_uint, structs.CCameraFormat] + self.cdll.EveGetCamera.restype = structs.EveCamera + self.cdll.EveGetCamera.argtypes = [ctypes.c_uint] + self.cdll.EveSetCamera.restype = structs.EveError + self.cdll.EveSetCamera.argtypes = [ctypes.c_uint, structs.CCameraFormat] + self.cdll.EveGetNumberOfCameras.restype = structs.EveNumberOfCameras + self.cdll.EveGetNumberOfCameras.argtypes = [] + self.cdll.EveGetMonitors.restype = structs.EveMonitors + self.cdll.EveGetMonitors.argtypes = [] + self.cdll.EveChangeCameraLocation.restype = structs.EveCameraLocation + self.cdll.EveChangeCameraLocation.argtypes = [structs.EveCameraLocation] + self.cdll.EveGetLiveCameraParameters.restype = structs.EveCameraParameters + self.cdll.EveGetLiveCameraParameters.argtypes = [] + # EveControlInterface.h + self.cdll.CreateEve.restype = structs.EveError + self.cdll.CreateEve.argtypes = [structs.EveStartupParameters] + self.cdll.EveRegisterDataCallback.restype = structs.EveError + self.cdll.EveRegisterDataCallback.argtypes = [EveProcessingCallbackFn] + self.cdll.StartEve.restype = structs.EveError + self.cdll.StartEve.argtypes = [] + self.cdll.StartEveWithParameters.restype = structs.EveError + self.cdll.StartEveWithParameters.argtypes = [structs.EveProcessingParameters] + self.cdll.EveSendImageForProcessing.restype = structs.EveError + self.cdll.EveSendImageForProcessing.argtypes = [structs.EveInputImage] + self.cdll.EveSendImageForProcessingWithParams.restype = structs.EveError + self.cdll.EveSendImageForProcessingWithParams.argtypes = [structs.EveInputImage, structs.CCameraParameters] + self.cdll.ShutdownEve.restype = structs.EveError + self.cdll.ShutdownEve.argtypes = [] + self.cdll.EveCheckForLicense.restype = structs.EveLicenseResult + self.cdll.EveCheckForLicense.argtypes = [] + self.cdll.EveResetPipeline.restype = structs.EveError + self.cdll.EveResetPipeline.argtypes = [] + + # EveKarolinska.h + self.cdll.EveConfigureKarolinska.restype = structs.EveKarolinskaOptions + self.cdll.EveConfigureKarolinska.argtypes = [structs.EveKarolinskaOptions] + + self.cdll.EveGetKarolinskaData.restype = structs.EveKarolinskaData + self.cdll.EveGetKarolinskaData.argtypes = [] + + # EveFaceId.h + self.cdll.EveConfigureFaceId.restype = structs.EveFaceIdOptions + self.cdll.EveConfigureFaceId.argtypes = [structs.EveFaceIdOptions] + self.cdll.EveFaceIdCalibrateCurrent.restype = structs.EveError + self.cdll.EveFaceIdCalibrateCurrent.argtypes = [] + self.cdll.EveFaceIdCalibrateNew.restype = structs.EveError + self.cdll.EveFaceIdCalibrateNew.argtypes = [] + self.cdll.EveFaceIdForceIdentify.restype = structs.EveError + self.cdll.EveFaceIdForceIdentify.argtypes = [] + self.cdll.EveFaceIdRemoveCurrent.restype = structs.EveError + self.cdll.EveFaceIdRemoveCurrent.argtypes = [] + self.cdll.EveFaceIdRemoveAll.restype = structs.EveError + self.cdll.EveFaceIdRemoveAll.argtypes = [] + self.cdll.EveFaceIdReloadGallery.restype = structs.EveError + self.cdll.EveFaceIdReloadGallery.argtypes = [] + self.cdll.EveFaceIdCommandWaiting.restype = ctypes.c_uint + self.cdll.EveFaceIdCommandWaiting.argtypes = [] + self.cdll.EveGetFaceIdData.restype = structs.EveFaceIdData + self.cdll.EveGetFaceIdData.argtypes = [] + self.cdll.EveSendFaceIdCommand.restype = structs.EveFaceIdCommandStruct + self.cdll.EveSendFaceIdCommand.argtypes = [structs.EveFaceIdCommandStruct] + # EveFaceTracker.h + self.cdll.EveConfigureFaceTracker.restype = structs.EveFaceTrackerOptions + self.cdll.EveConfigureFaceTracker.argtypes = [structs.EveFaceTrackerOptions] + self.cdll.EveGetEyesData.restype = structs.EveEyes + self.cdll.EveGetEyesData.argtypes = [] + self.cdll.EveGetPupilsData.restype = structs.EvePupils + self.cdll.EveGetPupilsData.argtypes = [] + self.cdll.EveGetAllFaceData.restype = structs.EveAllFacesData + self.cdll.EveGetAllFaceData.argtypes = [] + # EveFpga.h + self.cdll.EveConfigureFpga.restype = structs.EveFpgaOptions + self.cdll.EveConfigureFpga.argtypes = [structs.EveFpgaOptions] + self.cdll.EveConfigureFpgaDebug.restype = structs.EveFpgaDebugOptions + self.cdll.EveConfigureFpgaDebug.argtypes = [structs.EveFpgaDebugOptions] + self.cdll.QueryFpgaSetting.restype = structs.EveError + self.cdll.QueryFpgaSetting.argtypes = [structs.pipeline_config_t, ctypes.c_bool] + self.cdll.QueryFpgaSettings.restype = structs.EveError + self.cdll.QueryFpgaSettings.argtypes = [ctypes.c_uint16, ctypes.c_uint32, ctypes.c_bool] + self.cdll.SendSetSetting.restype = structs.EveError + self.cdll.SendSetSetting.argtypes = [structs.pipeline_config_t] + self.cdll.PopQueuedSetting.restype = structs.CFpgaGetSetting + self.cdll.PopQueuedSetting.argtypes = [] + self.cdll.EveGetFpgaData.restype = structs.EveFpgaData + self.cdll.EveGetFpgaData.argtypes = [] + self.cdll.FpgaReadJson.restype = structs.EveFpgaJsonMetadata + self.cdll.FpgaReadJson.argtypes = [] + self.cdll.FpgaReadData.restype = structs.EveFpgaData + self.cdll.FpgaReadData.argtypes = [] + self.cdll.EveSendImageForProcessingWithFpgaData.restype = structs.EveError + self.cdll.EveSendImageForProcessingWithFpgaData.argtypes = [structs.EveInputImage, structs.EveFpgaManualData] + + # EveImageManipulation.h + self.cdll.EveConfigureImageManipulation.restype = structs.EveImageManipulationOptions + self.cdll.EveConfigureImageManipulation.argtypes = [structs.EveImageManipulationOptions] + + # EveImage.h + self.cdll.EveGetProcessedImage.restype = structs.EveProcessedImage + self.cdll.EveGetProcessedImage.argtypes = [] + self.cdll.EveGetProcessedFrameTime.restype = structs.EveProcessedFrameTime + self.cdll.EveGetProcessedFrameTime.argtypes = [] + self.cdll.EveConfigureProcessedImage.restype = structs.EveImageFormatRequest + self.cdll.EveConfigureProcessedImage.argtypes = [structs.EveImageFormatRequest] + self.cdll.EveConfigureRawImage.restype = structs.EveRawImageRequest + self.cdll.EveConfigureRawImage.argtypes = [structs.EveRawImageRequest] + self.cdll.EveGetRawImage.restype = structs.EveProcessedImage + self.cdll.EveGetRawImage.argtypes = [] + self.cdll.EveGetJsonData.restype = structs.EveJsonData + self.cdll.EveGetJsonData.argtypes = [] + + # EveObjectDetection.h + self.cdll.EveConfigureObjectDetection.restype = structs.EveObjectDetectionOptions + self.cdll.EveConfigureObjectDetection.argtypes = [structs.EveObjectDetectionOptions] + self.cdll.EveGetDefaultObjectDetectionOptions.restype = structs.EveObjectDetectionOptions + self.cdll.EveGetDefaultObjectDetectionOptions.argtypes = [] + self.cdll.EveConfigurePersonDetection.restype = structs.EvePersonDetectionOptions + self.cdll.EveConfigurePersonDetection.argtypes = [structs.EvePersonDetectionOptions] + self.cdll.EveGetObjectDetectionData.restype = structs.EveDetectionData + self.cdll.EveGetObjectDetectionData.argtypes = [] + self.cdll.EveCopyObjectDetectionData.restype = structs.EveDetectionData + self.cdll.EveCopyObjectDetectionData.argtypes = [] + self.cdll.EveGetPersonDetectionData.restype = structs.EveDetectionData + self.cdll.EveGetPersonDetectionData.argtypes = [] + self.cdll.EveCopyPersonDetectionData.restype = structs.EveDetectionData + self.cdll.EveCopyPersonDetectionData.argtypes = [] + self.cdll.DeleteDetectionData.restype = structs.EveError + self.cdll.DeleteDetectionData.argtypes = [structs.EveDetectionData] + # EveROI.h + self.cdll.EveConfigureROIs.restype = structs.EveROIOptions + self.cdll.EveConfigureROIs.argtypes = [structs.EveROIOptions] + self.cdll.EveGetROIScoreData.restype = structs.EveROIScoreData + self.cdll.EveGetROIScoreData.argtypes = [] + # EveHandGesture.h + self.cdll.EveConfigureHandGesture.restype = structs.EveHandGestureOptions + self.cdll.EveConfigureHandGesture.argtypes = [structs.EveHandGestureOptions] + self.cdll.EveGetHandGestureData.restype = structs.EveHandGestureData + self.cdll.EveGetHandGestureData.argtypes = [] + self.cdll.EveCopyHandGestureData.restype = structs.EveHandGestureData + self.cdll.EveCopyHandGestureData.argtypes = [] + self.cdll.EveDeleteHandGestureData.restype = structs.EveError + self.cdll.EveDeleteHandGestureData.argtypes = [structs.EveHandGestureData] + self.cdll.EveGetStaticGestureDetections.restype = structs.EveStaticGestureData + self.cdll.EveGetStaticGestureDetections.argtypes = [] + self.cdll.EveGetStaticGestureDefinitions.restype = structs.EveStaticGestureDefinitions + self.cdll.EveGetStaticGestureDefinitions.argtypes = [] + self.cdll.EveAddStaticGesture.restype = structs.EveError + self.cdll.EveAddStaticGesture.argtypes = [structs.EveStaticGestureDefinition] + self.cdll.EveDeleteStaticGesture.restype = structs.EveError + self.cdll.EveDeleteStaticGesture.argtypes = [structs.EveStaticGestureDefinition] + # EveAlgorithm.h + self.cdll.EveGetAlgorithms.restype = structs.EveSupportedAlgorithms + self.cdll.EveGetAlgorithms.argtypes = [] + + # EveTiming.h + self.cdll.EveGetTimingInformation.restype = structs.EveTiming + self.cdll.EveGetTimingInformation.argtypes = [] + + + # EveCamera.h + def EveGetFormats(self, cameraId: ctypes.c_uint, filter: structs.CCameraFormat) -> structs.EveCameraFormats: + return self.cdll.EveGetFormats(cameraId, filter) + + def EveGetCamera(self, cameraId: ctypes.c_uint) -> structs.EveCamera: + return self.cdll.EveGetCamera(cameraId) + + def EveSetCamera(self, cameraId: ctypes.c_uint, filter: structs.CCameraFormat) -> structs.EveError: + return self.cdll.EveSetCamera(cameraId, filter) + + def EveGetNumberOfCameras(self) -> structs.EveNumberOfCameras: + return self.cdll.EveGetNumberOfCameras() + + def EveGetMonitors(self) -> structs.EveMonitors: + return self.cdll.EveGetMonitors() + + def EveChangeCameraLocation(self, location: structs.EveCameraLocation) -> structs.EveCameraLocation: + return self.cdll.EveChangeCameraLocation(location) + + def EveGetLiveCameraParameters(self) -> structs.EveCameraParameters: + return self.cdll.EveGetLiveCameraParameters() + + # EveControlInterface.h + def CreateEve(self, options: structs.EveStartupParameters) -> structs.EveError: + return self.cdll.CreateEve(options) + + def EveRegisterDataCallback(self, callback) -> structs.EveError: + return self.cdll.EveRegisterDataCallback(callback) + + def StartEve(self) -> structs.EveError: + return self.cdll.StartEve() + + def StartEveWithParameters(self, parameters: structs.EveProcessingParameters) -> structs.EveError: + return self.cdll.StartEveWithParameters(parameters) + + def EveSendImageForProcessing(self, image: structs.EveInputImage) -> structs.EveError: + return self.cdll.EveSendImageForProcessing(image) + + def EveSendImageForProcessingWithParams(self, image: structs.EveInputImage, params: structs.CCameraParameters) -> structs.EveError: + return self.cdll.EveSendImageForProcessingWithParams(image, params) + + def EveSendImageForProcessingWithFpgaData(self, image: structs.EveInputImage, data: structs.EveFpgaManualData) -> structs.EveError: + return self.cdll.EveSendImageForProcessingWithFpgaData(image, data) + + def ShutdownEve(self) -> structs.EveError: + return self.cdll.ShutdownEve() + + def EveCheckForLicense(self) -> structs.EveLicenseResult: + return self.cdll.EveCheckForLicense() + + def EveResetPipeline(self) -> structs.EveError: + return self.cdll.EveResetPipeline() + + # EveFaceId.h + def EveConfigureFaceId(self, options: structs.EveFaceIdOptions) -> structs.EveFaceIdOptions: + return self.cdll.EveConfigureFaceId(options) + + def EveFaceIdCalibrateCurrent(self) -> structs.EveError: + return self.cdll.EveFaceIdCalibrateCurrent() + + def EveFaceIdCalibrateNew(self) -> structs.EveError: + return self.cdll.EveFaceIdCalibrateNew() + + def EveFaceIdForceIdentify(self) -> structs.EveError: + return self.cdll.EveFaceIdForceIdentify() + + def EveFaceIdRemoveCurrent(self) -> structs.EveError: + return self.cdll.EveFaceIdRemoveCurrent() + + def EveFaceIdRemoveAll(self) -> structs.EveError: + return self.cdll.EveFaceIdRemoveAll() + + def EveFaceIdReloadGallery(self) -> structs.EveError: + return self.cdll.EveFaceIdReloadGallery() + + def EveFaceIdCommandWaiting(self) -> ctypes.c_uint: + return self.cdll.EveFaceIdCommandWaiting() + + def EveGetFaceIdData(self) -> structs.EveFaceIdData: + return self.cdll.EveGetFaceIdData() + + def EveSendFaceIdCommand(self, command: structs.EveFaceIdCommandStruct) -> structs.EveFaceIdCommandStruct: + return self.cdll.EveSendFaceIdCommand(command) + + # EveFaceTracker.h + def EveConfigureFaceTracker(self, options: structs.EveFaceTrackerOptions) -> structs.EveFaceTrackerOptions: + return self.cdll.EveConfigureFaceTracker(options) + + def EveGetEyesData(self) -> structs.EveEyes: + return self.cdll.EveGetEyesData() + + def EveGetPupilsData(self) -> structs.EvePupils: + return self.cdll.EveGetPupilsData() + + def EveGetAllFaceData(self) -> structs.EveAllFacesData: + return self.cdll.EveGetAllFaceData() + + # EveFpga.h + def EveGetFpgaData(self) -> structs.EveFpgaData: + return self.cdll.EveGetFpgaData() + + def EveConfigureFpga(self, options: structs.EveFpgaOptions) -> structs.EveFpgaOptions: + return self.cdll.EveConfigureFpga(options) + + def EveConfigureFpgaDebug(self, options: structs.EveFpgaDebugOptions) -> structs.EveFpgaDebugOptions: + return self.cdll.EveConfigureFpgaDebug(options) + + def QueryFpgaSetting(self, command: structs.pipeline_config_t, notify: ctypes.c_bool) -> structs.EveError: + return self.cdll.QueryFpgaSetting(command, notify) + + def QueryFpgaSettings(self, typeMask: ctypes.c_uint16, settingsMask: ctypes.c_uint32, notify: ctypes.c_bool) -> structs.EveError: + return self.cdll.QueryFpgaSettings(typeMask, settingsMask, notify) + + def SendSetSetting(self, command: structs.pipeline_config_t) -> structs.EveError: + return self.cdll.SendSetSetting(command) + + def PopQueuedSetting(self) -> structs.CFpgaGetSetting: + return self.cdll.PopQueuedSetting() + + def FpgaReadJson(self) -> structs.EveFpgaJsonMetadata: + return self.cdll.FpgaReadJson() + + def FpgaReadData(self) -> structs.EveFpgaData: + return self.cdll.FpgaReadData() + + # EveKarolinska.h + def EveConfigureKarolinska(self, parameters: structs.EveKarolinskaOptions) -> structs.EveKarolinskaOptions: + return self.cdll.EveConfigureKarolinska(parameters) + + def EveGetKarolinskaData(self) -> structs.EveKarolinskaData: + return self.cdll.EveGetKarolinskaData() + + # EveImageManipulation.h + def EveConfigureImageManipulation(self, options: structs.EveImageManipulationOptions) -> structs.EveImageManipulationOptions: + return self.cdll.EveConfigureImageManipulation(options) + + # EveImage.h + def EveGetProcessedImage(self) -> structs.EveProcessedImage: + return self.cdll.EveGetProcessedImage() + + def EveGetProcessedFrameTime(self) -> structs.EveProcessedFrameTime: + return self.cdll.EveGetProcessedFrameTime() + + def EveConfigureProcessedImage(self, fmt: structs.EveImageFormatRequest) -> structs.EveImageFormatRequest: + return self.cdll.EveConfigureProcessedImage(fmt) + + def EveConfigureRawImage(self, fmt: structs.EveRawImageRequest) -> structs.EveRawImageRequest: + return self.cdll.EveConfigureRawImage(fmt) + + def EveGetRawImage(self) -> structs.EveProcessedImage: + return self.cdll.EveGetRawImage() + + def EveGetJsonData(self) -> structs.EveJsonData: + return self.cdll.EveGetJsonData() + + # EveObjectDetection.h + def EveConfigureObjectDetection(self, options: structs.EveObjectDetectionOptions) -> structs.EveObjectDetectionOptions: + return self.cdll.EveConfigureObjectDetection(options) + + def EveGetDefaultObjectDetectionOptions(self) -> structs.EveObjectDetectionOptions: + return self.cdll.EveGetDefaultObjectDetectionOptions() + + def EveConfigurePersonDetection(self, options: structs.EvePersonDetectionOptions) -> structs.EvePersonDetectionOptions: + return self.cdll.EveConfigurePersonDetection(options) + + def EveGetObjectDetectionData(self) -> structs.EveDetectionData: + return self.cdll.EveGetObjectDetectionData() + + def EveCopyObjectDetectionData(self) -> structs.EveDetectionData: + return self.cdll.EveCopyObjectDetectionData() + + def EveGetPersonDetectionData(self) -> structs.EveDetectionData: + return self.cdll.EveGetPersonDetectionData() + + def EveCopyPersonDetectionData(self) -> structs.EveDetectionData: + return self.cdll.EveCopyPersonDetectionData() + + def DeleteDetectionData(self, data: structs.EveDetectionData) -> structs.EveError: + return self.cdll.DeleteDetectionData(data) + + # EveROI.h + def EveConfigureROIs(self, options: structs.EveROIOptions) -> structs.EveROIOptions: + return self.cdll.EveConfigureROIs(options) + + def EveGetROIScoreData(self) -> structs.EveROIScoreData: + return self.cdll.EveGetROIScoreData() + + # EveHandGesture.h + def EveConfigureHandGesture(self, options: structs.EveHandGestureOptions) -> structs.EveHandGestureOptions: + return self.cdll.EveConfigureHandGesture(options) + + def EveGetHandGestureData(self) -> structs.EveHandGestureData: + return self.cdll.EveGetHandGestureData() + + def EveCopyHandGestureData(self) -> structs.EveHandGestureData: + return self.cdll.EveCopyHandGestureData() + + def EveDeleteHandGestureData(self, data: structs.EveHandGestureData) -> structs.EveError: + return self.cdll.EveDeleteHandGestureData(data) + + def EveGetStaticGestureDetections(self) -> structs.EveStaticGestureData: + return self.cdll.EveGetStaticGestureDetections() + + def EveGetStaticGestureDefinitions(self) -> structs.EveStaticGestureDefinitions: + return self.cdll.EveGetStaticGestureDefinitions() + + def EveAddStaticGesture(self, definition: structs.EveStaticGestureDefinition) -> structs.EveError: + return self.cdll.EveAddStaticGesture(definition) + + def EveDeleteStaticGesture(self, definition: structs.EveStaticGestureDefinition) -> structs.EveError: + return self.cdll.EveDeleteStaticGesture(definition) + + # EveAlgorithm.h + def EveGetAlgorithms(self) -> structs.EveSupportedAlgorithms: + return self.cdll.EveGetAlgorithms() + + # EveTiming.h + def EveGetTimingInformation(self) -> structs.EveTiming: + return self.cdll.EveGetTimingInformation() diff --git a/shared/eve_python/eve_sdk_structs.py b/shared/eve_python/eve_sdk_structs.py index 01d5977656b8b8fdca372a65f67e572c8298ff0f..2d78a07020f7dcc8b5894c26da9281c53b0d7911 100644 --- a/shared/eve_python/eve_sdk_structs.py +++ b/shared/eve_python/eve_sdk_structs.py @@ -11,8 +11,9 @@ from .structs.CFpgaData import * from .structs.CHandGesture import * from .structs.CImageManipulation import * from .structs.CKarolinska import * +from .structs.CLandmarkMaps import * +from .structs.CLicenseResult import * from .structs.CROIStructs import * -from .structs.CScreenLocation import * from .structs.CVisualSpeechStructs import * from .structs.EveProcessingStatus import * from .structs.EveAlgorithm import * @@ -42,7 +43,5 @@ from .structs.EveObjectDetection import * from .structs.EveObjectDetectionStructs import * from .structs.EveROI import * from .structs.EveROIStructs import * -from .structs.EveScreenLocation import * -from .structs.EveScreenLocationStructs import * from .structs.EveTiming import * from .structs.EveTimingStructs import * diff --git a/shared/eve_python/structs/CAlgorithms.py b/shared/eve_python/structs/CAlgorithms.py index cd9b4bcda53ee7d8aac734340299c51957bcb37c..9038d43071259c7ce1370767c34446ce6b6c8c5a 100644 --- a/shared/eve_python/structs/CAlgorithms.py +++ b/shared/eve_python/structs/CAlgorithms.py @@ -1,27 +1,27 @@ -import ctypes -from ctypes_enum import CtypesEnum - - -class EveAlgorithms(CtypesEnum): - EVE_ALGO_NONE = 0 - EVE_ALGO_BACKGROUND_SEGMENTATION = 1 - EVE_ALGO_OBJECT_DETECTION = 2 - EVE_ALGO_PERSON_DETECTION = 3 - EVE_ALGO_HEADPOSE_3D = 4 - EVE_ALGO_HAND_GESTURE = 5 - EVE_ALGO_DEPTH = 6 - EVE_ALGO_EYEWEAR_DETECTION = 7 - EVE_ALGO_KAROLINSKA = 8 - EVE_ALGO_GAZE = 9 - EVE_ALGO_GAZE_SINGLE_OUTPUT = 10 - EVE_ALGO_FACE_ID = 11 - EVE_ALGO_ROI_SELECTION = 12 - EVE_ALGO_FACE_ENHANCEMENT = 13 - EVE_ALGO_VISUAL_SPEECH_DETECTION = 14 - EVE_ALGO_BACKGROUND_BLUR = 15 - EVE_ALGO_BACKGROUND_REPLACEMENT = 16 - EVE_ALGO_USER_HILIGHT = 17 - EVE_ALGO_USER_FRAMING = 18 - EVE_ALGO_MIRROR_IMAGE = 19 - EVE_ALGO_FPGA_DRAWING = 20 - +import ctypes +from ctypes_enum import CtypesEnum + + +class EveAlgorithms(CtypesEnum): + EVE_ALGO_NONE = 0 + EVE_ALGO_BACKGROUND_SEGMENTATION = 1 + EVE_ALGO_OBJECT_DETECTION = 2 + EVE_ALGO_PERSON_DETECTION = 3 + EVE_ALGO_HEADPOSE_3D = 4 + EVE_ALGO_HAND_GESTURE = 5 + EVE_ALGO_DEPTH = 6 + EVE_ALGO_EYEWEAR_DETECTION = 7 + EVE_ALGO_KAROLINSKA = 8 + EVE_ALGO_GAZE = 9 + EVE_ALGO_GAZE_SINGLE_OUTPUT = 10 + EVE_ALGO_FACE_ID = 11 + EVE_ALGO_ROI_SELECTION = 12 + EVE_ALGO_FACE_ENHANCEMENT = 13 + EVE_ALGO_VISUAL_SPEECH_DETECTION = 14 + EVE_ALGO_BACKGROUND_BLUR = 15 + EVE_ALGO_BACKGROUND_REPLACEMENT = 16 + EVE_ALGO_USER_HILIGHT = 17 + EVE_ALGO_USER_FRAMING = 18 + EVE_ALGO_MIRROR_IMAGE = 19 + EVE_ALGO_FPGA_DRAWING = 20 + diff --git a/shared/eve_python/structs/CBasicStructs.py b/shared/eve_python/structs/CBasicStructs.py index f6bb776edc75c60512dea6bd6f1c90c684d159a1..2f8f711c1defff67c829e4c0f4f4cf5e3437b84d 100644 --- a/shared/eve_python/structs/CBasicStructs.py +++ b/shared/eve_python/structs/CBasicStructs.py @@ -1,86 +1,92 @@ -import ctypes -from ctypes_enum import CtypesEnum - -EVE_ENCODING_SIZE = 9 -EVE_LOCATION_SIZE = 2 - -class EveVideoFormat(CtypesEnum): - EVE_NONE = 0 - EVE_BGRA = 1 - EVE_YUY2 = 2 - EVE_NV12 = 3 - EVE_MJPG = 4 - EVE_BGR = 5 - EVE_GRAYSCALE = 6 - EVE_RGBA = 7 - EVE_RGB = 8 - EVE_ENCODING_SIZE = 9 - -class EveImageLocation(CtypesEnum): - EVE_CPU = 0 - EVE_GPU = 1 - EVE_LOCATION_SIZE = 2 - -class CPoint2i(ctypes.Structure): - _fields_ = [ - ("x", ctypes.c_int), - ("y", ctypes.c_int), - ] - -class CPoint2f(ctypes.Structure): - _fields_ = [ - ("x", ctypes.c_float), - ("y", ctypes.c_float), - ] - -class CPoint3i(ctypes.Structure): - _fields_ = [ - ("x", ctypes.c_int), - ("y", ctypes.c_int), - ("z", ctypes.c_int), - ] - -class CPoint3f(ctypes.Structure): - _fields_ = [ - ("x", ctypes.c_float), - ("y", ctypes.c_float), - ("z", ctypes.c_float), - ] - -class CAngles3f(ctypes.Structure): - _fields_ = [ - ("pitch", ctypes.c_float), - ("yaw", ctypes.c_float), - ("roll", ctypes.c_float), - ] - -class CRect2i(ctypes.Structure): - _fields_ = [ - ("left", ctypes.c_int), - ("top", ctypes.c_int), - ("right", ctypes.c_int), - ("bottom", ctypes.c_int), - ] - -class CRect2iWH(ctypes.Structure): - _fields_ = [ - ("x", ctypes.c_int), - ("y", ctypes.c_int), - ("width", ctypes.c_int), - ("height", ctypes.c_int), - ] - -class CRect2fWH(ctypes.Structure): - _fields_ = [ - ("x", ctypes.c_float), - ("y", ctypes.c_float), - ("width", ctypes.c_float), - ("height", ctypes.c_float), - ] - -class CResolution(ctypes.Structure): - _fields_ = [ - ("width", ctypes.c_uint), - ("height", ctypes.c_uint), - ] - +import ctypes +from ctypes_enum import CtypesEnum + +EVE_ENCODING_SIZE = 9 +EVE_LOCATION_SIZE = 2 + +class EveVideoFormat(CtypesEnum): + EVE_NONE = 0 + EVE_BGRA = 1 + EVE_YUY2 = 2 + EVE_NV12 = 3 + EVE_MJPG = 4 + EVE_BGR = 5 + EVE_GRAYSCALE = 6 + EVE_RGBA = 7 + EVE_RGB = 8 + EVE_ENCODING_SIZE = 9 + +class EveImageLocation(CtypesEnum): + EVE_CPU = 0 + EVE_GPU = 1 + EVE_LOCATION_SIZE = 2 + +class CPoint2i(ctypes.Structure): + _fields_ = [ + ("x", ctypes.c_int), + ("y", ctypes.c_int), + ] + +class CPoint2f(ctypes.Structure): + _fields_ = [ + ("x", ctypes.c_float), + ("y", ctypes.c_float), + ] + +class CPoint3i(ctypes.Structure): + _fields_ = [ + ("x", ctypes.c_int), + ("y", ctypes.c_int), + ("z", ctypes.c_int), + ] + +class CPoint3f(ctypes.Structure): + _fields_ = [ + ("x", ctypes.c_float), + ("y", ctypes.c_float), + ("z", ctypes.c_float), + ] + +class CAngles3f(ctypes.Structure): + _fields_ = [ + ("pitch", ctypes.c_float), + ("yaw", ctypes.c_float), + ("roll", ctypes.c_float), + ] + +class CRect2i(ctypes.Structure): + _fields_ = [ + ("left", ctypes.c_int), + ("top", ctypes.c_int), + ("right", ctypes.c_int), + ("bottom", ctypes.c_int), + ] + +class CRect2iWH(ctypes.Structure): + _fields_ = [ + ("x", ctypes.c_int), + ("y", ctypes.c_int), + ("width", ctypes.c_int), + ("height", ctypes.c_int), + ] + +class CRect2fWH(ctypes.Structure): + _fields_ = [ + ("x", ctypes.c_float), + ("y", ctypes.c_float), + ("width", ctypes.c_float), + ("height", ctypes.c_float), + ] + +class CResolution(ctypes.Structure): + _fields_ = [ + ("width", ctypes.c_uint), + ("height", ctypes.c_uint), + ] + +class CStringData(ctypes.Structure): + _fields_ = [ + ("data", ctypes.POINTER(ctypes.c_byte)), + ("size", ctypes.c_ulonglong), + ] + diff --git a/shared/eve_python/structs/CCameraStructs.py b/shared/eve_python/structs/CCameraStructs.py index d100e5251d96b2c4826cf09fea9195dc040b9d89..975a79687343039a2353332f69a34d3728c60f4f 100644 --- a/shared/eve_python/structs/CCameraStructs.py +++ b/shared/eve_python/structs/CCameraStructs.py @@ -1,48 +1,66 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .CBasicStructs import * - -CAMERA_PID_VID_SIZE = 8 -CAMERA_NAME_SIZE = 64 - -class EveCompare(CtypesEnum): - EVE_EQUAL = 0 - EVE_AT_MOST = 1 - EVE_AT_LEAST = 2 - -class CCameraFormat(ctypes.Structure): - _fields_ = [ - ("resolution", CResolution), - ("format", ctypes.c_int), - ("fps", ctypes.c_float), - ("compareResolution", ctypes.c_int), - ("compareFps", ctypes.c_int), - ] - -class CCamera(ctypes.Structure): - _fields_ = [ - ("id", ctypes.c_int), - ("pid", ctypes.c_byte * CAMERA_PID_VID_SIZE), - ("vid", ctypes.c_byte * CAMERA_PID_VID_SIZE), - ("name", ctypes.c_byte * CAMERA_NAME_SIZE), - ("isHardwareCamera", ctypes.c_uint), - ("isFpgaCamera", ctypes.c_uint), - ("isIrCamera", ctypes.c_uint), - ] - -class CCameraParameters(ctypes.Structure): - _fields_ = [ - ("width", ctypes.c_int), - ("height", ctypes.c_int), - ("focalLength", ctypes.c_double), - ("pixelSizeX", ctypes.c_double), - ("pixelSizeY", ctypes.c_double), - ("principalPointX", ctypes.c_double), - ("principalPointY", ctypes.c_double), - ("depthMin", ctypes.c_double), - ("depthMax", ctypes.c_double), - ("screenLocationXinMM", ctypes.c_float), - ("screenLocationYinMM", ctypes.c_float), - ("isInfrared", ctypes.c_uint), - ] - +import ctypes +from ctypes_enum import CtypesEnum +from .CBasicStructs import * + +CAMERA_PID_VID_SIZE = 8 +CAMERA_NAME_SIZE = 64 + +class EveCompare(CtypesEnum): + EVE_EQUAL = 0 + EVE_AT_MOST = 1 + EVE_AT_LEAST = 2 + +class CCameraFormat(ctypes.Structure): + _fields_ = [ + ("resolution", CResolution), + ("format", ctypes.c_int), + ("fps", ctypes.c_float), + ("compareResolution", ctypes.c_int), + ("compareFps", ctypes.c_int), + ] + +class CCamera(ctypes.Structure): + _fields_ = [ + ("id", ctypes.c_int), + ("pid", ctypes.c_byte * CAMERA_PID_VID_SIZE), + ("vid", ctypes.c_byte * CAMERA_PID_VID_SIZE), + ("name", ctypes.c_byte * CAMERA_NAME_SIZE), + ("isHardwareCamera", ctypes.c_uint), + ("isFpgaCamera", ctypes.c_uint), + ("isIrCamera", ctypes.c_uint), + ("screenLocationXinMM", ctypes.c_float), + ("screenLocationYinMM", ctypes.c_float), + ] + +class CCameraParameters(ctypes.Structure): + _fields_ = [ + ("width", ctypes.c_int), + ("height", ctypes.c_int), + ("focalLength", ctypes.c_double), + ("pixelSizeX", ctypes.c_double), + ("pixelSizeY", ctypes.c_double), + ("principalPointX", ctypes.c_double), + ("principalPointY", ctypes.c_double), + ("depthMin", ctypes.c_double), + ("depthMax", ctypes.c_double), + ("screenLocationXinMM", ctypes.c_float), + ("screenLocationYinMM", ctypes.c_float), + ("isInfrared", ctypes.c_uint), + ] + +class CMonitor(ctypes.Structure): + _fields_ = [ + ("rectangle", CRect2iWH), + ("dpiRatio", ctypes.c_float), + ("dpiX", ctypes.c_float), + ("dpiY", ctypes.c_float), + ("primary", ctypes.c_uint), + ] + +class CCameraLocation(ctypes.Structure): + _fields_ = [ + ("id", ctypes.c_int), + ("screenLocationXinMM", ctypes.c_float), + ("screenLocationYinMM", ctypes.c_float), + ] + diff --git a/shared/eve_python/structs/CDetectionStructs.py b/shared/eve_python/structs/CDetectionStructs.py index 1cc8771bcbe5a32c639e2ce440ccdaf51ca65f4a..eaaeb970ceadf98f2bfe142895a7e550b6fa748f 100644 --- a/shared/eve_python/structs/CDetectionStructs.py +++ b/shared/eve_python/structs/CDetectionStructs.py @@ -1,38 +1,44 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .EveProcessingStatus import * - -EVE_DETECTIONS_SIZE = 256 -EVE_CLASS_ID_NAME_SIZE = 32 - -class EveActionStatus(CtypesEnum): - EVE_IDLE = 0 - EVE_INTERPOLATED = 1 - EVE_COMPUTED = 2 - EVE_NO_OUTPUT = 3 - -class FrontalStatus(CtypesEnum): - UNKNOWN = 0 - FRONTAL = 1 - NON_FRONTAL = 2 - -class CSingleDetectionData(ctypes.Structure): - _fields_ = [ - ("topLeftX", ctypes.c_int), - ("topLeftY", ctypes.c_int), - ("bottomRightX", ctypes.c_int), - ("bottomRightY", ctypes.c_int), - ("classScore", ctypes.c_float), - ("classId", ctypes.c_int), - ("classIdName", ctypes.c_byte * EVE_CLASS_ID_NAME_SIZE), - ("frontalStatus", ctypes.c_int), - ] - -class CDetectionData(ctypes.Structure): - _fields_ = [ - ("processingStatus", ctypes.c_int), - ("actionStatus", ctypes.c_int), - ("numberOfDetections", ctypes.c_int), - ("detections", CSingleDetectionData * EVE_DETECTIONS_SIZE), - ] - +import ctypes +from ctypes_enum import CtypesEnum +from .EveProcessingStatus import * + +EVE_DETECTIONS_SIZE = 256 +EVE_CLASS_ID_NAME_SIZE = 32 + +class EveActionStatus(CtypesEnum): + EVE_IDLE = 0 + EVE_INTERPOLATED = 1 + EVE_COMPUTED = 2 + EVE_NO_OUTPUT = 3 + +class FrontalStatus(CtypesEnum): + UNKNOWN = 0 + FRONTAL = 1 + NON_FRONTAL = 2 + +class PPEStatus(CtypesEnum): + PPE_UNKNOWN = 0 + PPE_HARD_HAT = 1 + NO_PPE = 2 + +class CSingleDetectionData(ctypes.Structure): + _fields_ = [ + ("topLeftX", ctypes.c_int), + ("topLeftY", ctypes.c_int), + ("bottomRightX", ctypes.c_int), + ("bottomRightY", ctypes.c_int), + ("classScore", ctypes.c_float), + ("classId", ctypes.c_int), + ("classIdName", ctypes.c_byte * EVE_CLASS_ID_NAME_SIZE), + ("frontalStatus", ctypes.c_int), + ("ppeStatus", ctypes.c_int), + ] + +class CDetectionData(ctypes.Structure): + _fields_ = [ + ("processingStatus", ctypes.c_int), + ("actionStatus", ctypes.c_int), + ("numberOfDetections", ctypes.c_int), + ("detections", CSingleDetectionData * EVE_DETECTIONS_SIZE), + ] + diff --git a/shared/eve_python/structs/CFaceData.py b/shared/eve_python/structs/CFaceData.py index d8e1be7edcea3a28b8e63c90a51564dfaaa30c81..a548d7ec69d92f52d46a6db1bdef628dccaa820f 100644 --- a/shared/eve_python/structs/CFaceData.py +++ b/shared/eve_python/structs/CFaceData.py @@ -1,55 +1,61 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .CBasicStructs import * -from .CFaceIdStructs import * - -EVE_MAX_FACES = 10 -EVE_EYE_LANDMARK_SIZE = 14 -EVE_PUPIL_LANDMARK_SIZE = 2 - -class EveEyeLandmark(CtypesEnum): - EVE_EYE_RIGHT_CORNER_TEMPORAL = 0 - EVE_EYE_RIGHT_EYELID_UPPER_1 = 1 - EVE_EYE_RIGHT_EYELID_UPPER_2 = 2 - EVE_EYE_RIGHT_CORNER_NASAL = 3 - EVE_EYE_RIGHT_EYELID_LOWER_1 = 4 - EVE_EYE_RIGHT_EYELID_LOWER_2 = 5 - EVE_EYE_LEFT_CORNER_NASAL = 6 - EVE_EYE_LEFT_EYELID_UPPER_2 = 7 - EVE_EYE_LEFT_EYELID_UPPER_1 = 8 - EVE_EYE_LEFT_CORNER_TEMPORAL = 9 - EVE_EYE_LEFT_EYELID_LOWER_2 = 10 - EVE_EYE_LEFT_EYELID_LOWER_1 = 11 - EVE_EYE_RIGHT_PUPIL_CENTER = 12 - EVE_EYE_LEFT_PUPIL_CENTER = 13 - EVE_EYE_LANDMARK_SIZE = 14 - -class EvePupilLandmark(CtypesEnum): - EVE_RIGHT_PUPIL_CENTER = 0 - EVE_LEFT_PUPIL_CENTER = 1 - EVE_PUPIL_LANDMARK_SIZE = 2 - -class CEyeLandmarks(ctypes.Structure): - _fields_ = [ - ("landmarks", CPoint3f * EVE_EYE_LANDMARK_SIZE), - ] - -class CPupilLandmarks(ctypes.Structure): - _fields_ = [ - ("landmarks", CPoint3f * EVE_PUPIL_LANDMARK_SIZE), - ] - -class CFaceData(ctypes.Structure): - _fields_ = [ - ("angles", CAngles3f), - ("faceId", CFaceIdentityData), - ("depth", ctypes.c_float), - ("trackNumber", ctypes.c_int), - ] - -class CAllFaces(ctypes.Structure): - _fields_ = [ - ("detectedFacesCount", ctypes.c_uint), - ("faces", CFaceData * EVE_MAX_FACES), - ] - +import ctypes +from ctypes_enum import CtypesEnum +from .CBasicStructs import * +from .CFaceIdStructs import * + +EVE_MAX_FACE_LANDMARKS = 68 +EVE_MAX_FACES = 10 +EVE_EYE_LANDMARK_SIZE = 14 +EVE_PUPIL_LANDMARK_SIZE = 2 + +class EveEyeLandmark(CtypesEnum): + EVE_EYE_RIGHT_CORNER_TEMPORAL = 0 + EVE_EYE_RIGHT_EYELID_UPPER_1 = 1 + EVE_EYE_RIGHT_EYELID_UPPER_2 = 2 + EVE_EYE_RIGHT_CORNER_NASAL = 3 + EVE_EYE_RIGHT_EYELID_LOWER_1 = 4 + EVE_EYE_RIGHT_EYELID_LOWER_2 = 5 + EVE_EYE_LEFT_CORNER_NASAL = 6 + EVE_EYE_LEFT_EYELID_UPPER_2 = 7 + EVE_EYE_LEFT_EYELID_UPPER_1 = 8 + EVE_EYE_LEFT_CORNER_TEMPORAL = 9 + EVE_EYE_LEFT_EYELID_LOWER_2 = 10 + EVE_EYE_LEFT_EYELID_LOWER_1 = 11 + EVE_EYE_RIGHT_PUPIL_CENTER = 12 + EVE_EYE_LEFT_PUPIL_CENTER = 13 + EVE_EYE_LANDMARK_SIZE = 14 + +class EvePupilLandmark(CtypesEnum): + EVE_RIGHT_PUPIL_CENTER = 0 + EVE_LEFT_PUPIL_CENTER = 1 + EVE_PUPIL_LANDMARK_SIZE = 2 + +class CEyeLandmarks(ctypes.Structure): + _fields_ = [ + ("landmarks", CPoint3f * EVE_EYE_LANDMARK_SIZE), + ] + +class CPupilLandmarks(ctypes.Structure): + _fields_ = [ + ("landmarks", CPoint3f * EVE_PUPIL_LANDMARK_SIZE), + ] + +class CFaceData(ctypes.Structure): + _fields_ = [ + ("angles", CAngles3f), + ("faceId", CFaceIdentityData), + ("depth", ctypes.c_float), + ("trackNumber", ctypes.c_int), + ("box", CRect2iWH), + ("landmarksCount", ctypes.c_uint), + ("landmarksICS", CPoint2f * EVE_MAX_FACE_LANDMARKS), + ("landmarksCCS", CPoint3f * EVE_MAX_FACE_LANDMARKS), + ("midEyeCCS", CPoint3f), + ] + +class CAllFaces(ctypes.Structure): + _fields_ = [ + ("detectedFacesCount", ctypes.c_uint), + ("faces", CFaceData * EVE_MAX_FACES), + ] + diff --git a/shared/eve_python/structs/CFaceIdStructs.py b/shared/eve_python/structs/CFaceIdStructs.py index 38c3a0fed2c54028341271b715d2e5426cf82a92..3efaa8c2c459508522f473c5c1136958c64aafa3 100644 --- a/shared/eve_python/structs/CFaceIdStructs.py +++ b/shared/eve_python/structs/CFaceIdStructs.py @@ -1,68 +1,68 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .EveProcessingStatus import * - -EVE_FACE_ID_MAX_MISSING_CALIBRATION_POSES = 5 - -class EveFaceIdActionStatus(CtypesEnum): - EVE_FACE_ID_ACTION_IDLE = 0 - EVE_FACE_ID_ACTION_CALIBRATING = 1 - EVE_FACE_ID_ACTION_CALIBRATED = 2 - EVE_FACE_ID_ACTION_IDENTIFIED = 3 - -class EveFaceIdCalibrationStatus(CtypesEnum): - EVE_FACE_ID_CALIB_NONE = 0 - EVE_FACE_ID_CALIB_RUNNING = 1 - EVE_FACE_ID_CALIB_SUCCESS = 2 - EVE_FACE_ID_CALIB_FAILURE_LACK_POSE_MOTION = 3 - EVE_FACE_ID_CALIB_FAILURE_OTHER = 4 - -class EveFaceIdIdentificationStatus(CtypesEnum): - EVE_FACE_ID_NONE = 0 - EVE_FACE_ID_SUCCESS = 1 - EVE_FACE_ID_FAILURE_VERIFICATION = 2 - EVE_FACE_ID_FAILURE_ANGLE_PITCH = 3 - EVE_FACE_ID_FAILURE_ANGLE_YAW = 4 - EVE_FACE_ID_FAILURE_ANGLE_ROLL = 5 - EVE_FACE_ID_FAILURE_ANGLE_BOTH = 6 - EVE_FACE_ID_FAILURE_NO_GALLERY = 7 - EVE_FACE_ID_FAILURE_EXP_SMILE = 8 - EVE_FACE_ID_FAILURE_EXP_SQUINT = 9 - EVE_FACE_ID_FAILURE_EXP_EYES_CLOSED = 10 - EVE_FACE_ID_FAILURE_DEPTH = 11 - EVE_FACE_ID_FAILURE_OTHER = 12 - -class EveFaceIdPose(CtypesEnum): - EVE_FACE_ID_POSE_FRONTAL = 0 - EVE_FACE_ID_POSE_LEFT = 1 - EVE_FACE_ID_POSE_RIGHT = 2 - EVE_FACE_ID_POSE_UP = 3 - EVE_FACE_ID_POSE_DOWN = 4 - -class EveFaceIdCommand(CtypesEnum): - EVE_FACE_ID_COMMAND_NONE = 0 - EVE_FACE_ID_COMMAND_ADD_NEW_USER = 1 - EVE_FACE_ID_COMMAND_CALIBRATE_CURRENT_USER = 2 - EVE_FACE_ID_COMMAND_FORCE_ID = 3 - EVE_FACE_ID_COMMAND_REMOVE_CURRENT_USER = 4 - EVE_FACE_ID_COMMAND_REMOVE_ALL_USERS = 5 - EVE_FACE_ID_COMMAND_RELOAD_GALLERY = 6 - -class CFaceIdentity(ctypes.Structure): - _fields_ = [ - ("id", ctypes.c_longlong), - ("confidence", ctypes.c_float), - ("similarity", ctypes.c_float), - ] - -class CFaceIdentityData(ctypes.Structure): - _fields_ = [ - ("processingStatus", ctypes.c_int), - ("actionStatus", ctypes.c_int), - ("calibrationStatus", ctypes.c_int), - ("identificationStatus", ctypes.c_int), - ("faceIdentity", CFaceIdentity), - ("missingCalibrationPosesCount", ctypes.c_uint), - ("missingCalibrationPoses", ctypes.c_int * EVE_FACE_ID_MAX_MISSING_CALIBRATION_POSES), - ] - +import ctypes +from ctypes_enum import CtypesEnum +from .EveProcessingStatus import * + +EVE_FACE_ID_MAX_MISSING_CALIBRATION_POSES = 5 + +class EveFaceIdActionStatus(CtypesEnum): + EVE_FACE_ID_ACTION_IDLE = 0 + EVE_FACE_ID_ACTION_CALIBRATING = 1 + EVE_FACE_ID_ACTION_CALIBRATED = 2 + EVE_FACE_ID_ACTION_IDENTIFIED = 3 + +class EveFaceIdCalibrationStatus(CtypesEnum): + EVE_FACE_ID_CALIB_NONE = 0 + EVE_FACE_ID_CALIB_RUNNING = 1 + EVE_FACE_ID_CALIB_SUCCESS = 2 + EVE_FACE_ID_CALIB_FAILURE_LACK_POSE_MOTION = 3 + EVE_FACE_ID_CALIB_FAILURE_OTHER = 4 + +class EveFaceIdIdentificationStatus(CtypesEnum): + EVE_FACE_ID_NONE = 0 + EVE_FACE_ID_SUCCESS = 1 + EVE_FACE_ID_FAILURE_VERIFICATION = 2 + EVE_FACE_ID_FAILURE_ANGLE_PITCH = 3 + EVE_FACE_ID_FAILURE_ANGLE_YAW = 4 + EVE_FACE_ID_FAILURE_ANGLE_ROLL = 5 + EVE_FACE_ID_FAILURE_ANGLE_BOTH = 6 + EVE_FACE_ID_FAILURE_NO_GALLERY = 7 + EVE_FACE_ID_FAILURE_EXP_SMILE = 8 + EVE_FACE_ID_FAILURE_EXP_SQUINT = 9 + EVE_FACE_ID_FAILURE_EXP_EYES_CLOSED = 10 + EVE_FACE_ID_FAILURE_DEPTH = 11 + EVE_FACE_ID_FAILURE_OTHER = 12 + +class EveFaceIdPose(CtypesEnum): + EVE_FACE_ID_POSE_FRONTAL = 0 + EVE_FACE_ID_POSE_LEFT = 1 + EVE_FACE_ID_POSE_RIGHT = 2 + EVE_FACE_ID_POSE_UP = 3 + EVE_FACE_ID_POSE_DOWN = 4 + +class EveFaceIdCommand(CtypesEnum): + EVE_FACE_ID_COMMAND_NONE = 0 + EVE_FACE_ID_COMMAND_ADD_NEW_USER = 1 + EVE_FACE_ID_COMMAND_CALIBRATE_CURRENT_USER = 2 + EVE_FACE_ID_COMMAND_FORCE_ID = 3 + EVE_FACE_ID_COMMAND_REMOVE_CURRENT_USER = 4 + EVE_FACE_ID_COMMAND_REMOVE_ALL_USERS = 5 + EVE_FACE_ID_COMMAND_RELOAD_GALLERY = 6 + +class CFaceIdentity(ctypes.Structure): + _fields_ = [ + ("id", ctypes.c_longlong), + ("confidence", ctypes.c_float), + ("similarity", ctypes.c_float), + ] + +class CFaceIdentityData(ctypes.Structure): + _fields_ = [ + ("processingStatus", ctypes.c_int), + ("actionStatus", ctypes.c_int), + ("calibrationStatus", ctypes.c_int), + ("identificationStatus", ctypes.c_int), + ("faceIdentity", CFaceIdentity), + ("missingCalibrationPosesCount", ctypes.c_uint), + ("missingCalibrationPoses", ctypes.c_int * EVE_FACE_ID_MAX_MISSING_CALIBRATION_POSES), + ] + diff --git a/shared/eve_python/structs/CFpgaData.py b/shared/eve_python/structs/CFpgaData.py index ea12acf45b52a81fe935f584ad58d34787d47c10..e5d45c04b09617712cdceadb0a6491f1dd44bbb8 100644 --- a/shared/eve_python/structs/CFpgaData.py +++ b/shared/eve_python/structs/CFpgaData.py @@ -1,350 +1,350 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .CBasicStructs import * - -EVE_FPGA_MAX_USERS = 10 -EVE_FPGA_MAX_PERSONS = 5 -EVE_FPGA_MAX_HAND_LANDMARKS = 11 -EVE_FPGA_HAND_LANDMARKS = 10 -EVE_FPGA_MAX_OBJECT_DETECTION = 50 -PT_SIZE = 6 -MT_SIZE = 4 -RT_SIZE = 4 - -class EveFpgaConnectionType(CtypesEnum): - EVE_FPGA_AUTO_SELECT = 0 - EVE_FPGA_UART = 1 - EVE_FPGA_I2C = 2 - EVE_FPGA_HUB = 3 - EVE_FPGA_MANUAL = 4 - -class EveFpgaConnectionRequest(CtypesEnum): - EVE_FPGA_STOP = 0 - EVE_FPGA_CONTINUE = 1 - -class pipeline_config_type_t(CtypesEnum): - PT_FD = 0 - PT_LM_FV = 1 - PT_FID = 2 - PT_PD = 3 - PT_HD = 4 - PT_HLMV = 5 - PT_SIZE = 6 - -class setting_type_t(CtypesEnum): - CS_ENABLED = 0x00 - CS_IPS = 0x01 - CS_RESERVED_2_7 = 0x02 - CS_COMMAND = 0x08 - CS_CUSTOM = 0x10 - CS_MAX = 0x11 - -class message_type_t(CtypesEnum): - MT_NONE = 0 - MT_SET = 1 - MT_GET = 2 - MT_GET_BATCH = 3 - MT_SIZE = 4 - -class response_type_t(CtypesEnum): - RT_NONE = 0 - RT_DATA = 1 - RT_GET = 2 - RT_ACK = 3 - RT_SIZE = 4 - -class EveFpgaSerialStatus(CtypesEnum): - EVE_FPGA_SUCCESS = 0 - EVE_FPGA_NO_DATA = 1 - EVE_FPGA_READ_START_MARKER_FAILED = 2 - EVE_FPGA_FIND_START_MARKER_FAILED = 3 - EVE_FPGA_READ_DATA_LENGTH_FAILED = 4 - EVE_FPGA_READ_DATA_FAILED = 5 - EVE_FPGA_CORRUPTED_DATA = 6 - EVE_FPGA_UNEXPECTED_RESPONSE_TYPE = 7 - EVE_FPGA_API_ERROR_START = 8 - EVE_FPGA_NO_CALLBACK = 9 - EVE_FPGA_DATA_ACCESSED_OUTSIDE_CALLBACK = 10 - EVE_FPGA_INIT_FAILED = 11 - EVE_FPGA_NOT_INIT = 12 - EVE_FPGA_NOT_IMPLEMENTED = 13 - EVE_FPGA_API_ERROR_END = 14 - -class EveWakeupDetectionType(CtypesEnum): - EVE_USER_DETECTION = 0 - EVE_STRANGER_DETECTION = 1 - -class EveFpgaPipelineType(CtypesEnum): - EVE_UNKNOWN_PIPELINE = 0 - EVE_HEAD_POSE_PIPELINE = 1 - EVE_FACE_ID_PIPELINE = 2 - EVE_HAND_GESTURE_PIPELINE = 3 - EVE_COMPACT_HEAD_POSE_PIPELINE = 4 - EVE_HMI_PIPELINE = 5 - EVE_STANDALONE_HAND_GESTURE_PIPELINE = 6 - -class EvePersonBodyPose(CtypesEnum): - EVE_FRONT = 0 - EVE_NOT_FRONT = 1 - -class EveDistanceFromCamera(CtypesEnum): - EVE_DISTANCE_CLOSE = 0 - EVE_DISTANCE_MID = 1 - EVE_DISTANCE_FAR = 2 - -class EvePersonRegistrationStatus(CtypesEnum): - EVE_REGISTERED = 0 - EVE_UNREGISTERED = 1 - EVE_UNKNOWN = 2 - EVE_REQUIREMENTS_UNMET = 3 - EVE_DISABLED = 4 - EVE_NO_GALLERY = 5 - -class EveFpgaHandGesture(CtypesEnum): - EVE_FPGA_HAND_GESTURE_NO_GESTURE = 0 - EVE_FPGA_HAND_GESTURE_CLOSE = 1 - EVE_FPGA_HAND_GESTURE_OPEN = 2 - EVE_FPGA_HAND_GESTURE_OPEN_LEFT = 3 - EVE_FPGA_HAND_GESTURE_OPEN_RIGHT = 4 - EVE_FPGA_HAND_GESTURE_INDEX_UP = 5 - EVE_FPGA_HAND_GESTURE_INDEX_DOWN = 6 - EVE_FPGA_HAND_GESTURE_TIP_LEFT = 7 - EVE_FPGA_HAND_GESTURE_TIP_RIGHT = 8 - EVE_FPGA_HAND_GESTURE_UNKNOWN = 9 - -class EveFpgaObjectClass(CtypesEnum): - EVE_FPGA_OBJECT_CLASS_PERSON = 0 - EVE_FPGA_OBJECT_CLASS_BICYCLE = 1 - EVE_FPGA_OBJECT_CLASS_CAR = 2 - EVE_FPGA_OBJECT_CLASS_MOTORCYCLE = 3 - EVE_FPGA_OBJECT_CLASS_BUS = 4 - EVE_FPGA_OBJECT_CLASS_TRUCK = 5 - EVE_FPGA_OBJECT_CLASS_TRAFFIC_LIGHT = 6 - EVE_FPGA_OBJECT_CLASS_STOP_SIGN = 7 - -class pipeline_setting_t(ctypes.Structure): - _fields_ = [ - ("settingType", ctypes.c_int), - ("value", ctypes.c_uint32), - ] - -class pipeline_config_t(ctypes.Structure): - _fields_ = [ - ("type", ctypes.c_int), - ("setting", pipeline_setting_t), - ] - -class CFpgaIdealPersonData(ctypes.Structure): - _fields_ = [ - ("valid", ctypes.c_uint), - ("index", ctypes.c_uint), - ("status", ctypes.c_int), - ("faceAngles", CAngles3f), - ("faceLandmarksConfidence", ctypes.c_float), - ("isFaceLandmarksConfidenceValid", ctypes.c_bool), - ] - -class CFpgaImageDimensions(ctypes.Structure): - _fields_ = [ - ("width", ctypes.c_int), - ("height", ctypes.c_int), - ("cropArea", CRect2i), - ("reserved1", ctypes.c_int), - ("reserved2", ctypes.c_int), - ] - -class CFpgaDataContent(ctypes.Structure): - _fields_ = [ - ("numberOfUsers", ctypes.c_int16), - ("idealUserIndex", ctypes.c_int16), - ("numberOfDetectedFaces", ctypes.c_int16), - ("numberOfFacesConfidence", ctypes.c_float), - ("numberOfDetectedPersons", ctypes.c_int16), - ("numberOfPersonsConfidence", ctypes.c_float), - ("isIdealUserDataAvailable", ctypes.c_bool), - ("idealUserDetected", ctypes.c_bool), - ("isIdealUserIndexValid", ctypes.c_bool), - ("isNumberOfDetectedFacesAvailable", ctypes.c_bool), - ("isNumberOfFacesConfidenceAvailable", ctypes.c_bool), - ("isNumberOfDetectedPersonsAvailable", ctypes.c_bool), - ("isNumberOfPersonsConfidenceAvailable", ctypes.c_bool), - ("isUsersDataAvilable", ctypes.c_bool), - ("isFaceIdDataAvailable", ctypes.c_bool), - ("isObjectDetectionAvailable", ctypes.c_bool), - ("isCameraStreaming", ctypes.c_bool), - ("isHandGestureDataAvailable", ctypes.c_bool), - ("isDefectDetectionAvailable", ctypes.c_bool), - ] - -class CFpgaHandData(ctypes.Structure): - _fields_ = [ - ("validationScore", ctypes.c_float), - ("handBox", CRect2i), - ("landmarks", CPoint3f * EVE_FPGA_MAX_HAND_LANDMARKS), - ] - -class CFpgaHandsData(ctypes.Structure): - _fields_ = [ - ("numberOfHandLandmarkPoints", ctypes.c_int16), - ("handData", CFpgaHandData), - ("gesture", ctypes.c_int), - ("isHandBoxAvailable", ctypes.c_bool), - ("isHandLandmark3D", ctypes.c_bool), - ] - -class CFpgaDefectData(ctypes.Structure): - _fields_ = [ - ("defectBox", CRect2i), - ("width", ctypes.c_int), - ("height", ctypes.c_int), - ("similarity", ctypes.c_float), - ("isDefective", ctypes.c_bool), - ] - -class CFpgaFaceData(ctypes.Structure): - _fields_ = [ - ("faceConfidence", ctypes.c_float), - ("faceDistance", ctypes.c_int16), - ("faceCenter", CPoint3i), - ("anglesICS", CAngles3f), - ("anglesCCS", CAngles3f), - ("faceLandmarksConfidence", ctypes.c_float), - ("faceBox", CRect2i), - ("faceIDStatus", ctypes.c_int), - ("faceID", ctypes.c_int16), - ("isFaceConfidenceAvailable", ctypes.c_bool), - ("isFaceDistanceAvailable", ctypes.c_bool), - ("isFacePositionAvailable", ctypes.c_bool), - ("isEulerAnglesIcsAvailable", ctypes.c_bool), - ("isEulerAnglesCcsAvailable", ctypes.c_bool), - ("isFaceLandmark3D", ctypes.c_bool), - ("isFaceLandmarksConfidenceAvailable", ctypes.c_bool), - ("isFaceGeometricBoxAvailable", ctypes.c_bool), - ("isStatusAvailable", ctypes.c_bool), - ] - -class CFpgaPersonData(ctypes.Structure): - _fields_ = [ - ("personConfidence", ctypes.c_float), - ("personDistance", ctypes.c_int), - ("personPosture", ctypes.c_int), - ("personFrontalPostureConfidence", ctypes.c_float), - ("personNotFrontalPostureConfidence", ctypes.c_float), - ("position", CPoint3i), - ("personBox", CRect2i), - ("isPersonDataAvailable", ctypes.c_bool), - ] - -class CFpgaObjectDetection(ctypes.Structure): - _fields_ = [ - ("objectClass", ctypes.c_int), - ("objectConfidence", ctypes.c_float), - ("objectBox", CRect2i), - ] - -class CFpgaObjectData(ctypes.Structure): - _fields_ = [ - ("numberOfObjects", ctypes.c_int16), - ("objects", CFpgaObjectDetection * EVE_FPGA_MAX_OBJECT_DETECTION), - ] - -class CFpgaUserData(ctypes.Structure): - _fields_ = [ - ("id", ctypes.c_int16), - ("status", ctypes.c_int), - ("scale", ctypes.c_float), - ("faceData", CFpgaFaceData), - ("personData", CFpgaPersonData), - ("isIdealUser", ctypes.c_bool), - ("isIdValid", ctypes.c_bool), - ("isStatusAvailable", ctypes.c_bool), - ("isScaleAvailable", ctypes.c_bool), - ] - -class CFpgaFaceIdData(ctypes.Structure): - _fields_ = [ - ("command", ctypes.c_int16), - ("userId", ctypes.c_int16), - ("freeEntry", ctypes.c_int16), - ("statusCode", ctypes.c_int16), - ("faceId", ctypes.c_int16), - ("lastRegisteredFaceID", ctypes.c_int16), - ("usersInGallery", ctypes.c_int16), - ("gallerySize", ctypes.c_int16), - ] - -class CFpgaPipelineData(ctypes.Structure): - _fields_ = [ - ("pipelineType", ctypes.c_int), - ("imageDimensions", CFpgaImageDimensions), - ("dataContent", CFpgaDataContent), - ("userData", CFpgaUserData * EVE_FPGA_MAX_USERS), - ("objectData", CFpgaObjectData), - ("faceId", CFpgaFaceIdData), - ("handsData", CFpgaHandsData), - ("defectData", CFpgaDefectData), - ] - -class CFpgaMessage(ctypes.Structure): - _fields_ = [ - ("responseType", ctypes.c_int), - ("responseVersion", ctypes.c_uint8), - ("serialStatus", ctypes.c_int), - ("serialReadTimeNano", ctypes.c_longlong), - ] - -class CFpgaData(ctypes.Structure): - _fields_ = [ - ("message", CFpgaMessage), - ("pipelineData", CFpgaPipelineData), - ] - -class CFpgaGetSetting(ctypes.Structure): - _fields_ = [ - ("message", CFpgaMessage), - ("type", ctypes.c_int), - ("setting", ctypes.c_int), - ("value", ctypes.c_uint32), - ] - -class CFpgaParameters(ctypes.Structure): - _fields_ = [ - ("comport", ctypes.c_uint), - ("socWakeupDelay", ctypes.c_uint), - ("wakeupType", ctypes.c_int), - ("forceCameraOn", ctypes.c_ubyte), - ("registerNewFace", ctypes.c_ubyte), - ("clearCurrentFace", ctypes.c_ubyte), - ("enableFaceId", ctypes.c_ubyte), - ("allPipelinesSupported", ctypes.c_ubyte), - ("pipelineVersion", ctypes.c_uint), - ("connection", ctypes.c_int), - ("i2cAdapterNumber", ctypes.c_uint), - ("i2cDeviceNumber", ctypes.c_uint), - ("i2cIRQPin", ctypes.c_uint), - ] - -class CFpgaCallbackControl(ctypes.Structure): - _fields_ = [ - ("request", ctypes.c_int), - ] - -class EveFpgaMetadata(ctypes.Structure): - _fields_ = [ - ("data", ctypes.POINTER(CFpgaData)), - ("errorCode", ctypes.c_int), - ] - -class EveFpgaManualData(ctypes.Structure): - _fields_ = [ - ("data", ctypes.POINTER(ctypes.c_ubyte)), - ("size", ctypes.c_int), - ] - -class EveFpgaJsonMetadata(ctypes.Structure): - _fields_ = [ - ("textStart", ctypes.POINTER(ctypes.c_byte)), - ("textSize", ctypes.c_uint), - ("errorCode", ctypes.c_int), - ] - +import ctypes +from ctypes_enum import CtypesEnum +from .CBasicStructs import * + +EVE_FPGA_MAX_USERS = 10 +EVE_FPGA_MAX_PERSONS = 5 +EVE_FPGA_MAX_HAND_LANDMARKS = 11 +EVE_FPGA_HAND_LANDMARKS = 10 +EVE_FPGA_MAX_OBJECT_DETECTION = 50 +PT_SIZE = 6 +MT_SIZE = 4 +RT_SIZE = 4 + +class EveFpgaConnectionType(CtypesEnum): + EVE_FPGA_AUTO_SELECT = 0 + EVE_FPGA_UART = 1 + EVE_FPGA_I2C = 2 + EVE_FPGA_HUB = 3 + EVE_FPGA_MANUAL = 4 + +class EveFpgaConnectionRequest(CtypesEnum): + EVE_FPGA_STOP = 0 + EVE_FPGA_CONTINUE = 1 + +class pipeline_config_type_t(CtypesEnum): + PT_FD = 0 + PT_LM_FV = 1 + PT_FID = 2 + PT_PD = 3 + PT_HD = 4 + PT_HLMV = 5 + PT_SIZE = 6 + +class setting_type_t(CtypesEnum): + CS_ENABLED = 0x00 + CS_IPS = 0x01 + CS_RESERVED_2_7 = 0x02 + CS_COMMAND = 0x08 + CS_CUSTOM = 0x10 + CS_MAX = 0x11 + +class message_type_t(CtypesEnum): + MT_NONE = 0 + MT_SET = 1 + MT_GET = 2 + MT_GET_BATCH = 3 + MT_SIZE = 4 + +class response_type_t(CtypesEnum): + RT_NONE = 0 + RT_DATA = 1 + RT_GET = 2 + RT_ACK = 3 + RT_SIZE = 4 + +class EveFpgaSerialStatus(CtypesEnum): + EVE_FPGA_SUCCESS = 0 + EVE_FPGA_NO_DATA = 1 + EVE_FPGA_READ_START_MARKER_FAILED = 2 + EVE_FPGA_FIND_START_MARKER_FAILED = 3 + EVE_FPGA_READ_DATA_LENGTH_FAILED = 4 + EVE_FPGA_READ_DATA_FAILED = 5 + EVE_FPGA_CORRUPTED_DATA = 6 + EVE_FPGA_UNEXPECTED_RESPONSE_TYPE = 7 + EVE_FPGA_API_ERROR_START = 8 + EVE_FPGA_NO_CALLBACK = 9 + EVE_FPGA_DATA_ACCESSED_OUTSIDE_CALLBACK = 10 + EVE_FPGA_INIT_FAILED = 11 + EVE_FPGA_NOT_INIT = 12 + EVE_FPGA_NOT_IMPLEMENTED = 13 + EVE_FPGA_API_ERROR_END = 14 + +class EveWakeupDetectionType(CtypesEnum): + EVE_USER_DETECTION = 0 + EVE_STRANGER_DETECTION = 1 + +class EveFpgaPipelineType(CtypesEnum): + EVE_UNKNOWN_PIPELINE = 0 + EVE_HEAD_POSE_PIPELINE = 1 + EVE_FACE_ID_PIPELINE = 2 + EVE_HAND_GESTURE_PIPELINE = 3 + EVE_COMPACT_HEAD_POSE_PIPELINE = 4 + EVE_HMI_PIPELINE = 5 + EVE_STANDALONE_HAND_GESTURE_PIPELINE = 6 + +class EvePersonBodyPose(CtypesEnum): + EVE_FRONT = 0 + EVE_NOT_FRONT = 1 + +class EveDistanceFromCamera(CtypesEnum): + EVE_DISTANCE_CLOSE = 0 + EVE_DISTANCE_MID = 1 + EVE_DISTANCE_FAR = 2 + +class EvePersonRegistrationStatus(CtypesEnum): + EVE_REGISTERED = 0 + EVE_UNREGISTERED = 1 + EVE_UNKNOWN = 2 + EVE_REQUIREMENTS_UNMET = 3 + EVE_DISABLED = 4 + EVE_NO_GALLERY = 5 + +class EveFpgaHandGesture(CtypesEnum): + EVE_FPGA_HAND_GESTURE_NO_GESTURE = 0 + EVE_FPGA_HAND_GESTURE_CLOSE = 1 + EVE_FPGA_HAND_GESTURE_OPEN = 2 + EVE_FPGA_HAND_GESTURE_OPEN_LEFT = 3 + EVE_FPGA_HAND_GESTURE_OPEN_RIGHT = 4 + EVE_FPGA_HAND_GESTURE_INDEX_UP = 5 + EVE_FPGA_HAND_GESTURE_INDEX_DOWN = 6 + EVE_FPGA_HAND_GESTURE_TIP_LEFT = 7 + EVE_FPGA_HAND_GESTURE_TIP_RIGHT = 8 + EVE_FPGA_HAND_GESTURE_UNKNOWN = 9 + +class EveFpgaObjectClass(CtypesEnum): + EVE_FPGA_OBJECT_CLASS_PERSON = 0 + EVE_FPGA_OBJECT_CLASS_BICYCLE = 1 + EVE_FPGA_OBJECT_CLASS_CAR = 2 + EVE_FPGA_OBJECT_CLASS_MOTORCYCLE = 3 + EVE_FPGA_OBJECT_CLASS_BUS = 4 + EVE_FPGA_OBJECT_CLASS_TRUCK = 5 + EVE_FPGA_OBJECT_CLASS_TRAFFIC_LIGHT = 6 + EVE_FPGA_OBJECT_CLASS_STOP_SIGN = 7 + +class pipeline_setting_t(ctypes.Structure): + _fields_ = [ + ("settingType", ctypes.c_int), + ("value", ctypes.c_uint32), + ] + +class pipeline_config_t(ctypes.Structure): + _fields_ = [ + ("type", ctypes.c_int), + ("setting", pipeline_setting_t), + ] + +class CFpgaIdealPersonData(ctypes.Structure): + _fields_ = [ + ("valid", ctypes.c_uint), + ("index", ctypes.c_uint), + ("status", ctypes.c_int), + ("faceAngles", CAngles3f), + ("faceLandmarksConfidence", ctypes.c_float), + ("isFaceLandmarksConfidenceValid", ctypes.c_bool), + ] + +class CFpgaImageDimensions(ctypes.Structure): + _fields_ = [ + ("width", ctypes.c_int), + ("height", ctypes.c_int), + ("cropArea", CRect2i), + ("reserved1", ctypes.c_int), + ("reserved2", ctypes.c_int), + ] + +class CFpgaDataContent(ctypes.Structure): + _fields_ = [ + ("numberOfUsers", ctypes.c_int16), + ("idealUserIndex", ctypes.c_int16), + ("numberOfDetectedFaces", ctypes.c_int16), + ("numberOfFacesConfidence", ctypes.c_float), + ("numberOfDetectedPersons", ctypes.c_int16), + ("numberOfPersonsConfidence", ctypes.c_float), + ("isIdealUserDataAvailable", ctypes.c_bool), + ("idealUserDetected", ctypes.c_bool), + ("isIdealUserIndexValid", ctypes.c_bool), + ("isNumberOfDetectedFacesAvailable", ctypes.c_bool), + ("isNumberOfFacesConfidenceAvailable", ctypes.c_bool), + ("isNumberOfDetectedPersonsAvailable", ctypes.c_bool), + ("isNumberOfPersonsConfidenceAvailable", ctypes.c_bool), + ("isUsersDataAvilable", ctypes.c_bool), + ("isFaceIdDataAvailable", ctypes.c_bool), + ("isObjectDetectionAvailable", ctypes.c_bool), + ("isCameraStreaming", ctypes.c_bool), + ("isHandGestureDataAvailable", ctypes.c_bool), + ("isDefectDetectionAvailable", ctypes.c_bool), + ] + +class CFpgaHandData(ctypes.Structure): + _fields_ = [ + ("validationScore", ctypes.c_float), + ("handBox", CRect2i), + ("landmarks", CPoint3f * EVE_FPGA_MAX_HAND_LANDMARKS), + ] + +class CFpgaHandsData(ctypes.Structure): + _fields_ = [ + ("numberOfHandLandmarkPoints", ctypes.c_int16), + ("handData", CFpgaHandData), + ("gesture", ctypes.c_int), + ("isHandBoxAvailable", ctypes.c_bool), + ("isHandLandmark3D", ctypes.c_bool), + ] + +class CFpgaDefectData(ctypes.Structure): + _fields_ = [ + ("defectBox", CRect2i), + ("width", ctypes.c_int), + ("height", ctypes.c_int), + ("similarity", ctypes.c_float), + ("isDefective", ctypes.c_bool), + ] + +class CFpgaFaceData(ctypes.Structure): + _fields_ = [ + ("faceConfidence", ctypes.c_float), + ("faceDistance", ctypes.c_int16), + ("faceCenter", CPoint3i), + ("anglesICS", CAngles3f), + ("anglesCCS", CAngles3f), + ("faceLandmarksConfidence", ctypes.c_float), + ("faceBox", CRect2i), + ("faceIDStatus", ctypes.c_int), + ("faceID", ctypes.c_int16), + ("isFaceConfidenceAvailable", ctypes.c_bool), + ("isFaceDistanceAvailable", ctypes.c_bool), + ("isFacePositionAvailable", ctypes.c_bool), + ("isEulerAnglesIcsAvailable", ctypes.c_bool), + ("isEulerAnglesCcsAvailable", ctypes.c_bool), + ("isFaceLandmark3D", ctypes.c_bool), + ("isFaceLandmarksConfidenceAvailable", ctypes.c_bool), + ("isFaceGeometricBoxAvailable", ctypes.c_bool), + ("isStatusAvailable", ctypes.c_bool), + ] + +class CFpgaPersonData(ctypes.Structure): + _fields_ = [ + ("personConfidence", ctypes.c_float), + ("personDistance", ctypes.c_int), + ("personPosture", ctypes.c_int), + ("personFrontalPostureConfidence", ctypes.c_float), + ("personNotFrontalPostureConfidence", ctypes.c_float), + ("position", CPoint3i), + ("personBox", CRect2i), + ("isPersonDataAvailable", ctypes.c_bool), + ] + +class CFpgaObjectDetection(ctypes.Structure): + _fields_ = [ + ("objectClass", ctypes.c_int), + ("objectConfidence", ctypes.c_float), + ("objectBox", CRect2i), + ] + +class CFpgaObjectData(ctypes.Structure): + _fields_ = [ + ("numberOfObjects", ctypes.c_int16), + ("objects", CFpgaObjectDetection * EVE_FPGA_MAX_OBJECT_DETECTION), + ] + +class CFpgaUserData(ctypes.Structure): + _fields_ = [ + ("id", ctypes.c_int16), + ("status", ctypes.c_int), + ("scale", ctypes.c_float), + ("faceData", CFpgaFaceData), + ("personData", CFpgaPersonData), + ("isIdealUser", ctypes.c_bool), + ("isIdValid", ctypes.c_bool), + ("isStatusAvailable", ctypes.c_bool), + ("isScaleAvailable", ctypes.c_bool), + ] + +class CFpgaFaceIdData(ctypes.Structure): + _fields_ = [ + ("command", ctypes.c_int16), + ("userId", ctypes.c_int16), + ("freeEntry", ctypes.c_int16), + ("statusCode", ctypes.c_int16), + ("faceId", ctypes.c_int16), + ("lastRegisteredFaceID", ctypes.c_int16), + ("usersInGallery", ctypes.c_int16), + ("gallerySize", ctypes.c_int16), + ] + +class CFpgaPipelineData(ctypes.Structure): + _fields_ = [ + ("pipelineType", ctypes.c_int), + ("imageDimensions", CFpgaImageDimensions), + ("dataContent", CFpgaDataContent), + ("userData", CFpgaUserData * EVE_FPGA_MAX_USERS), + ("objectData", CFpgaObjectData), + ("faceId", CFpgaFaceIdData), + ("handsData", CFpgaHandsData), + ("defectData", CFpgaDefectData), + ] + +class CFpgaMessage(ctypes.Structure): + _fields_ = [ + ("responseType", ctypes.c_int), + ("responseVersion", ctypes.c_uint8), + ("serialStatus", ctypes.c_int), + ("serialReadTimeNano", ctypes.c_longlong), + ] + +class CFpgaData(ctypes.Structure): + _fields_ = [ + ("message", CFpgaMessage), + ("pipelineData", CFpgaPipelineData), + ] + +class CFpgaGetSetting(ctypes.Structure): + _fields_ = [ + ("message", CFpgaMessage), + ("type", ctypes.c_int), + ("setting", ctypes.c_int), + ("value", ctypes.c_uint32), + ] + +class CFpgaParameters(ctypes.Structure): + _fields_ = [ + ("comport", ctypes.c_uint), + ("socWakeupDelay", ctypes.c_uint), + ("wakeupType", ctypes.c_int), + ("forceCameraOn", ctypes.c_ubyte), + ("registerNewFace", ctypes.c_ubyte), + ("clearCurrentFace", ctypes.c_ubyte), + ("enableFaceId", ctypes.c_ubyte), + ("allPipelinesSupported", ctypes.c_ubyte), + ("pipelineVersion", ctypes.c_uint), + ("connection", ctypes.c_int), + ("i2cAdapterNumber", ctypes.c_uint), + ("i2cDeviceNumber", ctypes.c_uint), + ("i2cIRQPin", ctypes.c_uint), + ] + +class CFpgaCallbackControl(ctypes.Structure): + _fields_ = [ + ("request", ctypes.c_int), + ] + +class EveFpgaMetadata(ctypes.Structure): + _fields_ = [ + ("data", ctypes.POINTER(CFpgaData)), + ("errorCode", ctypes.c_int), + ] + +class EveFpgaManualData(ctypes.Structure): + _fields_ = [ + ("data", ctypes.POINTER(ctypes.c_ubyte)), + ("size", ctypes.c_int), + ] + +class EveFpgaJsonMetadata(ctypes.Structure): + _fields_ = [ + ("textStart", ctypes.POINTER(ctypes.c_byte)), + ("textSize", ctypes.c_uint), + ("errorCode", ctypes.c_int), + ] + diff --git a/shared/eve_python/structs/CHandGesture.py b/shared/eve_python/structs/CHandGesture.py index c4b589d7b3c35e06122ce6bc0b282d6f04ae71bd..bef4291100942581c4b1c2e4ad9710e4c6c26f0a 100644 --- a/shared/eve_python/structs/CHandGesture.py +++ b/shared/eve_python/structs/CHandGesture.py @@ -1,144 +1,105 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .CBasicStructs import * -from .EveProcessingStatus import * - -EVE_MAX_HAND_DETECTIONS = 8 -EVE_MAX_DYNAMIC_GESTURE_SEQUENCE = 8 -EVE_MAX_CUSTOM_STATIC_GESTURES = 20 -EVE_MAX_STATIC_GESTURES = 40 -EVE_HAND_LANDMARKS_SIZE = 2 -EVE_HAND_LANDMARK_SIZE = 11 -EVE_STATIC_GESTURE_SIZE = 22 -EVE_DYNAMIC_GESTURE_SIZE = 12 - -class EveRunHandLandmarks(CtypesEnum): - EVE_HAND_LANDMARKS_ALL_HANDS = 0 - EVE_HAND_LANDMARKS_MAIN_HAND_ONLY = 1 - EVE_HAND_LANDMARKS_SIZE = 2 - -class EveHandLandmark(CtypesEnum): - EVE_WRIST = 0 - EVE_THUMB_IP = 1 - EVE_THUMB_TIP = 2 - EVE_INDEX_MCP = 3 - EVE_INDEX_TIP = 4 - EVE_MIDDLE_MCP = 5 - EVE_MIDDLE_TIP = 6 - EVE_RING_MCP = 7 - EVE_RING_TIP = 8 - EVE_PINKY_MCP = 9 - EVE_PINKY_TIP = 10 - EVE_HAND_LANDMARK_SIZE = 11 - -class EveGestureQuality(CtypesEnum): - EVE_POOR_QUALITY_LOW_CONFIDENCE = 0 - EVE_POOR_QUALITY_HAND_OVER_FACE = 1 - EVE_GOOD_QUALITY = 2 - -class EveStaticGestureType(CtypesEnum): - EVE_STATIC_GESTURE_NONE = 0 - EVE_OPEN_HAND = 1 - EVE_OPEN_HAND_LEFT = 2 - EVE_OPEN_HAND_RIGHT = 3 - EVE_CLOSED_HAND = 4 - EVE_THUMBS_LEFT = 5 - EVE_THUMBS_RIGHT = 6 - EVE_RESERVED_STATIC_GESTURE_1 = 7 - EVE_RESERVED_STATIC_GESTURE_2 = 8 - EVE_RESERVED_STATIC_GESTURE_3 = 9 - EVE_RESERVED_STATIC_GESTURE_4 = 10 - EVE_RESERVED_STATIC_GESTURE_5 = 11 - EVE_CUSTOM_STATIC_GESTURE_1 = 12 - EVE_CUSTOM_STATIC_GESTURE_2 = 13 - EVE_CUSTOM_STATIC_GESTURE_3 = 14 - EVE_CUSTOM_STATIC_GESTURE_4 = 15 - EVE_CUSTOM_STATIC_GESTURE_5 = 16 - EVE_CUSTOM_STATIC_GESTURE_6 = 17 - EVE_CUSTOM_STATIC_GESTURE_7 = 18 - EVE_CUSTOM_STATIC_GESTURE_8 = 19 - EVE_CUSTOM_STATIC_GESTURE_9 = 20 - EVE_CUSTOM_STATIC_GESTURE_10 = 21 - EVE_STATIC_GESTURE_SIZE = 22 - -class EveDynamicGestureType(CtypesEnum): - EVE_DYNAMIC_GESTURE_NONE = 0 - EVE_GRAB = 1 - EVE_RESERVED_DYNAMIC_GESTURE_1 = 2 - EVE_RESERVED_DYNAMIC_GESTURE_2 = 3 - EVE_RESERVED_DYNAMIC_GESTURE_3 = 4 - EVE_RESERVED_DYNAMIC_GESTURE_4 = 5 - EVE_RESERVED_DYNAMIC_GESTURE_5 = 6 - EVE_CUSTOM_DYNAMIC_GESTURE_1 = 7 - EVE_CUSTOM_DYNAMIC_GESTURE_2 = 8 - EVE_CUSTOM_DYNAMIC_GESTURE_3 = 9 - EVE_CUSTOM_DYNAMIC_GESTURE_4 = 10 - EVE_CUSTOM_DYNAMIC_GESTURE_5 = 11 - EVE_DYNAMIC_GESTURE_SIZE = 12 - -class EveStaticGesture(ctypes.Structure): - _fields_ = [ - ("handId", ctypes.c_int), - ("isMainUserHand", ctypes.c_int), - ("type", ctypes.c_int), - ("confidence", ctypes.c_float), - ("quality", ctypes.c_int), - ] - -class EveStaticGestures(ctypes.Structure): - _fields_ = [ - ("count", ctypes.c_uint), - ("gestures", EveStaticGesture * EVE_MAX_HAND_DETECTIONS), - ] - -class EveStaticGestureDefinition(ctypes.Structure): - _fields_ = [ - ("gestureType", ctypes.c_int), - ("id", ctypes.c_uint), - ("landmarksMap", CPoint2f * EVE_HAND_LANDMARK_SIZE), - ] - -class EveDynamicGesture(ctypes.Structure): - _fields_ = [ - ("handId", ctypes.c_int), - ("isMainUserHand", ctypes.c_int), - ("type", ctypes.c_int), - ("quality", ctypes.c_int), - ] - -class EveDynamicGestures(ctypes.Structure): - _fields_ = [ - ("count", ctypes.c_uint), - ("gestures", EveDynamicGesture * EVE_MAX_HAND_DETECTIONS), - ] - -class EveDynamicGestureDefinition(ctypes.Structure): - _fields_ = [ - ("gestureType", ctypes.c_int), - ("sequenceCount", ctypes.c_uint), - ("gestureSequence", ctypes.c_int * EVE_MAX_DYNAMIC_GESTURE_SEQUENCE), - ] - -class EveSingleHandDetection(ctypes.Structure): - _fields_ = [ - ("id", ctypes.c_int), - ("isHandValid", ctypes.c_int), - ("boundingBox", CRect2iWH), - ("boundingBoxScore", ctypes.c_float), - ("landmarksICS", CPoint2f * EVE_HAND_LANDMARK_SIZE), - ("validationScore", ctypes.c_float), - ("inPlaneAngle", ctypes.c_float), - ("depth", ctypes.c_float), - ("isMainUserHand", ctypes.c_int), - ("isInCurrentFrame", ctypes.c_int), - ] - -class EveHandDetections(ctypes.Structure): - _fields_ = [ - ("status", ctypes.c_int), - ("hasFaceROI", ctypes.c_int), - ("faceROI", CRect2fWH), - ("detectedHandCount", ctypes.c_uint), - ("hands", EveSingleHandDetection * EVE_MAX_HAND_DETECTIONS), - ] - +import ctypes +from ctypes_enum import CtypesEnum +from .CBasicStructs import * +from .EveProcessingStatus import * + +EVE_MAX_HAND_DETECTIONS = 8 +EVE_MAX_CUSTOM_STATIC_GESTURES = 20 +EVE_MAX_STATIC_GESTURES = 40 +EVE_HAND_LANDMARKS_SIZE = 2 +EVE_HAND_LANDMARK_SIZE = 11 +EVE_STATIC_GESTURE_SIZE = 22 + +class EveRunHandLandmarks(CtypesEnum): + EVE_HAND_LANDMARKS_ALL_HANDS = 0 + EVE_HAND_LANDMARKS_MAIN_HAND_ONLY = 1 + EVE_HAND_LANDMARKS_SIZE = 2 + +class EveHandLandmark(CtypesEnum): + EVE_WRIST = 0 + EVE_THUMB_IP = 1 + EVE_THUMB_TIP = 2 + EVE_INDEX_MCP = 3 + EVE_INDEX_TIP = 4 + EVE_MIDDLE_MCP = 5 + EVE_MIDDLE_TIP = 6 + EVE_RING_MCP = 7 + EVE_RING_TIP = 8 + EVE_PINKY_MCP = 9 + EVE_PINKY_TIP = 10 + EVE_HAND_LANDMARK_SIZE = 11 + +class EveGestureQuality(CtypesEnum): + EVE_POOR_QUALITY_LOW_CONFIDENCE = 0 + EVE_POOR_QUALITY_HAND_OVER_FACE = 1 + EVE_GOOD_QUALITY = 2 + +class EveStaticGestureType(CtypesEnum): + EVE_STATIC_GESTURE_NONE = 0 + EVE_OPEN_HAND = 1 + EVE_OPEN_HAND_LEFT = 2 + EVE_OPEN_HAND_RIGHT = 3 + EVE_CLOSED_HAND = 4 + EVE_THUMBS_LEFT = 5 + EVE_THUMBS_RIGHT = 6 + EVE_RESERVED_STATIC_GESTURE_1 = 7 + EVE_RESERVED_STATIC_GESTURE_2 = 8 + EVE_RESERVED_STATIC_GESTURE_3 = 9 + EVE_RESERVED_STATIC_GESTURE_4 = 10 + EVE_RESERVED_STATIC_GESTURE_5 = 11 + EVE_CUSTOM_STATIC_GESTURE_1 = 12 + EVE_CUSTOM_STATIC_GESTURE_2 = 13 + EVE_CUSTOM_STATIC_GESTURE_3 = 14 + EVE_CUSTOM_STATIC_GESTURE_4 = 15 + EVE_CUSTOM_STATIC_GESTURE_5 = 16 + EVE_CUSTOM_STATIC_GESTURE_6 = 17 + EVE_CUSTOM_STATIC_GESTURE_7 = 18 + EVE_CUSTOM_STATIC_GESTURE_8 = 19 + EVE_CUSTOM_STATIC_GESTURE_9 = 20 + EVE_CUSTOM_STATIC_GESTURE_10 = 21 + EVE_STATIC_GESTURE_SIZE = 22 + +class EveStaticGesture(ctypes.Structure): + _fields_ = [ + ("handId", ctypes.c_int), + ("isMainUserHand", ctypes.c_int), + ("type", ctypes.c_int), + ("confidence", ctypes.c_float), + ("quality", ctypes.c_int), + ] + +class EveStaticGestures(ctypes.Structure): + _fields_ = [ + ("count", ctypes.c_uint), + ("gestures", EveStaticGesture * EVE_MAX_HAND_DETECTIONS), + ] + +class EveStaticGestureDefinition(ctypes.Structure): + _fields_ = [ + ("gestureType", ctypes.c_int), + ("id", ctypes.c_uint), + ("landmarksMap", CPoint2f * EVE_HAND_LANDMARK_SIZE), + ] + +class EveSingleHandDetection(ctypes.Structure): + _fields_ = [ + ("id", ctypes.c_int), + ("isHandValid", ctypes.c_int), + ("boundingBox", CRect2iWH), + ("boundingBoxScore", ctypes.c_float), + ("landmarksICS", CPoint2f * EVE_HAND_LANDMARK_SIZE), + ("validationScore", ctypes.c_float), + ("inPlaneAngle", ctypes.c_float), + ("depth", ctypes.c_float), + ("isMainUserHand", ctypes.c_int), + ] + +class EveHandDetections(ctypes.Structure): + _fields_ = [ + ("status", ctypes.c_int), + ("hasFaceROI", ctypes.c_int), + ("faceROI", CRect2fWH), + ("detectedHandCount", ctypes.c_uint), + ("hands", EveSingleHandDetection * EVE_MAX_HAND_DETECTIONS), + ] + diff --git a/shared/eve_python/structs/CImageManipulation.py b/shared/eve_python/structs/CImageManipulation.py index 89ebfe21ee394e86c3a5a62126fe27bd68db3010..17bafc2c99fa00a36c6d84a03e4d6c1715d36876 100644 --- a/shared/eve_python/structs/CImageManipulation.py +++ b/shared/eve_python/structs/CImageManipulation.py @@ -1,12 +1,12 @@ -import ctypes -from ctypes_enum import CtypesEnum - - -class CImageManipulationSettings(ctypes.Structure): - _fields_ = [ - ("mirrorImage", ctypes.c_uint), - ("reserved1", ctypes.c_uint), - ("reserved2", ctypes.c_uint), - ("reserved3", ctypes.c_uint), - ] - +import ctypes +from ctypes_enum import CtypesEnum + + +class CImageManipulationSettings(ctypes.Structure): + _fields_ = [ + ("mirrorImage", ctypes.c_uint), + ("reserved1", ctypes.c_uint), + ("reserved2", ctypes.c_uint), + ("reserved3", ctypes.c_uint), + ] + diff --git a/shared/eve_python/structs/CKarolinska.py b/shared/eve_python/structs/CKarolinska.py index e19807667ad7f80bf3086928200e5b44a5a3e55e..9abf6b338c31c3b61fd9cdf6c925a8979a9237ef 100644 --- a/shared/eve_python/structs/CKarolinska.py +++ b/shared/eve_python/structs/CKarolinska.py @@ -1,57 +1,57 @@ -import ctypes -from ctypes_enum import CtypesEnum - - -class EveKarolinskaSleepiness(CtypesEnum): - EVE_KAROLINSKA_DISABLED = 0 - EVE_KAROLINSKA_1 = 1 - EVE_KAROLINSKA_2 = 2 - EVE_KAROLINSKA_3 = 3 - EVE_KAROLINSKA_4 = 4 - EVE_KAROLINSKA_5 = 5 - EVE_KAROLINSKA_6 = 6 - EVE_KAROLINSKA_7 = 7 - EVE_KAROLINSKA_8 = 8 - EVE_KAROLINSKA_9 = 9 - EVE_KAROLINSKA_MAX = 10 - -class EveEyeClosureState(CtypesEnum): - EVE_EYE_STATE_UNKNOWN = 0 - EVE_EYE_OPEN = 1 - EVE_EYE_CLOSED = 2 - -class EveKarolinskaStatus(CtypesEnum): - EVE_KAROLINSKA_OFF = 0 - EVE_KAROLINSKA_NO_FACE = 1 - EVE_KAROLINSKA_BLINKS_ONLY = 2 - EVE_KAROLINSKA_ON = 3 - -class CEyeState(ctypes.Structure): - _fields_ = [ - ("state", ctypes.c_int), - ("closure", ctypes.c_float), - ("confidence", ctypes.c_float), - ("eyelidDistanceMM", ctypes.c_float), - ] - -class CEyeStates(ctypes.Structure): - _fields_ = [ - ("left", CEyeState), - ("right", CEyeState), - ("fused", CEyeState), - ("blinkCount", ctypes.c_uint), - ] - -class CKarolinskaData(ctypes.Structure): - _fields_ = [ - ("status", ctypes.c_int), - ("scale", ctypes.c_int), - ("headPitchScale", ctypes.c_int), - ("yawnScale", ctypes.c_int), - ("blinkDurationScale", ctypes.c_int), - ("yawn", ctypes.c_float), - ("yawnConfidence", ctypes.c_float), - ("yawnCount", ctypes.c_uint), - ("eyes", CEyeStates), - ] - +import ctypes +from ctypes_enum import CtypesEnum + + +class EveKarolinskaSleepiness(CtypesEnum): + EVE_KAROLINSKA_DISABLED = 0 + EVE_KAROLINSKA_1 = 1 + EVE_KAROLINSKA_2 = 2 + EVE_KAROLINSKA_3 = 3 + EVE_KAROLINSKA_4 = 4 + EVE_KAROLINSKA_5 = 5 + EVE_KAROLINSKA_6 = 6 + EVE_KAROLINSKA_7 = 7 + EVE_KAROLINSKA_8 = 8 + EVE_KAROLINSKA_9 = 9 + EVE_KAROLINSKA_MAX = 10 + +class EveEyeClosureState(CtypesEnum): + EVE_EYE_STATE_UNKNOWN = 0 + EVE_EYE_OPEN = 1 + EVE_EYE_CLOSED = 2 + +class EveKarolinskaStatus(CtypesEnum): + EVE_KAROLINSKA_OFF = 0 + EVE_KAROLINSKA_NO_FACE = 1 + EVE_KAROLINSKA_BLINKS_ONLY = 2 + EVE_KAROLINSKA_ON = 3 + +class CEyeState(ctypes.Structure): + _fields_ = [ + ("state", ctypes.c_int), + ("closure", ctypes.c_float), + ("confidence", ctypes.c_float), + ("eyelidDistanceMM", ctypes.c_float), + ] + +class CEyeStates(ctypes.Structure): + _fields_ = [ + ("left", CEyeState), + ("right", CEyeState), + ("fused", CEyeState), + ("blinkCount", ctypes.c_uint), + ] + +class CKarolinskaData(ctypes.Structure): + _fields_ = [ + ("status", ctypes.c_int), + ("scale", ctypes.c_int), + ("headPitchScale", ctypes.c_int), + ("yawnScale", ctypes.c_int), + ("blinkDurationScale", ctypes.c_int), + ("yawn", ctypes.c_float), + ("yawnConfidence", ctypes.c_float), + ("yawnCount", ctypes.c_uint), + ("eyes", CEyeStates), + ] + diff --git a/shared/eve_python/structs/CLandmarkMaps.py b/shared/eve_python/structs/CLandmarkMaps.py index 75adb9a72bc3426e5b80f54a0fba7092ee353198..6e7bc37b14471f2df9f8ff0113f500aad473defe 100644 --- a/shared/eve_python/structs/CLandmarkMaps.py +++ b/shared/eve_python/structs/CLandmarkMaps.py @@ -1,40 +1,40 @@ -import ctypes -from ctypes_enum import CtypesEnum - -EVE_HMI_P_L_SIZE = 23 -EVE_HMI_S_L_SIZE = 5 - -class EveHmiPrimaryLandmarks(CtypesEnum): - EVE_HMI_P_L_RIGHT_TEMPLE = 0 - EVE_HMI_P_L_RIGHT_JAW = 1 - EVE_HMI_P_L_CENTER_JAW = 2 - EVE_HMI_P_L_LEFT_JAW = 3 - EVE_HMI_P_L_LEFT_TEMPLE = 4 - EVE_HMI_P_L_RIGHT_EYEBROW = 5 - EVE_HMI_P_L_LEFT_EYEBROW = 6 - EVE_HMI_P_L_NOSE_BRIDGE = 7 - EVE_HMI_P_L_NOSE_TIP_HIGH = 8 - EVE_HMI_P_L_NOSE_TIP = 9 - EVE_HMI_P_L_NOSE_TIP_LOW = 10 - EVE_HMI_P_L_RIGHT_EYE_1 = 11 - EVE_HMI_P_L_RIGHT_EYE_2 = 12 - EVE_HMI_P_L_LEFT_EYE_1 = 13 - EVE_HMI_P_L_LEFT_EYE_2 = 14 - EVE_HMI_P_L_MOUTH_RIGHT_CORNER = 15 - EVE_HMI_P_L_MOUTH_UPPER_LIP = 16 - EVE_HMI_P_L_MOUTH_LEFT_CORNER = 17 - EVE_HMI_P_L_MOUTH_LOWER_LIP = 18 - EVE_HMI_P_L_MOUTH_OPEN_TOP = 19 - EVE_HMI_P_L_MOUTH_OPEN_BOTTOM = 20 - EVE_HMI_P_L_RIGHT_PUPIL = 21 - EVE_HMI_P_L_LEFT_PUPIL = 22 - EVE_HMI_P_L_SIZE = 23 - -class EveHmiSecondaryLandmarks(CtypesEnum): - EVE_HMI_S_L_RIGHT_PUPIL = 0 - EVE_HMI_S_L_LEFT_PUPIL = 1 - EVE_HMI_S_L_NOSE_TIP_LOW = 2 - EVE_HMI_S_L_RIGHT_MOUTH_CORNER = 3 - EVE_HMI_S_L_LEFT_MOUTH_CORNER = 4 - EVE_HMI_S_L_SIZE = 5 - +import ctypes +from ctypes_enum import CtypesEnum + +EVE_HMI_P_L_SIZE = 23 +EVE_HMI_S_L_SIZE = 5 + +class EveHmiPrimaryLandmarks(CtypesEnum): + EVE_HMI_P_L_RIGHT_TEMPLE = 0 + EVE_HMI_P_L_RIGHT_JAW = 1 + EVE_HMI_P_L_CENTER_JAW = 2 + EVE_HMI_P_L_LEFT_JAW = 3 + EVE_HMI_P_L_LEFT_TEMPLE = 4 + EVE_HMI_P_L_RIGHT_EYEBROW = 5 + EVE_HMI_P_L_LEFT_EYEBROW = 6 + EVE_HMI_P_L_NOSE_BRIDGE = 7 + EVE_HMI_P_L_NOSE_TIP_HIGH = 8 + EVE_HMI_P_L_NOSE_TIP = 9 + EVE_HMI_P_L_NOSE_TIP_LOW = 10 + EVE_HMI_P_L_RIGHT_EYE_1 = 11 + EVE_HMI_P_L_RIGHT_EYE_2 = 12 + EVE_HMI_P_L_LEFT_EYE_1 = 13 + EVE_HMI_P_L_LEFT_EYE_2 = 14 + EVE_HMI_P_L_MOUTH_RIGHT_CORNER = 15 + EVE_HMI_P_L_MOUTH_UPPER_LIP = 16 + EVE_HMI_P_L_MOUTH_LEFT_CORNER = 17 + EVE_HMI_P_L_MOUTH_LOWER_LIP = 18 + EVE_HMI_P_L_MOUTH_OPEN_TOP = 19 + EVE_HMI_P_L_MOUTH_OPEN_BOTTOM = 20 + EVE_HMI_P_L_RIGHT_PUPIL = 21 + EVE_HMI_P_L_LEFT_PUPIL = 22 + EVE_HMI_P_L_SIZE = 23 + +class EveHmiSecondaryLandmarks(CtypesEnum): + EVE_HMI_S_L_RIGHT_PUPIL = 0 + EVE_HMI_S_L_LEFT_PUPIL = 1 + EVE_HMI_S_L_NOSE_TIP_LOW = 2 + EVE_HMI_S_L_RIGHT_MOUTH_CORNER = 3 + EVE_HMI_S_L_LEFT_MOUTH_CORNER = 4 + EVE_HMI_S_L_SIZE = 5 + diff --git a/shared/eve_python/structs/CLicenseResult.py b/shared/eve_python/structs/CLicenseResult.py new file mode 100644 index 0000000000000000000000000000000000000000..9bc26747a9296580aba24b94674e79b41793fd0b --- /dev/null +++ b/shared/eve_python/structs/CLicenseResult.py @@ -0,0 +1,10 @@ +import ctypes +from ctypes_enum import CtypesEnum + + +class EveLicenseResult(ctypes.Structure): + _fields_ = [ + ("licenseReturnCode", ctypes.c_uint), + ("licenseWarnings", ctypes.c_byte * 256), + ] + diff --git a/shared/eve_python/structs/CROIStructs.py b/shared/eve_python/structs/CROIStructs.py index b5d7d214c7e7aa51c5e10532c53da98be2e42a8d..db88f1d22d8304d593f138621e017b9130b0fc1f 100644 --- a/shared/eve_python/structs/CROIStructs.py +++ b/shared/eve_python/structs/CROIStructs.py @@ -1,29 +1,29 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .EveProcessingStatus import * - -EVE_ROI_MAX_SCORE_COUNT = 20 - -class EveROIState(CtypesEnum): - EVE_ROI_STATE_INACTIVE = 0 - EVE_ROI_STATE_ENTERING = 1 - EVE_ROI_STATE_LEAVING = 2 - EVE_ROI_STATE_SELECTED = 3 - -class CROIScore(ctypes.Structure): - _fields_ = [ - ("id", ctypes.c_uint), - ("intersectionScore", ctypes.c_double), - ("filteredScore", ctypes.c_double), - ("state", ctypes.c_int), - ] - -class CROIScoreData(ctypes.Structure): - _fields_ = [ - ("processingStatus", ctypes.c_int), - ("fusedRoiScoresCount", ctypes.c_uint), - ("fusedRoiScores", CROIScore * EVE_ROI_MAX_SCORE_COUNT), - ("faceRoiScoresCount", ctypes.c_uint), - ("faceRoiScores", CROIScore * EVE_ROI_MAX_SCORE_COUNT), - ] - +import ctypes +from ctypes_enum import CtypesEnum +from .EveProcessingStatus import * + +EVE_ROI_MAX_SCORE_COUNT = 20 + +class EveROIState(CtypesEnum): + EVE_ROI_STATE_INACTIVE = 0 + EVE_ROI_STATE_ENTERING = 1 + EVE_ROI_STATE_LEAVING = 2 + EVE_ROI_STATE_SELECTED = 3 + +class CROIScore(ctypes.Structure): + _fields_ = [ + ("id", ctypes.c_uint), + ("intersectionScore", ctypes.c_double), + ("filteredScore", ctypes.c_double), + ("state", ctypes.c_int), + ] + +class CROIScoreData(ctypes.Structure): + _fields_ = [ + ("processingStatus", ctypes.c_int), + ("fusedRoiScoresCount", ctypes.c_uint), + ("fusedRoiScores", CROIScore * EVE_ROI_MAX_SCORE_COUNT), + ("faceRoiScoresCount", ctypes.c_uint), + ("faceRoiScores", CROIScore * EVE_ROI_MAX_SCORE_COUNT), + ] + diff --git a/shared/eve_python/structs/CVisualSpeechStructs.py b/shared/eve_python/structs/CVisualSpeechStructs.py index 6696e6c823217ab47a1ba642cbabaa28e163b1f1..0473dc611989cbefc395a2e85230c779d9be0535 100644 --- a/shared/eve_python/structs/CVisualSpeechStructs.py +++ b/shared/eve_python/structs/CVisualSpeechStructs.py @@ -1,18 +1,18 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .EveProcessingStatus import * - - -class EveVisualSpeechState(CtypesEnum): - EVE_NOT_SET = 0 - EVE_NOT_SPEAKING = 1 - EVE_SPEAKING = 2 - -class CVisualSpeechData(ctypes.Structure): - _fields_ = [ - ("processingStatus", ctypes.c_int), - ("speechState", ctypes.c_int), - ("notSpeakingProbability", ctypes.c_double), - ("speakingProbability", ctypes.c_double), - ] - +import ctypes +from ctypes_enum import CtypesEnum +from .EveProcessingStatus import * + + +class EveVisualSpeechState(CtypesEnum): + EVE_NOT_SET = 0 + EVE_NOT_SPEAKING = 1 + EVE_SPEAKING = 2 + +class CVisualSpeechData(ctypes.Structure): + _fields_ = [ + ("processingStatus", ctypes.c_int), + ("speechState", ctypes.c_int), + ("notSpeakingProbability", ctypes.c_double), + ("speakingProbability", ctypes.c_double), + ] + diff --git a/shared/eve_python/structs/EveAlgorithm.py b/shared/eve_python/structs/EveAlgorithm.py index 48b251b546bd62fee87cb03f16e7ced724869aab..ca2fa7f8db978e9e90801b97cf34a9e96f3a9aa4 100644 --- a/shared/eve_python/structs/EveAlgorithm.py +++ b/shared/eve_python/structs/EveAlgorithm.py @@ -1,5 +1,5 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .EveAlgorithmStructs import * - - +import ctypes +from ctypes_enum import CtypesEnum +from .EveAlgorithmStructs import * + + diff --git a/shared/eve_python/structs/EveAlgorithmStructs.py b/shared/eve_python/structs/EveAlgorithmStructs.py index 79f7337f8c1699f7c0c18a069be4631224537853..dbf1255b3b4d08f48b1b9f2dbf7b58268c08ce5e 100644 --- a/shared/eve_python/structs/EveAlgorithmStructs.py +++ b/shared/eve_python/structs/EveAlgorithmStructs.py @@ -1,14 +1,14 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .CAlgorithms import * -from .EveErrors import * - -EVE_ALGORITHMS_SIZE = 20 - -class EveSupportedAlgorithms(ctypes.Structure): - _fields_ = [ - ("errorCode", ctypes.c_int), - ("count", ctypes.c_uint), - ("algorithms", ctypes.c_int * EVE_ALGORITHMS_SIZE), - ] - +import ctypes +from ctypes_enum import CtypesEnum +from .CAlgorithms import * +from .EveErrors import * + +EVE_ALGORITHMS_SIZE = 20 + +class EveSupportedAlgorithms(ctypes.Structure): + _fields_ = [ + ("errorCode", ctypes.c_int), + ("count", ctypes.c_uint), + ("algorithms", ctypes.c_int * EVE_ALGORITHMS_SIZE), + ] + diff --git a/shared/eve_python/structs/EveCallbackReturnData.py b/shared/eve_python/structs/EveCallbackReturnData.py index 7e05c11672da36c1a4ada3f4d7e4a2dff8b4c32d..673156d95b19ab6cf5ebe8aa7f04038c4b8ed919 100644 --- a/shared/eve_python/structs/EveCallbackReturnData.py +++ b/shared/eve_python/structs/EveCallbackReturnData.py @@ -1,13 +1,13 @@ -import ctypes -from ctypes_enum import CtypesEnum - - -class EveRequestedProcessingState(CtypesEnum): - EVE_REQUESTED_PROCESSING_STATE_CONTINUE = 0 - EVE_REQUESTED_PROCESSING_STATE_STOP = 1 - -class EveProcessingCallbackReturnData(ctypes.Structure): - _fields_ = [ - ("requestedState", ctypes.c_int), - ] - +import ctypes +from ctypes_enum import CtypesEnum + + +class EveRequestedProcessingState(CtypesEnum): + EVE_REQUESTED_PROCESSING_STATE_CONTINUE = 0 + EVE_REQUESTED_PROCESSING_STATE_STOP = 1 + +class EveProcessingCallbackReturnData(ctypes.Structure): + _fields_ = [ + ("requestedState", ctypes.c_int), + ] + diff --git a/shared/eve_python/structs/EveCamera.py b/shared/eve_python/structs/EveCamera.py index 49775c99e9b9388610997b20a10dd9c15681ba75..3893dd035ac359374600b1d0b5cdd34346b246c3 100644 --- a/shared/eve_python/structs/EveCamera.py +++ b/shared/eve_python/structs/EveCamera.py @@ -1,5 +1,5 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .EveCameraStructs import * - - +import ctypes +from ctypes_enum import CtypesEnum +from .EveCameraStructs import * + + diff --git a/shared/eve_python/structs/EveCameraStructs.py b/shared/eve_python/structs/EveCameraStructs.py index 31f14735f4cf0c64707920be0c26ec922ad41b9d..49ffb5e5ddfc3ddf7467303eb00a9dcb3cf00ba7 100644 --- a/shared/eve_python/structs/EveCameraStructs.py +++ b/shared/eve_python/structs/EveCameraStructs.py @@ -1,27 +1,47 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .CCameraStructs import * -from .EveErrors import * - -EVE_CAMERA_FORMATS_SIZE = 20 - -class EveCameraFormats(ctypes.Structure): - _fields_ = [ - ("formats", CCameraFormat * EVE_CAMERA_FORMATS_SIZE), - ("formatsCount", ctypes.c_uint), - ("hadMoreFormats", ctypes.c_uint), - ("error", ctypes.c_int), - ] - -class EveCamera(ctypes.Structure): - _fields_ = [ - ("data", CCamera), - ("error", ctypes.c_int), - ] - -class EveNumberOfCameras(ctypes.Structure): - _fields_ = [ - ("count", ctypes.c_uint), - ("error", ctypes.c_int), - ] - +import ctypes +from ctypes_enum import CtypesEnum +from .CCameraStructs import * +from .EveErrors import * + +EVE_CAMERA_FORMATS_SIZE = 20 +EVE_MONITOR_SIZE = 4 + +class EveCameraFormats(ctypes.Structure): + _fields_ = [ + ("formats", CCameraFormat * EVE_CAMERA_FORMATS_SIZE), + ("formatsCount", ctypes.c_uint), + ("hadMoreFormats", ctypes.c_uint), + ("error", ctypes.c_int), + ] + +class EveCamera(ctypes.Structure): + _fields_ = [ + ("data", CCamera), + ("error", ctypes.c_int), + ] + +class EveNumberOfCameras(ctypes.Structure): + _fields_ = [ + ("count", ctypes.c_uint), + ("error", ctypes.c_int), + ] + +class EveMonitors(ctypes.Structure): + _fields_ = [ + ("monitorCount", ctypes.c_uint), + ("error", ctypes.c_int), + ("monitors", CMonitor * EVE_MONITOR_SIZE), + ] + +class EveCameraLocation(ctypes.Structure): + _fields_ = [ + ("location", CCameraLocation), + ("error", ctypes.c_int), + ] + +class EveCameraParameters(ctypes.Structure): + _fields_ = [ + ("parameters", CCameraParameters), + ("error", ctypes.c_int), + ] + diff --git a/shared/eve_python/structs/EveConfigurationParameters.py b/shared/eve_python/structs/EveConfigurationParameters.py index 28b28be60335a27a703be2a87e5fb3103c6ea37b..bbe529a289b569e4e7d54e0c60363cc61fd738d6 100644 --- a/shared/eve_python/structs/EveConfigurationParameters.py +++ b/shared/eve_python/structs/EveConfigurationParameters.py @@ -1,36 +1,45 @@ -import ctypes -from ctypes_enum import CtypesEnum - -EVE_PIPELINE_TYPE_SIZE = 2 - -class EveImageProvider(CtypesEnum): - EVE_CAMERA = 0 - EVE_CLIENT_PROVIDED = 1 - -class EveGpuPreference(CtypesEnum): - EVE_GPU_LOW_POWER = 0 - EVE_GPU_HIGH_PERFORMANCE = 1 - EVE_NO_GPU = 2 - -class EveStartupType(CtypesEnum): - EVE_SYNC = 0 - EVE_ASYNC = 1 - -class EveProcessingPipelineType(CtypesEnum): - EVE_FULL = 0 - EVE_HMI = 1 - EVE_PIPELINE_TYPE_SIZE = 2 - -class EveStartupParameters(ctypes.Structure): - _fields_ = [ - ("gpuPreference", ctypes.c_int), - ("imageProvider", ctypes.c_int), - ("startupType", ctypes.c_int), - ("pathOverride", ctypes.c_byte * 512), - ] - -class EveProcessingParameters(ctypes.Structure): - _fields_ = [ - ("type", ctypes.c_int), - ] - +import ctypes +from ctypes_enum import CtypesEnum + +EVE_PIPELINE_TYPE_SIZE = 2 +EVE_CAMERA_TYPE_SIZE = 3 + +class EveImageProvider(CtypesEnum): + EVE_CAMERA = 0 + EVE_CLIENT_PROVIDED = 1 + +class EveGpuPreference(CtypesEnum): + EVE_GPU_LOW_POWER = 0 + EVE_GPU_HIGH_PERFORMANCE = 1 + EVE_NO_GPU = 2 + +class EveStartupType(CtypesEnum): + EVE_SYNC = 0 + EVE_ASYNC = 1 + +class EveProcessingPipelineType(CtypesEnum): + EVE_FULL = 0 + EVE_HMI = 1 + EVE_PIPELINE_TYPE_SIZE = 2 + +class EveCameraType(CtypesEnum): + EVE_CAMERA_AUTO = 0 + EVE_CAMERA_RGB = 1 + EVE_CAMERA_IR = 2 + EVE_CAMERA_TYPE_SIZE = 3 + +class EveStartupParameters(ctypes.Structure): + _fields_ = [ + ("gpuPreference", ctypes.c_int), + ("imageProvider", ctypes.c_int), + ("startupType", ctypes.c_int), + ("pathOverride", ctypes.c_byte * 512), + ] + +class EveProcessingParameters(ctypes.Structure): + _fields_ = [ + ("type", ctypes.c_int), + ("cameraType", ctypes.c_int), + ("imageProvider", ctypes.c_int), + ] + diff --git a/shared/eve_python/structs/EveControlInterface.py b/shared/eve_python/structs/EveControlInterface.py index 7bf10108a1e3e3d1ff5f13559acdaa2271e16323..60822d8c3217c890e02f03cad62d127a86cfe825 100644 --- a/shared/eve_python/structs/EveControlInterface.py +++ b/shared/eve_python/structs/EveControlInterface.py @@ -1,9 +1,10 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .CCameraStructs import * -from .EveCallbackReturnData import * -from .EveConfigurationParameters import * -from .EveErrors import * -from .EveImageStructs import * - - +import ctypes +from ctypes_enum import CtypesEnum +from .CCameraStructs import * +from .CLicenseResult import * +from .EveCallbackReturnData import * +from .EveConfigurationParameters import * +from .EveErrors import * +from .EveImageStructs import * + + diff --git a/shared/eve_python/structs/EveControlOption.py b/shared/eve_python/structs/EveControlOption.py index 33566e29d3f3700761107a9985aaed7887894a32..42ceca5b2991b298154331b09c8be85b377fd406 100644 --- a/shared/eve_python/structs/EveControlOption.py +++ b/shared/eve_python/structs/EveControlOption.py @@ -1,8 +1,8 @@ -import ctypes -from ctypes_enum import CtypesEnum - - -class EveOptionEnabled(CtypesEnum): - EVE_OPTION_DISABLED = 0 - EVE_OPTION_ENABLED = 1 - +import ctypes +from ctypes_enum import CtypesEnum + + +class EveOptionEnabled(CtypesEnum): + EVE_OPTION_DISABLED = 0 + EVE_OPTION_ENABLED = 1 + diff --git a/shared/eve_python/structs/EveErrors.py b/shared/eve_python/structs/EveErrors.py index 2f0ce4f3af7bd4e71ceccab3af7aa01a37783f60..0cecee834252675b23aa0584c505a1ad6010c3a6 100644 --- a/shared/eve_python/structs/EveErrors.py +++ b/shared/eve_python/structs/EveErrors.py @@ -1,22 +1,26 @@ -import ctypes -from ctypes_enum import CtypesEnum - - -class EveError(CtypesEnum): - EVE_ERROR_NO_ERROR = 0 - EVE_ERROR_NOT_CREATED = 1 - EVE_ERROR_NOT_STARTED = 2 - EVE_ERROR_PIPELINE_NOT_FOUND = 3 - EVE_ERROR_CAMERA_MANAGER_NOT_FOUND = 4 - EVE_ERROR_NO_CALLBACK = 5 - EVE_ERROR_NOT_ACCESSED_FROM_CALLBACK = 6 - EVE_INVALID_IMAGE_ENCODING = 7 - EVE_CALLBACK_WITHOUT_CONNECTING_TO_CAMERA = 8 - EVE_CAMERA_INTERACTION_WITHOUT_CAMERA = 9 - EVE_NO_MORE_DATA = 10 - EVE_INVALID_CAMERA_ID = 11 - EVE_FACE_ID_INVALID_THRESHOLD = 12 - EVE_ERROR_NO_CAMERA_INTERACTION_WITH_CAMERA = 13 - EVE_ERROR_NOT_IMPLEMENTED = 14 - EVE_ERROR_UNSUPPORTED_FORMAT = 15 - +import ctypes +from ctypes_enum import CtypesEnum + + +class EveError(CtypesEnum): + EVE_ERROR_NO_ERROR = 0 + EVE_ERROR_NOT_CREATED = 1 + EVE_ERROR_NOT_STARTED = 2 + EVE_ERROR_PIPELINE_NOT_FOUND = 3 + EVE_ERROR_CAMERA_MANAGER_NOT_FOUND = 4 + EVE_ERROR_NO_CALLBACK = 5 + EVE_ERROR_NOT_ACCESSED_FROM_CALLBACK = 6 + EVE_INVALID_IMAGE_ENCODING = 7 + EVE_CALLBACK_WITHOUT_CONNECTING_TO_CAMERA = 8 + EVE_CAMERA_INTERACTION_WITHOUT_CAMERA = 9 + EVE_NO_MORE_DATA = 10 + EVE_INVALID_CAMERA_ID = 11 + EVE_FACE_ID_INVALID_THRESHOLD = 12 + EVE_ERROR_NO_CAMERA_INTERACTION_WITH_CAMERA = 13 + EVE_ERROR_NOT_IMPLEMENTED = 14 + EVE_ERROR_UNSUPPORTED_FORMAT = 15 + EVE_ERROR_NO_MONITORS = 16 + EVE_OBJECT_DETECTION_INVALID_THRESHOLD = 17 + EVE_OBJECT_DETECTION_INVALID_MODEL_PATH = 18 + EVE_OBJECT_DETECTION_INVALID_CLASS_COUNT = 19 + diff --git a/shared/eve_python/structs/EveFaceId.py b/shared/eve_python/structs/EveFaceId.py index 41e0a0c46161be056c89e3ec50edb1ff968658d9..7257676a9e49e15de6308ae4d3633e20214d2cb7 100644 --- a/shared/eve_python/structs/EveFaceId.py +++ b/shared/eve_python/structs/EveFaceId.py @@ -1,5 +1,5 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .EveFaceIdStructs import * - - +import ctypes +from ctypes_enum import CtypesEnum +from .EveFaceIdStructs import * + + diff --git a/shared/eve_python/structs/EveFaceIdStructs.py b/shared/eve_python/structs/EveFaceIdStructs.py index d7cc0802aa9a7821966d236165fe2afc86c9e70a..c4eae62a41f479e497b1188cd164f21781e59951 100644 --- a/shared/eve_python/structs/EveFaceIdStructs.py +++ b/shared/eve_python/structs/EveFaceIdStructs.py @@ -1,31 +1,31 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .CFaceIdStructs import * -from .EveControlOption import * -from .EveErrors import * - - -class EveFaceIdCalibrationPoseMode(CtypesEnum): - EVE_FACEID_CALIBRATION_FRONTAL_ONLY = 1 - -class EveFaceIdCommandStruct(ctypes.Structure): - _fields_ = [ - ("command", ctypes.c_int), - ("errorCode", ctypes.c_int), - ] - -class EveFaceIdOptions(ctypes.Structure): - _fields_ = [ - ("enabled", ctypes.c_int), - ("calibrationPoses", ctypes.c_int), - ("galleryPath", ctypes.c_byte * 256), - ("threshold", ctypes.c_float), - ("error", ctypes.c_int), - ] - -class EveFaceIdData(ctypes.Structure): - _fields_ = [ - ("data", CFaceIdentityData), - ("error", ctypes.c_int), - ] - +import ctypes +from ctypes_enum import CtypesEnum +from .CFaceIdStructs import * +from .EveControlOption import * +from .EveErrors import * + + +class EveFaceIdCalibrationPoseMode(CtypesEnum): + EVE_FACEID_CALIBRATION_FRONTAL_ONLY = 1 + +class EveFaceIdCommandStruct(ctypes.Structure): + _fields_ = [ + ("command", ctypes.c_int), + ("errorCode", ctypes.c_int), + ] + +class EveFaceIdOptions(ctypes.Structure): + _fields_ = [ + ("enabled", ctypes.c_int), + ("calibrationPoses", ctypes.c_int), + ("galleryPath", ctypes.c_byte * 256), + ("threshold", ctypes.c_float), + ("error", ctypes.c_int), + ] + +class EveFaceIdData(ctypes.Structure): + _fields_ = [ + ("data", CFaceIdentityData), + ("error", ctypes.c_int), + ] + diff --git a/shared/eve_python/structs/EveFaceTracker.py b/shared/eve_python/structs/EveFaceTracker.py index 9e44ace41a23a2bf1436064f216ea8bb2599f1e8..e10003b9ab1c55c164b28be2b1e05cd8c4615b77 100644 --- a/shared/eve_python/structs/EveFaceTracker.py +++ b/shared/eve_python/structs/EveFaceTracker.py @@ -1,5 +1,5 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .EveFaceTrackerStructs import * - - +import ctypes +from ctypes_enum import CtypesEnum +from .EveFaceTrackerStructs import * + + diff --git a/shared/eve_python/structs/EveFaceTrackerStructs.py b/shared/eve_python/structs/EveFaceTrackerStructs.py index 945706c8a086979972abbf655689796f893287ab..0a65730c8df21458bc24ff38394684079006d0b7 100644 --- a/shared/eve_python/structs/EveFaceTrackerStructs.py +++ b/shared/eve_python/structs/EveFaceTrackerStructs.py @@ -1,40 +1,40 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .CFaceData import * -from .EveErrors import * - - -class EveFaceTrackerMinimumMode(CtypesEnum): - EVE_FACETRACKER_MINIMUM_MODE_OFF = 0 - EVE_FACETRACKER_MINIMUM_MODE_MINIMAL = 1 - EVE_FACETRACKER_MINIMUM_MODE_AVERAGE = 2 - EVE_FACETRACKER_MINIMUM_MODE_MAXIMAL = 3 - -class EveFaceTrackerOptions(ctypes.Structure): - _fields_ = [ - ("faceTrackerMode", ctypes.c_int), - ("enableEyeLandmarks", ctypes.c_uint), - ("enable3DFaceTracking", ctypes.c_uint), - ("enablePersonDetection", ctypes.c_uint), - ("fitSecondaryUsers", ctypes.c_uint), - ("error", ctypes.c_int), - ] - -class EveEyes(ctypes.Structure): - _fields_ = [ - ("data", CEyeLandmarks), - ("errorCode", ctypes.c_int), - ] - -class EvePupils(ctypes.Structure): - _fields_ = [ - ("data", CPupilLandmarks), - ("errorCode", ctypes.c_int), - ] - -class EveAllFacesData(ctypes.Structure): - _fields_ = [ - ("faceData", ctypes.POINTER(CAllFaces)), - ("errorCode", ctypes.c_int), - ] - +import ctypes +from ctypes_enum import CtypesEnum +from .CFaceData import * +from .EveErrors import * + + +class EveFaceTrackerMinimumMode(CtypesEnum): + EVE_FACETRACKER_MINIMUM_MODE_OFF = 0 + EVE_FACETRACKER_MINIMUM_MODE_MINIMAL = 1 + EVE_FACETRACKER_MINIMUM_MODE_AVERAGE = 2 + EVE_FACETRACKER_MINIMUM_MODE_MAXIMAL = 3 + +class EveFaceTrackerOptions(ctypes.Structure): + _fields_ = [ + ("faceTrackerMode", ctypes.c_int), + ("enableEyeLandmarks", ctypes.c_uint), + ("enable3DFaceTracking", ctypes.c_uint), + ("enablePersonDetection", ctypes.c_uint), + ("fitSecondaryUsers", ctypes.c_uint), + ("error", ctypes.c_int), + ] + +class EveEyes(ctypes.Structure): + _fields_ = [ + ("data", CEyeLandmarks), + ("errorCode", ctypes.c_int), + ] + +class EvePupils(ctypes.Structure): + _fields_ = [ + ("data", CPupilLandmarks), + ("errorCode", ctypes.c_int), + ] + +class EveAllFacesData(ctypes.Structure): + _fields_ = [ + ("faceData", ctypes.POINTER(CAllFaces)), + ("errorCode", ctypes.c_int), + ] + diff --git a/shared/eve_python/structs/EveFpga.py b/shared/eve_python/structs/EveFpga.py index 2a60a0e27970002f9569df0690b34267f7c5c1bc..52c2c0387a5b84266ccc68ae6d58cc5076797444 100644 --- a/shared/eve_python/structs/EveFpga.py +++ b/shared/eve_python/structs/EveFpga.py @@ -1,7 +1,7 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .CFpgaData import * -from .EveFpgaStructs import * -from .EveImageStructs import * - - +import ctypes +from ctypes_enum import CtypesEnum +from .CFpgaData import * +from .EveFpgaStructs import * +from .EveImageStructs import * + + diff --git a/shared/eve_python/structs/EveFpgaStructs.py b/shared/eve_python/structs/EveFpgaStructs.py index cf9f898a3e4389dc592b85fba74389ec21aa8ae1..9f7813c780f417a45ae9cc3857f17de57d44554a 100644 --- a/shared/eve_python/structs/EveFpgaStructs.py +++ b/shared/eve_python/structs/EveFpgaStructs.py @@ -1,24 +1,24 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .CFpgaData import * -from .EveErrors import * - - -class EveFpgaOptions(ctypes.Structure): - _fields_ = [ - ("parameters", CFpgaParameters), - ("error", ctypes.c_int), - ] - -class EveFpgaDebugOptions(ctypes.Structure): - _fields_ = [ - ("enableDrawingOnImage", ctypes.c_uint), - ("error", ctypes.c_int), - ] - -class EveFpgaData(ctypes.Structure): - _fields_ = [ - ("data", ctypes.POINTER(CFpgaData)), - ("error", ctypes.c_int), - ] - +import ctypes +from ctypes_enum import CtypesEnum +from .CFpgaData import * +from .EveErrors import * + + +class EveFpgaOptions(ctypes.Structure): + _fields_ = [ + ("parameters", CFpgaParameters), + ("error", ctypes.c_int), + ] + +class EveFpgaDebugOptions(ctypes.Structure): + _fields_ = [ + ("enableDrawingOnImage", ctypes.c_uint), + ("error", ctypes.c_int), + ] + +class EveFpgaData(ctypes.Structure): + _fields_ = [ + ("data", ctypes.POINTER(CFpgaData)), + ("error", ctypes.c_int), + ] + diff --git a/shared/eve_python/structs/EveHandGesture.py b/shared/eve_python/structs/EveHandGesture.py index f6a4adf6725096c11c7dbcef0c47303f0d45556e..d052d6295eba75d92222b90744ddd89aed32e312 100644 --- a/shared/eve_python/structs/EveHandGesture.py +++ b/shared/eve_python/structs/EveHandGesture.py @@ -1,5 +1,5 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .EveHandGestureStructs import * - - +import ctypes +from ctypes_enum import CtypesEnum +from .EveHandGestureStructs import * + + diff --git a/shared/eve_python/structs/EveHandGestureStructs.py b/shared/eve_python/structs/EveHandGestureStructs.py index 825fe46f65c4eabc91250787f2397af33cd87237..8ed3a899e8924ffd4b6e31bbbc7a5954018ac3a3 100644 --- a/shared/eve_python/structs/EveHandGestureStructs.py +++ b/shared/eve_python/structs/EveHandGestureStructs.py @@ -1,48 +1,35 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .CHandGesture import * -from .EveControlOption import * -from .EveErrors import * - - -class EveHandGestureOptions(ctypes.Structure): - _fields_ = [ - ("enabled", ctypes.c_int), - ("redetectionDelay", ctypes.c_int), - ("async", ctypes.c_int), - ("run", ctypes.c_int), - ("errorCode", ctypes.c_int), - ] - -class EveHandGestureData(ctypes.Structure): - _fields_ = [ - ("hands", ctypes.POINTER(EveHandDetections)), - ("errorCode", ctypes.c_int), - ] - -class EveStaticGestureData(ctypes.Structure): - _fields_ = [ - ("gestures", EveStaticGestures), - ("errorCode", ctypes.c_int), - ] - -class EveDynamicGestureData(ctypes.Structure): - _fields_ = [ - ("gestures", EveDynamicGestures), - ("errorCode", ctypes.c_int), - ] - -class EveStaticGestureDefinitions(ctypes.Structure): - _fields_ = [ - ("count", ctypes.c_uint), - ("errorCode", ctypes.c_int), - ("definitions", EveStaticGestureDefinition * EVE_MAX_STATIC_GESTURES), - ] - -class EveDynamicGestureDefinitions(ctypes.Structure): - _fields_ = [ - ("count", ctypes.c_uint), - ("errorCode", ctypes.c_int), - ("definitions", EveDynamicGestureDefinition * EVE_DYNAMIC_GESTURE_SIZE), - ] - +import ctypes +from ctypes_enum import CtypesEnum +from .CHandGesture import * +from .EveControlOption import * +from .EveErrors import * + + +class EveHandGestureOptions(ctypes.Structure): + _fields_ = [ + ("enabled", ctypes.c_int), + ("redetectionDelay", ctypes.c_int), + ("async", ctypes.c_int), + ("run", ctypes.c_int), + ("errorCode", ctypes.c_int), + ] + +class EveHandGestureData(ctypes.Structure): + _fields_ = [ + ("hands", ctypes.POINTER(EveHandDetections)), + ("errorCode", ctypes.c_int), + ] + +class EveStaticGestureData(ctypes.Structure): + _fields_ = [ + ("gestures", EveStaticGestures), + ("errorCode", ctypes.c_int), + ] + +class EveStaticGestureDefinitions(ctypes.Structure): + _fields_ = [ + ("count", ctypes.c_uint), + ("errorCode", ctypes.c_int), + ("definitions", EveStaticGestureDefinition * EVE_MAX_STATIC_GESTURES), + ] + diff --git a/shared/eve_python/structs/EveImage.py b/shared/eve_python/structs/EveImage.py index 3071fb0c5b29058ae26e4130bfa0d51220b84388..70300637e20b1a7020ea245d52455653eb87150b 100644 --- a/shared/eve_python/structs/EveImage.py +++ b/shared/eve_python/structs/EveImage.py @@ -1,5 +1,5 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .EveImageStructs import * - - +import ctypes +from ctypes_enum import CtypesEnum +from .EveImageStructs import * + + diff --git a/shared/eve_python/structs/EveImageManipulation.py b/shared/eve_python/structs/EveImageManipulation.py index 1bb76a79a9a8040c206b8e21a973b926f9757004..d4ac5222873809eff4721204dceb16c9b5dd1806 100644 --- a/shared/eve_python/structs/EveImageManipulation.py +++ b/shared/eve_python/structs/EveImageManipulation.py @@ -1,5 +1,5 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .EveImageManipulationStructs import * - - +import ctypes +from ctypes_enum import CtypesEnum +from .EveImageManipulationStructs import * + + diff --git a/shared/eve_python/structs/EveImageManipulationStructs.py b/shared/eve_python/structs/EveImageManipulationStructs.py index 1139a637db637598d3882037a756db705ae0e155..99db73f1c8ee96c6d9bc55b62ea0d0e6abbdc127 100644 --- a/shared/eve_python/structs/EveImageManipulationStructs.py +++ b/shared/eve_python/structs/EveImageManipulationStructs.py @@ -1,12 +1,12 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .CImageManipulation import * -from .EveErrors import * - - -class EveImageManipulationOptions(ctypes.Structure): - _fields_ = [ - ("settings", CImageManipulationSettings), - ("errorCode", ctypes.c_int), - ] - +import ctypes +from ctypes_enum import CtypesEnum +from .CImageManipulation import * +from .EveErrors import * + + +class EveImageManipulationOptions(ctypes.Structure): + _fields_ = [ + ("settings", CImageManipulationSettings), + ("errorCode", ctypes.c_int), + ] + diff --git a/shared/eve_python/structs/EveImageStructs.py b/shared/eve_python/structs/EveImageStructs.py index d80ed90f4d66fcd8e25d74b6bcacc3c07c36a7b6..432899be97ade7894beab0467f3c4716c293a566 100644 --- a/shared/eve_python/structs/EveImageStructs.py +++ b/shared/eve_python/structs/EveImageStructs.py @@ -1,38 +1,53 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .CBasicStructs import * -from .EveErrors import * - - -class EveInputImage(ctypes.Structure): - _fields_ = [ - ("data", ctypes.POINTER(ctypes.c_ubyte)), - ("width", ctypes.c_int), - ("height", ctypes.c_int), - ("encoding", ctypes.c_int), - ] - -class EveProcessedImage(ctypes.Structure): - _fields_ = [ - ("data", ctypes.POINTER(ctypes.c_ubyte)), - ("width", ctypes.c_int), - ("height", ctypes.c_int), - ("channels", ctypes.c_int), - ("timestamp", ctypes.c_longlong), - ("error", ctypes.c_int), - ("location", ctypes.c_int), - ] - -class EveProcessedFrameTime(ctypes.Structure): - _fields_ = [ - ("frameTime", ctypes.c_double), - ("error", ctypes.c_int), - ] - -class EveImageFormatRequest(ctypes.Structure): - _fields_ = [ - ("format", ctypes.c_int), - ("location", ctypes.c_int), - ("error", ctypes.c_int), - ] - +import ctypes +from ctypes_enum import CtypesEnum +from .CBasicStructs import * +from .EveControlOption import * +from .EveErrors import * + + +class EveInputImage(ctypes.Structure): + _fields_ = [ + ("data", ctypes.POINTER(ctypes.c_ubyte)), + ("width", ctypes.c_int), + ("height", ctypes.c_int), + ("encoding", ctypes.c_int), + ] + +class EveProcessedImage(ctypes.Structure): + _fields_ = [ + ("data", ctypes.POINTER(ctypes.c_ubyte)), + ("width", ctypes.c_int), + ("height", ctypes.c_int), + ("channels", ctypes.c_int), + ("timestamp", ctypes.c_longlong), + ("error", ctypes.c_int), + ("location", ctypes.c_int), + ("format", ctypes.c_int), + ] + +class EveProcessedFrameTime(ctypes.Structure): + _fields_ = [ + ("frameTime", ctypes.c_double), + ("error", ctypes.c_int), + ] + +class EveImageFormatRequest(ctypes.Structure): + _fields_ = [ + ("format", ctypes.c_int), + ("location", ctypes.c_int), + ("error", ctypes.c_int), + ] + +class EveRawImageRequest(ctypes.Structure): + _fields_ = [ + ("enabled", ctypes.c_int), + ("recordResults", ctypes.c_int), + ("error", ctypes.c_int), + ] + +class EveJsonData(ctypes.Structure): + _fields_ = [ + ("string", CStringData), + ("error", ctypes.c_int), + ] + diff --git a/shared/eve_python/structs/EveKarolinska.py b/shared/eve_python/structs/EveKarolinska.py index 8c03da5d42b45addcc836dd33a1c38c8faeb7da6..05e843ca40c936fff8dc11d68e7ad9de7fd77689 100644 --- a/shared/eve_python/structs/EveKarolinska.py +++ b/shared/eve_python/structs/EveKarolinska.py @@ -1,5 +1,5 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .EveKarolinskaStructs import * - - +import ctypes +from ctypes_enum import CtypesEnum +from .EveKarolinskaStructs import * + + diff --git a/shared/eve_python/structs/EveKarolinskaStructs.py b/shared/eve_python/structs/EveKarolinskaStructs.py index c36c40bab0b3d099536c793465d9ac87c6f579e6..d6d182be44d7b923d8411329fb93703e88b191b9 100644 --- a/shared/eve_python/structs/EveKarolinskaStructs.py +++ b/shared/eve_python/structs/EveKarolinskaStructs.py @@ -1,19 +1,19 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .CKarolinska import * -from .EveControlOption import * -from .EveErrors import * - - -class EveKarolinskaOptions(ctypes.Structure): - _fields_ = [ - ("enabled", ctypes.c_int), - ("error", ctypes.c_int), - ] - -class EveKarolinskaData(ctypes.Structure): - _fields_ = [ - ("data", CKarolinskaData), - ("error", ctypes.c_int), - ] - +import ctypes +from ctypes_enum import CtypesEnum +from .CKarolinska import * +from .EveControlOption import * +from .EveErrors import * + + +class EveKarolinskaOptions(ctypes.Structure): + _fields_ = [ + ("enabled", ctypes.c_int), + ("error", ctypes.c_int), + ] + +class EveKarolinskaData(ctypes.Structure): + _fields_ = [ + ("data", CKarolinskaData), + ("error", ctypes.c_int), + ] + diff --git a/shared/eve_python/structs/EveObjectDetection.py b/shared/eve_python/structs/EveObjectDetection.py index 6c2a7c8fe5e98e1f960ccd3ead229675bf52efab..6b541e96aa7fa9b2b4d7f2e9dab8007608bcd01a 100644 --- a/shared/eve_python/structs/EveObjectDetection.py +++ b/shared/eve_python/structs/EveObjectDetection.py @@ -1,5 +1,5 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .EveObjectDetectionStructs import * - - +import ctypes +from ctypes_enum import CtypesEnum +from .EveObjectDetectionStructs import * + + diff --git a/shared/eve_python/structs/EveObjectDetectionStructs.py b/shared/eve_python/structs/EveObjectDetectionStructs.py index 900cf2cd68b96063f87e6cb4d601fe7c2e1c9945..7344d3807cd932564d3731b42c822d46cac8d337 100644 --- a/shared/eve_python/structs/EveObjectDetectionStructs.py +++ b/shared/eve_python/structs/EveObjectDetectionStructs.py @@ -1,25 +1,31 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .CDetectionStructs import * -from .EveControlOption import * -from .EveErrors import * - - -class EveObjectDetectionOptions(ctypes.Structure): - _fields_ = [ - ("enabled", ctypes.c_int), - ("error", ctypes.c_int), - ] - -class EvePersonDetectionOptions(ctypes.Structure): - _fields_ = [ - ("enabled", ctypes.c_int), - ("error", ctypes.c_int), - ] - -class EveDetectionData(ctypes.Structure): - _fields_ = [ - ("data", ctypes.POINTER(CDetectionData)), - ("error", ctypes.c_int), - ] - +import ctypes +from ctypes_enum import CtypesEnum +from .CDetectionStructs import * +from .EveControlOption import * +from .EveErrors import * + +EVE_MAX_OBJECT_DETECTION_CLASSES = 128 + +class EveObjectDetectionOptions(ctypes.Structure): + _fields_ = [ + ("enabled", ctypes.c_int), + ("modelPath", ctypes.c_byte * 512), + ("nmsThreshold", ctypes.c_float), + ("iouThreshold", ctypes.c_float), + ("classNames", ctypes.c_byte * EVE_CLASS_ID_NAME_SIZE * EVE_MAX_OBJECT_DETECTION_CLASSES), + ("classCount", ctypes.c_int), + ("error", ctypes.c_int), + ] + +class EvePersonDetectionOptions(ctypes.Structure): + _fields_ = [ + ("enabled", ctypes.c_int), + ("error", ctypes.c_int), + ] + +class EveDetectionData(ctypes.Structure): + _fields_ = [ + ("data", ctypes.POINTER(CDetectionData)), + ("error", ctypes.c_int), + ] + diff --git a/shared/eve_python/structs/EveProcessingStatus.py b/shared/eve_python/structs/EveProcessingStatus.py index 7d9fdf8a0dadf4c38d227051893e049ac28b7e92..4fb13c39ea80196471237edee380133e971af5c6 100644 --- a/shared/eve_python/structs/EveProcessingStatus.py +++ b/shared/eve_python/structs/EveProcessingStatus.py @@ -1,10 +1,10 @@ -import ctypes -from ctypes_enum import CtypesEnum - - -class EveProcessingStatus(CtypesEnum): - EVE_PROCESSING_DISABLED = 0 - EVE_PROCESSING_ENABLED_FAILURE = 1 - EVE_PROCESSING_ENABLED_SUCCESS = 2 - EVE_SOURCED_FROM_FPGA = 3 - +import ctypes +from ctypes_enum import CtypesEnum + + +class EveProcessingStatus(CtypesEnum): + EVE_PROCESSING_DISABLED = 0 + EVE_PROCESSING_ENABLED_FAILURE = 1 + EVE_PROCESSING_ENABLED_SUCCESS = 2 + EVE_SOURCED_FROM_FPGA = 3 + diff --git a/shared/eve_python/structs/EveROI.py b/shared/eve_python/structs/EveROI.py index d577ee75757cb31b6c9f75095307f418d64f6ca3..cdf2dd2480059e7520128216d5aa7437949b2138 100644 --- a/shared/eve_python/structs/EveROI.py +++ b/shared/eve_python/structs/EveROI.py @@ -1,5 +1,5 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .EveROIStructs import * - - +import ctypes +from ctypes_enum import CtypesEnum +from .EveROIStructs import * + + diff --git a/shared/eve_python/structs/EveROIStructs.py b/shared/eve_python/structs/EveROIStructs.py index 5b162b80ff69a26dcae31de8c24411f1c8c3175f..556db22412697a4e03f70b72d7d4421cb1c0a97e 100644 --- a/shared/eve_python/structs/EveROIStructs.py +++ b/shared/eve_python/structs/EveROIStructs.py @@ -1,34 +1,34 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .CROIStructs import * -from .EveControlOption import * -from .EveErrors import * - -EVE_ROI_MAX_COUNT = 20 - -class EveROI(ctypes.Structure): - _fields_ = [ - ("id", ctypes.c_uint), - ("x", ctypes.c_int), - ("y", ctypes.c_int), - ("width", ctypes.c_int), - ("height", ctypes.c_int), - ("scoreThresholdForInactive", ctypes.c_double), - ] - -class EveROIOptions(ctypes.Structure): - _fields_ = [ - ("enabled", ctypes.c_int), - ("roiSelectionResponseTime", ctypes.c_double), - ("roiCount", ctypes.c_uint), - ("rois", EveROI * EVE_ROI_MAX_COUNT), - ("error", ctypes.c_int), - ("headVectorOnly", ctypes.c_uint), - ] - -class EveROIScoreData(ctypes.Structure): - _fields_ = [ - ("data", CROIScoreData), - ("error", ctypes.c_int), - ] - +import ctypes +from ctypes_enum import CtypesEnum +from .CROIStructs import * +from .EveControlOption import * +from .EveErrors import * + +EVE_ROI_MAX_COUNT = 20 + +class EveROI(ctypes.Structure): + _fields_ = [ + ("id", ctypes.c_uint), + ("x", ctypes.c_int), + ("y", ctypes.c_int), + ("width", ctypes.c_int), + ("height", ctypes.c_int), + ("scoreThresholdForInactive", ctypes.c_double), + ] + +class EveROIOptions(ctypes.Structure): + _fields_ = [ + ("enabled", ctypes.c_int), + ("roiSelectionResponseTime", ctypes.c_double), + ("roiCount", ctypes.c_uint), + ("rois", EveROI * EVE_ROI_MAX_COUNT), + ("error", ctypes.c_int), + ("headVectorOnly", ctypes.c_uint), + ] + +class EveROIScoreData(ctypes.Structure): + _fields_ = [ + ("data", CROIScoreData), + ("error", ctypes.c_int), + ] + diff --git a/shared/eve_python/structs/EveTiming.py b/shared/eve_python/structs/EveTiming.py index 7185b439663dec5a7eb3cf4bf782c96632e6beba..9dfa6d90d427e5cf7f4953fecc1bf883ec1e5190 100644 --- a/shared/eve_python/structs/EveTiming.py +++ b/shared/eve_python/structs/EveTiming.py @@ -1,5 +1,5 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .EveTimingStructs import * - - +import ctypes +from ctypes_enum import CtypesEnum +from .EveTimingStructs import * + + diff --git a/shared/eve_python/structs/EveTimingStructs.py b/shared/eve_python/structs/EveTimingStructs.py index b70c1a85193935851802a998c26bcc46df8fd063..e7c0965a52fbd79957be2d6dcf8aac1ea078c587 100644 --- a/shared/eve_python/structs/EveTimingStructs.py +++ b/shared/eve_python/structs/EveTimingStructs.py @@ -1,28 +1,28 @@ -import ctypes -from ctypes_enum import CtypesEnum -from .EveErrors import * - -TIME_SOURCE_SIZE = 16 - - -class EveTiming(ctypes.Structure): - _fields_ = [ - ("errorCode", ctypes.c_int), - ("eveCameraImageAcquisitionTimepoint", ctypes.c_longlong), - ("eveAlgorithmDuration", ctypes.c_longlong), - ("time1", ctypes.c_longlong), - ("time1Source", ctypes.c_byte * TIME_SOURCE_SIZE), - ("time2", ctypes.c_longlong), - ("time2Source", ctypes.c_byte * TIME_SOURCE_SIZE), - ("time3", ctypes.c_longlong), - ("time3Source", ctypes.c_byte * TIME_SOURCE_SIZE), - ("time4", ctypes.c_longlong), - ("time4Source", ctypes.c_byte * TIME_SOURCE_SIZE), - ("time5", ctypes.c_longlong), - ("time5Source", ctypes.c_byte * TIME_SOURCE_SIZE), - ("time6", ctypes.c_longlong), - ("time6Source", ctypes.c_byte * TIME_SOURCE_SIZE), - ("time7", ctypes.c_longlong), - ("time7Source", ctypes.c_byte * TIME_SOURCE_SIZE), - ] - +import ctypes +from ctypes_enum import CtypesEnum +from .EveErrors import * + +TIME_SOURCE_SIZE = 16 + + +class EveTiming(ctypes.Structure): + _fields_ = [ + ("errorCode", ctypes.c_int), + ("eveCameraImageAcquisitionTimepoint", ctypes.c_longlong), + ("eveAlgorithmDuration", ctypes.c_longlong), + ("time1", ctypes.c_longlong), + ("time1Source", ctypes.c_byte * TIME_SOURCE_SIZE), + ("time2", ctypes.c_longlong), + ("time2Source", ctypes.c_byte * TIME_SOURCE_SIZE), + ("time3", ctypes.c_longlong), + ("time3Source", ctypes.c_byte * TIME_SOURCE_SIZE), + ("time4", ctypes.c_longlong), + ("time4Source", ctypes.c_byte * TIME_SOURCE_SIZE), + ("time5", ctypes.c_longlong), + ("time5Source", ctypes.c_byte * TIME_SOURCE_SIZE), + ("time6", ctypes.c_longlong), + ("time6Source", ctypes.c_byte * TIME_SOURCE_SIZE), + ("time7", ctypes.c_longlong), + ("time7Source", ctypes.c_byte * TIME_SOURCE_SIZE), + ] + diff --git a/shared/eve_worker_pool.py b/shared/eve_worker_pool.py index bd1c42bcc8492e0240736660bf0cf0287a15208a..adfd1dfc891582fef934da09da8bf99ebf2d07ce 100644 --- a/shared/eve_worker_pool.py +++ b/shared/eve_worker_pool.py @@ -247,7 +247,7 @@ def _eve_worker_main( ) eve.enable_face_id(enabled=features.face_id) eve.enable_hand_gesture(enabled=features.hand_gesture) - eve.enable_object_detection(model_name=features.mod_model) + eve.enable_object_detection(config=features.mod_model_config) eve.enable_mirror(True) result = eve.inference(frame) del frame @@ -297,6 +297,12 @@ def _eve_worker_main( features = cmd.features + # Workers are reused across jobs, so reset the EVE pipeline + # before each video — otherwise tracking / ideal-user state + # leaks from the previous run and the second video shows no + # ideal user. + eve.reset_pipeline() + # Gallery restore (if requested) — must happen before # applying user feature flags because restore_gallery() # internally enables face/person detection for calibration. @@ -321,7 +327,7 @@ def _eve_worker_main( ) eve.enable_face_id(enabled=features.face_id) eve.enable_hand_gesture(enabled=features.hand_gesture) - eve.enable_object_detection(model_name=features.mod_model) + eve.enable_object_detection(config=features.mod_model_config) eve.enable_mirror(False) # Video processing loop diff --git a/shared/eve_wrapper.py b/shared/eve_wrapper.py index d72625e0e5a52bed76d0bd863867ac6cd2f2f338..20dbe0f683cc0b32f9cea3f8ca38fc6588a4b2ca 100644 --- a/shared/eve_wrapper.py +++ b/shared/eve_wrapper.py @@ -1,589 +1,674 @@ -import ctypes -import glob -import os -import platform -import sys -import time -from dataclasses import dataclass - -import cv2 -import numpy as np -from eve_python import eve_sdk as sdk -from eve_python.structs.CFaceIdStructs import ( - EveFaceIdCommand, - EveFaceIdIdentificationStatus, -) -from log_utils import setup_logger - -logger = setup_logger("EveWrapper") - -_is_windows = platform.system() == "Windows" - -DO_FAKE_MIRROR = True - -# Gate timing instrumentation behind the profiler env var -_TIMING_ENABLED = os.environ.get("ENABLE_PROFILER", "").strip() not in ("", "0", "false") - - -@dataclass -class CalibrationResult: - """Result of a face ID calibration attempt.""" - - success: bool - user_id: int - message: str - - -class EveWrapper: - def __init__(self, eve_bin_path="", eve_lib_path=""): - self._ensure_config_dir() - eve_bin_path, eve_lib_path = self._resolve_eve_paths(eve_bin_path, eve_lib_path) - - self._mirror = False - self._inference_frame_count = 0 - # Per-call timing: {name: [call_count, total_seconds]} - self._timings: dict[str, list[float]] = {} - self._timing_enabled = _TIMING_ENABLED - - image_provider = sdk.structs.EveImageProvider.EVE_CLIENT_PROVIDED - self.eve_sdk = self._load_and_create_eve(eve_bin_path, eve_lib_path, image_provider) - - if image_provider == sdk.structs.EveImageProvider.EVE_CAMERA: - self._set_camera() - - image_request = sdk.structs.EveImageFormatRequest( - location=sdk.structs.EveImageLocation.EVE_CPU, - format=sdk.structs.EveVideoFormat.EVE_BGRA, - ) - self.eve_sdk.EveConfigureProcessedImage(image_request) - - err = self.eve_sdk.StartEveWithParameters( - sdk.structs.EveProcessingParameters(type=sdk.structs.EveProcessingPipelineType.EVE_HMI) - ) - if err != sdk.structs.EveError.EVE_ERROR_NO_ERROR: - logger.info(f"StartEveWithParameters error code: {err}") - sys.exit(err) - - os.chdir(self._backup_cwd) - logger.info("EVE initialized") - - def _record_timing(self, name: str, elapsed: float) -> None: - entry = self._timings.get(name) - if entry is None: - self._timings[name] = [1, elapsed] - else: - entry[0] += 1 - entry[1] += elapsed - - def get_timing_stats(self, reset: bool = False) -> dict[str, tuple[int, float]]: - """Return accumulated per-call timings as {name: (count, total_seconds)}. - - Args: - reset: If True, clear the accumulators after reading. - """ - result = {k: (int(v[0]), v[1]) for k, v in self._timings.items()} - if reset: - self._timings.clear() - return result - - def inference(self, image: np.ndarray) -> np.ndarray: - t = self._timing_enabled - - if self._mirror and DO_FAKE_MIRROR: - if t: - _t0 = time.perf_counter() - image = cv2.flip(image, 1) - if t: - self._record_timing("flip", time.perf_counter() - _t0) - - if t: - _t0 = time.perf_counter() - if not self._send_frame(image): - return image - if t: - self._record_timing("EveSendImageForProcessing", time.perf_counter() - _t0) - - if t: - _t0 = time.perf_counter() - processed_image = self.eve_sdk.EveGetProcessedImage() - if t: - self._record_timing("EveGetProcessedImage", time.perf_counter() - _t0) - if processed_image.error != sdk.structs.EveError.EVE_ERROR_NO_ERROR: - logger.info(f"EveGetProcessedImage() error code: {processed_image.error}") - sys.exit(processed_image.error) - - if t: - _t0 = time.perf_counter() - img = np.ctypeslib.as_array( - processed_image.data, - shape=(processed_image.height, processed_image.width, processed_image.channels), - ).copy() - del processed_image - if t: - self._record_timing("as_array+copy", time.perf_counter() - _t0) - - if img.shape[2] == 2: - if t: - _t0 = time.perf_counter() - img = cv2.cvtColor(img, cv2.COLOR_YUV2BGR_YUYV) - if t: - self._record_timing("cvtColor", time.perf_counter() - _t0) - elif img.shape[2] == 4: - if t: - _t0 = time.perf_counter() - img = cv2.cvtColor(img, cv2.COLOR_RGBA2BGR) - if t: - self._record_timing("cvtColor", time.perf_counter() - _t0) - - # SDK requires all outputs to be consumed before the next frame - if t: - _t0 = time.perf_counter() - person_detection_data = self.eve_sdk.EveGetPersonDetectionData() - if t: - self._record_timing("EveGetPersonDetectionData", time.perf_counter() - _t0) - if person_detection_data.error != sdk.structs.EveError.EVE_ERROR_NO_ERROR: - logger.info(f"EveGetPersonDetectionData() error code: {person_detection_data.error}") - sys.exit(person_detection_data.error) - del person_detection_data - - if t: - _t0 = time.perf_counter() - all_faces = self.eve_sdk.EveGetAllFaceData() - if t: - self._record_timing("EveGetAllFaceData", time.perf_counter() - _t0) - if all_faces.errorCode == sdk.structs.EveError.EVE_ERROR_NO_ERROR: - face_count = all_faces.faceData.contents.detectedFacesCount - if face_count > 0: - self._inference_frame_count += 1 - # Log face ID data periodically to avoid flooding - if self._inference_frame_count % self._INFERENCE_LOG_INTERVAL == 1: - self._log_all_faces("inference", self._inference_frame_count, all_faces) - del all_faces - - if img.shape[2] in (1, 3): - return img - - print( - f"WRONG FORMAT: {img.shape} " - "(Consider converting it above here, or making EveImageFormatRequest work)" - ) - return None - - def shutdown(self) -> None: - """Cleanly shut down the Eve SDK instance.""" - try: - self.eve_sdk.ShutdownEve() - logger.info("EVE shut down") - except Exception as exc: - logger.warning(f"EVE shutdown error: {exc}") - - def enable_mirror(self, enabled: bool = True) -> None: - """Enable or disable image mirroring.""" - if DO_FAKE_MIRROR: - self._mirror = enabled - return - options = sdk.structs.EveImageManipulationOptions() - options.settings.mirrorImage = 1 if enabled else 0 - result = self.eve_sdk.EveConfigureImageManipulation(options) - if result.errorCode != sdk.structs.EveError.EVE_ERROR_NO_ERROR: - logger.info(f"EveConfigureImageManipulation() error code: {result.errorCode}") - sys.exit(result.errorCode) - - def enable_object_detection(self, model_name: str | None = "GMOD-80"): - """Enable EVE's object detection (MOD) feature. - - Pass ``None`` / ``""`` / ``False`` to disable. Any truthy ``model_name`` - enables MOD; the name is recorded for future model-switching support - but is **not** acted on yet — the EVE SDK currently ships a single - hardcoded MOD model (GMOD-80, see ``EveEthosNpu/Models.h``). - - TODO: When the EVE C SDK gains a ``EveLoadObjectDetectionModel(path)`` - (or similar) entry point, hand-add the binding in - ``eve_python/eve_sdk.py`` and call it here before - ``EveConfigureObjectDetection`` to actually switch models. - """ - enabled = bool(model_name) - if enabled and model_name not in (None, "GMOD-80"): - logger.info( - f"enable_object_detection: requested {model_name!r} but SDK only " - f"ships GMOD-80; falling back to GMOD-80 weights." - ) - result = self.eve_sdk.EveConfigureObjectDetection( - sdk.structs.EveObjectDetectionOptions( - enabled=( - sdk.structs.EveOptionEnabled.EVE_OPTION_ENABLED - if enabled - else sdk.structs.EveOptionEnabled.EVE_OPTION_DISABLED - ) - ) - ) - if result.error != sdk.structs.EveError.EVE_ERROR_NO_ERROR: - logger.info(f"eveConfigureObjectDetection() error code: {result.error}") - sys.exit(result.error) - - def enable_face_and_person_detection( - self, faceEnabled: bool = True, personEnabled: bool = True - ): - mode = sdk.structs.EveFaceTrackerMinimumMode.EVE_FACETRACKER_MINIMUM_MODE_OFF - - params = sdk.structs.EveFaceTrackerOptions( - faceTrackerMode=mode, - enable3DFaceTracking=( - sdk.structs.EveOptionEnabled.EVE_OPTION_ENABLED - if faceEnabled - else sdk.structs.EveOptionEnabled.EVE_OPTION_DISABLED - ), - fitSecondaryUsers=( - sdk.structs.EveOptionEnabled.EVE_OPTION_ENABLED - if faceEnabled - else sdk.structs.EveOptionEnabled.EVE_OPTION_DISABLED - ), - enablePersonDetection=( - sdk.structs.EveOptionEnabled.EVE_OPTION_ENABLED - if personEnabled - else sdk.structs.EveOptionEnabled.EVE_OPTION_DISABLED - ), - enableEyeLandmarks=sdk.structs.EveOptionEnabled.EVE_OPTION_DISABLED, - ) - result = self.eve_sdk.EveConfigureFaceTracker(params) - if result.error != sdk.structs.EveError.EVE_ERROR_NO_ERROR: - logger.info(f"EveConfigureFaceTracker() error code: {result.error}") - sys.exit(result.error) - - def enable_face_id(self, enabled: bool = True, threshold: float = 0.7) -> None: - eve_enabled = ( - sdk.structs.EveOptionEnabled.EVE_OPTION_ENABLED - if enabled - else sdk.structs.EveOptionEnabled.EVE_OPTION_DISABLED - ) - options = sdk.structs.EveFaceIdOptions(enabled=eve_enabled, threshold=threshold) - if enabled: - options.calibrationPoses = ( - sdk.structs.EveFaceIdCalibrationPoseMode.EVE_FACEID_CALIBRATION_FRONTAL_ONLY - ) - result = self.eve_sdk.EveConfigureFaceId(options) - if result.error != sdk.structs.EveError.EVE_ERROR_NO_ERROR: - logger.info(f"EveConfigureFaceId() error code: {result.error}") - sys.exit(result.error) - - def enable_hand_gesture(self, enabled=True, redetection_delay_ms=0): - eve_enabled = ( - sdk.structs.EveOptionEnabled.EVE_OPTION_ENABLED - if enabled - else sdk.structs.EveOptionEnabled.EVE_OPTION_DISABLED - ) - result = self.eve_sdk.EveConfigureHandGesture( - sdk.structs.EveHandGestureOptions( - enabled=eve_enabled, redetectionDelay=redetection_delay_ms - ) - ) - if result.errorCode != sdk.structs.EveError.EVE_ERROR_NO_ERROR: - logger.info(f"EveConfigureHandGesture() error code: {result.errorCode}") - sys.exit(result.errorCode) - - def _send_face_id_command( - self, command: EveFaceIdCommand - ) -> sdk.structs.EveFaceIdCommandStruct: - cmd = sdk.structs.EveFaceIdCommandStruct(command=command) - return self.eve_sdk.EveSendFaceIdCommand(cmd) - - def _log_all_faces(self, context: str, frame_idx: int, all_faces) -> None: - """Log face ID details for every detected face in one frame.""" - face_count = all_faces.faceData.contents.detectedFacesCount - if face_count == 0: - logger.debug(f"[{context}] frame {frame_idx}: no faces detected") - return - for j in range(face_count): - f = all_faces.faceData.contents.faces[j] - fid = f.faceId.faceIdentity - logger.debug( - f"[{context}] frame {frame_idx}: face {j}: " - f"id={fid.id}, confidence={fid.confidence:.4f}, " - f"similarity={fid.similarity:.4f}, " - f"identificationStatus={f.faceId.identificationStatus}, " - f"calibrationStatus={f.faceId.calibrationStatus}" - ) - - def _send_frame(self, frame: np.ndarray) -> None: - """Send a single frame through the SDK pipeline (send + consume output).""" - frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) - eve_image = self._create_eve_input_image(frame, frame.shape[1], frame.shape[0], "BGR") - send_err = self.eve_sdk.EveSendImageForProcessing(eve_image) - if send_err != sdk.structs.EveError.EVE_ERROR_NO_ERROR: - logger.warning(f"EveSendImageForProcessing failed: {send_err}") - return False - return True - - _FLUSH_FRAME_COUNT = 6 - _CALIBRATION_MAX_ATTEMPTS = 5 - _INFERENCE_LOG_INTERVAL = 30 # log face ID data every N frames during inference - - def calibrate_new_user(self, frames: list[np.ndarray]) -> CalibrationResult: - """Register a new face by sending frames through the SDK calibration pipeline. - - Retries up to ``_CALIBRATION_MAX_ATTEMPTS`` times because the SDK can - intermittently reject borderline-frontal faces. - - Args: - frames: BGR images to use for calibration. Each frame is sent exactly once - per attempt; returns at the first successful attempt. - - Returns: - CalibrationResult with success flag, SDK-assigned user ID, and message. - """ - last_result: CalibrationResult | None = None - for attempt in range(self._CALIBRATION_MAX_ATTEMPTS): - last_result = self._calibrate_new_user_once(frames) - if last_result.success: - return last_result - logger.info( - "calibrate_new_user: attempt %d/%d failed: %s", - attempt + 1, - self._CALIBRATION_MAX_ATTEMPTS, - last_result.message, - ) - return last_result # type: ignore[return-value] - - def _calibrate_new_user_once(self, frames: list[np.ndarray]) -> CalibrationResult: - """Single calibration attempt — flush, send ADD_NEW_USER + frames, check result.""" - self.enable_face_and_person_detection(faceEnabled=True) - self.enable_face_id(enabled=True) - - h, w = frames[0].shape[:2] - blank = np.zeros((h, w, 3), dtype=np.uint8) - for _ in range(self._FLUSH_FRAME_COUNT): - self._send_frame(blank) - - success_frame = -1 - for i, frame in enumerate(frames): - result = self._send_face_id_command(EveFaceIdCommand.EVE_FACE_ID_COMMAND_ADD_NEW_USER) - if result.errorCode != sdk.structs.EveError.EVE_ERROR_NO_ERROR: - return CalibrationResult( - False, 0, f"ADD_NEW_USER command failed: {result.errorCode}" - ) - - self._send_frame(frame) - - all_faces = self.eve_sdk.EveGetAllFaceData() - if all_faces.errorCode != sdk.structs.EveError.EVE_ERROR_NO_ERROR: - return CalibrationResult( - False, 0, f"EveGetAllFaceData failed: {all_faces.errorCode}" - ) - - face_count = all_faces.faceData.contents.detectedFacesCount - self._log_all_faces("calibrate frame", i, all_faces) - - matched_face = None - for fi in range(face_count): - face = all_faces.faceData.contents.faces[fi] - if ( - face.faceId.faceIdentity.id >= 0 - and face.faceId.identificationStatus - == EveFaceIdIdentificationStatus.EVE_FACE_ID_SUCCESS - ): - matched_face = face - break - if matched_face is not None: - success_frame = i - break - - if success_frame > -1: - user_id = matched_face.faceId.faceIdentity.id - confidence = matched_face.faceId.faceIdentity.confidence - similarity = matched_face.faceId.faceIdentity.similarity - - logger.debug( - f"calibrate_new_user: SUCCESS on frame {success_frame}, " - f"id={user_id}, confidence={confidence:.4f}, similarity={similarity:.4f}" - ) - if len(frames) == 1: - return CalibrationResult(True, user_id, f"Registered as user {user_id}") - else: - return CalibrationResult( - True, - user_id, - f"Calibration succeeded on frame {success_frame}. " - f"Registered as user {user_id}.", - ) - else: - return CalibrationResult( - False, - 0, - "Calibration did not succeed. " - "Ensure a clear, frontal face is visible in the upload.", - ) - - def remove_all_users(self) -> bool: - """Remove all users from the SDK face ID gallery. - - Returns: - True if removal succeeded. - """ - result = self._send_face_id_command(EveFaceIdCommand.EVE_FACE_ID_COMMAND_REMOVE_ALL_USERS) - if result.errorCode != sdk.structs.EveError.EVE_ERROR_NO_ERROR: - logger.warning(f"REMOVE_ALL_USERS command error: {result.errorCode}") - return False - return True - - def restore_gallery(self, frames_per_user: list[list[np.ndarray]]) -> list[CalibrationResult]: - """Wipe the SDK gallery and re-register users from stored frames. - - Used before video processing to sync the SDK gallery with a session's - registered users. Sends a frame after removing to flush the command - through the SDK pipeline before re-registering. - - Args: - frames_per_user: List of frame lists, one per user to re-register. - - Returns: - List of CalibrationResult, one per user. - """ - if not frames_per_user: - return [] - - self.enable_face_and_person_detection(faceEnabled=True) - self.enable_face_id(enabled=True) - - self.remove_all_users() - # SDK commands are async — flush the remove by sending a frame - self._send_frame(frames_per_user[0][0]) - - results = [] - for idx, frames in enumerate(frames_per_user): - r = self.calibrate_new_user(frames) - logger.info( - f"restore_gallery: user {idx}: success={r.success}, " - f"sdk_id={r.user_id}, message='{r.message}'" - ) - results.append(r) - return results - - @staticmethod - def _ensure_config_dir(): - from pathlib import Path - - try: - new_dir_path = Path.home() / ".config" - new_dir_path.mkdir(exist_ok=True) - except Exception as e: - print(f"Error creating directory: {e}") - - @staticmethod - def _resolve_eve_paths(eve_bin_path="", eve_lib_path=""): - if eve_bin_path and eve_lib_path: - return eve_bin_path, eve_lib_path - - if _is_windows: - eve_bin_path = r"C:\TLT_SRC_DIR\EdgeVisionEngine\x64\Release\\" - eve_lib_path = eve_bin_path - else: - eve_dir_default_paths = glob.glob("/opt/EVE-*-Source", recursive=False) - eve_bin_path = eve_bin_path or ( - os.path.join(eve_dir_default_paths[0], "bin") if eve_dir_default_paths else "" - ) - eve_lib_path = eve_lib_path or ( - os.path.join(eve_dir_default_paths[0], "lib") if eve_dir_default_paths else "" - ) - return eve_bin_path, eve_lib_path - - def _load_and_create_eve(self, eve_bin_path, eve_lib_path, image_provider): - from pathlib import Path - - self._backup_cwd = os.getcwd() - os.chdir(eve_bin_path) - - if _is_windows: - eve_sdk_path = os.path.join(eve_bin_path, "EveSDK.dll") - root = Path(os.path.abspath(__file__)).parent - if not os.path.isfile(eve_sdk_path): - eve_sdk_path = os.path.join(root.parent.parent, eve_bin_path, "EveSDK.dll") - else: - eve_sdk_path = os.path.join(eve_bin_path, "libEveSDK.so") - if not os.path.isfile(eve_sdk_path): - eve_sdk_path = os.path.join(eve_lib_path, "libEveSDK.so") - - eve_sdk_instance = sdk.EveSDK(eve_sdk_path) - - ByteArray512 = ctypes.c_byte * 512 - encoded = os.path.dirname(eve_bin_path + os.sep).encode("utf-8") # EVE needs os.sep - pathOverride = ByteArray512(*encoded, *([0] * (512 - len(encoded)))) # zero-pad to 512 - - startup_options = sdk.structs.EveStartupParameters( - pathOverride=pathOverride, - gpuPreference=sdk.structs.EveGpuPreference.EVE_NO_GPU, - imageProvider=image_provider, - startupType=sdk.structs.EveStartupType.EVE_SYNC, - ) - err = eve_sdk_instance.CreateEve(startup_options) - if err != sdk.structs.EveError.EVE_ERROR_NO_ERROR: - logger.info(f"CreateEve error code: {err}") - sys.exit(err) - - return eve_sdk_instance - - def _set_camera(self): - i = 0 - self._metaDataFpgaCameraId = -1 - self._fpgaCameraId = -1 - while True: - cameraInfo = self.eve_sdk.EveGetCamera(i) - if ( - cameraInfo.error == sdk.structs.EveError.EVE_INVALID_CAMERA_ID - or cameraInfo.error == sdk.structs.EveError.EVE_NO_MORE_DATA - ): - break - - pid = ctypes.cast(cameraInfo.data.pid, ctypes.c_char_p).value - vid = ctypes.cast(cameraInfo.data.vid, ctypes.c_char_p).value - if cameraInfo.data.isFpgaCamera == 1: - if self._metaDataFpgaCameraId == -1 and vid == b"META" and pid == b"DATA": - self._metaDataFpgaCameraId = i - elif self._fpgaCameraId == -1: - self._fpgaCameraId = i - print(i, self._fpgaCameraId, self._metaDataFpgaCameraId, cameraInfo.error, pid, vid) - if self._fpgaCameraId >= 0 and self._metaDataFpgaCameraId >= 0: - break - i += 1 - - if self._fpgaCameraId == -1 and self._metaDataFpgaCameraId == -1: - raise RuntimeError("No FPGA camera found") - print( - f" \n\t\t *** FPGA camera found: {self._fpgaCameraId}, metadata {self._metaDataFpgaCameraId}\n" - ) - - useMetadataCamera = False - if useMetadataCamera: - self._usedCameraId = self._metaDataFpgaCameraId - else: - self._usedCameraId = self._fpgaCameraId - - cameraFormat = sdk.structs.CCameraFormat() - cameraFormat.resolution.width = 640 - cameraFormat.resolution.height = 480 - cameraFormat.compareResolution = sdk.structs.EveCompare.EVE_AT_MOST - cameraFormat.compareFps = sdk.structs.EveCompare.EVE_AT_LEAST - formats = self.eve_sdk.EveGetFormats(self._usedCameraId, cameraFormat) - f = formats.formats[0] - - print( - f"camera selected: ID#{self._usedCameraId}: {f.resolution.width}x{f.resolution.height}, " - f"Format: {f.format} @ {f.fps}FPS" - ) - - errorCode = self.eve_sdk.EveSetCamera(self._usedCameraId, f) - if errorCode != sdk.structs.EveError.EVE_ERROR_NO_ERROR: - raise RuntimeError(f"Could't set camera {errorCode}") - - @staticmethod - def _create_eve_input_image(image_bin, width, height, encoding): - image = sdk.structs.EveInputImage() - image.data = image_bin.ctypes.data_as(ctypes.POINTER(ctypes.c_ubyte)) - image.width = width - image.height = height - if encoding == "YUY2": - image.encoding = sdk.structs.EveVideoFormat.EVE_YUY2 - elif encoding == "NV12": - image.encoding = sdk.structs.EveVideoFormat.EVE_NV12 - elif encoding == "BGR": - image.encoding = sdk.structs.EveVideoFormat.EVE_BGR - return image +import ctypes +import glob +import os +import platform +import sys +import time +from dataclasses import dataclass + +import cv2 +import numpy as np +from eve_messages import ModelConfig +from eve_python import eve_sdk as sdk +from eve_python.structs.CFaceIdStructs import ( + EveFaceIdCommand, + EveFaceIdIdentificationStatus, +) +from log_utils import setup_logger + +logger = setup_logger("EveWrapper") + + +def _pack_cstring(dst, value: str) -> None: + """Write ``value`` as a null-terminated UTF-8 string into a ``c_byte`` array. + + ``c_byte`` is signed (-128..127), so bytes above 127 are folded into their + signed two's-complement form — the underlying memory is identical to an + unsigned ``char[]`` on the C side. The array is fully written so any stale + bytes from a recycled options struct are cleared. + + Args: + dst: A ctypes ``c_byte`` array (the destination buffer). + value: The string to store; must fit with room for the null terminator. + + Raises: + ValueError: If ``value`` does not leave room for a null terminator. + """ + raw = value.encode("utf-8") + capacity = len(dst) + if len(raw) >= capacity: + raise ValueError(f"{value!r} ({len(raw)} bytes) exceeds buffer of {capacity}") + for i in range(capacity): + b = raw[i] if i < len(raw) else 0 + dst[i] = b - 256 if b > 127 else b + + +def _pack_class_names(dst, names: tuple[str, ...]) -> None: + """Write ``names`` into a 2-D ``c_byte`` class-name table, one row each. + + Args: + dst: A ctypes 2-D ``c_byte`` array (rows of fixed-width names). + names: Class labels to store, in output-index order. + + Raises: + ValueError: If there are more names than table rows. + """ + if len(names) > len(dst): + raise ValueError(f"{len(names)} class names exceed table of {len(dst)} rows") + for i, name in enumerate(names): + _pack_cstring(dst[i], name) + + +_is_windows = platform.system() == "Windows" + +DO_FAKE_MIRROR = True + +# Gate timing instrumentation behind the profiler env var +_TIMING_ENABLED = os.environ.get("ENABLE_PROFILER", "").strip() not in ("", "0", "false") + + +@dataclass +class CalibrationResult: + """Result of a face ID calibration attempt.""" + + success: bool + user_id: int + message: str + + +class EveWrapper: + def __init__(self, eve_bin_path="", eve_lib_path=""): + self._ensure_config_dir() + eve_bin_path, eve_lib_path = self._resolve_eve_paths(eve_bin_path, eve_lib_path) + + self._mirror = False + self._inference_frame_count = 0 + self._last_sent_frame: np.ndarray | None = None + # Per-call timing: {name: [call_count, total_seconds]} + self._timings: dict[str, list[float]] = {} + self._timing_enabled = _TIMING_ENABLED + + image_provider = sdk.structs.EveImageProvider.EVE_CLIENT_PROVIDED + self.eve_sdk = self._load_and_create_eve(eve_bin_path, eve_lib_path, image_provider) + + if image_provider == sdk.structs.EveImageProvider.EVE_CAMERA: + self._set_camera() + + image_request = sdk.structs.EveImageFormatRequest( + location=sdk.structs.EveImageLocation.EVE_CPU, + format=sdk.structs.EveVideoFormat.EVE_BGRA, + ) + self.eve_sdk.EveConfigureProcessedImage(image_request) + + err = self.eve_sdk.StartEveWithParameters( + sdk.structs.EveProcessingParameters(type=sdk.structs.EveProcessingPipelineType.EVE_HMI) + ) + if err != sdk.structs.EveError.EVE_ERROR_NO_ERROR: + logger.info(f"StartEveWithParameters error code: {err}") + sys.exit(err) + + logger.info("EVE initialized") + + def _record_timing(self, name: str, elapsed: float) -> None: + entry = self._timings.get(name) + if entry is None: + self._timings[name] = [1, elapsed] + else: + entry[0] += 1 + entry[1] += elapsed + + def get_timing_stats(self, reset: bool = False) -> dict[str, tuple[int, float]]: + """Return accumulated per-call timings as {name: (count, total_seconds)}. + + Args: + reset: If True, clear the accumulators after reading. + """ + result = {k: (int(v[0]), v[1]) for k, v in self._timings.items()} + if reset: + self._timings.clear() + return result + + def inference(self, image: np.ndarray) -> np.ndarray: + t = self._timing_enabled + + if self._mirror and DO_FAKE_MIRROR: + if t: + _t0 = time.perf_counter() + image = cv2.flip(image, 1) + if t: + self._record_timing("flip", time.perf_counter() - _t0) + + if t: + _t0 = time.perf_counter() + if not self._send_frame(image): + return image + if t: + self._record_timing("EveSendImageForProcessing", time.perf_counter() - _t0) + + if t: + _t0 = time.perf_counter() + processed_image = self.eve_sdk.EveGetProcessedImage() + if t: + self._record_timing("EveGetProcessedImage", time.perf_counter() - _t0) + if processed_image.error != sdk.structs.EveError.EVE_ERROR_NO_ERROR: + logger.info(f"EveGetProcessedImage() error code: {processed_image.error}") + sys.exit(processed_image.error) + + if t: + _t0 = time.perf_counter() + img = np.ctypeslib.as_array( + processed_image.data, + shape=(processed_image.height, processed_image.width, processed_image.channels), + ).copy() + del processed_image + if t: + self._record_timing("as_array+copy", time.perf_counter() - _t0) + + if img.shape[2] == 2: + if t: + _t0 = time.perf_counter() + img = cv2.cvtColor(img, cv2.COLOR_YUV2BGR_YUYV) + if t: + self._record_timing("cvtColor", time.perf_counter() - _t0) + elif img.shape[2] == 4: + if t: + _t0 = time.perf_counter() + img = cv2.cvtColor(img, cv2.COLOR_RGBA2BGR) + if t: + self._record_timing("cvtColor", time.perf_counter() - _t0) + elif img.shape[2] == 3: + if t: + _t0 = time.perf_counter() + img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) + if t: + self._record_timing("cvtColor", time.perf_counter() - _t0) + + # SDK requires all outputs to be consumed before the next frame + if t: + _t0 = time.perf_counter() + person_detection_data = self.eve_sdk.EveGetPersonDetectionData() + if t: + self._record_timing("EveGetPersonDetectionData", time.perf_counter() - _t0) + if person_detection_data.error != sdk.structs.EveError.EVE_ERROR_NO_ERROR: + logger.info(f"EveGetPersonDetectionData() error code: {person_detection_data.error}") + sys.exit(person_detection_data.error) + del person_detection_data + + if t: + _t0 = time.perf_counter() + all_faces = self.eve_sdk.EveGetAllFaceData() + if t: + self._record_timing("EveGetAllFaceData", time.perf_counter() - _t0) + if all_faces.errorCode == sdk.structs.EveError.EVE_ERROR_NO_ERROR: + face_count = all_faces.faceData.contents.detectedFacesCount + if face_count > 0: + self._inference_frame_count += 1 + # Log face ID data periodically to avoid flooding + if self._inference_frame_count % self._INFERENCE_LOG_INTERVAL == 1: + self._log_all_faces("inference", self._inference_frame_count, all_faces) + del all_faces + + if img.shape[2] in (1, 3): + return img + + print( + f"WRONG FORMAT: {img.shape} " + "(Consider converting it above here, or making EveImageFormatRequest work)" + ) + return None + + def reset_pipeline(self) -> None: + """Reset the EVE processing pipeline to a clean state. + + Pipeline state (face tracking, ideal-user selection) persists on the + long-lived SDK handle across inference calls. Workers are reused across + offline video jobs, so without a reset the second video inherits the + first run's pipeline state — most visibly, no ideal user is selected. + Call this before processing each new video. + """ + err = self.eve_sdk.EveResetPipeline() + if err != sdk.structs.EveError.EVE_ERROR_NO_ERROR: + logger.warning(f"EveResetPipeline error code: {err}") + + def shutdown(self) -> None: + """Cleanly shut down the Eve SDK instance.""" + try: + self.eve_sdk.ShutdownEve() + logger.info("EVE shut down") + except Exception as exc: + logger.warning(f"EVE shutdown error: {exc}") + + def enable_mirror(self, enabled: bool = True) -> None: + """Enable or disable image mirroring.""" + if DO_FAKE_MIRROR: + self._mirror = enabled + return + options = sdk.structs.EveImageManipulationOptions() + options.settings.mirrorImage = 1 if enabled else 0 + result = self.eve_sdk.EveConfigureImageManipulation(options) + if result.errorCode != sdk.structs.EveError.EVE_ERROR_NO_ERROR: + logger.info(f"EveConfigureImageManipulation() error code: {result.errorCode}") + sys.exit(result.errorCode) + + def enable_object_detection(self, config: "ModelConfig | None" = None) -> None: + """Enable and configure EVE's object detection (MOD) feature. + + Pass ``None`` to leave MOD off (the worker simply does not configure + it, matching the SDK's disabled-by-default state). Otherwise: + + - ``config.model_path`` empty / ``None`` selects the SDK's bundled + default model (GMOD-80) with its default class names. + - a populated ``config.model_path`` loads that ``.tflite`` and, if + given, replaces the class table with ``config.class_names``. + + ``modelPath`` and ``classCount`` are rewritten on every call rather + than left to the values returned by + ``EveGetDefaultObjectDetectionOptions``: that getter echoes the + *previously configured* options, not pristine defaults. Without the + unconditional reset, switching from a custom model (e.g. AMOD-8) back + to the bundled default would leave the prior model's class names in + EVE's table. An empty ``modelPath`` with ``classCount == 0`` is the + SDK's documented "use the default model and its default class names". + + Args: + config: The resolved MOD model to load, or ``None`` to skip MOD + configuration entirely. + + Raises: + SystemExit: If ``EveConfigureObjectDetection`` returns an error. + """ + if config is None: + return + + options = self.eve_sdk.EveGetDefaultObjectDetectionOptions() + options.enabled = sdk.structs.EveOptionEnabled.EVE_OPTION_ENABLED + + _pack_cstring(options.modelPath, config.model_path or "") + if config.model_path and config.class_names: + _pack_class_names(options.classNames, config.class_names) + options.classCount = len(config.class_names) + else: + options.classCount = 0 + if config.nms_threshold is not None: + options.nmsThreshold = config.nms_threshold + if config.iou_threshold is not None: + options.iouThreshold = config.iou_threshold + + result = self.eve_sdk.EveConfigureObjectDetection(options) + if result.error != sdk.structs.EveError.EVE_ERROR_NO_ERROR: + logger.info(f"EveConfigureObjectDetection() error code: {result.error}") + sys.exit(result.error) + + def enable_face_and_person_detection( + self, faceEnabled: bool = True, personEnabled: bool = True + ): + mode = sdk.structs.EveFaceTrackerMinimumMode.EVE_FACETRACKER_MINIMUM_MODE_OFF + + params = sdk.structs.EveFaceTrackerOptions( + faceTrackerMode=mode, + enable3DFaceTracking=( + sdk.structs.EveOptionEnabled.EVE_OPTION_ENABLED + if faceEnabled + else sdk.structs.EveOptionEnabled.EVE_OPTION_DISABLED + ), + fitSecondaryUsers=( + sdk.structs.EveOptionEnabled.EVE_OPTION_ENABLED + if faceEnabled + else sdk.structs.EveOptionEnabled.EVE_OPTION_DISABLED + ), + enablePersonDetection=( + sdk.structs.EveOptionEnabled.EVE_OPTION_ENABLED + if personEnabled + else sdk.structs.EveOptionEnabled.EVE_OPTION_DISABLED + ), + enableEyeLandmarks=sdk.structs.EveOptionEnabled.EVE_OPTION_DISABLED, + ) + result = self.eve_sdk.EveConfigureFaceTracker(params) + if result.error != sdk.structs.EveError.EVE_ERROR_NO_ERROR: + logger.info(f"EveConfigureFaceTracker() error code: {result.error}") + sys.exit(result.error) + + def enable_face_id(self, enabled: bool = True, threshold: float = 0.7) -> None: + eve_enabled = ( + sdk.structs.EveOptionEnabled.EVE_OPTION_ENABLED + if enabled + else sdk.structs.EveOptionEnabled.EVE_OPTION_DISABLED + ) + options = sdk.structs.EveFaceIdOptions(enabled=eve_enabled, threshold=threshold) + if enabled: + options.calibrationPoses = ( + sdk.structs.EveFaceIdCalibrationPoseMode.EVE_FACEID_CALIBRATION_FRONTAL_ONLY + ) + result = self.eve_sdk.EveConfigureFaceId(options) + if result.error != sdk.structs.EveError.EVE_ERROR_NO_ERROR: + logger.info(f"EveConfigureFaceId() error code: {result.error}") + sys.exit(result.error) + + def enable_hand_gesture(self, enabled=True, redetection_delay_ms=0): + eve_enabled = ( + sdk.structs.EveOptionEnabled.EVE_OPTION_ENABLED + if enabled + else sdk.structs.EveOptionEnabled.EVE_OPTION_DISABLED + ) + result = self.eve_sdk.EveConfigureHandGesture( + sdk.structs.EveHandGestureOptions( + enabled=eve_enabled, redetectionDelay=redetection_delay_ms + ) + ) + if result.errorCode != sdk.structs.EveError.EVE_ERROR_NO_ERROR: + logger.info(f"EveConfigureHandGesture() error code: {result.errorCode}") + sys.exit(result.errorCode) + + def _send_face_id_command( + self, command: EveFaceIdCommand + ) -> sdk.structs.EveFaceIdCommandStruct: + cmd = sdk.structs.EveFaceIdCommandStruct(command=command) + return self.eve_sdk.EveSendFaceIdCommand(cmd) + + def _log_all_faces(self, context: str, frame_idx: int, all_faces) -> None: + """Log face ID details for every detected face in one frame.""" + face_count = all_faces.faceData.contents.detectedFacesCount + if face_count == 0: + logger.debug(f"[{context}] frame {frame_idx}: no faces detected") + return + for j in range(face_count): + f = all_faces.faceData.contents.faces[j] + fid = f.faceId.faceIdentity + logger.debug( + f"[{context}] frame {frame_idx}: face {j}: " + f"id={fid.id}, confidence={fid.confidence:.4f}, " + f"similarity={fid.similarity:.4f}, " + f"identificationStatus={f.faceId.identificationStatus}, " + f"calibrationStatus={f.faceId.calibrationStatus}" + ) + + def _send_frame(self, frame: np.ndarray) -> None: + """Send a single frame through the SDK pipeline (send + consume output).""" + rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + # The SDK keeps the input pointer live past EveSendImageForProcessing and + # dereferences it during the matching EveGet*() calls. Retain the ndarray + # on the instance so it outlives every follow-up SDK call until the next + # frame is sent. Dropping the local ref here caused 1080p video runs to + # segfault inside libc memmove (use-after-free on the RGB buffer). + self._last_sent_frame = rgb + eve_image = self._create_eve_input_image(rgb, rgb.shape[1], rgb.shape[0], "RGB") + send_err = self.eve_sdk.EveSendImageForProcessing(eve_image) + if send_err != sdk.structs.EveError.EVE_ERROR_NO_ERROR: + logger.warning(f"EveSendImageForProcessing failed: {send_err}") + return False + return True + + _FLUSH_FRAME_COUNT = 6 + _CALIBRATION_MAX_ATTEMPTS = 5 + _INFERENCE_LOG_INTERVAL = 30 # log face ID data every N frames during inference + + def calibrate_new_user(self, frames: list[np.ndarray]) -> CalibrationResult: + """Register a new face by sending frames through the SDK calibration pipeline. + + Retries up to ``_CALIBRATION_MAX_ATTEMPTS`` times because the SDK can + intermittently reject borderline-frontal faces. + + Args: + frames: BGR images to use for calibration. Each frame is sent exactly once + per attempt; returns at the first successful attempt. + + Returns: + CalibrationResult with success flag, SDK-assigned user ID, and message. + """ + last_result: CalibrationResult | None = None + for attempt in range(self._CALIBRATION_MAX_ATTEMPTS): + last_result = self._calibrate_new_user_once(frames) + if last_result.success: + return last_result + logger.info( + "calibrate_new_user: attempt %d/%d failed: %s", + attempt + 1, + self._CALIBRATION_MAX_ATTEMPTS, + last_result.message, + ) + return last_result # type: ignore[return-value] + + def _calibrate_new_user_once(self, frames: list[np.ndarray]) -> CalibrationResult: + """Single calibration attempt — flush, send ADD_NEW_USER + frames, check result.""" + self.enable_face_and_person_detection(faceEnabled=True) + self.enable_face_id(enabled=True) + + h, w = frames[0].shape[:2] + blank = np.zeros((h, w, 3), dtype=np.uint8) + for _ in range(self._FLUSH_FRAME_COUNT): + self._send_frame(blank) + + success_frame = -1 + for i, frame in enumerate(frames): + result = self._send_face_id_command(EveFaceIdCommand.EVE_FACE_ID_COMMAND_ADD_NEW_USER) + if result.errorCode != sdk.structs.EveError.EVE_ERROR_NO_ERROR: + return CalibrationResult( + False, 0, f"ADD_NEW_USER command failed: {result.errorCode}" + ) + + self._send_frame(frame) + + all_faces = self.eve_sdk.EveGetAllFaceData() + if all_faces.errorCode != sdk.structs.EveError.EVE_ERROR_NO_ERROR: + return CalibrationResult( + False, 0, f"EveGetAllFaceData failed: {all_faces.errorCode}" + ) + + face_count = all_faces.faceData.contents.detectedFacesCount + self._log_all_faces("calibrate frame", i, all_faces) + + matched_face = None + for fi in range(face_count): + face = all_faces.faceData.contents.faces[fi] + if ( + face.faceId.faceIdentity.id >= 0 + and face.faceId.identificationStatus + == EveFaceIdIdentificationStatus.EVE_FACE_ID_SUCCESS + ): + matched_face = face + break + if matched_face is not None: + success_frame = i + break + + if success_frame > -1: + user_id = matched_face.faceId.faceIdentity.id + confidence = matched_face.faceId.faceIdentity.confidence + similarity = matched_face.faceId.faceIdentity.similarity + + logger.debug( + f"calibrate_new_user: SUCCESS on frame {success_frame}, " + f"id={user_id}, confidence={confidence:.4f}, similarity={similarity:.4f}" + ) + if len(frames) == 1: + return CalibrationResult(True, user_id, f"Registered as user {user_id}") + else: + return CalibrationResult( + True, + user_id, + f"Calibration succeeded on frame {success_frame}. " + f"Registered as user {user_id}.", + ) + else: + return CalibrationResult( + False, + 0, + "Calibration did not succeed. " + "Ensure a clear, frontal face is visible in the upload.", + ) + + def remove_all_users(self) -> bool: + """Remove all users from the SDK face ID gallery. + + Returns: + True if removal succeeded. + """ + result = self._send_face_id_command(EveFaceIdCommand.EVE_FACE_ID_COMMAND_REMOVE_ALL_USERS) + if result.errorCode != sdk.structs.EveError.EVE_ERROR_NO_ERROR: + logger.warning(f"REMOVE_ALL_USERS command error: {result.errorCode}") + return False + return True + + def restore_gallery(self, frames_per_user: list[list[np.ndarray]]) -> list[CalibrationResult]: + """Wipe the SDK gallery and re-register users from stored frames. + + Used before video processing to sync the SDK gallery with a session's + registered users. Sends a frame after removing to flush the command + through the SDK pipeline before re-registering. + + Args: + frames_per_user: List of frame lists, one per user to re-register. + + Returns: + List of CalibrationResult, one per user. + """ + if not frames_per_user: + return [] + + self.enable_face_and_person_detection(faceEnabled=True) + self.enable_face_id(enabled=True) + + self.remove_all_users() + # SDK commands are async — flush the remove by sending a frame + self._send_frame(frames_per_user[0][0]) + + results = [] + for idx, frames in enumerate(frames_per_user): + r = self.calibrate_new_user(frames) + logger.info( + f"restore_gallery: user {idx}: success={r.success}, " + f"sdk_id={r.user_id}, message='{r.message}'" + ) + results.append(r) + return results + + @staticmethod + def _ensure_config_dir(): + from pathlib import Path + + try: + new_dir_path = Path.home() / ".config" + new_dir_path.mkdir(exist_ok=True) + except Exception as e: + print(f"Error creating directory: {e}") + + @staticmethod + def _resolve_eve_paths(eve_bin_path="", eve_lib_path=""): + if eve_bin_path and eve_lib_path: + return eve_bin_path, eve_lib_path + + if _is_windows: + eve_bin_path = r"C:\TLT_SRC_DIR\EdgeVisionEngine\x64\Release\\" + eve_lib_path = eve_bin_path + else: + eve_dir_default_paths = glob.glob("/opt/EVE-*-Source", recursive=False) + eve_bin_path = eve_bin_path or ( + os.path.join(eve_dir_default_paths[0], "bin") if eve_dir_default_paths else "" + ) + eve_lib_path = eve_lib_path or ( + os.path.join(eve_dir_default_paths[0], "lib") if eve_dir_default_paths else "" + ) + return eve_bin_path, eve_lib_path + + def _load_and_create_eve(self, eve_bin_path, eve_lib_path, image_provider): + from pathlib import Path + + os.chdir(eve_bin_path) + + if _is_windows: + eve_sdk_path = os.path.join(eve_bin_path, "EveSDK.dll") + root = Path(os.path.abspath(__file__)).parent + if not os.path.isfile(eve_sdk_path): + eve_sdk_path = os.path.join(root.parent.parent, eve_bin_path, "EveSDK.dll") + else: + eve_sdk_path = os.path.join(eve_bin_path, "libEveSDK.so") + if not os.path.isfile(eve_sdk_path): + eve_sdk_path = os.path.join(eve_lib_path, "libEveSDK.so") + + eve_sdk_instance = sdk.EveSDK(eve_sdk_path) + + ByteArray512 = ctypes.c_byte * 512 + encoded = os.path.dirname(eve_bin_path + os.sep).encode("utf-8") # EVE needs os.sep + pathOverride = ByteArray512(*encoded, *([0] * (512 - len(encoded)))) # zero-pad to 512 + + startup_options = sdk.structs.EveStartupParameters( + pathOverride=pathOverride, + gpuPreference=sdk.structs.EveGpuPreference.EVE_NO_GPU, + imageProvider=image_provider, + startupType=sdk.structs.EveStartupType.EVE_SYNC, + ) + err = eve_sdk_instance.CreateEve(startup_options) + if err != sdk.structs.EveError.EVE_ERROR_NO_ERROR: + logger.info(f"CreateEve error code: {err}") + sys.exit(err) + + return eve_sdk_instance + + def _set_camera(self): + i = 0 + self._metaDataFpgaCameraId = -1 + self._fpgaCameraId = -1 + while True: + cameraInfo = self.eve_sdk.EveGetCamera(i) + if ( + cameraInfo.error == sdk.structs.EveError.EVE_INVALID_CAMERA_ID + or cameraInfo.error == sdk.structs.EveError.EVE_NO_MORE_DATA + ): + break + + pid = ctypes.cast(cameraInfo.data.pid, ctypes.c_char_p).value + vid = ctypes.cast(cameraInfo.data.vid, ctypes.c_char_p).value + if cameraInfo.data.isFpgaCamera == 1: + if self._metaDataFpgaCameraId == -1 and vid == b"META" and pid == b"DATA": + self._metaDataFpgaCameraId = i + elif self._fpgaCameraId == -1: + self._fpgaCameraId = i + print(i, self._fpgaCameraId, self._metaDataFpgaCameraId, cameraInfo.error, pid, vid) + if self._fpgaCameraId >= 0 and self._metaDataFpgaCameraId >= 0: + break + i += 1 + + if self._fpgaCameraId == -1 and self._metaDataFpgaCameraId == -1: + raise RuntimeError("No FPGA camera found") + print( + f" \n\t\t *** FPGA camera found: {self._fpgaCameraId}, metadata {self._metaDataFpgaCameraId}\n" + ) + + useMetadataCamera = False + if useMetadataCamera: + self._usedCameraId = self._metaDataFpgaCameraId + else: + self._usedCameraId = self._fpgaCameraId + + cameraFormat = sdk.structs.CCameraFormat() + cameraFormat.resolution.width = 640 + cameraFormat.resolution.height = 480 + cameraFormat.compareResolution = sdk.structs.EveCompare.EVE_AT_MOST + cameraFormat.compareFps = sdk.structs.EveCompare.EVE_AT_LEAST + formats = self.eve_sdk.EveGetFormats(self._usedCameraId, cameraFormat) + f = formats.formats[0] + + print( + f"camera selected: ID#{self._usedCameraId}: {f.resolution.width}x{f.resolution.height}, " + f"Format: {f.format} @ {f.fps}FPS" + ) + + errorCode = self.eve_sdk.EveSetCamera(self._usedCameraId, f) + if errorCode != sdk.structs.EveError.EVE_ERROR_NO_ERROR: + raise RuntimeError(f"Could't set camera {errorCode}") + + @staticmethod + def _create_eve_input_image(image_bin, width, height, encoding): + image = sdk.structs.EveInputImage() + image.data = image_bin.ctypes.data_as(ctypes.POINTER(ctypes.c_ubyte)) + image.width = width + image.height = height + if encoding == "YUY2": + image.encoding = sdk.structs.EveVideoFormat.EVE_YUY2 + elif encoding == "NV12": + image.encoding = sdk.structs.EveVideoFormat.EVE_NV12 + elif encoding == "BGR": + image.encoding = sdk.structs.EveVideoFormat.EVE_BGR + elif encoding == "RGB": + image.encoding = sdk.structs.EveVideoFormat.EVE_RGB + return image diff --git a/shared/face_id_tab.py b/shared/face_id_tab.py index 65a056bd4b0408c04d1c651ef5181efc1c70708d..8cbdfaf616a9d323d1e4cf560ddaa90c42d26f7b 100644 --- a/shared/face_id_tab.py +++ b/shared/face_id_tab.py @@ -1,963 +1,969 @@ -"""Face ID Registration Gradio tab for Eve SDK applications. - -Provides a self-contained Gradio tab for registering and unregistering faces -via the Eve SDK. Registration media is stored in per-session tmp directories -(``tmp/