Opencv-python_信用卡数字识别

Opencv教程

信用卡识别练习

代码练习

# 导入工具包
# 相关文件在接下来的内容中补充

import numpy as np
import cv2 as cv
# 绘图展示函数
# def 函数名 后面要加冒号

def cv_image_show(name,img):
    cv.imshow(name,img)
    cv.waitKey(0)
    cv.destroyAllWindows()
# 读取模板图像 并展示
# python的文件要用"\"而不是"/"

TemplateImage = cv.imread("ocr_a_reference.png")
cv_image_show("TemplateImage",TemplateImage)
# 变成灰度图

TemplateImageGray = cv.cvtColor(TemplateImage,cv.COLOR_BGR2GRAY)
cv_image_show("TemplateImageGray",TemplateImageGray)
print(type(TemplateImageGray))
<class 'numpy.ndarray'>
# 进行二值化处理
# threshold(src, thresh, maxval, type[, dst]) -> retval, dst

_,TemplateImageBinary = cv.threshold(TemplateImageGray,127,255,cv.THRESH_BINARY)
cv_image_show("TemplateImageBinary",TemplateImageBinary)
# 进行轮廓检测 生成轮廓

TemplateImageBinaryCopy = TemplateImageBinary.copy()
TemplateImageContoursGet,BBB = cv.findContours(TemplateImageBinaryCopy,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE)
print(type(TemplateImageContoursGet))
<class 'tuple'>
# 在原图片上绘制轮廓

TemplateImageContoursDraw = cv.drawContours(TemplateImage,TemplateImageContoursGet,-1,(0,0,255),1)
cv_image_show("TemplateImageContoursDraw",TemplateImageContoursDraw)
# 编写一个轮廓排序函数

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 = [cv.boundingRect(c) for c in cnts] #用一个最小的矩形,把找到的形状包起来x,y,h,w
    (cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
                                        key=lambda b: b[1][i], reverse=reverse))

    return cnts, boundingBoxes
# 编写一个图像重整大小的函数

def resize(image, width=None, height=None, inter=cv.INTER_AREA):
    dim = None
    (h, w) = image.shape[:2]
    if width is None and height is None:
        return image
    if width is None:
        r = height / float(h)
        dim = (int(w * r), height)
    else:
        r = width / float(w)
        dim = (width, int(h * r))
    resized = cv.resize(image, dim, interpolation=inter)
    return resized
# 对轮廓进行排序,从左至右/从上至下,并进行遍历

TemplateImageContoursGet,_ = sort_contours(TemplateImageContoursGet)
Digits = {
    
    }

for (i,c) in enumerate(TemplateImageContoursGet):
    (x,y,w,h) = cv.boundingRect(c)
    roi = TemplateImageBinary[y:y+h,x:x+w]
    roi = cv.resize(roi,(57,88))
    Digits[i] = roi
# 初始化卷积核

RectangleKernel = cv.getStructuringElement(cv.MORPH_RECT,(9,3))
SquareKernel = cv.getStructuringElement(cv.MORPH_RECT,(5,5))
# 读取实际图像

SelectImage = cv.imread("images/credit_card_03.png")
SelectImage = resize(SelectImage,width=300)
cv_image_show("SelectImage",SelectImage)
# 先转换成灰度图

SelectImageGray = cv.cvtColor(SelectImage,cv.COLOR_BGR2GRAY)
cv_image_show("SelectImageGray",SelectImageGray)
# 进行里帽操作

SelectImageTophat = cv.morphologyEx(SelectImageGray,cv.MORPH_TOPHAT,RectangleKernel)
cv_image_show("SelectImageTophat",SelectImageTophat)
# 用Sobel算法计算梯度

SelectImageSobel_X = cv.Sobel(SelectImageTophat,cv.CV_32F,1,0,ksize=-1)
SelectImageSobel_X = np.absolute(SelectImageSobel_X)
(MaxSobel_X,MinSobel_X) = (np.max(SelectImageSobel_X),np.min(SelectImageSobel_X))
SelectImageSobel_X = (SelectImageSobel_X - MinSobel_X)/(MaxSobel_X-MinSobel_X)*255
SelectImageSobel_X = SelectImageSobel_X.astype("uint8")
cv_image_show("SelectImageSobel_X",SelectImageSobel_X)
# 通过闭操作将数字连接在一起

