Opencv实战案例——模板匹配实现银行卡号识别(附详细介绍及完整代码下载地址)(二)

简介: Opencv实战案例——模板匹配实现银行卡号识别(附详细介绍及完整代码下载地址)

5.形态学变化

5.1腐蚀

cv2.erode(image,kernel,iterations)

  • image:需要进行操作的图片对象
  • kernel:领域的大小
  • iterations:迭代的次数

腐蚀的原理很简单,就是用规定领域内像素的最小值代替当前的像素值,迭代次数就是腐蚀一边之后,是否还要腐蚀多次,腐蚀越多,图片的像素越小,图片也会越黑。

5.2膨胀

cv2.dilate(img,kernel,iterations)

  • image:需要进行操作的图片对象
  • kernel:领域的大小
  • iterations:迭代的次数

膨胀的原理和腐蚀非常相似,只不过膨胀是用邻域内像素的最大值代替当前的像素值,其他的参数意义一样。

5.3开运算和闭运算、礼帽和黑帽

开运算与闭运算以及下面所要介绍的礼帽黑帽所用的API的是一样的,只不是是op参数不同。

cv2.morghologyEx(image,op,kernel)

  • cv2.MORPH_OPEN:开运算,腐蚀—>膨胀
  • cv2.MORPH_CLOSE:闭运算,膨胀—>腐蚀
  • cv2.MORPH_TOPHAT:礼帽,开运算减原图 得到噪声图像
  • cv2.MORPH_BLACKHAT:黑帽 闭运算减原图 得到图像内的孔洞
    开运算
    含义:先腐蚀后膨胀,去除背景(黑)中的噪声
    闭运算
    含义:先膨胀后腐蚀,去除背景(白)中的黑色孔洞

    礼帽
    cv2.
    含义:开运算与原图做差
    黑帽
    cv2.
    含义:闭运算与原图做差

6.项目实战

6.1读取图片转化为灰度图

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project :OpenCV识别银行卡数字 
@File    :6.1导入包读取图片.py
@IDE     :PyCharm 
@Author  :咋
@Date    :2023/1/14 19:54 
"""
import cv2
import numpy as np
# 读取图片
image = cv2.imread("bank_card41.jpg")
# 转化为灰度图
image = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
# 调整图片大小
image = cv2.resize(image,(4*image.shape[1],4*image.shape[0]))
cv2.imshow("image",image)
cv2.waitKey(0)
# 销毁窗口
cv2.destroyAllWindows()

6.2自适应阈值处理

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project :OpenCV识别银行卡数字 
@File    :6.2自适应阈值处理.py
@IDE     :PyCharm 
@Author  :咋
@Date    :2023/1/14 19:57 
"""
import cv2
import numpy as np
# 读取图片
image = cv2.imread("bank_card4.jpg")
# 转化为灰度图
image = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
# 调整图片大小
image = cv2.resize(image,(640,480))
# 自适应阈值处理
threshold_img = cv2.adaptiveThreshold(image,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,21,3)
# 取反操作
thresh = cv2.bitwise_not(threshold_img)
cv2.imshow("image",np.hstack((image,thresh)))
cv2.waitKey(0)
# 销毁窗口
cv2.destroyAllWindows()

