Delphi C++ Builder Face Recognition Source Code — Complete Project WalkthroughThis walkthrough shows how to build a face-recognition application in Delphi C++ Builder from project setup through source-code structure, key algorithms, integration steps, optimization tips, and deployment. It targets developers familiar with Delphi/C++ Builder and basic computer-vision concepts. Example code snippets are C++ Builder compatible; adapt where your project uses Delphi (Object Pascal) units.
Project overview
Goal: create a desktop application that detects faces from a webcam, extracts facial features (embeddings), and recognizes people by comparing embeddings to a labeled database.
Core components:
- Camera capture (OpenCV)
- Face detection (Haar cascade, DNN, or modern detector)
- Face alignment (optional, improves accuracy)
- Feature extraction (pretrained embedding network like FaceNet, ArcFace, or MobileFaceNet)
- Database and matching (store embeddings and labels, nearest-neighbor search)
- UI (Delphi/C++ Builder forms for capture, registration, and recognition)
- Packaging and deployment (Windows EXE)
Key constraints and choices:
- Use OpenCV for capture/detection; C++ Builder can link OpenCV libraries.
- For embeddings use a pretrained ONNX model (easier integration) or TensorFlow/Torch via C API or third-party wrappers.
- Keep inference on CPU for simplicity; GPU possible with additional setup.
- Privacy/security: store embeddings rather than raw images; encrypt database if needed.
Required libraries and tools
- Embarcadero C++ Builder (RAD Studio) — project environment.
- OpenCV (4.x) — build with MinGW or use precompiled Windows libraries compatible with C++ Builder.
- ONNX Runtime (or TensorRT if using NVIDIA GPU) — for running pretrained embedding models exported to ONNX.
- Pretrained face-embedding model (FaceNet, ArcFace) exported to ONNX.
- Haar cascade XML (optional) or DNN face detector (OpenCV DNN, SSD/MTCNN).
- SQLite (or simple file) for storing embeddings and labels.
- C++ Builder components for UI and multi-threading (TThread).
Project structure
- src/
- main.cpp — application entry, form creation.
- frmMain.h/.cpp — main form UI (camera preview, controls).
- CameraCapture.h/.cpp — webcam capture wrapper using OpenCV VideoCapture.
- FaceDetector.h/.cpp — detection pipeline (Haar/DNN).
- FaceAligner.h/.cpp — optional alignment using landmarks.
- EmbeddingModel.h/.cpp — ONNX Runtime wrapper to compute embeddings.
- EmbeddingsDB.h/.cpp — store/load embeddings and labels (SQLite or JSON).
- Recognizer.h/.cpp — matching logic (cosine or Euclidean).
- Utils.h/.cpp — helper functions (image conversion, normalization).
- models/
- face_detector.prototxt / weights / haarcascade_frontalface.xml
- face_embedding.onnx
- data/
- db_embeddings.sqlite
- registered_images/
- resources/ and project files
Camera capture (CameraCapture)
Use OpenCV VideoCapture to get frames from the webcam. Wrap capture into a class that provides frames as cv::Mat and runs on a separate thread to avoid blocking the UI.
Example snippet (C++ Builder compatible):
// CameraCapture.h #pragma once #include <opencv2/opencv.hpp> #include <atomic> #include <thread> #include <functional> class CameraCapture { public: CameraCapture(int device = 0); ~CameraCapture(); void start(std::function<void(const cv::Mat&)> onFrame); void stop(); private: int deviceId; std::atomic<bool> running; std::thread worker; cv::VideoCapture cap; };
// CameraCapture.cpp (core loop) #include "CameraCapture.h" CameraCapture::CameraCapture(int device): deviceId(device), running(false) {} CameraCapture::~CameraCapture() { stop(); } void CameraCapture::start(std::function<void(const cv::Mat&)> onFrame) { if (running) return; cap.open(deviceId); if (!cap.isOpened()) return; running = true; worker = std::thread([this, onFrame]() { cv::Mat frame; while (running) { cap >> frame; if (frame.empty()) break; onFrame(frame); std::this_thread::sleep_for(std::chrono::milliseconds(10)); } }); } void CameraCapture::stop() { running = false; if (worker.joinable()) worker.join(); if (cap.isOpened()) cap.release(); }
Notes:
- Convert between cv::Mat and VCL TBitmap for display.
- Use thread-safe callbacks to update UI via TThread::Synchronize or PostMessage.
Face detection (FaceDetector)
Options:
- Haar cascades (fast, lower accuracy)
- OpenCV DNN (better accuracy — use SSD or YOLO)
- MTCNN (more accurate landmarks)
For simplicity, OpenCV DNN with an SSD or a Haar cascade can be used.
Example detector interface:
class FaceDetector { public: FaceDetector(const std::string& modelPath); std::vector<cv::Rect> detect(const cv::Mat& frame); private: cv::dnn::Net net; cv::CascadeClassifier cascade; bool useDNN; };
Detection pipeline:
- Preprocess frame (resize, mean subtraction)
- Run detector
- Return bounding boxes
Face alignment (optional)
Aligning faces improves embedding quality:
- Detect five landmarks (eyes, nose, mouth corners) using a landmark detector.
- Compute similarity transform to warp the face to a canonical size (e.g., 112×112).
Simple approach: use dlib or a lightweight landmark model with ONNX, then cv::warpAffine.
Embedding extraction (EmbeddingModel)
Run a pretrained embedding model (FaceNet/ArcFace) converted to ONNX. Use ONNX Runtime C++ API for inference.
Interface:
class EmbeddingModel { public: EmbeddingModel(const std::string& onnxPath); std::vector<float> compute(const cv::Mat& alignedFace); private: // ONNX runtime members };
Preprocessing:
- Resize to expected input (e.g., 112×112 or 160×160)
- Convert BGR to RGB if model expects RGB
- Normalize pixels (scale / mean/std)
Postprocessing:
- L2-normalize embeddings before storing/comparing.
Example pseudo-flow:
- aligned = align(faceROI)
- blob = preprocess(aligned)
- embedding = session.Run(blob)
- normalize(embedding)
Embeddings database (EmbeddingsDB)
Store embeddings (float vectors) with labels and metadata. Use SQLite with a table:
- id INTEGER PRIMARY KEY
- label TEXT
- embedding BLOB (binary floats)
- created_at TIMESTAMP
Implement:
- addEmbedding(label, vector
) - findNearest(vector
, k=1) - listLabels(), removeLabel()
Matching:
- Cosine similarity or Euclidean distance on L2-normalized vectors.
- Use KD-tree or FAISS for larger datasets.
Recognition logic (Recognizer)
Simple nearest-neighbor approach:
- For each detected face compute embedding.
- Compare with database embeddings using cosine similarity.
- Accept match if similarity > threshold (e.g., 0.5–0.7 depending on model).
Provide operations:
- Register: capture N images, compute average embedding, store with label.
- Recognize: find top-k matches, return label and score.
Decision examples:
- If best_score > 0.6 => recognized; else unknown.
- For more reliability, require multiple consecutive recognitions within a short window.
UI design (frmMain)
Main features:
- Live camera preview with detection boxes and labels.
- Register user flow (enter name → capture several frames → save).
- Database management (list/remove users).
- Settings (thresholds, model paths).
Implementation notes:
- Convert cv::Mat to TBitmap for display in TImage.
- Use TThread for processing frames to keep UI responsive.
- Provide visual feedback (progress bar) during registration.
Example integration flow (runtime)
- Start camera capture.
- On new frame: run detector → for each face run alignment → compute embedding.
- Query EmbeddingsDB for nearest neighbor.
- Update UI with box + label + confidence.
- On register action: save embedding(s) under provided label.
Performance and optimization
- Resize frames for detection to speed up.
- Run detection at lower fps (e.g., every 2nd–3rd frame) and tracking between detections.
- Use multi-threading: capture, detect, infer on separate threads.
- Use ONNX Runtime with the appropriate execution provider (CPU, CUDA) for speed.
- Quantize model (INT8) if supported to reduce latency.
- Cache embeddings for recent faces to avoid repeated inference.
Security & privacy
- Store only embeddings, not raw images, to reduce privacy risk.
- Encrypt the embeddings DB if storing sensitive identities.
- Provide user consent and clear UI for data collection.
- Offer option to delete data per user.
Deployment
- Link required DLLs (OpenCV, ONNX Runtime) with your EXE.
- Test on target Windows versions; consider building an installer.
- Verify licensing for models/libraries before distribution.
Troubleshooting & common issues
- OpenCV compatibility with C++ Builder: use compatible prebuilt binaries or compile from source with appropriate compiler settings.
- ONNX Runtime ABI mismatches: ensure runtimes match your compiler and architecture.
- Color/normalization mismatches: check model expected input (RGB vs BGR, scaling).
- False positives: increase detection confidence threshold, improve alignment, or use a better detector.
- Poor accuracy: use a higher-quality embedding model (ArcFace) and collect diverse enrollment images.
Example resources and next steps
- Convert and test a pretrained model to ONNX (FaceNet, ArcFace).
- Prototype detection + embedding in a small C++ console app before integrating UI.
- Consider using modern libraries (MediaPipe, dlib, InsightFace) for higher accuracy.
If you want, I can: provide a ready-to-run minimal C++ Builder example (camera capture + Haar detection + simple matching), a sample ONNX preprocessing function tailored to a specific model, or a template SQLite schema and code to store embeddings. Which would you like next?
Leave a Reply