Classic face detection in OpenCV uses trained cascade files to scan an image for frontal face patterns. Haar cascades are a lightweight fit for local smoke tests, simple camera prototypes, and legacy code paths where a neural-network detector is more setup than the task needs.
The Python smoke script loads the packaged haarcascade_frontalface_default.xml file through cv.data.haarcascades, converts the input image to grayscale, equalizes the histogram, and passes the result to detectMultiScale(). It writes a boxed copy of the image and prints the face count plus each detected rectangle.
Use a sample image or a consented local image with a clear frontal face for the first run. Haar cascades can miss rotated, covered, or side-profile faces and can return false positives, so the printed count is a detector check, not identity recognition.
Related: How to install OpenCV on Ubuntu
Related: How to capture camera video with OpenCV
Related: How to run object detection with OpenCV DNN
Steps to detect faces with OpenCV Haar cascades:
- Create the input directory.
$ mkdir -p input
- Download a sample face image.
$ curl --location --silent --show-error --output input/person.jpg https://raw.githubusercontent.com/opencv/opencv/4.x/samples/data/lena.jpg
Use a consented local image instead by copying it to input/person.jpg.
- Create the Haar cascade detection script.
- detect_faces_haar.py
#!/usr/bin/env python3 import argparse from pathlib import Path import cv2 as cv default_cascade = ( Path(cv.data.haarcascades) / "haarcascade_frontalface_default.xml" ) parser = argparse.ArgumentParser( description="Detect frontal faces with an OpenCV Haar cascade." ) parser.add_argument("image", help="input image path") parser.add_argument( "--output", default="output/faces.jpg", help="annotated image path to write", ) parser.add_argument( "--cascade", default=str(default_cascade), help="Haar cascade XML file", ) parser.add_argument( "--scale-factor", type=float, default=1.1, help="image pyramid step used by detectMultiScale", ) parser.add_argument( "--min-neighbors", type=int, default=5, help="neighbor count required to keep a detection", ) args = parser.parse_args() image_path = Path(args.image) output_path = Path(args.output) cascade_path = Path(args.cascade) image = cv.imread(str(image_path)) if image is None: raise SystemExit(f"Could not read image: {image_path}") classifier = cv.CascadeClassifier(str(cascade_path)) if classifier.empty(): raise SystemExit(f"Could not load cascade: {cascade_path}") gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY) gray = cv.equalizeHist(gray) faces = classifier.detectMultiScale( gray, scaleFactor=args.scale_factor, minNeighbors=args.min_neighbors, minSize=(30, 30), ) annotated = image.copy() for x, y, width, height in faces: cv.rectangle( annotated, (x, y), (x + width, y + height), (0, 255, 0), 3, ) output_path.parent.mkdir(parents=True, exist_ok=True) if not cv.imwrite(str(output_path), annotated): raise SystemExit(f"Could not write output image: {output_path}") height, width = image.shape[:2] print(f"cascade: {cascade_path.name}") print(f"image size: {width}x{height}") print(f"faces detected: {len(faces)}") for index, (x, y, face_width, face_height) in enumerate(faces, start=1): print( f"face {index}: x={x} y={y} " f"width={face_width} height={face_height}" ) print(f"wrote: {output_path}")
- Run the detector and confirm that the cascade reports a face rectangle.
$ python3 detect_faces_haar.py input/person.jpg --output output/faces.png cascade: haarcascade_frontalface_default.xml image size: 512x512 faces detected: 1 face 1: x=216 y=202 width=174 height=174 wrote: output/faces.png
A count of 0 means no region passed the cascade threshold. Try a clearer frontal face before lowering minNeighbors.
- Open output/faces.png in an image viewer.
The green rectangle should surround the detected face. If the box is offset or a non-face region is marked, test a different scaleFactor or minNeighbors value before using the result downstream.
- Remove the smoke-test files when the detector check is complete.
$ rm -f detect_faces_haar.py input/person.jpg output/faces.png
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.