6.3第一次寻找合适的轮廓

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project :OpenCV识别银行卡数字 
@File    :6.3寻找合适的轮廓.py
@IDE     :PyCharm 
@Author  :咋
@Date    :2023/1/14 19:59 
"""
import cv2
import numpy as np
# 读取图片
image = cv2.imread("bank_card41.jpg")
# 转化为灰度图
image = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
# 调整图片大小
image = cv2.resize(image,(4*image.shape[1],4*image.shape[0]))
# 自适应阈值处理
threshold_img = cv2.adaptiveThreshold(image,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,21,3)
# 取反操作
thresh = cv2.bitwise_not(threshold_img)
# 寻找合适的轮廓
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
print(contours)
# 判断合适的轮廓
for i in range(len(contours)):
    # 根据轮廓的面积
    if cv2.contourArea(contours[i]) < 60:
        thresh = cv2.drawContours(thresh, contours, i, (0,0,0), -1)
cv2.imshow("image",np.vstack((image,thresh)))
cv2.waitKey(0)
# 销毁窗口
cv2.destroyAllWindows()

6.4黑帽+腐蚀操作

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project :OpenCV识别银行卡数字 
@File    :6.4黑帽+腐蚀py
@IDE     :PyCharm 
@Author  :咋
@Date    :2023/1/14 20:12 
"""
import cv2
import numpy as np
# 读取图片
image = cv2.imread("bank_card41.jpg")
# 转化为灰度图
image = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
# 调整图片大小
image = cv2.resize(image,(4*image.shape[1],4*image.shape[0]))
# 自适应阈值处理
threshold_img = cv2.adaptiveThreshold(image,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,21,3)
# 取反操作
thresh = cv2.bitwise_not(threshold_img)
# 寻找合适的轮廓
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
print(contours)
# 判断合适的轮廓
for i in range(len(contours)):
    # 根据轮廓的面积
    if cv2.contourArea(contours[i]) < 60:
        thresh = cv2.drawContours(thresh, contours, i, (0,0,0), -1)
# 黑帽操作
kernel = np.ones((15,15),dtype=np.uint8)
blackhat = cv2.morphologyEx(thresh, cv2.MORPH_BLACKHAT, kernel)
# 腐蚀操作
kernel = np.ones((3,3),dtype=np.uint8)
erosion = cv2.erode(blackhat,kernel,iterations = 1)
cv2.imshow("image",np.vstack((image,erosion)))
cv2.waitKey(0)
# 销毁窗口
cv2.destroyAllWindows()

