深度学习图像处理基础工具——opencv 实战信用卡数字识别

任务 信用卡数字识别

穿插之前学的知识点  形态学操作 模板匹配 等

总体流程与方法

1.有一个模板 2 用轮廓检测把模板中数字拿出来 外接矩形(模板和输入图像的大小要一致

)3 一系列预处理操作

问题的解决思路

1.分析准备:准备模板,读取文件——转化为灰度图——转化为二值图——提取轮廓——遍历每一个轮廓 得到每个数字的模板,排序,大小裁剪为指定大小(57*88)digits[i] = roi

2.处理输入的带数字的银行卡  (1)预处理 我们需要拿到的是 一组一组的数字 一共四组  读取文件——变换大小——转化为灰度图——形态学操作(礼帽操作突出明亮区域——梯度操作计算轮廓信息——闭操作将数字连在一起——二值化操作寻找合适阈值——再来一个闭操作——计算轮廓——遍历轮廓(选择合适区域 排除不是数字的轮廓)——轮廓排序——遍历轮廓的每一个数字——预处理计算每一组轮廓——计算每一组中的每一个值——匹配得分——得到数字画出来——得到结果——打印结果)

#设置参数

ap = argparse.ArgumentParser()#编写命令行接口
ap.add_argument("-i", "--image", required=True,
	help="path to input image")#添加命令行参数
ap.add_argument("-t", "--template", required=True,
	help="path to template OCR-A image")
args = vars(ap.parse_args())#解析参数 将参数转化为字典的形式

img = cv2.imread(args["template"])
def cv_show(name,img):
    cv2.imshow(name, img)
    cv2.waitKey(0)# waitKey()#是在一个给定的时间内(单位ms)等待用户按键触发 0 无限等待 按任意键继续
    cv2.destroyAllWindows()

1.cv2.cvtColor颜色空间转换函数 cv2.imread()和cv2.cvtColor() 的使用-CSDN博客

ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#颜色空间转换函数
2.cv2.threshold  二值化函数 [OpenCV] cv2.threshold二值化函数使用方法总结_cv2.threshold函数-CSDN博客
ref = cv2.threshold(ref, 100, 255, cv2.THRESH_BINARY_INV)[1]#二值化函数

3.计算轮廓 

refCnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)#查找轮廓函数 只检测外轮廓 只保留四个点轮廓信息

4.画出轮廓

cv2.drawContours(img,refCnts,-1,(0,0,255),3) #画出轮廓函数

5.轮廓排序

refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0] #排序,从左到右,从上到下

6.遍历轮廓

digits = {}
# 遍历每一个轮廓
for (i, c) in enumerate(refCnts):
    # 计算外接矩形并且resize成合适大小
    (x, y, w, h) = cv2.boundingRect(c)
    roi = ref[y:y + h, x:x + w]
    roi = cv2.resize(roi, (57, 88))
    # 每一个数字对应每一个模板
    digits[i] = roi
2.0初始化卷积核
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))

2.1 对要识别的图像进行大小灰度处理

#读取输入图像,预处理
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)

2.2 #礼帽操作,突出更明亮的区域

#礼帽操作,突出更明亮的区域
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)
cv_show('tophat',tophat)
#
gradX = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, #ksize=-1相当于用3*3的
    ksize=-1)


gradX = np.absolute(gradX)
(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)
2.3#通过闭操作(先膨胀,再腐蚀)将数字连在一起
gradX = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel) 
cv_show('gradX',gradX)
#THRESH_OTSU会自动寻找合适的阈值,适合双峰,需把阈值参数设置为0
thresh = cv2.threshold(gradX, 0, 255,
    cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] 
cv_show('thresh',thresh)

#再来一个闭操作

thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel) #再来一个闭操作
cv_show('thresh',thresh)

2.4# 计算轮廓

threshCnts, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
    cv2.CHAIN_APPROX_SIMPLE)

cnts = threshCnts
cur_img = image.copy()
cv2.drawContours(cur_img,cnts,-1,(0,0,255),3) 
cv_show('img',cur_img)
locs = []

