android 数据存储怎么保存图片_遇到验证码怎么办?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 = 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))# 當前文件名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 -=1QtWidgets.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)# 當前圖像索引加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 = 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))# 當前文件名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 += 1QtWidgets.QMessageBox.information(self, '提示', '圖片列表到頂了!',QtWidgets.QMessageBox.Ok)可以看到,這和切換下一張圖片的代碼幾乎是一致的,因為其核心邏輯本來就是一樣的,我們將“上一張”按鈕的點擊信號綁定在這個方法上,就可以實現切換上一張圖片的功能了:
self.previous_img_btn.clicked.connect(self.previous_img_click)其效果如下動圖所示:
五、圖片縮放
到這里,我們的驗證碼圖片數據標注程序基本上已經完成了,但是突然發現,有些驗證碼圖片很變態,它的干擾線和干擾點簡直讓人無法看清它到底是什么字符,這樣的情況下可能需要把圖片放大或縮小一點,方便我們確認驗證碼圖片上的信息,所以,我們的程序還需要一個圖片縮放功能。最終,我們實現的效果是,按住Ctrl+鼠標滾輪,滾輪向上,圖片放大,滾輪向下,圖片縮小。這是通過重寫鼠標滾輪事件來實現的:
# 重寫鼠標滾輪事件 def wheelEvent(self, event):# 如果按住了Ctrlif event.modifiers() == QtCore.Qt.ControlModifier:try:delta = event.angleDelta().y()if delta > 0:self.img_scale += 0.25self.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.25self.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等打包工具,將其打包為二進制的可執行文件,方便傳播使用。
總結
以上是生活随笔為你收集整理的android 数据存储怎么保存图片_遇到验证码怎么办?Python编写一个验证码图片数据标注GUI程序!...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ont维修使能工具_上海OTC机器人维修
- 下一篇: 如何编写第三方接口_Python接口测试