6.5再次寻找轮廓+膨胀操作

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project :OpenCV识别银行卡数字 
@File    :再次寻找轮廓+膨胀操作.py
@IDE     :PyCharm 
@Author  :咋
@Date    :2023/1/14 20:21 
"""
import cv2
import numpy as np
# 读取图片
image = cv2.imread("bank_card41.jpg")
# 转化为灰度图
image = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
# 调整图片大小
image = cv2.resize(image,(4*image.shape[1],4*image.shape[0]))
# 自适应阈值处理
threshold_img = cv2.adaptiveThreshold(image,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,9,3)
# 取反操作
thresh = cv2.bitwise_not(threshold_img)
# 寻找合适的轮廓
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
print(contours)
# 判断合适的轮廓
for i in range(len(contours)):
    # 根据轮廓的面积
    if cv2.contourArea(contours[i]) < 60:
        thresh = cv2.drawContours(thresh, contours, i, (0,0,0), -1)
# 黑帽操作
kernel = np.ones((15,15),dtype=np.uint8)
blackhat = cv2.morphologyEx(thresh, cv2.MORPH_BLACKHAT, kernel)
# 腐蚀操作
kernel = np.ones((3,3),dtype=np.uint8)
erosion = cv2.erode(blackhat,kernel,iterations = 1)
contours, hierarchy = cv2.findContours(erosion,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
for i in range(len(contours)):
    x,y,w,h = cv2.boundingRect(contours[i])
    aspect_ratio = float(w)/h
    A = float(w)*h
    if A < 1800:
        erosion = cv2.drawContours(erosion, contours, i, (0,0,0), -1)
    else:
        if aspect_ratio > 0.6 or aspect_ratio < 0.57:
            erosion = cv2.drawContours(erosion, contours, i, (0,0,0), -1)
cv2.imshow('erosion2',erosion)
kernel = np.ones((7,7),dtype=np.uint8)
dilation = cv2.dilate(erosion,kernel,iterations = 1)
# cv2.imshow('dilation',)
cv2.imshow("image",np.vstack((image,dilation)))
cv2.waitKey(0)
# 销毁窗口
cv2.destroyAllWindows()

6.6 模板匹配

numTemplate = cv2.imread('bankCardNumTemplate.jpg')
numTemplate_GRAY = cv2.cvtColor(numTemplate, cv2.COLOR_BGR2GRAY)
ret, numTemplate_GRAY = cv2.threshold(numTemplate_GRAY, 200, 255, cv2.THRESH_BINARY)
# cv2.imshow('thresh',thresh)
# cv2.imshow('numTemplate_GRAY', numTemplate_GRAY)
contours, hierarchy = cv2.findContours(numTemplate_GRAY, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# print(np.size(contours))
def sequence_contours(dst_Binary, method, Rect_width, Rect_height):
    if method == "Left_to_Right" or method == 2:
        contours, hierarchy = cv2.findContours(dst_Binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        n = np.size(contours)
        RectBoxes0 = np.ones((n, 4), dtype=int)
        # print(n)
        for i in range(0, n):
            RectBoxes0[i] = cv2.boundingRect(contours[i])
            # print(RectBoxes0)
        RectBoxes = np.ones((n, 4), dtype=int)
        for i in range(0, n):
            sequence = 0
            for j in range(0, n):
                if RectBoxes0[i][0] > RectBoxes0[j][0]:
                    sequence = sequence + 1
            RectBoxes[sequence] = RectBoxes0[i]
        RectImgBoxes = [[] for i in range(n)]
        for i in range(0, n):
            img = dst_Binary[RectBoxes[i, 1]:(RectBoxes[i, 1] + RectBoxes[i, 3]),
                  RectBoxes[i, 0]:(RectBoxes[i, 0] + RectBoxes[i, 2])]
            # cv2.imshow('number'+ str(i), img)
            img = cv2.resize(img, (Rect_width, Rect_height))
            ret, img = cv2.threshold(img, 200, 255, cv2.THRESH_BINARY)
            RectImgBoxes[i] = img
        # print(RectBoxes)
        # print(np.size(RectImgBoxes))
    return RectBoxes, RectImgBoxes
RectBoxes_Temp, RectImgBoxes_Temp = sequence_contours(numTemplate_GRAY, method="Left_to_Right", Rect_width=50,
                                                      Rect_height=80)
# print(RectBoxes)
# cv2.imshow('numberTemp', RectImgBoxes_Temp[3])
RectBoxes, RectImgBoxes = sequence_contours(dilation, method="Left_to_Right", Rect_width=50, Rect_height=80)
# cv2.imshow('numberfin', RectImgBoxes[3])
# print(len(RectImgBoxes))
result = []
for i in range(len(RectImgBoxes)):
    score = np.zeros(len(RectImgBoxes_Temp), dtype=int)
    for j in range(len(RectImgBoxes_Temp)):
        score[j] = cv2.matchTemplate(RectImgBoxes[i], RectImgBoxes_Temp[j], cv2.TM_CCOEFF)
    # print(score)
    min_val, max_val, min_indx, max_indx = cv2.minMaxLoc(score)
    result.append(max_indx[1])
# 定义添加数字到图片的函数
def add_num(image,num_list):
    text = ""
    for i in num_list:
        text += str(i)
    font = ImageFont.truetype("msyh.ttc",50)
    # 创建一个pillow的图片
    pil_img = Image.fromarray(image)
    # 绘制图片
    draw = ImageDraw.Draw(pil_img)
    # 利用draw去绘制中文
    draw.text((0, 0), text , font=font, fill=0)  # 后面的fill即颜色,RGBA
    # 重新变为ndarray
    image = np.array(pil_img)
    return image
print(result)
image = add_num(image,result)
cv2.imshow("image",image)
# cv2.imshow("image",np.vstack((image,dilation)))
cv2.waitKey(0)

7.完整代码

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project :OpenCV识别银行卡数字 
@File    :模板匹配.py
@IDE     :PyCharm
@Author  :咋
@Date    :2023/1/14 20:29
"""
import cv2
import numpy as np
from PIL import ImageFont,ImageDraw,Image
# 读取图片
image = cv2.imread("bank_card41.jpg")
true_img = cv2.imread("bank_card4.jpg")
# 转化为灰度图
image = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
# 调整图片大小
image = cv2.resize(image,(4*image.shape[1],4*image.shape[0]))
# 自适应阈值处理
threshold_img = cv2.adaptiveThreshold(image,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,9,3)
# 取反操作
thresh = cv2.bitwise_not(threshold_img)
# 寻找合适的轮廓
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
# print(contours)
# 判断合适的轮廓
for i in range(len(contours)):
    # 根据轮廓的面积
    if cv2.contourArea(contours[i]) < 60:
        thresh = cv2.drawContours(thresh, contours, i, (0,0,0), -1)