# 遍历轮廓
for (i, c) in enumerate(cnts):
    # 计算矩形
    (x, y, w, h) = cv2.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 = []

# 遍历每一个轮廓中的数字
for (i, (gX, gY, gW, gH)) in enumerate(locs):
    # initialize the list of group digits
    groupOutput = []

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

    # 计算每一组中的每一个数值
    for c in digitCnts:
       # 找到当前数值的轮廓,resize成合适的的大小
       (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)

       # 计算匹配得分
       scores = []

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

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

    # 画出来
    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)

    # 得到结果
    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)

总的代码

# 导入工具包
from imutils import contours
import numpy as np
import argparse
import cv2
import myutils

# 设置参数
ap = argparse.ArgumentParser()#编写命令行接口
ap.add_argument("-i", "--image", required=True,
	help="path to input image")#添加命令行参数
ap.add_argument("-t", "--template", required=True,
	help="path to template OCR-A image")
args = vars(ap.parse_args())#解析参数 将参数转化为字典的形式

# 指定信用卡类型
FIRST_NUMBER = {
	"3": "American Express",
	"4": "Visa",
	"5": "MasterCard",
	"6": "Discover Card"
}
# 绘图展示
def cv_show(name,img):
	cv2.imshow(name, img)
	cv2.waitKey(0)# waitKey()–是在一个给定的时间内(单位ms)等待用户按键触发 0 无限等待 按任意键继续
	cv2.destroyAllWindows()
# 读取一个模板图像
img = cv2.imread(args["template"])
cv_show('img',img)
# 灰度图
ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#颜色空间转换函数
cv_show('ref',ref)
# 二值图像
ref = cv2.threshold(ref, 100, 255, cv2.THRESH_BINARY_INV)[1]#二值化函数
cv_show('ref',ref)

# 计算轮廓
#cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图),cv2.RETR_EXTERNAL只检测外轮廓,cv2.CHAIN_APPROX_SIMPLE只保留终点坐标
#返回的list中每个元素都是图像中的一个轮廓

refCnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)#查找轮廓函数 只检测外轮廓 只保留四个点轮廓信息

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] #排序,从左到右,从上到下
digits = {}
# 遍历每一个轮廓
for (i, c) in enumerate(refCnts):
	# 计算外接矩形并且resize成合适大小
	(x, y, w, h) = cv2.boundingRect(c)
	roi = ref[y:y + h, x:x + w]
	roi = cv2.resize(roi, (57, 88))
	# 每一个数字对应每一个模板
	digits[i] = roi

# 初始化卷积核
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))

#读取输入图像,预处理
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)

#礼帽操作,突出更明亮的区域
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)
cv_show('tophat',tophat)
#
gradX = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, #ksize=-1相当于用3*3的
	ksize=-1)


gradX = np.absolute(gradX)
(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)

#通过闭操作(先膨胀,再腐蚀)将数字连在一起
gradX = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel)
cv_show('gradX',gradX)
#THRESH_OTSU会自动寻找合适的阈值,适合双峰,需把阈值参数设置为0
thresh = cv2.threshold(gradX, 0, 255,
	cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv_show('thresh',thresh)

#再来一个闭操作

thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel) #再来一个闭操作
cv_show('thresh',thresh)

# 计算轮廓

threshCnts, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
	cv2.CHAIN_APPROX_SIMPLE)


cnts = threshCnts
cur_img = image.copy()
cv2.drawContours(cur_img,cnts,-1,(0,0,255),3) 
cv_show('img',cur_img)
locs = []

# 遍历轮廓
for (i, c) in enumerate(cnts):
	# 计算矩形
	(x, y, w, h) = cv2.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 = []

# 遍历每一个轮廓中的数字
for (i, (gX, gY, gW, gH)) in enumerate(locs):
	# initialize the list of group digits
	groupOutput = []

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

	# 计算每一组中的每一个数值
	for c in digitCnts:
		# 找到当前数值的轮廓,resize成合适的的大小
		(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)

		# 计算匹配得分
		scores = []

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

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

	# 画出来
	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)

	# 得到结果
	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)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/542650.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

