Face Recognition in Delphi C++ Builder: Open-Source Source Code & Examples

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:

  1. aligned = align(faceROI)
  2. blob = preprocess(aligned)
  3. embedding = session.Run(blob)
  4. 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)

  1. Start camera capture.
  2. On new frame: run detector → for each face run alignment → compute embedding.
  3. Query EmbeddingsDB for nearest neighbor.
  4. Update UI with box + label + confidence.
  5. 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?

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *