1. 程式人生 > 程式設計 >Python編寫一個驗證碼圖片資料標註GUI程式附原始碼

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,4,4)
 self.main_layout.addWidget(self.opera_widget,5,1)
 self.main_layout.addWidget(self.img_input,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,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_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程式附原始碼,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回覆大家的。在此也非常感謝大家對我們網站的支援!
如果你覺得本文對你有幫助,歡迎轉載,煩請註明出處,謝謝!