侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

Python编写一个验证码图片数据标注GUI程序附源码

Python  /  管理员 发布于 7年前   166

做验证码图片的识别,不论是使用传统的ORC技术,还是使用统计机器学习或者是使用深度学习神经网络,都少不了从网络上采集大量相关的验证码图片做数据集样本来进行训练。

采集验证码图片,可以直接使用Python进行批量下载,下载完之后,就需要对下载下来的验证码图片进行标注。一般情况下,一个验证码图片的文件名就是图片中验证码的实际字符串。

在不借助工具的情况下,我们对验证码图片进行上述标注的流程是:

1、打开图片所在的文件夹;
2、选择一个图片;
3、鼠标右键重命名;
4、输入正确的字符串;
5、保存

州的先生亲身体验,一个验证码完成数据的标注,大概需要10到20秒。大量的时间浪费在了重复地进行鼠标右键重命名操作了。于是,使用Qt的Python封装包――PyQt5,编写了一个小工具,方便进行验证码图片的数据标注,节省时间,珍惜生命。

程序的运行如下动图所示:

下面我们来了解一下如何编写这个验证码图片数据标注程序。

首先,我们来构建一个图形界面。这个图形界面里面包含了一个图像展示控件、一个文本输入控件、四个按钮控件。基于此,我们选择三个布局来排列图形界面的布局。图形界面窗口中的核心控件是一个QWidget(),其布局层设置为网格布局QGridLayout()。在其中放置三个控件:图像展示控件QWidget()、文本输入控件QLineText()、四个按钮组QWidget()。

同时,图像展示控件QWidget()用水平布局层QHBoxLayout()包含一个QLabel()标签来占位;按钮组控件QWidget()用一个垂直布局层QVBoxLayout()将4个按钮控件QPushButton()添加进去。最后,代码如下所示:

class ImgTag(QtWidgets.QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("验证码图片标注 州的先生 zmister.com") # 主控件和主控件布局 self.main_widget = QtWidgets.QWidget() self.main_layout = QtWidgets.QGridLayout() self.main_widget.setLayout(self.main_layout) # 图像展示控件 self.img_widget = QtWidgets.QWidget() self.img_layout = QtWidgets.QHBoxLayout() self.img_widget.setLayout(self.img_layout) # 标签占位 self.img_view = QtWidgets.QLabel("请选择一个文件夹!") self.img_view.setAlignment(QtCore.Qt.AlignCenter) self.img_layout.addWidget(self.img_view) # 图像标注控件 self.img_input = QtWidgets.QLineEdit() # 控制按钮控件 self.opera_widget = QtWidgets.QWidget() self.opera_layout = QtWidgets.QVBoxLayout() self.opera_widget.setLayout(self.opera_layout) # 各个按钮 self.select_img_btn = QtWidgets.QPushButton("选择目录") self.previous_img_btn = QtWidgets.QPushButton("上一张") self.previous_img_btn.setEnabled(False) self.next_img_btn = QtWidgets.QPushButton("下一张") self.next_img_btn.setEnabled(False) self.save_img_btn = QtWidgets.QPushButton("保存") self.save_img_btn.setEnabled(False) # 添加按钮到布局 self.opera_layout.addWidget(self.select_img_btn) self.opera_layout.addWidget(self.previous_img_btn) self.opera_layout.addWidget(self.next_img_btn) self.opera_layout.addWidget(self.save_img_btn) # 将控件添加到主控件布局层 self.main_layout.addWidget(self.img_widget,0,0,4,4) self.main_layout.addWidget(self.opera_widget,0,4,5,1) self.main_layout.addWidget(self.img_input,4,0,1,4) # 状态栏 self.img_total_current_label = QtWidgets.QLabel() self.img_total_label = QtWidgets.QLabel() self.statusBar().addPermanentWidget(self.img_total_current_label) self.statusBar().addPermanentWidget(self.img_total_label, stretch=0) # 在状态栏添加永久控件 # 设置UI界面核心控件 self.setCentralWidget(self.main_widget)

运行上述代码,我们可以得到以下如下图所示的图形界面:

下面,我们为这个静态的图形界面添加事件响应。

二、选择目录读取文件

首先,我们来实现“选择目录”按钮的功能。这个按钮点击之后,需要打开文件夹选择框,然后在选择一个文件夹之后,自动读取文件夹内的图片文件,并将第一张图片显示到图形展示控件上。

在这里,我们通过QFileDialog.getExistingDirectory()来实现调用文件夹对话框,其会返回所选择文件夹路径的字符串。然后通过os模块的listdir()方法,获取文件夹下所有的文件,对其进行遍历,提取出图片文件,将这些图片文件添加到一个新的列表中。代码如下所示:

# 选择目录按钮def select_img_click(self): self.dir_path = QtWidgets.QFileDialog.getExistingDirectory(self,'选择文件夹') # print(self.dir_path) dir_list = os.listdir(self.dir_path) img_list = [] for dir in dir_list: suffix_list = ['jpg','png','jpeg','bmp',] if dir.split('.')[-1].lower() in suffix_list:  img_list.append(dir)

接着,我们继续遍历这个列表,生成一个图片的索引字典,用于记录每个图片的顺序信息,方便进行上一张、下一张按钮的切换操作。

# 图像文件索引字典self.img_index_dict = dict()for i,d in enumerate(img_list): self.img_index_dict[i] = dself.current_index = 0 # 当前的图像索引# 当前图片文件路径self.current_filename = os.path.join( self.dir_path,self.img_index_dict[self.current_index])

然后,借助QImage()类实例化一个Qt的图像,在图像占位标签中通过setPixmap设置显示图像。

# 实例化一个图像image = QtGui.QImage(self.current_filename)self.img_width = image.width() # 图片宽度self.img_height = image.height() # 图片高度self.img_scale = 1self.image = image.scaled(self.img_width*self.img_scale,self.img_height*self.img_scale)# 在img_view控件中显示图像self.img_view.setPixmap(QtGui.QPixmap.fromImage(self.image))

接着再设置文本输入框的内容、获取文本输入框的焦点并全选文本输入框的内容:

# 设置img_input控件文本内容self.img_input.setText(self.current_text)self.img_input.setFocus() # 获取输入框焦点self.img_input.selectAll() # 全选文本

最后在状态栏设置图片数量的信息,包括当前图片和图片总数:

# 设置状态栏 图片数量信息self.img_total_current_label.setText("{}".format(self.current_index+1))self.img_total_label.setText("/{total}".format(total=len(img_list)))

以上这些代码都是写在select_img_click()方法操作。在完成select_img_click()这个方法的编写后,我们将其绑定到“选择目录”的点击信号上:

self.select_img_btn.clicked.connect(self.select_img_click)

这样,就实现了选择目录,并显示目录中的第一张图片的功能。效果如下动图所示:

下面,我们再来实现下一张图片的按钮功能

三、切换下一张图片

要切换下一张图片,我们首先需要将当前显示的图片重命名为文本输入框中的内容:

# 下一张图片def next_img_click(self): # 修改当前图像文件名 new_tag = self.img_input.text() # 获取当前输入框内容 current_img = self.img_index_dict[self.current_index] # 获取当前图片名称 try: os.rename(  os.path.join(self.dir_path,current_img),  os.path.join(self.dir_path,new_tag+'.'+current_img.split('.')[-1]) ) # 修改文件名 self.img_index_dict[self.current_index] = new_tag+'.'+current_img.split('.')[-1] except FileExistsError as e: # 同名文件异常 print(repr(e)) QtWidgets.QMessageBox.information(  self, '提示', '已存在同名文件!',  QtWidgets.QMessageBox.Ok )

接下来,将图片当前索引变量值加1,通过这个索引值获取到下一张图片的文件名,再按照之前的方式将其读取为图像并显示在标签占位控件上,同时更新状态栏的信息:

# 当前图像索引加1self.current_index += 1if self.current_index in self.img_index_dict.keys(): # 当前图片文件路径 self.current_filename = os.path.join( self.dir_path, self.img_index_dict[self.current_index] ) # 实例化一个图像 image = QtGui.QImage(self.current_filename) self.img_width = image.width() # 图片宽度 self.img_height = image.height() # 图片高度 self.img_scale = 1 self.image = image.scaled(self.img_width * self.img_scale, self.img_height * self.img_scale) # 在img_view控件中显示图像 self.img_view.setPixmap(QtGui.QPixmap.fromImage(self.image)) # 当前文件名 self.current_text = self.img_index_dict[self.current_index].split('.')[0] # 设置img_input控件文本内容 self.img_input.setText(self.current_text) self.img_input.setFocus() # 获取输入框焦点 self.img_input.selectAll() # 全选文本 # 设置状态栏 self.img_total_current_label.setText(str(self.current_index+1))else: self.current_index -=1 QtWidgets.QMessageBox.information( self,'提示','所有图片已标注完!', QtWidgets.QMessageBox.Ok )

这样,调用next_img_click()方法,我们就可以切换下一张图片。我们将其绑定在“下一张”按钮、“保存”按钮和文本输入框的回车信号上,就可以实现点击“下一张”按钮、“保存”按钮或是在标注完一个数据后直接回车就能切换到下一张图片:

self.next_img_btn.clicked.connect(self.next_img_click)self.save_img_btn.clicked.connect(self.next_img_click)self.img_input.returnPressed.connect(self.next_img_click) # 回车事件绑定

这样,切换下一张图片的功能也实现了,其效果如下动图所示:

四、切换上一张图片

有时候我们需要返回前面标注的图片,这时候切换上一张图片的功能也是很有必要的。切换上一张图片的逻辑与切换下一张图片的逻辑基本一致,只是需要将图像的索引值减1:

# 上一张图片def previous_img_click(self): # 修改当前图像文件名 new_tag = self.img_input.text() # 获取当前输入框内容 current_img = self.img_index_dict[self.current_index] # 获取当前图片名称 try: os.rename(  os.path.join(self.dir_path, current_img),  os.path.join(self.dir_path, new_tag + '.' + current_img.split('.')[-1]) ) # 修改文件名 self.img_index_dict[self.current_index] = new_tag + '.' + current_img.split('.')[-1] except FileExistsError as e: # 同名文件异常 print(repr(e)) QtWidgets.QMessageBox.information(  self, '提示', '已存在同名文件!',  QtWidgets.QMessageBox.Ok ) # 当前图像索引加1 self.current_index -= 1 if self.current_index in self.img_index_dict.keys(): # 当前图片文件路径 self.current_filename = os.path.join(  self.dir_path, self.img_index_dict[self.current_index] ) # 实例化一个图像 image = QtGui.QImage(self.current_filename) self.img_width = image.width() # 图片宽度 self.img_height = image.height() # 图片高度 self.img_scale = 1 self.image = image.scaled(self.img_width * self.img_scale, self.img_height * self.img_scale) # 在img_view控件中显示图像 self.img_view.setPixmap(QtGui.QPixmap.fromImage(self.image)) # 当前文件名 self.current_text = self.img_index_dict[self.current_index].split('.')[0] # 设置img_input控件文本内容 self.img_input.setText(self.current_text) self.img_input.setFocus() # 获取输入框焦点 self.img_input.selectAll() # 全选文本 # 设置状态栏 self.img_total_current_label.setText(str(self.current_index + 1)) else: self.current_index += 1 QtWidgets.QMessageBox.information(  self, '提示', '图片列表到顶了!',  QtWidgets.QMessageBox.Ok )

可以看到,这和切换下一张图片的代码几乎是一致的,因为其核心逻辑本来就是一样的,我们将“上一张”按钮的点击信号绑定在这个方法上,就可以实现切换上一张图片的功能了:

self.previous_img_btn.clicked.connect(self.previous_img_click)

其效果如下动图所示:

五、图片缩放

到这里,我们的验证码图片数据标注程序基本上已经完成了,但是突然发现,有些验证码图片很变态,它的干扰线和干扰点简直让人无法看清它到底是什么字符,这样的情况下可能需要把图片放大或缩小一点,方便我们确认验证码图片上的信息,所以,我们的程序还需要一个图片缩放功能。最终,我们实现的效果是,按住Ctrl+鼠标滚轮,滚轮向上,图片放大,滚轮向下,图片缩小。这是通过重写鼠标滚轮事件来实现的:

# 重写鼠标滚轮事件def wheelEvent(self, event): # 如果按住了Ctrl if event.modifiers() == QtCore.Qt.ControlModifier: try:  delta = event.angleDelta().y()  if delta > 0:  self.img_scale += 0.25  self.image_scaled = self.image.scaled(self.img_width * self.img_scale, self.img_height * self.img_scale)  self.img_view.setPixmap(QtGui.QPixmap.fromImage(self.image_scaled))  self.statusBar().showMessage("当前图片缩放比例为:{}%".format(self.img_scale * 100))  elif delta < 0:  if self.img_scale > 0.25:   self.img_scale -= 0.25   self.image_scaled = self.image.scaled(self.img_width * self.img_scale, self.img_height * self.img_scale)   self.img_view.setPixmap(QtGui.QPixmap.fromImage(self.image_scaled))   self.statusBar().showMessage("当前图片缩放比例为:{}%".format(self.img_scale * 100)) except Exception as e:  print(traceback.print_exc())  print(repr(e))

最后,这样图片缩放的功能也实现了,其效果如下所示:

六、程序完整代码

以上,我们的图片验证码数据标注程序就完全编写好了,基于此,我们可以进一步使用Pyinstaller等打包工具,将其打包为二进制的可执行文件,方便传播使用。

源码下载地址:链接: https://pan.baidu.com/s/1FadzPC2FoIJNPMCmpYBKRg 提取码: e4w4

总结

以上所述是小编给大家介绍的Python编写一个验证码图片数据标注GUI程序附源码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!


  • 上一条:
    基于YUV 数据格式详解及python实现方式
    下一条:
    Python内置方法实现字符串的秘钥加解密(推荐)
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在python语言中Flask框架的学习及简单功能示例(0个评论)
    • 在Python语言中实现GUI全屏倒计时代码示例(0个评论)
    • Python + zipfile库实现zip文件解压自动化脚本示例(0个评论)
    • python爬虫BeautifulSoup快速抓取网站图片(1个评论)
    • vscode 配置 python3开发环境的方法(0个评论)
    • 近期文章
    • 智能合约Solidity学习CryptoZombie第三课:组建僵尸军队(高级Solidity理论)(0个评论)
    • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2018-04
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2022-01
    • 2023-07
    • 2023-10
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客