Template matching in OpenCV compares a small image patch against every possible position in a larger image. It fits controlled image checks where the target icon, marker, part, or UI element keeps the same scale and orientation and the application needs pixel coordinates instead of a trained detector.
In Python, cv2.matchTemplate() creates a one-channel score map and cv2.minMaxLoc() chooses the strongest location. Correlation methods such as TM_CCOEFF_NORMED and TM_CCORR_NORMED use the highest score, while TM_SQDIFF_NORMED uses the lowest score.
A source image and template image are enough when the template is not larger than the source. For a flat color patch, sqdiff-normed avoids the zero-variance ambiguity that can affect correlation methods, and the annotated PNG confirms the chosen rectangle after OpenCV writes it.
Steps to match a template with OpenCV:
- Place the source image and template image under input.
Use input/scene.png and input/template.png. The template must have the same scale and orientation as the target region and must not be larger than the scene image.
- Create match_template.py.
- match_template.py
#!/usr/bin/env python3 import argparse from pathlib import Path import cv2 METHODS = { "ccoeff-normed": cv2.TM_CCOEFF_NORMED, "ccorr-normed": cv2.TM_CCORR_NORMED, "sqdiff-normed": cv2.TM_SQDIFF_NORMED, } parser = argparse.ArgumentParser(description="Locate a template image inside a larger image with OpenCV.") parser.add_argument("scene", type=Path) parser.add_argument("template", type=Path) parser.add_argument("output", type=Path) parser.add_argument("--method", choices=METHODS, default="ccoeff-normed") args = parser.parse_args() scene_color = cv2.imread(str(args.scene), cv2.IMREAD_COLOR) scene_gray = cv2.imread(str(args.scene), cv2.IMREAD_GRAYSCALE) template_gray = cv2.imread(str(args.template), cv2.IMREAD_GRAYSCALE) if scene_color is None or scene_gray is None: raise SystemExit(f"could not read scene image: {args.scene}") if template_gray is None: raise SystemExit(f"could not read template image: {args.template}") if template_gray.shape[0] > scene_gray.shape[0] or template_gray.shape[1] > scene_gray.shape[1]: raise SystemExit("template image must not be larger than the scene image") method = METHODS[args.method] result = cv2.matchTemplate(scene_gray, template_gray, method) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result) if method == cv2.TM_SQDIFF_NORMED: top_left = min_loc score = min_val better = "lower" else: top_left = max_loc score = max_val better = "higher" height, width = template_gray.shape bottom_right = (top_left[0] + width, top_left[1] + height) cv2.rectangle(scene_color, top_left, bottom_right, (0, 0, 255), 3) cv2.putText( scene_color, f"{args.method} {score:.3f}", (top_left[0], max(25, top_left[1] - 10)), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2, ) args.output.parent.mkdir(parents=True, exist_ok=True) if not cv2.imwrite(str(args.output), scene_color): raise SystemExit(f"could not write output image: {args.output}") print(f"method: {args.method} ({better} score is better)") print(f"scene size: {scene_gray.shape[1]}x{scene_gray.shape[0]}") print(f"template size: {width}x{height}") print(f"result map: {result.shape[1]}x{result.shape[0]}") print(f"best score: {score:.3f}") print(f"top-left: x={top_left[0]}, y={top_left[1]}") print(f"bottom-right: x={bottom_right[0]}, y={bottom_right[1]}") print(f"output: {args.output}")
- Run the template match with sqdiff-normed.
$ python3 match_template.py input/scene.png input/template.png output/template-match.png --method sqdiff-normed method: sqdiff-normed (lower score is better) scene size: 720x480 template size: 155x130 result map: 566x351 best score: 0.000 top-left: x=60, y=70 bottom-right: x=215, y=200 output: output/template-match.png
Use sqdiff-normed when a lower score should represent a closer pixel difference. Use ccoeff-normed or ccorr-normed for textured templates where a stronger correlation should produce a higher score.
- Confirm that OpenCV can read the annotated result.
$ python3 -c 'import cv2; image = cv2.imread("output/template-match.png"); print(f"annotated image: {image.shape[1]}x{image.shape[0]} channels={image.shape[2]}")' annotated image: 720x480 channels=3
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.