当前位置:网站首页>Credit card number recognition (openCV, code analysis)
Credit card number recognition (openCV, code analysis)
2022-07-26 15:25:00 【csp_】
Catalog
Project source code
Can be found in github download :
https://github.com/chenshunpeng/Credit-card-digital-identification
Environment configuration and pretreatment
Import toolkit
# imutils Is in OPenCV Based on a package , To achieve a simpler call OPenCV Purpose of the interface
from imutils import contours
# It is mainly used to calculate multidimensional arrays , It greatly simplifies the operation of vectors and matrices
import numpy as np
# argparse yes python Standard module for parsing command line arguments and options
import argparse
# OpenCV2(OpenCV It's based on BSD The license ( Open source ) Distributed cross-platform computer vision library )
import cv2
# Import myutils.py The method in the document
import myutils
Set parameters
About argparse The use of can be seen :
Python, argparse, and command line arguments( recommend )
python And parser.add_argument() usage —— Command line options 、 Parameter and subcommand parsers
First of all Parameter form Set the position of the input image and template , Here the parameter specifies the default value , Therefore, it is necessary to required=True Change to required=False, Otherwise, an error will be reported ( reference : Resolve errors : Default parameters are set , Still report a mistake :error: the following arguments are required:)
# argparse The module is Python A built-in module for command options and parameter parsing ,
# argparse Module makes it easy to write user-friendly command-line interface .
# By defining the parameters we need in the program , then argparse Will be from sys.argv Resolve these parameters .
# argparse The module also automatically generates help and user manuals , And report an error message when the user passes in invalid parameters to the program .
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image",default='./images/credit_card_03.png', required=False,
help="path to input image")
ap.add_argument("-t", "--template",default='./images/ocr_a_reference.png', required=False,
help="path to template OCR-A image")
args = vars(ap.parse_args())
Template processing method
Turn binary image
cv2.threshold() The method can be seen :CV2 Simple threshold function :cv2.threshold()
# Graphic display
def cv_show(name,img):
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# Read a template image ( because BGR, So every pixel is [255 255 255])
img = cv2.imread(args["template"])
cv_show('img',img)
# Convert to grayscale (BGR To GRAY)
ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv_show('ref',ref)
# Binary image ( The options are cv2.THRESH_BINARY_INV)
ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1]
cv_show('ref',ref)
- grayscale : stay RGB In the model , If R=G=B when , Then color represents a grayscale color , among R=G=B The value of is called gray value , therefore , Gray image each pixel only needs one byte to store the gray value ( Also called strength value 、 Brightness value ), The gray range is 0-255. Generally, the weighted average method is commonly used to obtain the gray value of each pixel .
- Binary figure : Binary image , Is to set the gray value of pixels on the image to 0 or 255, That is to say, the whole image has only black and white visual effects .
- Color image : A special case of multispectral images , The three primary colors corresponding to human vision are red 、 green 、 Blue three bands , It is an approximation of the spectral quantization properties of the human eye .
It can be seen that the gray image and binary image occupy less space , It's a color image (BGR) One third
Step by step debugging ( The method can be seen : Portal ):


Original picture :

The binary image is as follows :

Calculate the contour
Then calculate this 10 The outline of the number , Because of this 10 The order of the outlines does not necessarily follow this 0-9 The outline of corresponds to , We need to calculate the coordinates of the upper left corner of each contour , Sort from small to large , So that's a guarantee When matching, the order is corresponding ( such as “354” The corresponding is indeed template pass the civil examinations 4,6,5 A digital )
# Calculate the contour
#cv2.findContours() The parameters accepted by the function are binary graphs , Black and white ( It's not grayscale ),cv2.RETR_EXTERNAL Only the outer contour is detected ,cv2.CHAIN_APPROX_SIMPLE Keep only the end coordinates
# Back to list Each element in is an outline in the image
# ref_, refCnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
refCnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
# -1 Means to draw all the contours , Behind is the brush color , Brush size
# refCnts Return to the image with the outline drawn
cv2.drawContours(img,refCnts,-1,(0,0,255),3)
cv_show('img',img)
print (np.array(refCnts).shape)
refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0] # Sort , From left to right , From top to bottom
digits = {
}
Before ordering refCnts:

After ordering refCnts:

Sorting function sort_contours:
boundingBoxes Yes 4 Return values (x,y,h,w), By virtue of x You can judge the position relationship between the front and back of the number
def sort_contours(cnts, method="left-to-right"):
reverse = False
i = 0
if method == "right-to-left" or method == "bottom-to-top":
reverse = True
if method == "top-to-bottom" or method == "bottom-to-top":
i = 1
boundingBoxes = [cv2.boundingRect(c) for c in cnts] # Use the smallest rectangle , Wrap the shapes you find x,y,h,w
(cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes), key=lambda b: b[1][i], reverse=reverse))
return cnts, boundingBoxes
result :

Then corresponding to each number ,resize To the right size , Put in digits Make a template in the array 
# Traverse every contour
for (i, c) in enumerate(refCnts):
# Calculate the circumscribed rectangle and resize To the right size
(x, y, w, h) = cv2.boundingRect(c)
roi = ref[y:y + h, x:x + w]
roi = cv2.resize(roi, (57, 88))
# Each number corresponds to each template
digits[i] = roi
digits The final result of the array :

Input data processing method
Initialize convolution kernel , Image preprocessing
First, initialize the convolution kernel , Read input image , Preprocessing
# Initialize convolution kernel
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
# Read input image , Preprocessing
image = cv2.imread(args["image"])
cv_show('image',image)
image = myutils.resize(image, width=300)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv_show('gray',gray)
rectKernel:

sqKernel:

Images :

Resize , After converting to grayscale :

Top hat operation
Some morphological operations can be seen
Top hat operation of image morphological operation (TopHat) Operate with black hat (BlackHat)
# Top hat operation , Highlight brighter areas
# Carry out the top hat operation according to the core size specified by yourself
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)
cv_show('tophat',tophat)
result :

Sobel Operator for high pass filtering
Some morphological operations can be seen :Sobel operator
# ksize: yes Sobel The size of the operator , That is, the size of the convolution kernel , Must be odd , The default value is 3(ksize=-1 Equivalent to using 3*3 Of )
gradX = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=-1)
# The absolute value
gradX = np.absolute(gradX)
# normalization
(minVal, maxVal) = (np.min(gradX), np.max(gradX))
gradX = (255 * ((gradX - minVal) / (maxVal - minVal)))
gradX = gradX.astype("uint8")
print (np.array(gradX).shape)
cv_show('gradX',gradX)
result :

Close your operations , Two valued
after 2 Secondary closing operation ( Inflate first , Corrode again ) Put the numbers together , You can use THRESH_OTSU Binarization , Its advantage is that it can automatically find the appropriate threshold
# By closing ( Inflate first , Corrode again ) Put the numbers together
gradX = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel)
cv_show('gradX',gradX)
#THRESH_OTSU Will automatically find the right threshold , Suitable for bimodal , The threshold parameter needs to be set to 0
thresh = cv2.threshold(gradX, 0, 255,
cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv_show('thresh',thresh)
# Repeat the closing operation once
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel)
cv_show('thresh',thresh)
The first 1 Secondary closing operation :

binarization :

The first 2 Secondary closing operation :

Calculate the contour
# Calculate the contour
# thresh_, threshCnts, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
threshCnts, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
Draw the outline on the color map
cnts = threshCnts
cur_img = image.copy()
cv2.drawContours(cur_img,cnts,-1,(0,0,255),3)
cv_show('img',cur_img)
result :

Filter profile
Then filter the contour , That is, by calculating the size of all outline circumscribed rectangles , Find valuable digital areas , Put this 4 Put areas locs Sort the list
locs = []
# Traverse the outline
for (i, c) in enumerate(cnts):
# Calculate rectangle
(x, y, w, h) = cv2.boundingRect(c)
ar = w / float(h)
# Choose the right area , According to the actual task , It's basically a set of four numbers
if ar > 2.5 and ar < 4.0:
if (w > 40 and w < 55) and (h > 10 and h < 20):
# The right ones stay
locs.append((x, y, w, h))
# Sort the matching contours from left to right
locs = sorted(locs, key=lambda x:x[0])
locs List content :

