目录
一、实训内容
选择合适的算法,编写程序进行信用卡号识别;制作交互式用户界面,实现一个能读入信用卡图片并识别信用卡号的系统,系统界面上需要对输入图像、识别结果等进行展示。并对实验结果进行分析,评价算法性能。
二、实现思路
2.1.Python工具和库的选择
选择使用Python工具和库来实现信用卡号识别系统,安装Python所需要使用的库OpenCV、numpy、os、sys、PyQt5、pytesseract、QT Desinger、contours等。确保选择的工具和库提供了所需的图像处理功能,并且易于使用和集成到银行卡识别系统中。
2.2.主程序界面实现思路
该模块主要是实现了一个基于PyQt5的信用卡号识别系统的UI设计,包含有一个Mywindow类的定义和2个功能窗口类的定义以及两个自定义函数。算法原理主要包括以下几个部分:
1.导入需要使用的模块和库:从PyQt5中导入QApplication、QMainWindow、QFileDialog等类,从PyQt5.QtGui中导入用于图像操作的类,从cv2和numpy库中导入用于图像处理的模块,从card_recognize.py模块中导入信用卡号识别的功能。
2.导入UI文件:通过from card_re import Card_re_Window语句将识别信用卡号的窗口的UI文件导入到主程序中。这个UI文件使用Qt Designer软件设计而成,包含了各个窗口的布局、控件和信号槽等信息。
3.创建主窗口并设置UI:自定义一个 MyWindow 类继承于 QMainWindow 和 Ui_Mainwindow,用于界面的初始化和 button 的信号链接。 先调用父类的构造函数进行界面的初始化,加载界面。
4.窗口类的定义:定义了Card_re_class类,该类继承了QMainWindow和对应的UI界面类,如Card_re_class继承了QMainWindow和Card_re_Window类。这些类中定义了对应功能窗口上的按钮、标签、图像显示区等控件,并实现了对应的功能函数,如打开和保存文件、选择文件夹等操作,将图像数据加载到内存中,然后对其进行操作和显示。
5.实现窗口间的跳转:MyWindow类添加了function1、function2两个方法,分别对应主界面上的2个功能按钮。每个方法调用对应的功能窗口类,并且关闭当前界面。这样,当用户点击主界面上的某个功能按钮时,就会自动打开对应的功能窗口,实现了不同功能窗口之间的切换。
6.添加图标:使用QIcon类给窗口添加图标的功能,为窗口添加南阳理工学院校徽图标以增强软件的视觉效果和用户体验,同时也给代码增添了一些标志性特点。
7.两个自定义函数:主要实现了将Qt中的QPixmap对象转换为OpenCV中的Mat对象,以及将OpenCV中的Mat对象转换为Qt中的QImage或QPixmap对象。
总体思路是通过PyQt5信用卡号识别系统的GUI界面,将不同的功能模块分别设计为不同的窗口,用户可以在主界面上选择要进行的操作,然后跳转到相应的功能窗口进行图像处理。
2.3.对模板图片进行预处理
对模板图片进行处理,这部分的主要作用是对一个数字模板(t_img.png)进行图像处理,提取其中的数字轮廓和特征,并将以此识别的外轮廓分割存储到一个列表变量 digits 中,以便后续识别图像时比对。
2.4.对轮廓排序处理
这部分实现对轮廓进行排序的功能。它可以按照指定的排序方法,对一组轮廓 cnts 进行排序,并返回排序后的轮廓集合和对应的外接矩形列表。
2.5.对信用卡进行卡号识别
这部分是代码的核心,主要对输入的信用卡图片进行解析处理,提取出所需要的卡号部分,对卡号部分计算外接矩形,然后分割为每一个数字轮廓为一部分,最后对每个数字轮廓与模板数字轮廓比对,选取得分最高的即认为该数字模板为数字号码,最后将号码输出。
具体思路为:初始化卷积核:rectKernel 和 sqKernel,用于后续进行形态学操作。对输入的图片进行预处理操作:调整尺寸为宽度为 300,转换为灰度图像。使用礼帽(顶帽)操作突出更明亮的区域,使用 Sobel 算子进行边缘检测,对结果进行归一化和二值化。对二值化结果进行闭操作,即先膨胀再腐蚀,将数字连在一起。对闭操作后的结果,再次进行闭操作,对缝隙进行填充。对闭操作后的结果进行轮廓检测,找到符合要求的轮廓区域。将符合要求的轮廓从左到右排序,并遍历每一个轮廓中的数字。根据坐标提取每一个数字组,对每个数字组进行预处理并进行轮廓检测,计算每个数字的匹配得分。找到合适的数字并输出,画出每个数字所在的矩形框。
流程图如下:
三、程序代码
主界面代码:
# UI设计
import sys
from PyQt5.QtWidgets import QApplication,QMainWindow
# 用于打开和保存文件、选择文件夹等操作
from PyQt5.QtWidgets import QFileDialog
# 将图像数据加载到内存中,然后对其进行操作和显示
from PyQt5.QtGui import *
# 导入Ui
from main_win import Ui_Mainwindow
from card_re import Card_re_Window
# 给窗口添加图标
from PyQt5.QtGui import QIcon
# 银行卡识别
import card_recognize
# 图像处理
import cv2
import numpy as np
class MyWindow(QMainWindow,Ui_Mainwindow):
def __init__(self):
# 调用父类构造函数
super().__init__()
# 使用 Ui_MainWindow 类中的 setupUi 方法来加载界面
self.setupUi(self)
# 创建图标对象并设置窗口图标
self.setWindowIcon(QIcon("logo_64.png"))
# 按钮信号链接
self.pushButton1.clicked.connect(self.function1)
def function1(self):
self.fun1=Card_re_class()
self.fun1.show()
self.close()
class Card_re_class(QMainWindow,Card_re_Window):
def __init__(self):
super(Card_re_class,self).__init__()
# 加载UI
self.setupUi(self)
# 创建图标对象并设置窗口图标
self.setWindowIcon(QIcon("logo_64.png"))
# 按钮信号链接
self.pushButton_return.clicked.connect(self.push_return)
self.pushButton_upload.clicked.connect(self.openimage)
self.pushButton_save.clicked.connect(self.saveimage)
self.pushButton_card_re.clicked.connect(self.fun)
def push_return(self):
self.Re_main = MyWindow()
# 关闭当前窗口
self.close()
# 打开新窗口
self.Re_main.show()
def openimage(self):
# 打开一个文件选择对话框,让用户选择要打开的图片文件
fname = QFileDialog.getOpenFileName(self, '打开图片', './', "Images (*.png *.jpg *.bmp)")
# 检查是否选择了一个文件,fname 不为空,则进入下面的代码块
if fname[0]:
# 使用 QPixmap 函数从文件路径创建一个 QPixmap 对象
# 然后使用 setPixmap 方法将其设置为 label_daichuli 控件的图片
self.label_daichuli.setPixmap(QPixmap(fname[0]))
# 自动换行功能,确保图片可以完全显示在控件中
self.label_daichuli.setWordWrap(True)
# 调整为图片大小,以确保图片不会被缩小或拉伸
self.label_daichuli.setScaledContents(True)
def saveimage(self):
# 打开一个文件选择对话框,让用户选择要保存的图片文件
nfname = QFileDialog.getSaveFileName(self, "保存图片", "./", "Images (*.png *.jpg *.bmp)")
if nfname[0]:
# 使用pixmap()方法获取label_jieguo标签中的当前图像
# 然后使用save()方法将其保存到用户指定的文件名nfname[0]中
self.label_jieguo.pixmap().save(nfname[0])
def fun(self): #
# 获取图像信息,并存储在qimg中,pixmap()方法返回一个QPixmap对象,表示标签中显示的图像
qimg = self.label_daichuli.pixmap()
# 将QImage对象格式图像信息转换为numpy数组格式
src = qimage_to_mat(qimg)
# 使用自定义模块,将彩色图转换为灰度图像
newsrc,re_text= card_recognize.main_run(src)
# 将numpy数组格式的图像数据转化为QImage对象格式的图像数据
pix = mat_to_qimage(newsrc)
# 将图像显示在名为结果的标签中,setPixmap()方法接受一个QPixmap对象作为参数,并将其设置为标签中的图像
self.label_jieguo.setPixmap(pix)
# setWordWrap()方法接受一个布尔值参数,如果设置为True,则文本将自动换行
self.label_jieguo.setWordWrap(True)
# setScaledContents()方法接受一个布尔值参数,如果设置为True,则标签将自动缩放其内容以适应标签大小
self.label_jieguo.setScaledContents(True)
###########在 QLabel 控件中显示识别的文本
self.label_cardnum.setText(re_text)
# setWordWrap()方法接受一个布尔值参数,如果设置为True,则文本将自动换行
self.label_cardnum.setWordWrap(True)
# setScaledContents()方法接受一个布尔值参数,如果设置为True,则标签将自动缩放其内容以适应标签大小
self.label_cardnum.setScaledContents(True)
##################################################################################
def qimage_to_mat(qtpixmap): #qtpixmap转opencv
# 将输入的QPixmap对象转换成了一个QImage对象
qimg = qtpixmap.toImage()
# 计算了输出的NumPy数组的形状。height是图像的高度,bytesPerLine是每行扫描线的字节数,depth是每个像素的位数
temp_shape = (qimg.height(), qimg.bytesPerLine() * 8 // qimg.depth())
# 将形状元组添加了第四个维度。第四个维度表示RGBA颜色通道
temp_shape += (4,)
ptr = qimg.bits()
# 获取了指向QImage对象内存缓冲区的指针,并将指针大小设置为QImage对象的大小(以字节为单位)
ptr.setsize(qimg.byteCount())
# 创建了一个NumPy数组。该数组的形状为temp_shape,数据类型为uint8
result = np.array(ptr, dtype=np.uint8).reshape(temp_shape)
# 丢弃图像的第四个(alpha)通道。结果得到的NumPy数组的形状为(height, width, 3),表示图像的RGB颜色通道
result = result[..., :3]
# 将NumPy数组作为qimage2mat函数的输出
return result
def mat_to_qimage(cvimg): #opencv转QImage
# 判断输入的图像是否是单通道的,也就是灰度图像
if cvimg.ndim==2: #单通道
# 获取图像的高度和宽度
height, width= cvimg.shape
# 将BGR格式的图像数据转换为RGB格式
cvimg = cv2.cvtColor(cvimg, cv2.COLOR_BGR2RGB)
# 将图像数据转换为QImage对象,并使用QImage.Format_RGB888格式表示。
cvimg = QImage(cvimg.data, width, height, QImage.Format_RGB888)
# 将QImage对象转换为QPixmap对象并存储在pix变量中
pix = QPixmap.fromImage(cvimg)
return pix
else: #多个通道
# 获取图像的高度和宽度
width = cvimg.shape[1]
height = cvimg.shape[0]
# 根据已知的高度和宽度新建一个空的QPixmap对象
pixmap = QPixmap(width, height)
# 将QPixmap对象转换为QImage对象类型的qimg
qimg = pixmap.toImage()
# 嵌套循环遍历图像的所有像素,获取每个像素的红、绿、蓝三个通道的值
for row in range(0, height):
for col in range(0, width):
b = cvimg[row, col, 0]
g = cvimg[row, col, 1]
r = cvimg[row, col, 2]
# 使用qRgb()函数将其转换为QColor对象
pix = qRgb(r, g, b)
qimg.setPixel(col, row, pix)
# 将QImage对象转换为QPixmap对象
pix = QPixmap.fromImage(qimg)
return pix
if __name__ == '__main__':
app = QApplication(sys.argv)
# app.setWindowIcon(QIcon('img.png')) 加载头像
mywindow = MyWindow()
mywindow.show()
sys.exit(app.exec_())
银行卡识别代码:
import cv2
import numpy as np
from imutils import contours
#对图像中的边缘和轮廓进行识别、分割和提取。使用imutils库的contours函数能够方便地检测到图像中的轮廓,
# 并且按照一定的顺序返回,可以用于数字的识别、字符的识别等应用。
#设为全局变量
digits = {}
global output
output = []
#################################################图像绘图
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
##################################################对输入的轮廓进行排序
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] # 元组x,y,h,w
# 对轮廓进行排序操作
(cnts,boundingBoxes)=zip(*sorted(zip(cnts,boundingBoxes),key=lambda b:b[1][i],reverse=reverse))
return cnts,boundingBoxes
#重置大小,用于比较模板和图像中的数字是否一致
#插值方法如下:
#INTER_NEAREST:最邻近插值
#INTER_LINEAR:双线性插值,默认情况下使用该方式进行插值.
#INTER_AREA:基于区域像素关系的一种重采样或者插值方式.该方法是图像抽取的首选方法,它可以产生更少的波纹,
#但是当图像放大时,它的效果与INTER_NEAREST效果相似.
#INTER_CUBIC:4×4邻域双3次插值
#INTER_LANCZOS4:8×8邻域兰索斯插值
########################################将输入的图像按照指定的宽度、高度进行缩放
def resize(image,width=None,height=None,inter=cv2.INTER_AREA):
dim=None
(h,w)=image.shape[:2] #(200,300,3)
# 当未指定宽度和高度时,直接返回原图像。
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))
# 利用OpenCV中resize函数对图像进行缩放
resized=cv2.resize(image,dim,interpolation=inter)
return resized
##################################################读取模板图片并处理###########
def process_template():
# 读取一个模板文件
img = cv2.imread("t_img.png")
# 灰度图
ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值图像
ref = cv2.threshold(ref, 10, 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)
# 只需要轮廓resCnts
cv2.drawContours(img, refCnts, -1, (0, 0, 255), 3)
cv_show("img",img)
refCnts = sorted(refCnts, key=cv2.contourArea, reverse=True)
refCnts = sort_contours(refCnts, method="left-to-right")[0] # 排序从左到右,从上到下
# 遍历每一个轮廓
for (i, c) in enumerate(refCnts):
# 计算外接矩形并且resize成合适大小
(x, y, w, h) = cv2.boundingRect(c)
# roi为外接矩形的区域
roi = ref[y:y + h, x:x + w]
roi = cv2.resize(roi, (57, 58))
cv_show("ror",roi)
# 每一个数字对应一个模板
digits[i] = roi
#####################################################选择图片并对银行卡号识别######
def process_img(image):
# 初始化卷积核
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
# 读取输入图像,预处理
#image = cv2.imread(img)
image = 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) # Sobel算子
gradX = np.absolute(gradX) # 绝对值
(minVal, maxVal) = (np.min(gradX), np.max(gradX))
gradX = (255 * ((gradX - minVal) / (maxVal - minVal))) # 归一化
gradX = gradX.astype("uint8")
# 通过闭操作,(先膨胀,在腐蚀)将数字连在一起
gradX = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel)
cv_show("gardX",gradX)
# THRESH_OTSU会自动寻找合适的阈值,适合双峰,需把阈值参数设置为0
thresh = cv2.threshold(gradX, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
# 再次闭操作,对缝隙进行填充
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('curimg', 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): # w = 46 h=13
# 符合的轮廓留下来
locs.append((x, y, w, h))
# 将符合的轮廓从左到右排序
locs = sorted(locs, key=lambda x: x[0])
# output = []
# 遍历每一个轮廓中的数字
for (i, (gX, gY, gW, gH)) in enumerate(locs):
# 初始化列表
groupOutput = []
# 根据坐标提取每一个组 多提取一些
group = gray[gY - 5:gY + gH + 5, gX - 5:gX + gW + 5]
# 预处理 轮廓检测
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, 58))
# 计算匹配得分
scores = []
# 在模板章中计算每一个得分
for (digit, digiROI) in digits.items():
# 模板匹配
result = cv2.matchTemplate(roi, digiROI, 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)
img_re=cv2.putText(image, "".join(groupOutput), (gX, gY - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)
# 得到结果
output.extend(groupOutput)
return img_re
def main_run(img):
process_template()
img2 =process_img(img)
# 避免再次识别卡号重复
text = "银行卡号为: {}".format("".join(output))[-16:]
text2="银行卡号为:"+text
return img2,text2
if __name__ == '__main__':
process_template()
img=".\images\card04.png"
#img = "card_01.png"
process_img(img)
print("银行卡号为: {}".format("".join(output)))
UI文件代码1:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'main_win.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Mainwindow(object):
def setupUi(self, Mainwindow):
Mainwindow.setObjectName("Mainwindow")
Mainwindow.resize(900, 650)
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
Mainwindow.setFont(font)
Mainwindow.setStyleSheet("QPushButton{\n"
" background-color:rgb(0,174,236);\n"
" border:none;\n"
" height:35px;\n"
" border-radius:12px;\n"
"}\n"
"QPushButton::hover{\n"
" background-color:rgb(65,184,131);\n"
"}\n"
"")
self.frame_3 = QtWidgets.QFrame(Mainwindow)
self.frame_3.setGeometry(QtCore.QRect(-10, 0, 901, 671))
self.frame_3.setStyleSheet("QFrame{\n"
" background-color:rgb(255,250,240);\n"
" border:none;\n"
" height:35px;\n"
" border-radius:12px;\n"
"}")
self.frame_3.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame_3.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame_3.setObjectName("frame_3")
self.frame = QtWidgets.QFrame(self.frame_3)
self.frame.setGeometry(QtCore.QRect(10, -10, 891, 391))
self.frame.setStyleSheet("QFrame{\n"
" background-color:rgb(191,239,255);\n"
" border:none;\n"
" height:35px;\n"
" border-radius:12px;\n"
"}")
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame.setObjectName("frame")
self.label = QtWidgets.QLabel(self.frame)
self.label.setGeometry(QtCore.QRect(320, 130, 241, 151))
font = QtGui.QFont()
font.setFamily("Bahnschrift")
font.setPointSize(23)
self.label.setFont(font)
self.label.setObjectName("label")
self.pushButton1 = QtWidgets.QPushButton(self.frame_3)
self.pushButton1.setGeometry(QtCore.QRect(380, 430, 110, 40))
self.pushButton1.setStyleSheet("QPushButton{\n"
" background-color:rgb(0,174,236);\n"
" border:none;\n"
" height:35px;\n"
" border-radius:12px;\n"
"}\n"
"QPushButton::hover{\n"
" background-color:rgb(65,184,131);\n"
"}")
self.pushButton1.setObjectName("pushButton1")
self.retranslateUi(Mainwindow)
QtCore.QMetaObject.connectSlotsByName(Mainwindow)
def retranslateUi(self, Mainwindow):
_translate = QtCore.QCoreApplication.translate
Mainwindow.setWindowTitle(_translate("Mainwindow", "银行卡号识别"))
self.label.setText(_translate("Mainwindow", "银行卡号识别"))
self.pushButton1.setText(_translate("Mainwindow", "选择"))
UI文件代码2:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'card_re.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Card_re_Window(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(900, 650)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.label_daichuli = QtWidgets.QLabel(self.centralwidget)
self.label_daichuli.setGeometry(QtCore.QRect(100, 70, 300, 189))
self.label_daichuli.setObjectName("label_daichuli")
self.label_jieguo = QtWidgets.QLabel(self.centralwidget)
self.label_jieguo.setGeometry(QtCore.QRect(510, 70, 300, 189))
self.label_jieguo.setObjectName("label_jieguo")
self.pushButton_upload = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_upload.setGeometry(QtCore.QRect(220, 370, 100, 35))
self.pushButton_upload.setStyleSheet("QPushButton{\n"
" background-color:rgb(0,174,236);\n"
" border:none;\n"
" height:35px;\n"
" border-radius:12px;\n"
"}\n"
"QPushButton::hover{\n"
" background-color:rgb(65,184,131);\n"
"}")
self.pushButton_upload.setObjectName("pushButton_upload")
self.pushButton_save = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_save.setGeometry(QtCore.QRect(580, 370, 100, 35))
self.pushButton_save.setStyleSheet("QPushButton{\n"
" background-color:rgb(0,174,236);\n"
" border:none;\n"
" height:35px;\n"
" border-radius:12px;\n"
"}\n"
"QPushButton::hover{\n"
" background-color:rgb(65,184,131);\n"
"}")
self.pushButton_save.setObjectName("pushButton_save")
self.pushButton_card_re = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_card_re.setGeometry(QtCore.QRect(390, 440, 110, 40))
self.pushButton_card_re.setStyleSheet("QPushButton{\n"
" background-color:rgb(0,174,236);\n"
" border:none;\n"
" height:35px;\n"
" border-radius:12px;\n"
"}\n"
"QPushButton::hover{\n"
" background-color:rgb(65,184,131);\n"
"}")
self.pushButton_card_re.setObjectName("pushButton_card_re")
self.pushButton_return = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_return.setGeometry(QtCore.QRect(390, 540, 110, 40))
self.pushButton_return.setStyleSheet("QPushButton{\n"
" background-color:rgb(0,174,236);\n"
" border:none;\n"
" height:35px;\n"
" border-radius:12px;\n"
"}\n"
"QPushButton::hover{\n"
" background-color:rgb(65,184,131);\n"
"}")
self.pushButton_return.setObjectName("pushButton")
self.label_cardnum = QtWidgets.QLabel(self.centralwidget)
self.label_cardnum.setGeometry(QtCore.QRect(510, 310, 411, 31))
font = QtGui.QFont()
font.setPointSize(12)
self.label_cardnum.setFont(font)
self.label_cardnum.setObjectName("label_cardnum")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 900, 26))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "银行卡识别系统"))
self.label_daichuli.setText(_translate("MainWindow", "银行卡"))
self.label_jieguo.setText(_translate("MainWindow", "识别后"))
self.pushButton_upload.setText(_translate("MainWindow", "选择银行卡"))
self.pushButton_save.setText(_translate("MainWindow", "保存图片"))
self.pushButton_card_re.setText(_translate("MainWindow", "识别"))
self.pushButton_return.setText(_translate("MainWindow", "返回"))
self.label_cardnum.setText(_translate("MainWindow", "银行卡号:"))
四、运行结果图片
运行结果主页面图
银行卡识别结果页面图