OpenCV's cv::CascadeClassifier can detect frontal faces in an image and return one bounding rectangle per detection. The example below targets OpenCV 4 and writes those rectangles as structured JSON. It is a face detector, not a face-recognition system: it locates face-like regions but does not determine anyone's identity.
C++ Implementation
#include <iostream>
#include <vector>
#include <opencv2/core.hpp>
#include <opencv2/core/persistence.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/objdetect.hpp>
int main(int argc, char** argv) {
if (argc != 3) {
std::cerr << "usage: face_detect <image> <cascade.xml>\n";
return 2;
}
const cv::Mat image = cv::imread(argv[1], cv::IMREAD_COLOR);
if (image.empty()) {
std::cerr << "unable to read image: " << argv[1] << '\n';
return 1;
}
cv::CascadeClassifier classifier;
if (!classifier.load(argv[2])) {
std::cerr << "unable to load cascade: " << argv[2] << '\n';
return 1;
}
cv::Mat gray;
cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
cv::equalizeHist(gray, gray);
std::vector<cv::Rect> faces;
classifier.detectMultiScale(
gray,
faces,
1.1,
3,
0,
cv::Size(30, 30)
);
cv::FileStorage json(
".json",
cv::FileStorage::WRITE |
cv::FileStorage::MEMORY |
cv::FileStorage::FORMAT_JSON
);
if (!json.isOpened()) {
std::cerr << "unable to initialize JSON output\n";
return 1;
}
json.startWriteStruct("faces", cv::FileNode::SEQ);
for (const cv::Rect& face : faces) {
json.startWriteStruct("", cv::FileNode::MAP);
json << "x" << face.x;
json << "y" << face.y;
json << "width" << face.width;
json << "height" << face.height;
json.endWriteStruct();
}
json.endWriteStruct();
std::cout << json.releaseAndGetString() << '\n';
return 0;
} OpenCV's FileStorage API produces the JSON rather than assembling it with string concatenation. A successful run writes an object of this form:
{
"faces": [
{ "x": 142, "y": 86, "width": 118, "height": 118 }
]
} Build and Run
On systems that provide an opencv4.pc file, compile with:
c++ -std=c++17 -O2 face_detect.cpp \
-o face_detect \
$(pkg-config --cflags --libs opencv4) Then pass an image and a trained cascade:
./face_detect portrait.jpg \
/path/to/haarcascade_frontalface_default.xml OpenCV distributes pretrained cascades in its data/haarcascades directory. Distribution packages install them in different locations, so locate the XML file through the package manager rather than hard-coding a system path.
Detection Parameters
The arguments after facesdetectMultiScale control the detector:
1.1is the image-pyramid scale factor. Values closer to one search more scales and cost more time.3isminNeighbors. Raising it usually suppresses false positives but may miss weaker detections.0is the legacy flags argument; modern cascades ignore it.Size(30, 30)rejects candidate faces smaller than 30 by 30 pixels.
The returned coordinates refer to the original image because this implementation converts color and equalizes the histogram without resizing. If preprocessing changes image dimensions, map every rectangle back to the source coordinate system before exporting it.
Limits of Haar Cascades
Haar cascades implement the Viola-Jones detection model: inexpensive rectangular features reject most non-face windows through a sequence of increasingly selective stages. It remains useful for compact CPU-only applications, but frontal-pose cascades are sensitive to head rotation, occlusion, lighting, image scale, and the population represented by their training data.
Evaluate false positives and false negatives on data representative of the actual application. For unconstrained photographs, varied poses, or higher accuracy requirements, use an OpenCV DNN face detector or another maintained model with documented training and evaluation data. Face detection also processes biometric data; collect, retain, and transmit images only with an appropriate legal basis and privacy policy.
References
- [OpenCV]OpenCV 4 Cascade Classifier documentation.
- [ViolaJones2001]Paul Viola and Michael Jones, Rapid Object Detection using a Boosted Cascade of Simple Features, CVPR 2001.