SelectImageSobel_X = cv.morphologyEx(SelectImageSobel_X,cv.MORPH_CLOSE,RectangleKernel)
cv_image_show("SelectImageSobel_X",SelectImageSobel_X)
# 设置阈值,生成双峰

_,SelectImageThreshold = cv.threshold(SelectImageSobel_X,10,255,cv.THRESH_BINARY|cv.THRESH_OTSU,RectangleKernel)
cv_image_show("SelectImageThreshold",SelectImageThreshold)
# 通过闭操作将数字连接在一起

SelectImageThreshold = cv.morphologyEx(SelectImageThreshold,cv.MORPH_CLOSE,RectangleKernel)
cv_image_show("SelectImageThreshold",SelectImageThreshold)
# 计算并生成轮廓

SelectImageThresholdCopy = SelectImageThreshold.copy()
SelectImageThresholdContourGet,_ = cv.findContours(SelectImageThresholdCopy,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE)
print(type(SelectImageThresholdContourGet))
<class 'tuple'>
# 绘制轮廓

SelectImageCopy = SelectImage.copy()
cv.drawContours(SelectImageCopy,SelectImageThresholdContourGet,-1,(0,0,255),1)
cv_image_show("SelectImageCopy",SelectImageCopy)
# 遍历轮廓

locs = []
for (i, c) in enumerate(SelectImageThresholdContourGet):
    # 计算矩形
	(x, y, w, h) = cv.boundingRect(c)
	ar = w / float(h)

	# 选择合适的区域,根据实际任务来,这里的基本都是四个数字一组
	if ar > 2.5 and ar < 4.0:

		if (w > 40 and w < 55) and (h > 10 and h < 20):
			#符合的留下来
			locs.append((x, y, w, h))
# 将符合的轮廓从左到右排序
locs = sorted(locs, key=lambda x:x[0])
output = []
print(locs)
[(35, 99, 45, 13), (94, 99, 46, 13), (154, 99, 46, 13), (214, 99, 46, 13)]
# 遍历每一个轮廓中的数字
for (i, (gX, gY, gW, gH)) in enumerate(locs):
	# initialize the list of group digits
	groupOutput = []

	# 根据坐标提取每一个组
	group = TemplateImageGray[gY - 5:gY + gH + 5, gX - 5:gX + gW + 5]
	cv_image_show('group',group)
	# 预处理
	group = cv.threshold(group, 127, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)[1]
	cv_image_show('group',group)
	# 计算每一组的轮廓
	digitCnts,hierarchy = cv.findContours(group.copy(), cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
	digitCnts = contours.sort_contours(digitCnts,method="left-to-right")[0]

	# 计算每一组中的每一个数值
	for c in digitCnts:
		# 找到当前数值的轮廓,resize成合适的的大小
		(x, y, w, h) = cv.boundingRect(c)
		roi = group[y:y + h, x:x + w]
		roi = cv.resize(roi, (57, 88))
		cv_image_show('roi',roi)

		# 计算匹配得分
		scores = []

		# 在模板中计算每一个得分
		for (digit, digitROI) in Digits.items():
			# 模板匹配
			result = cv.matchTemplate(roi, digitROI,cv.TM_CCOEFF)
			(_, score, _, _) = cv.minMaxLoc(result)
			scores.append(score)

		# 得到最合适的数字
		groupOutput.append(str(np.argmax(scores)))

	# 画出来
	cv.rectangle(image, (gX - 5, gY - 5),(gX + gW + 5, gY + gH + 5), (0, 0, 255), 1)
	cv.putText(image, "".join(groupOutput), (gX, gY - 15),cv.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)

	# 得到结果
	output.extend(groupOutput)
# 打印结果
print("Credit Card Type: {}".format(FIRST_NUMBER[output[0]]))
print("Credit Card #: {}".format("".join(output)))
cv2.imshow("Image", image)
cv2.waitKey(0)

猜你喜欢

转载自blog.csdn.net/m0_48948682/article/details/125609353
今日推荐