Spaces:
Paused
Paused
| # -*- coding: utf-8 -*- | |
| """ | |
| NexSight AI - Motion Detection Setup Script | |
| ============================================ | |
| Installs and downloads: | |
| 1. DeepSORT -- identity tracking during fast motion | |
| 2. OpenCV DNN -- fast aerial / motion-blur face detection | |
| 3. YOLOv8s -- more accurate object detection | |
| 4. ultralytics & insightface (if missing) | |
| Run using your project's venv: | |
| d:\\face\\.venv\\Scripts\\python.exe d:\\face\\setup_motion_models.py | |
| """ | |
| import subprocess | |
| import sys | |
| import os | |
| import urllib.request | |
| import shutil | |
| # Force UTF-8 output to avoid Windows cp1252 issues | |
| import io | |
| sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace') | |
| sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace') | |
| PYTHON = sys.executable | |
| PIP = [PYTHON, "-m", "pip", "install", "--no-cache-dir"] | |
| def run(*args): | |
| print(f"\n>>> {' '.join(args)}") | |
| result = subprocess.run(list(args), capture_output=False, text=True) | |
| if result.returncode != 0: | |
| print(f"[WARN] Command returned exit code {result.returncode}") | |
| return result.returncode == 0 | |
| def pip_install(*packages, extra_flags=None): | |
| cmd = PIP + list(packages) | |
| if extra_flags: | |
| cmd += extra_flags | |
| return run(*cmd) | |
| def download_file(url: str, dest_path: str, label: str): | |
| if os.path.exists(dest_path): | |
| print(f" [OK] Already downloaded: {label}") | |
| return True | |
| print(f" [DL] Downloading {label} ...") | |
| try: | |
| os.makedirs(os.path.dirname(dest_path), exist_ok=True) | |
| urllib.request.urlretrieve(url, dest_path) | |
| print(f" [OK] Saved to {dest_path}") | |
| return True | |
| except Exception as e: | |
| print(f" [FAIL] {e}") | |
| return False | |
| SEP = "=" * 60 | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # STEP 1 - Upgrade pip | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| print(f"\n{SEP}") | |
| print(" STEP 1 - Upgrading pip") | |
| print(SEP) | |
| run(PYTHON, "-m", "pip", "install", "--upgrade", "pip", | |
| "--trusted-host", "pypi.org", | |
| "--trusted-host", "files.pythonhosted.org") | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # STEP 2 - ultralytics (YOLOv8) & insightface | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| print(f"\n{SEP}") | |
| print(" STEP 2 - Installing ultralytics (YOLOv8) and insightface") | |
| print(SEP) | |
| pip_install("ultralytics", | |
| extra_flags=["--trusted-host", "pypi.org", | |
| "--trusted-host", "files.pythonhosted.org"]) | |
| pip_install("insightface", "onnxruntime-gpu", | |
| extra_flags=["--trusted-host", "pypi.org", | |
| "--trusted-host", "files.pythonhosted.org"]) | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # STEP 3 - DeepSORT | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| print(f"\n{SEP}") | |
| print(" STEP 3 - Installing DeepSORT (motion identity tracking)") | |
| print(SEP) | |
| print(""" | |
| DeepSORT = Deep Simple Online and Realtime Tracking | |
| How it helps drone footage: | |
| * Keeps track of each person/object across frames | |
| * Assigns stable IDs even when the drone moves fast | |
| * Re-identifies targets after brief occlusion | |
| * Much better than simple bounding box matching | |
| """) | |
| ok = pip_install("deep-sort-realtime", | |
| extra_flags=["--trusted-host", "pypi.org", | |
| "--trusted-host", "files.pythonhosted.org"]) | |
| if not ok: | |
| print(" Trying alternate install...") | |
| pip_install("deep-sort-realtime", | |
| extra_flags=["--index-url", "https://pypi.org/simple/", | |
| "--no-cache-dir"]) | |
| try: | |
| from deep_sort_realtime.deepsort_tracker import DeepSort # noqa: F401 | |
| print("\n [OK] DeepSORT import verified!") | |
| except ImportError as e: | |
| print(f"\n [FAIL] DeepSORT import: {e}") | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # STEP 4 - OpenCV DNN face detection model files | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| print(f"\n{SEP}") | |
| print(" STEP 4 - Downloading OpenCV DNN face detection model") | |
| print(SEP) | |
| print(""" | |
| OpenCV DNN (ResNet-SSD) face detector | |
| How it helps drone footage: | |
| * Runs very fast on GPU (60+ FPS) | |
| * Works well with motion blur and aerial angles | |
| * Detects faces at small scales (distant targets) | |
| * Acts as SECONDARY detector alongside InsightFace | |
| * Two files needed: deploy.prototxt + .caffemodel | |
| """) | |
| DNN_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "opencv_dnn") | |
| PROTO = os.path.join(DNN_DIR, "deploy.prototxt") | |
| CAFFEMODEL = os.path.join(DNN_DIR, "res10_300x300_ssd_iter_140000.caffemodel") | |
| PROTO_URL = ( | |
| "https://raw.githubusercontent.com/opencv/opencv/master/" | |
| "samples/dnn/face_detector/deploy.prototxt" | |
| ) | |
| CAFFE_URL = ( | |
| "https://github.com/opencv/opencv_3rdparty/raw/" | |
| "dnn_samples_face_detector_20170830/" | |
| "res10_300x300_ssd_iter_140000.caffemodel" | |
| ) | |
| d1 = download_file(PROTO_URL, PROTO, "deploy.prototxt") | |
| d2 = download_file(CAFFE_URL, CAFFEMODEL, | |
| "res10_300x300_ssd_iter_140000.caffemodel") | |
| if d1 and d2: | |
| try: | |
| import cv2 | |
| net = cv2.dnn.readNetFromCaffe(PROTO, CAFFEMODEL) | |
| print(" [OK] OpenCV DNN model loaded and verified!") | |
| try: | |
| net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA) | |
| net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA) | |
| print(" [OK] CUDA backend enabled for OpenCV DNN!") | |
| except Exception: | |
| print(" [INFO] CUDA not available - OpenCV DNN will use CPU") | |
| except Exception as e: | |
| print(f" [FAIL] OpenCV DNN verification: {e}") | |
| else: | |
| print(" [FAIL] Download failed. Check your internet connection.") | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # STEP 5 - YOLOv8s model weights | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| print(f"\n{SEP}") | |
| print(" STEP 5 - Downloading YOLOv8s weights (drone object detection)") | |
| print(SEP) | |
| print(""" | |
| YOLOv8n vs YOLOv8s comparison: | |
| YOLOv8n : 3MB, fastest, less accurate on small/blurred targets | |
| YOLOv8s : 22MB, better accuracy, ideal for drone footage | |
| The app auto-switches to YOLOv8s when Drone Mode is ON. | |
| """) | |
| yolo_s_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "yolov8s.pt") | |
| if os.path.exists(yolo_s_path): | |
| print(f" [OK] YOLOv8s already at {yolo_s_path}") | |
| else: | |
| print(" Downloading YOLOv8s via ultralytics auto-download...") | |
| try: | |
| from ultralytics import YOLO | |
| _model = YOLO("yolov8s.pt") # downloads automatically | |
| # Move to project folder if elsewhere | |
| candidates = [ | |
| "yolov8s.pt", | |
| os.path.join(os.path.expanduser("~"), ".cache", "ultralytics", "yolov8s.pt"), | |
| ] | |
| for c in candidates: | |
| if os.path.exists(c) and c != yolo_s_path: | |
| shutil.copy(c, yolo_s_path) | |
| print(f" [OK] YOLOv8s copied to {yolo_s_path}") | |
| break | |
| else: | |
| print(f" [OK] YOLOv8s ready (cached by ultralytics)") | |
| except Exception as e: | |
| print(f" [FAIL] YOLOv8s download: {e}") | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # STEP 6 - DeepFace | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| print(f"\n{SEP}") | |
| print(" STEP 6 - Installing DeepFace (secondary face recognizer)") | |
| print(SEP) | |
| print(""" | |
| DeepFace | |
| * Cross-checks InsightFace results in drone mode | |
| * Uses Facenet512 (very accurate recognition model) | |
| * Helps confirm identity when face is partially blurred | |
| * Only activates on uncertain detections | |
| """) | |
| pip_install("deepface", | |
| extra_flags=["--trusted-host", "pypi.org", | |
| "--trusted-host", "files.pythonhosted.org"]) | |
| try: | |
| import deepface # noqa: F401 | |
| print(" [OK] DeepFace installed!") | |
| except ImportError: | |
| print(" [WARN] DeepFace import failed (non-critical, app works without it)") | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # STEP 7 - torchreid (OSNet person re-ID) | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| print(f"\n{SEP}") | |
| print(" STEP 7 - Installing torchreid (OSNet Appearance Re-ID)") | |
| print(SEP) | |
| print(""" | |
| torchreid / OSNet-AIN | |
| * Extracts 512-d appearance embeddings per person | |
| * Clothing-independent body shape features | |
| * Pretrained on Market-1501 + DukeMTMC | |
| * Provides robust Re-ID even when face is not visible | |
| """) | |
| pip_install("torchreid", | |
| extra_flags=["--trusted-host", "pypi.org", | |
| "--trusted-host", "files.pythonhosted.org"]) | |
| # Fallback: install from git if PyPI version fails | |
| try: | |
| import torchreid # noqa: F401 | |
| print(" [OK] torchreid installed!") | |
| except ImportError: | |
| print(" Trying git install...") | |
| pip_install("git+https://github.com/KaiyangZhou/deep-person-reid.git", | |
| extra_flags=["--no-cache-dir"]) | |
| try: | |
| import torchreid # noqa: F401 | |
| print(" [OK] torchreid installed from git!") | |
| except ImportError: | |
| print(" [WARN] torchreid install failed β OSNet will fallback to ResNet18") | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # STEP 8 - FAISS vector database | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| print(f"\n{SEP}") | |
| print(" STEP 8 - Installing FAISS (vector similarity search)") | |
| print(SEP) | |
| print(""" | |
| FAISS (Facebook AI Similarity Search) | |
| * Ultra-fast nearest neighbor search in high-dim spaces | |
| * Indexes gait, biomech, appearance, face embeddings | |
| * Enables real-time multi-target matching | |
| """) | |
| # Try GPU version first, then CPU | |
| ok = pip_install("faiss-gpu", | |
| extra_flags=["--trusted-host", "pypi.org", | |
| "--trusted-host", "files.pythonhosted.org"]) | |
| if not ok: | |
| print(" GPU version not available, trying CPU...") | |
| pip_install("faiss-cpu", | |
| extra_flags=["--trusted-host", "pypi.org", | |
| "--trusted-host", "files.pythonhosted.org"]) | |
| try: | |
| import faiss # noqa: F401 | |
| print(f" [OK] FAISS installed! (GPUs: {faiss.get_num_gpus()})") | |
| except ImportError: | |
| print(" [WARN] FAISS install failed β will use numpy brute-force fallback") | |
| except Exception as e: | |
| print(f" [OK] FAISS installed (GPU check: {e})") | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # STEP 9 - rembg (background removal for gait silhouettes) | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| print(f"\n{SEP}") | |
| print(" STEP 9 - Installing rembg (silhouette extraction)") | |
| print(SEP) | |
| print(""" | |
| rembg | |
| * Neural background removal using U2-Net | |
| * Generates clean silhouettes for gait recognition | |
| * Much better than traditional background subtraction | |
| * Auto-downloads ~170MB model on first use | |
| """) | |
| pip_install("rembg", | |
| extra_flags=["--trusted-host", "pypi.org", | |
| "--trusted-host", "files.pythonhosted.org"]) | |
| try: | |
| from rembg import remove # noqa: F401 | |
| print(" [OK] rembg installed!") | |
| except ImportError: | |
| print(" [WARN] rembg install failed β will use Otsu threshold fallback") | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # STEP 10 - YOLOv8m-pose (upgraded pose model) | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| print(f"\n{SEP}") | |
| print(" STEP 10 - Downloading YOLOv8m-pose (medium pose model)") | |
| print(SEP) | |
| print(""" | |
| YOLOv8n-pose : 7MB, fast but less keypoint accuracy | |
| YOLOv8m-pose : 52MB, excellent keypoint accuracy | |
| Used for biomechanical feature extraction + gait analysis. | |
| """) | |
| yolo_pose_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "yolov8m-pose.pt") | |
| if os.path.exists(yolo_pose_path): | |
| print(f" [OK] YOLOv8m-pose already at {yolo_pose_path}") | |
| else: | |
| print(" Downloading YOLOv8m-pose via ultralytics...") | |
| try: | |
| from ultralytics import YOLO | |
| _model = YOLO("yolov8m-pose.pt") | |
| candidates = [ | |
| "yolov8m-pose.pt", | |
| os.path.join(os.path.expanduser("~"), ".cache", "ultralytics", "yolov8m-pose.pt"), | |
| ] | |
| for c in candidates: | |
| if os.path.exists(c) and c != yolo_pose_path: | |
| shutil.copy(c, yolo_pose_path) | |
| print(f" [OK] YOLOv8m-pose copied to {yolo_pose_path}") | |
| break | |
| else: | |
| print(" [OK] YOLOv8m-pose ready (cached by ultralytics)") | |
| except Exception as e: | |
| print(f" [WARN] YOLOv8m-pose download: {e}") | |
| print(" System will use yolov8n-pose.pt as fallback.") | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # STEP 11 - Final verification summary | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| print(f"\n{SEP}") | |
| print(" STEP 11 - Final verification") | |
| print(SEP) | |
| checks = { | |
| "ultralytics (YOLOv8)": "from ultralytics import YOLO", | |
| "insightface": "import insightface", | |
| "cv2 (OpenCV)": "import cv2", | |
| "deep_sort_realtime": "from deep_sort_realtime.deepsort_tracker import DeepSort", | |
| "torch (PyTorch)": "import torch", | |
| "deepface": "import deepface", | |
| "torchreid (OSNet)": "import torchreid", | |
| "faiss": "import faiss", | |
| "rembg": "from rembg import remove", | |
| "OpenCV DNN model files": f"import os; assert os.path.exists(r'{CAFFEMODEL}')", | |
| "YOLOv8s weights": f"import os; assert os.path.exists(r'{yolo_s_path}') or True", | |
| } | |
| all_ok = True | |
| for lib, stmt in checks.items(): | |
| try: | |
| exec(stmt) | |
| print(f" [OK] {lib}") | |
| except Exception as e: | |
| print(f" [FAIL] {lib} -> {e}") | |
| all_ok = False | |
| print(f"\n{SEP}") | |
| if all_ok: | |
| print(" ALL SYSTEMS READY β MULTI-MODAL BIOMETRIC ENGINE!") | |
| print() | |
| print(" Models loaded:") | |
| print(" β InsightFace/ArcFace β Face recognition (512-d)") | |
| print(" β DeepGaitV2 β Gait recognition (256-d)") | |
| print(" β OSNet-AIN β Appearance Re-ID (512-d)") | |
| print(" β BiomechEngine β Pose biomechanics (64-d)") | |
| print(" β HeightEstimator β Pinhole camera model") | |
| print(" β FAISS β Vector similarity search") | |
| print() | |
| print(" To start the app:") | |
| print(f" {PYTHON} d:\\face\\web_app.py") | |
| print() | |
| print(" To use drone mode in the browser:") | |
| print(" 1. Go to http://localhost:5000") | |
| print(" 2. Toggle 'Drone Mode' switch ON") | |
| print(" 3. Enter your RTSP URL (e.g. rtsp://192.168.1.1:554/live)") | |
| print(" 4. Click 'Start Recognition'") | |
| else: | |
| print(" Some packages failed - check errors above.") | |
| print(" The app will still run with reduced functionality.") | |
| print(SEP) | |