How to Recognize Credit Card Numbers with OpenCV: A Step‑by‑Step Tutorial

This tutorial walks through a project‑based OpenCV workflow that reads a digit template, preprocesses both template and credit‑card images, extracts individual numbers, matches them against the template, and finally overlays the recognized digits onto the original image, illustrating core computer‑vision techniques.

Huawei Cloud Developer Alliance
Huawei Cloud Developer Alliance
Huawei Cloud Developer Alliance
How to Recognize Credit Card Numbers with OpenCV: A Step‑by‑Step Tutorial

Practice Is the Sole Test of Truth

Because learning OpenCV in a rigid way feels dull, I followed a project‑oriented tutorial and started coding.

1. Case Introduction

Provide a digit template on a credit card.

Requirement: Recognize the digits on the credit card, print them on the original image, and optionally save them as text. The approach is similar to license‑plate recognition.

Example

Original image

Processed image

Overall Steps

1. Load template 2. Preprocess template (grayscale, threshold, contour detection, sorting) 3. Preprocess input image (resize, grayscale, tophat, Sobel, morphological operations, threshold) 4. Match digits with template.

1. Load Template and Import Packages

import cv2 as cv
import numpy as np
import myutils

def cv_show(name, img):
    cv.imshow(name, img)
    cv.waitKey(0)
# Load template image
img = cv.imread("images/ocr_a_reference.png")

2. Template Preprocessing

Convert to grayscale, invert binary, find contours, draw them.

# Convert to gray
ref = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# Invert binary
ref = cv.threshold(ref, 10, 255, cv.THRESH_BINARY_INV)[1]
# Find contours
refCnts, hierarchy = cv.findContours(ref.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE)
cv.drawContours(img, refCnts, -1, (0, 0, 255), 2)

Sort contours left‑to‑right and store each digit ROI in a dictionary.

refCnts = myutils.sort_contours(refCnts)[0]
digits = {}
for (i, c) in enumerate(refCnts):
    (x, y, w, h) = cv.boundingRect(c)
    roi = ref[y:y+h, x:x+w]
    roi = cv.resize(roi, (57, 88))
    digits[i] = roi

3. Input Image Preprocessing

Initialize structuring elements, read and resize the credit‑card image, convert to gray.

rectKernel = cv.getStructuringElement(cv.MORPH_RECT, (9, 3))
sqKernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
card_image = cv.imread("images/credit_card_01.png")
card_image = myutils.resize(card_image, width=300)
gray = cv.cvtColor(card_image, cv.COLOR_BGR2GRAY)

Apply tophat, Sobel gradient, morphological closing, and Otsu threshold.

tophat = cv.morphologyEx(gray, cv.MORPH_TOPHAT, rectKernel)
gradX = cv.Sobel(tophat, cv.CV_32F, 1, 0, ksize=3)
gradX = np.absolute(gradX)
min_Val, max_val = np.min(gradX), np.max(gradX)
gradX = (255 * (gradX - min_Val) / (max_val - min_Val)).astype("uint8")
gradX = cv.morphologyEx(gradX, cv.MORPH_CLOSE, rectKernel)
thresh = cv.threshold(gradX, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)[1]
thresh = cv.morphologyEx(thresh, cv.MORPH_CLOSE, sqKernel)

Find contours of the digit groups.

threshCnts = cv.findContours(thresh.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)[0]
card_copy = card_image.copy()
cv.drawContours(card_copy, threshCnts, -1, (0, 0, 255), 2)

4. Template Matching

Select contour bounding boxes with appropriate aspect ratio, sort them left‑to‑right.

locs = []
for i, c in enumerate(threshCnts):
    x, y, w, h = cv.boundingRect(c)
    ar = w / float(h)
    if 2.5 < ar < 4.0 and 40 < w < 55 and 10 < h < 20:
        locs.append((x, y, w, h))
locs = sorted(locs, key=lambda x: x[0])

For each group, extract the region, threshold, find digit contours, sort them, and match each digit against the template using cv.matchTemplate.

output = []
for (gx, gy, gw, gh) in locs:
    group = gray[gy-5:gy+gh+5, gx-5:gx+gw+5]
    group = cv.threshold(group, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)[1]
    digitCnts = cv.findContours(group.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)[0]
    digitCnts = myutils.sort_contours(digitCnts, method="left-to-right")[0]
    groupOutput = []
    for c in digitCnts:
        (x, y, w, h) = cv.boundingRect(c)
        roi = group[y:y+h, x:x+w]
        roi = cv.resize(roi, (57, 88))
        scores = []
        for (digit, digitROI) in digits.items():
            res = cv.matchTemplate(roi, digitROI, cv.TM_CCOEFF)
            scores.append(cv.minMaxLoc(res)[1])
        groupOutput.append(str(np.argmax(scores)))
    cv.rectangle(card_image, (gx-5, gy-5), (gx+gw+5, gy+gh+5), (0,0,255), 1)
    cv.putText(card_image, "".join(groupOutput), (gx, gy-15), cv.FONT_HERSHEY_SIMPLEX, 0.65, (0,0,255), 2)

Display the final image with recognized digits.

cv.imshow("Output_image", card_image)
cv.waitKey(0)

Conclusion

This credit‑card recognition example demonstrates basic image‑processing operations and provides a friendly entry point for newcomers to OpenCV.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Computer VisionPythonImage ProcessingOCROpenCVTemplate Matching
Huawei Cloud Developer Alliance
Written by

Huawei Cloud Developer Alliance

The Huawei Cloud Developer Alliance creates a tech sharing platform for developers and partners, gathering Huawei Cloud product knowledge, event updates, expert talks, and more. Together we continuously innovate to build the cloud foundation of an intelligent world.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.