微信小程序兼容iphone适配安全区域

背景&#xff1a; 小程序页面底部在ios中会有小黑条遮挡 上代码&#xff1a; padding-bottom: constant(safe-area-inset-bottom); /* 兼容 iOS < 11.2 */ padding-bottom: env(safe-area-inset-bottom); /* 兼容 iOS > 11.2 */ 项目描述&#xff1a; 微信小程序是通过…

中国绿色技术助力全球能源转型(国际论坛)

中国的清洁能源发展战略和实践对全球能源结构转型产生了深远影响。作为全球最大的可再生能源生产和消费国&#xff0c;中国在推动国内可再生能源产业发展的同时&#xff0c;也积极与世界各国分享技术和经验&#xff0c;促进全球范围内清洁能源技术的普及和应用成本的降低。例如…

FL Studio808鼓音在哪 FL Studio怎么让音乐鼓点更有力 FL Studio教程

FL Studio808鼓音在哪&#xff1f;808是一款电鼓机的名称&#xff0c;它发出的声音也被称之为808鼓&#xff0c;通常我们可以安装鼓机插件来使用&#xff0c;但FL Studio中自带的也有808鼓的采样音频。FL Studio怎么让音乐鼓点更有力&#xff1f;让鼓点更有力要从EQ均衡器、压缩…

ELK、ELKF企业级日志分析系统介绍

前言 随着企业级应用系统日益复杂&#xff0c;随之产生的海量日志数据。传统的日志管理和分析手段&#xff0c;难以做到高效检索、实时监控以及深度挖掘潜在价值。在此背景下&#xff0c;ELK日志分析系统应运而生。"Elastic" 是指 Elastic 公司所提供的一系列与搜索…

在 Google Cloud 上轻松部署开放大语言模型

今天&#xff0c;“在 Google Cloud 上部署”功能正式上线&#xff01; 这是 Hugging Face Hub 上的一个新功能&#xff0c;让开发者可以轻松地将数千个基础模型使用 Vertex AI 或 Google Kubernetes Engine (GKE) 部署到 Google Cloud。 Model Garden (模型库) 是 Google Clou…

AI大模型探索之路-实战篇:基于CVP架构-企业级知识库实战落地

目录 前言 一、概述 二、本地知识库需求分析 1. 知识库场景分析 2. 知识库应用特点 3. 知识库核心功能 三、本地知识库架构设计 1. RAG架构分析 2. 大模型方案选型 3. 应用技术架构选型 4. 向量数据库选型 5. 模型选型 三、本地知识库RAG评估 四、本地知识库代码落地 1. 文件…

CSS文本单行溢出和多行溢出样式

一、单行溢出 1.代码 <!DOCTYPE html> <html><head><meta charset"UTF-8" /><title>demo</title><style>#div2{overflow: hidden;white-space: nowrap;/*强制不换行*/text-overflow:ellipsis;/*超出的部分用省略号代替*…

一起学习python——基础篇(19)

今天来说一下python的如何修改文件名称、获取文件大小、读取文中指定的某一行内容。 1、修改文件名称&#xff1a; import os testPath"D:/pythonFile/test.txt" testPath2"D:/pythonFile/test2.txt" #修改文件名称使用rename方法&#xff0c; #第一个参…

Mac环境 llamafile 部署大语言模型LLM

文章目录 Github官网本地部署 llamafile 是一种可在你自己的电脑上运行的可执行大型语言模型&#xff08;LLM&#xff09;&#xff0c;它包含了给定的开放 LLM 的权重&#xff0c;以及运行该模型所需的一切。让人惊喜的是&#xff0c;你无需进行任何安装或配置。 Github https…

CSS核心样式-04-定位属性+轮播图静态结构布局案例

