How neerajjv/findx-language-driven-suspect-search works
Purpose and Entry Point
FindX is a local Python desktop investigation tool for locating people in CCTV footage from natural-language descriptions. The PyQt6 application starts at app.py, which composes the desktop UI and invokes the video-indexing/search core. The checked-in input corpus is a large local video set under CCTV/ (for example, CCTV/cam0001.mp4).
Application Shell and UI Coordination
src/ui/main_window.py is the primary UI composition boundary. It coordinates:
• source selection and scan controls from src/ui/sidebar.py;
• text-query submission through src/ui/top_bar.py;
• result selection, video review, and restoration actions.
The UI is native PyQt6, not a web application; it binds long-running local ML/video work to interactive investigation views.
Video Ingestion and Sampling
src/core/processor.py owns the OpenCV-facing video-processing stage. It accepts either a CCTV directory or individual upload, iterates video frames at a configured sampling rate, and supplies frames plus source/timestamp context to detection. src/config.py is the likely central boundary for sampling and model/storage constants. Raw MP4 files remain the source of truth; derived crops and metadata feed subsequent stages.
Person Detection and Crop Production
src/core/detector.py applies YOLOv8 through Ultralytics to sampled frames and retains person detections. This separates expensive pixel-level inference from later semantic retrieval. Bounding boxes are used to generate person crops, preserving the originating video and timestamp so a retrieved crop can lead back to evidence playback.
Cross-Modal Embedding
src/core/encoder.py uses OpenAI CLIP ViT-B/16 with PyTorch to embed detected person crops into image vectors and investigator descriptions into text vectors in the same feature space. The common embedding representation is the contract between indexing and natural-language search; it enables clothing, accessory, and person-description matching without a separate text metadata schema.
Vector Index and Retrieval
src/core/indexer.py persists and queries a FAISS similarity index over CLIP image embeddings. The intended flow is: processed crop vectors enter FAISS during scan; a query is text-encoded; FAISS returns nearest person occurrences ranked by semantic similarity. The README identifies cctv_index.faiss as the retrieval cache, although that artifact is not present in the supplied tree. Result records must retain enough local metadata to resolve a hit back to crop, video, timestamp, and detection region.
Evidence Review and Restoration
src/ui/results_grid.py presents ranked crop matches, and src/ui/viewer.py plays the originating local MP4 at the selected timestamp, with the person region highlighted. src/ui/restoration_panel.py invokes src/core/restoration.py, which uses GFPGAN for face enhancement/upscaling. Restoration is a downstream visual-review operation, not part of the search index pipeline.
Runtime and Infrastructure Boundaries
The system runs locally on Python 3.9+ with PyQt6, OpenCV, Pillow/NumPy, PyTorch/Torchvision, Ultralytics YOLOv8, OpenAI CLIP, FAISS, and GFPGAN. CUDA-capable PyTorch/NVIDIA hardware is an optional acceleration path for detection and embedding. Models are local or dynamically loaded according to the README; no server, database, cloud service, or network API is evidenced by the repository tree.
Main entry points: encoder.py CLIP encoder · main_window.py Main window · indexer.py FAISS indexer · processor.py Video processor
Components 17
Desktop UI
Native PyQt6 investigation workflow.
- Application entry · Composes and starts the desktop application.
app.py - Main window · Coordinates source scanning, queries, results, and review.
src/ui/main_window.py - Scan controls · Selects CCTV sources and starts scans.
src/ui/sidebar.py - Query input · Submits natural-language person descriptions.
src/ui/top_bar.py
Indexing Pipeline
Local video-to-vector processing.
- CCTV videos · Raw footage is the source of truth.
- Configuration · Defines sampling, model, and storage constants.
src/config.py - Video processor · Samples frames and preserves source and timestamp context.
src/core/processor.py - Person detector · Detects people and creates contextualized crops.
src/core/detector.py - Person crops · Crops retain video, timestamp, and detection-region metadata.
- CLIP encoder · Embeds person crops and text in one feature space.
src/core/encoder.py
Search & Review
Semantic retrieval and evidence inspection.
- FAISS indexer · Persists image vectors and resolves nearest occurrences.
src/core/indexer.py - FAISS index cache · Persisted CLIP image embeddings and occurrence metadata.
- Ranked results · Shows semantic crop matches.
src/ui/results_grid.py - Evidence viewer · Plays source footage at the hit timestamp and highlights the region.
src/ui/viewer.py - Restoration controls · Starts optional face enhancement for review.
src/ui/restoration_panel.py - Face restoration · Enhances or upscales faces after retrieval.
src/core/restoration.py
Other components
- Optional CUDA · Accelerates detection and embedding when available.
Connections 20
- Application entry → Main window: starts
- Main window → Scan controls: coordinates
- Main window → Query input: coordinates
- Scan controls → Video processor: starts scan
- CCTV videos → Video processor: video input
- Configuration → Video processor: sampling settings
- Video processor → Person detector: sampled frames
- Person detector → Person crops: person crops + context
- Person crops → CLIP encoder: image embeddings
- CLIP encoder → FAISS indexer: crop vectors
- FAISS indexer → FAISS index cache: persists and queries
- Query input → CLIP encoder: text description
- CLIP encoder → FAISS indexer: query vector
- FAISS indexer → Ranked results: ranked occurrences
- Ranked results → Evidence viewer: selected hit
- Evidence viewer → CCTV videos: opens source video
- Main window → Restoration controls: coordinates
- Restoration controls → Face restoration: enhancement request
- Person detector → Optional CUDA: optional compute
- CLIP encoder → Optional CUDA: optional compute