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.
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] = roi3. 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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