目录 十、定位属性 概念 定位属性 position 偏移量属性 1. 相对定位 性质 注意事项 实际应用 应用1&#xff1a;导航栏位置微调 应用2&#xff1a;文字位置微调 2. 绝对定位 绝对定位的性质 注意事项 为参考元素的参考点 祖先级为参考元素 祖先元素参考点 3. 固定…

【150套】基于SSM框架的Java毕业设计开发实战项目(附源码+演示视频+LW)

大家好&#xff01;我是程序员一帆&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f9e1;今天给大家分享150的Java毕业设计&#xff0c;基于ssm框架&#xff0c;这些项目都经过精心挑选&#xff0c;涵盖了不同的实战主题和用例&#xff0c;可做毕业设计和课程…

数据库SQL语言实战(一)

目录 创建SQL表 题目一 题目二 题目三 插入数据 题目一 题目二 题目三 总结 创建SQL表 题目一 创建学生信息表&#xff08;学生编号、姓名、性别、年龄、出生日期、院系名称、班级&#xff09;&#xff1a; test1_student&#xff1a;sid char 12 not null、nam…

C语言入门(第一天:基础语法)

一、 使用工具 1、我们学习C语言所用的编辑器是Vscode&#xff0c;大家应该都不陌生了&#xff0c;但是要在编辑器内部编写C语言&#xff0c;我们需要下载安装一些工具插件来运行C语言。 有了以上两个工具就可以进行我们的C语言编译学习了&#xff01; 二、基础语法 1.第一个…

【opencv】示例-epipolar_lines.cpp 对极线

这段代码总的功能是使用OpenCV库进行立体视觉的估计。它从命令行读取两个图像文件名&#xff0c;使用SIFT算法检测关键点并计算这些点的描述子&#xff0c;接着通过FLANN库进行快速近似最近邻搜索来找到匹配的关键点。然后使用RANSAC方法计算基础矩阵&#xff0c;找到内点&…

Python学习笔记15 - 字符串

字符串是一个不可变的字符序列&#xff0c;另一个不可变的序列是元组 字符串的驻留机制 字符串的常用操作 字符串的查询 字符串的大小写转换 字符串内容 对齐操作的方法 字符串的劈分操作 字符串的判断 字符串替换 字符串合并 字符串的比较 字符串的切片 格式化字符串 字符串…

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之三 简单动态聚光灯效果

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之三 简单动态聚光灯效果 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之三 简单动态聚光灯效果 一、简单介绍 二、简单动态聚光灯效果实现原理 三、简单动态聚光灯效果…

JVM、maven、Nexus

一、jvm简介 1.应用程序申请内存时出现的三种情况&#xff1a; ①OOM:内存溢出&#xff0c;是指应用系统中存在无法回收的内存或使用的内存过多&#xff0c;最终使得程序运行要用到的内存大于能提供的最大内存。此时程序就运行不了&#xff0c;系统会提示内存溢出&#xff0c…

GPT4.5发布了?OpenAI终于发布正式版Turbo,重回AI王座第一

令人惊讶的是&#xff0c;短短三个月内&#xff0c;全球最强AI的称号又一次易主了&#xff01;几个月前&#xff0c;Claude3 Opus的性能全面超过了GPT-4&#xff0c;全球网友纷纷转向Claude3&#xff0c;并分享了他们对Claude3的惊艳体验。然而&#xff0c;OpenAI最近再次展示了…

Nginx健康检查

Nginx健康检查nginx_upstream_check_module nginx健康检查介绍: ​ 主动健康检查&#xff0c;nignx定时主动地去ping后端的服务列表&#xff0c;当发现某服务出现异常时&#xff0c;把该服务从健康列表中移除&#xff0c;当发现某服务恢复时&#xff0c;又能够将该服务加回健…

网格(mesh)生成算法

mesh网格生成算法 1. 简介2. Points clouds Vs Meshes3. 为什么要生成mesh网格以及生成mesh网格的难点4. 常见的mesh网格生成算法 1. 简介 基于 3D视觉的新兴应用场景蓬勃发展&#xff0c;3D点云越来越受到人们的广泛关注。点云有着广泛的应用领域包括机器人技术、3D图形、自动…