Template matching results in recognition
Template matching
First enlarge the outline slightly , Then traverse the numbers in each contour , Similar to the above method , Find each number , Calculate each score in the template , Get the most appropriate number and draw it :
output = []
# Go through the numbers in each profile
for (i, (gX, gY, gW, gH)) in enumerate(locs):
# initialize the list of group digits
groupOutput = []
# Extract each group from the coordinates
group = gray[gY - 5:gY + gH + 5, gX - 5:gX + gW + 5]
cv_show('group',group)
# Preprocessing
group = cv2.threshold(group, 0, 255,
cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv_show('group',group)
# Calculate the outline of each group
# group_,digitCnts,hierarchy = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
digitCnts,hierarchy = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
digitCnts = contours.sort_contours(digitCnts,
method="left-to-right")[0]
# Calculate each value in each group
for c in digitCnts:
# Find the outline of the current value ,resize To the right size
(x, y, w, h) = cv2.boundingRect(c)
roi = group[y:y + h, x:x + w]
roi = cv2.resize(roi, (57, 88))
cv_show('roi',roi)
# Calculate the match score
scores = []
# Calculate each score in the template
for (digit, digitROI) in digits.items():
# Template matching
result = cv2.matchTemplate(roi, digitROI,
cv2.TM_CCOEFF)
(_, score, _, _) = cv2.minMaxLoc(result)
scores.append(score)
# Get the most appropriate number
groupOutput.append(str(np.argmax(scores)))
# Draw out
cv2.rectangle(image, (gX - 5, gY - 5),
(gX + gW + 5, gY + gH + 5), (0, 0, 255), 1)
cv2.putText(image, "".join(groupOutput), (gX, gY - 15),
cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)
# Get the results
output.extend(groupOutput)
Part of the result :




output list :

Print the results
# Print the results
print("Credit Card Type: {}".format(FIRST_NUMBER[output[0]]))
print("Credit Card #: {}".format("".join(output)))
cv2.imshow("Image", image)
cv2.waitKey(0)
result :

边栏推荐
- 数商云:引领化工业态数字升级,看摩贝如何快速打通全场景互融互通
- Yifang biological fell 16% on the first day of listing: the company's market value was 8.8 billion, and Hillhouse and Lilly were shareholders
- Pytorch--- advanced chapter (function usage skills / precautions)
- DICOM学习资料收集
- 企业数字化转型需要深入研究,不能为了转型而转型
- Deep Packet Inspection Using Quotient Filter论文总结
- 教程篇(7.0) 05. 通过FortiClient EMS发放FortiClient * FortiClient EMS * Fortinet 网络安全专家 NSE 5
- Complete MySQL commands
- Digital commerce cloud: lead the digital upgrading of chemical industry and see how Mobei can quickly open up the whole scene of mutual integration and interoperability
- Li Hongyi, machine learning 3. Gradient descent
猜你喜欢

Where is the foreign literature needed to write the graduation thesis?
![[leetcode daily question] - 268. Missing numbers](/img/96/dcf18522257dea7cb7e52f5bb7ced3.png)
[leetcode daily question] - 268. Missing numbers

anaconda No module named ‘cv2‘

固态硬盘对游戏运行的帮助有多少

Unity URP入门实战

FOC电机控制基础

Which software must be used by scientific researchers to read literature?

持续集成(一)基本概念简要介绍

Deep packet inspection using quotient filter paper summary

【静态代码质量分析工具】上海道宁为您带来SonarSource/SonarQube下载、试用、教程
随机推荐
Huawei applications have called the checkappupdate interface. Why is there no prompt for version update in the application
写综述,想用一个靠谱的整理文献的软件,有推荐的吗?
sqlDeveloper工具快速入门
Solve the problem that typora pictures cannot be displayed
大学生如何申请实用新型专利?
生泰尔科技IPO被终止:曾拟募资5.6亿 启明与济峰资本是股东
Jintuo shares listed on the Shanghai Stock Exchange: the market value of 2.6 billion Zhang Dong family business has a strong color
带你熟悉云网络的“电话簿”:DNS
pytorch---进阶篇(函数使用技巧/注意事项)
【LeetCode每日一题】——268.丢失的数字
[static code quality analysis tool] Shanghai daoning brings you sonarource/sonarqube download, trial and tutorial
R语言wilcox.test函数比较两个非参数样本的总体的中心位置是否具有显著差异(如果两个样本数据是配对数据设置paired参数为TRUE)
Yifang biological fell 16% on the first day of listing: the company's market value was 8.8 billion, and Hillhouse and Lilly were shareholders
怎样在nature上查文献?
软测(七)性能测试(1)简要介绍
DICOM学习资料收集
小白哪个券商开户最好 开户最安全
Remote desktop on Jetson nano
How to translate academic documents?
Ner of NLP: Exploration and practice of product title attribute recognition