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

做验证码图片的识别,不论是使用传统的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] = d
self.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 = 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))

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

# 设置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,通过这个索引值获取到下一张图片的文件名,再按照之前的方式将其读取为图像并显示在标签占位控件上,同时更新状态栏的信息:

# 当前图像索引加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
 )

这样,调用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程序附源码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

(0)

相关推荐

  • python selenium UI自动化解决验证码的4种方法

    本文介绍了python selenium UI自动化解决验证码的4种方法,分享给大家,具体如下: 测试环境 windows7+ firefox50+ geckodriver # firefox浏览器驱动 python3 selenium3 selenium UI自动化解决验证码的4种方法:去掉验证码.设置万能码.验证码识别技术-tesseract.添加cookie登录,本次主要讲解验证码识别技术-tesseract和添加cookie登录. 1. 去掉验证码 去掉验证码,直接通过用户名和密码登陆网

  • python验证码识别教程之利用投影法、连通域法分割图片

    前言 今天这篇文章主要记录一下如何切分验证码,用到的主要库就是Pillow和Linux下的图像处理工具GIMP.首先假设一个固定位置和宽度.无粘连.无干扰的例子学习一下如何使用Pillow来切割图片. 使用GIMP打开图片后,按 加号 放大图片,然后点击View->Show Grid来显示网格线: 其中,每个正方形边长为10像素,所以数字1切割坐标为左20.上20.右40.下70.以此类推可以知道剩下3个数字的切割位置. 代码如下: from PIL import Image p = Image

  • 这可能是最好玩的python GUI入门实例(推荐)

    简单的说,GUI编程就是给程序加上图形化界面. python的脚本开发简单,有时候只需几行代码就能实现丰富的功能,而且python本身是跨平台的,所以深受程序员的喜爱. 如果给程序加一个图形化界面,那么普通的用户也就能用上python的脚本,极大提升工作效率,所以给python程序加上图形化界面,把自己写的脚本,提供给普通用户,的确是一件激动人心的事! 如何给python脚本加图形化界面? 作者首先考虑了通过浏览器运行python的图形化界面,为了理想的效果,python需要借助javascri

  • python验证码识别教程之利用滴水算法分割图片

    滴水算法概述 滴水算法是一种用于分割手写粘连字符的算法,与以往的直线式地分割不同 ,它模拟水滴的滚动,通过水滴的滚动路径来分割字符,可以解决直线切割造成的过分分割问题. 引言 之前提过对于有粘连的字符可以使用滴水算法来解决分割,但智商捉急的我实在是领悟不了这个算法的精髓,幸好有小伙伴已经实现相关代码. 我对上面的代码进行了一些小修改,同时升级为python3的代码. 还是以这张图片为例: 在以前的我们已经知道这种简单的粘连可以通过控制阈值来实现分割,这里我们使用滴水算法. 首先使用之前文章中介绍

  • Python使用selenium实现网页用户名 密码 验证码自动登录功能

    好久没有学python了,反正各种理由吧(懒惰总会有千千万万的理由),最近网上学习了一下selenium,实现了一个简单的自动登录网页,具体如下. 1.安装selenium: 如果你已经安装好anaconda3,直接在windows的dos窗口输入命令安装selenium: python -m pip install --upgrade pip 查看版本pip show selenium 2.接着去http://chromedriver.storage.googleapis.com/index.

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

    做验证码图片的识别,不论是使用传统的ORC技术,还是使用统计机器学习或者是使用深度学习神经网络,都少不了从网络上采集大量相关的验证码图片做数据集样本来进行训练. 采集验证码图片,可以直接使用Python进行批量下载,下载完之后,就需要对下载下来的验证码图片进行标注.一般情况下,一个验证码图片的文件名就是图片中验证码的实际字符串. 在不借助工具的情况下,我们对验证码图片进行上述标注的流程是: 1.打开图片所在的文件夹: 2.选择一个图片: 3.鼠标右键重命名: 4.输入正确的字符串: 5.保存 州

  • python爬虫今日热榜数据到txt文件的源码

    今日热榜:https://tophub.today/ 爬取数据及保存格式: 爬取后保存为.txt文件: 部分内容: 源码及注释: import requests from bs4 import BeautifulSoup def download_page(url): headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko

  • Python实现GUI计算器(附源码)

    目录 效果 源码 效果 可执行正常加减乘除相关运算,源码已贴,自行测试. 源码 # coding=gbk """ 作者:川川 @时间 : 2022/11/6 3:10 """ from tkinter import * calc = Tk() calc.title('川川计算器') operator = '' def clear(): global operator operator='' txt_input.set("")

  • 趣味Python实战练习之自动更换桌面壁纸脚本附源码

    目录 前言 目标地址 先是爬虫代码 导入数据 请求数据 解析数据 保存数据 运行代码,查看结果 自动跟换桌面壁纸代码 最后实现效果 前言 发现一个不错的壁纸网站,里面都是超高清的图片,而且还是免费为的. 所以,我打算把这些壁纸都爬取下来,然后在做一个自动跟换桌面壁纸的脚本,这样基本上你一年都可以每天都有不重复桌面了 目标地址 先来看看我们这次的受害者:https://wallhaven.cc/ [付费VIP完整版]只要看了就能学会的教程,80集Python基础入门视频教学 点这里即可免费在线观看

  • 使用Python给头像加上圣诞帽或圣诞老人小图标附源码

    随着圣诞的到来,想给给自己的头像加上一顶圣诞帽.如果不是头像,就加一个圣诞老人陪伴. 用Python给头像加上圣诞帽,看了下大概也都是来自2017年大神的文章:https://zhuanlan.zhihu.com/p/32283641 主要流程 素材准备 人脸检测与人脸关键点检测 调整大小,添加帽子 用dlib的正脸检测器进行人脸检测,用dlib提供的模型提取人脸的五个关键点 调整帽子大小,带帽 选取两个眼角的点,求中心作为放置帽子的x方向的参考坐标,y方向的坐标用人脸框上线的y坐标表示.然后我

  • python opencv实现直线检测并测出倾斜角度(附源码+注释)

    由于学习需要,我想要检测出图片中的直线,并且得到这些直线的角度.于是我在网上搜了好多直线检测的代码,但是没有搜到附有计算直线倾斜角度的代码,所以我花了一点时间,自己写了一份直线检测并测出倾斜角度的代码,希望能够帮助到大家! 注:这份代码只能够检测简单结构图片的直线,复杂结构的图片还需要设置合理的参数 下面展示 源码. import cv2 import numpy as np def line_detect(image): # 将图片转换为HSV hsv = cv2.cvtColor(image

  • Python爬虫实战之网易云音乐加密解析附源码

    目录 环境 知识点 第一步 第二步 开始代码 先导入所需模块 请求数据 提取我们真正想要的 音乐的名称 id 导入js文件 保存文件 完整代码 环境 python3.8 pycharm2021.2 知识点 requests >>> pip install requests execjs >>> pip install PyExecJS 第一步 打开这个网站 在里面去分析我们需要的数据 每个音乐的名称 id 去网页源代码查找数据,发现并没有,这个网页 并不是一个静态页面

  • Python 写小游戏吃金币+打乒乓+滑雪(附源码)

    目录 1.吃金币 2.打乒乓 3.滑雪 1.吃金币 源码分享: import os import cfg import sys import pygame import random from modules import *     '''游戏初始化''' def initGame():     # 初始化pygame, 设置展示窗口     pygame.init()     screen = pygame.display.set_mode(cfg.SCREENSIZE)     pygam

  • ASP.NET图片上传实例(附源码)

    由于需要图片上传的功能,所以花了一些时间网上找相关资料终于搞定,效果图如下: 下面的是解决方案截图和上传的图片截图: 下面是代码: 1.界面代码 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="UploadPic.aspx.cs" Inherits="Pic_Try.UploadPic" %> <!DOCTYPE html PUBLIC &q

  • Vue 2.0+Vue-router构建一个简单的单页应用(附源码)

    一.介绍 vue.js 是 目前 最火的前端框架,vue.js 兼具 angular.js 和 react.js 的优点,并剔除它们的缺点,并且提供了很多的周边配套工具 如vue-router .vue-resource .vuex等等 ,通过他们我们可以很轻松的构建一个大型单页应用. 目前Vue版本为:Vue2.0 官网地址:http://vuejs.org.cn/ 查看API文档:https://vuefe.cn/v2/api/ 对比其他框架:http://vuejs.org.cn/guid

随机推荐