1. 程式人生 > 程式設計 >如何基於Python程式碼實現高精度免費OCR工具

如何基於Python程式碼實現高精度免費OCR工具

近期Github開源了一款基於Python開發、名為Textshot的截圖工具,剛開源不到半個月已經500+Star。

這兩天抽空看了一下Textshot的原始碼,的確是一個值得介紹的專案。

相對於大多數OCR工具複雜工程、差強人意的效果,Textshot具有明顯的優勢,

  • 專案簡單
  • 技術點豐富

專案簡單

Textshot整個專案只有1個Python檔案、139行程式碼,沒有複雜的第三方庫應用,也不涉及過多後端演算法的呼叫。

技術點豐富

Textshot這個專案雖然只有短短的139行程式碼,但是,卻涉及Python中多個方面的知識應用,

  • UI開發
  • 截圖工具開發
  • 後端引擎呼叫

通過這短短的專案,你不僅可以瞭解如何利用PyQt5實現一個使用者介面,還可以學會如何使用pyscreenshot開發一款自己的截圖工具。此外,還能夠學會後端tesseract的呼叫。

換句話說,這短短的139行程式碼囊括了前端至後端的整個流程,而且涉及到截圖和OCR兩款工具的銜接。因此,Textshot雖然工程不大,卻是一個非常完備、值得學習的專案。

本文就來剖析這個專案的原始碼,教你一步一步實現自用且永久免費的截圖&OCR工具!

tesseract

目前OCR工具數不勝數,但是大多數都是在相同的後端演算法上面進行了不同的封裝而已。而真正在OCR核心做的較好、值得大書特書的,那麼一定非tesseract莫屬

tesseract早在1985就已經開始由HP實驗室開始研發,而在1995年更是被評為最為準確的3款OCR工具之一。此後,tesseract被開源,經過Google對其不斷的進行優化和升級,它目前已經成為OCR方面一款標杆性的工具。很多開源或者付費的OCR工具,都是直接呼叫tesseract或者對其進行稍許優化。

而今天介紹的Textshot就是直接呼叫tesseract後端引擎進行OCR識別。因此,Textshot只是實現了一款截圖工具,起到前後端的串聯作用,在OCR識別演算法方面並沒有做任何工作。

tesseract安裝

由於Textshot的OCR識別需要呼叫tesseract後端引擎,所以,首先需要安裝tesseract。

Windows版安裝可以直接訪問下載連結[1].

Mac下可以使用Homebrew進行安裝,

brew install tesseract 

Textshot

Textshot是一款截圖識別文字的OCR工具,因此,它主要涉及2個環境,

截圖

OCR識別

Textshot首先通過截圖獲取需要進行文字識別的影象,然後對這副影象進行OCR文字識別,輸出識別結果。

前面已經介紹了,Textshot的OCR識別階段呼叫的是tesseract,所以只需要1行程式碼即可完成。

因此,Textshot的工作主要是圍繞前端視窗和截圖工具的實現方面。

截圖工具

截圖工具是我們經常會用到的一種工具,如何實現一款截圖工具?

很多人會把它想的非常複雜,其實,Python中有很多可以實現截圖的庫或者函式,例如,pyscreenshot或者pillow中的ImageGrab函式,它的呼叫方式如下,

shot = ImageGrab.grab(bbox=(x1,y1,x2,y2))

也就是說,我們只需要把滑鼠框選的起點和終點座標傳給grab方法就可以實現截圖功能。

那麼,現在問題就轉化為如何獲取滑鼠框選的起點和終點?

Textshot通過呼叫PyQt5並繼承QWidget來實現滑鼠框選過程中的一些方法來獲取框選的起點和終點。

Textshot繼承和重寫QWidget方法主要包括如下幾個,

  • keyPressEvent(self,event):鍵盤響應函式
  • paintEvent(self,event):UI繪製函式
  • mousePressEvent(self,event):滑鼠點選事件
  • mouseMoveEvent(self,event):滑鼠移動事件
  • mouseReleaseEvent(self,event):滑鼠釋放事件

可以看出,上面重寫的方法以及囊括了截圖過程中涉及的各個動作,

  • 點選滑鼠
  • 拖動、繪製截圖框
  • 釋放滑鼠
class Snipper(QtWidgets.QWidget):
  def __init__(self,parent=None,flags=Qt.WindowFlags()):
    super().__init__(parent=parent,flags=flags)
 
    self.setWindowTitle("TextShot")
    self.setWindowFlags(
      Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.Dialog
    )
 
    self.is_macos = sys.platform.startswith("darwin")
    if self.is_macos:
      self.setWindowState(self.windowState() | Qt.WindowMaximized)
    else:
      self.setWindowState(self.windowState() | Qt.WindowFullScreen)
 
    self.setStyleSheet("background-color: black")
    self.setWindowOpacity(0.5)
 
    QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))
 
    self.start,self.end = QtCore.QPoint(),QtCore.QPoint()
 
  def keyPressEvent(self,event):
    if event.key() == Qt.Key_Escape:
      QtWidgets.QApplication.quit()
 
    return super().keyPressEvent(event)
 
  def paintEvent(self,event):
    if self.start == self.end:
      return super().paintEvent(event)
 
    painter = QtGui.QPainter(self)
    painter.setPen(QtGui.QPen(QtGui.QColor(255,255,255),3))
    painter.setBrush(QtGui.QColor(255,100))
 
    if self.is_macos:
      start,end = (self.mapFromGlobal(self.start),self.mapFromGlobal(self.end))
    else:
      start,end = self.start,self.end
 
    painter.drawRect(QtCore.QRect(start,end))
    return super().paintEvent(event)
 
  def mousePressEvent(self,event):
    self.start = self.end = QtGui.QCursor.pos()
    self.update()
    return super().mousePressEvent(event)
 
  def mouseMoveEvent(self,event):
    self.end = QtGui.QCursor.pos()
    self.update()
    return super().mousePressEvent(event)
 
  def mouseReleaseEvent(self,event):
    if self.start == self.end:
      return super().mouseReleaseEvent(event)
 
    x1,x2 = sorted((self.start.x(),self.end.x()))
    y1,y2 = sorted((self.start.y(),self.end.y()))

然後啟動截圖介面,

QtCore.QCoreApplication.setAttribute(Qt.AA_DisableHighDpiScaling)
app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QMainWindow()
snipper = Snipper(window)
snipper.show()

使用者拖動、框選視窗,會獲取視窗的起點和終點的座標,這時候可以呼叫下面語句進行截圖,獲取需要OCR識別的文字影象,

shot = ImageGrab.grab(bbox=(x1,y2))  

OCR文字識別

通過ImageGrab.grab擷取到文字影象shot,下一步就是要把影象內容輸入給後端的tesseract引擎,讓它把影象轉化為字串

result = pytesseract.image_to_string(img,timeout=2,lang=(sys.argv[1] if len(sys.argv) > 1 else None))

到這裡,就實現了一款準確度高、永久免費的OCR工具。

回顧一下Textshot的專案,我們會發現截圖座標範圍內的影象、OCR識別只需要2行程式碼,大多數都是在圍繞獲取視窗起點和終點座標在開發。換句話說,Textshot這個專案對OCR核心部分並沒有做任何更改,只是在產品包裝方面做了一些巧妙的工作。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。