# 黑帽操作
kernel = np.ones((15,15),dtype=np.uint8)
blackhat = cv2.morphologyEx(thresh, cv2.MORPH_BLACKHAT, kernel)
# 腐蚀操作
kernel = np.ones((3,3),dtype=np.uint8)
erosion = cv2.erode(blackhat,kernel,iterations = 1)
contours, hierarchy = cv2.findContours(erosion,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
for i in range(len(contours)):
    x,y,w,h = cv2.boundingRect(contours[i])
    aspect_ratio = float(w)/h
    A = float(w)*h
    if A < 1800:
        erosion = cv2.drawContours(erosion, contours, i, (0,0,0), -1)
    else:
        if aspect_ratio > 0.6 or aspect_ratio < 0.57:
            erosion = cv2.drawContours(erosion, contours, i, (0,0,0), -1)
# cv2.imshow('erosion2',erosion)
kernel = np.ones((7,7),dtype=np.uint8)
dilation = cv2.dilate(erosion,kernel,iterations = 1)
# 模板匹配
numTemplate = cv2.imread('bankCardNumTemplate.jpg')
numTemplate_GRAY = cv2.cvtColor(numTemplate, cv2.COLOR_BGR2GRAY)
ret, numTemplate_GRAY = cv2.threshold(numTemplate_GRAY, 200, 255, cv2.THRESH_BINARY)
# cv2.imshow('thresh',thresh)
# cv2.imshow('numTemplate_GRAY', numTemplate_GRAY)
contours, hierarchy = cv2.findContours(numTemplate_GRAY, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# print(np.size(contours))
def sequence_contours(dst_Binary, method, Rect_width, Rect_height):
    if method == "Left_to_Right" or method == 2:
        contours, hierarchy = cv2.findContours(dst_Binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        n = np.size(contours)
        RectBoxes0 = np.ones((n, 4), dtype=int)
        # print(n)
        for i in range(0, n):
            RectBoxes0[i] = cv2.boundingRect(contours[i])
            # print(RectBoxes0)
        RectBoxes = np.ones((n, 4), dtype=int)
        for i in range(0, n):
            sequence = 0
            for j in range(0, n):
                if RectBoxes0[i][0] > RectBoxes0[j][0]:
                    sequence = sequence + 1
            RectBoxes[sequence] = RectBoxes0[i]
        RectImgBoxes = [[] for i in range(n)]
        for i in range(0, n):
            img = dst_Binary[RectBoxes[i, 1]:(RectBoxes[i, 1] + RectBoxes[i, 3]),
                  RectBoxes[i, 0]:(RectBoxes[i, 0] + RectBoxes[i, 2])]
            # cv2.imshow('number'+ str(i), img)
            img = cv2.resize(img, (Rect_width, Rect_height))
            ret, img = cv2.threshold(img, 200, 255, cv2.THRESH_BINARY)
            RectImgBoxes[i] = img
        # print(RectBoxes)
        # print(np.size(RectImgBoxes))
    return RectBoxes, RectImgBoxes
RectBoxes_Temp, RectImgBoxes_Temp = sequence_contours(numTemplate_GRAY, method="Left_to_Right", Rect_width=50,
                                                      Rect_height=80)
# print(RectBoxes)
# cv2.imshow('numberTemp', RectImgBoxes_Temp[3])
RectBoxes, RectImgBoxes = sequence_contours(dilation, method="Left_to_Right", Rect_width=50, Rect_height=80)
# cv2.imshow('numberfin', RectImgBoxes[3])
# print(len(RectImgBoxes))
result = []
for i in range(len(RectImgBoxes)):
    score = np.zeros(len(RectImgBoxes_Temp), dtype=int)
    for j in range(len(RectImgBoxes_Temp)):
        score[j] = cv2.matchTemplate(RectImgBoxes[i], RectImgBoxes_Temp[j], cv2.TM_CCOEFF)
    # print(score)
    min_val, max_val, min_indx, max_indx = cv2.minMaxLoc(score)
    result.append(max_indx[1])
# 定义添加数字到图片的函数
def add_num(image,num_list):
    text = ""
    for i in num_list:
        text += str(i)
    font = ImageFont.truetype("msyh.ttc",40)
    # 创建一个pillow的图片
    pil_img = Image.fromarray(image)
    # 绘制图片
    draw = ImageDraw.Draw(pil_img)
    # 利用draw去绘制中文
    draw.text((15, 80), text , font=font, fill=0)  # 后面的fill即颜色,RGBA
    # 重新变为ndarray
    image = np.array(pil_img)
    return image
print(result)
true_img = add_num(true_img,result)
cv2.imshow("image",true_img)
# cv2.imshow("image",np.vstack((image,dilation)))
cv2.waitKey(0)

附上图片和代码链接:欢迎需要的小伙伴自取链接https://pan.baidu.com/s/1UeXrFjLXn3LWiDoUudW13w?pwd=3hye

提取码:3hye

8.总结

识别银行卡可算是Opencv的经典项目了,尤其是模板匹配,算得上是计算机视觉的精髓所在了。通过这个案例对二值化、轮廓检测、形态学变化腐蚀膨胀、开运算闭运算、礼帽黑帽有所了解,并能够组合在一起运算,算得上有所进步。

以此类推,模板匹配可以应用在很多项目中,关键的难点就在于怎么把图片和模板调整好,通过上述的方法以及参数的调整,可以达到这样的效果,还是需要多练习,才能真正掌握Opencv’的精髓。

相关文章
|
3月前
|
算法 计算机视觉
基于qt的opencv实时图像处理框架FastCvLearn实战
本文介绍了一个基于Qt的OpenCV实时图像处理框架FastCvLearn,通过手撕代码的方式详细讲解了如何实现实时人脸马赛克等功能,并提供了结果展示和基础知识回顾。
141 7
基于qt的opencv实时图像处理框架FastCvLearn实战
|
3月前
|
文字识别 计算机视觉 开发者
基于QT的OCR和opencv融合框架FastOCRLearn实战
本文介绍了在Qt环境下结合OpenCV库构建OCR识别系统的实战方法,通过FastOCRLearn项目,读者可以学习Tesseract OCR的编译配置和在Windows平台下的实践步骤,文章提供了技术资源链接,帮助开发者理解并实现OCR技术。
176 9
基于QT的OCR和opencv融合框架FastOCRLearn实战
|
5月前
|
计算机视觉 Python
opencv识别颜色
opencv识别颜色
|
2月前
|
机器学习/深度学习 算法 计算机视觉
【Python篇】Python + OpenCV 全面实战:解锁图像处理与视觉智能的核心技能
【Python篇】Python + OpenCV 全面实战:解锁图像处理与视觉智能的核心技能
106 2
|
3月前
|
计算机视觉
基于QT的opencv插件框架qtCvFrameLearn实战
这篇文章详细介绍了如何基于Qt框架开发一个名为qtCvFrameLearn的OpenCV插件,包括项目配置、插件加载、Qt与OpenCV图像转换,以及通过各个插件学习OpenCV函数的使用,如仿射变换、卡通效果、腐蚀、旋转和锐化等。
58 10
|
4月前
|
算法 计算机视觉 Python
python利用opencv进行相机标定获取参数,并根据畸变参数修正图像附有全部代码(流畅无痛版)
该文章详细介绍了使用Python和OpenCV进行相机标定以获取畸变参数,并提供了修正图像畸变的全部代码,包括生成棋盘图、拍摄标定图像、标定过程和畸变矫正等步骤。
python利用opencv进行相机标定获取参数,并根据畸变参数修正图像附有全部代码(流畅无痛版)
|
4月前
|
计算机视觉 Python
opencv在pycharm不能自动补全代码
opencv在pycharm不能自动补全代码
34 0
|
5月前
|
机器学习/深度学习 数据采集 算法
Python基于OpenCV和卷积神经网络CNN进行车牌号码识别项目实战
Python基于OpenCV和卷积神经网络CNN进行车牌号码识别项目实战
|
5月前
|
机器学习/深度学习 人工智能 算法
|
6月前
|
计算机视觉
OpenCV下载、环境变量配置
OpenCV下载、环境变量配置