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)