如何基於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核心部分並沒有做任何更改,只是在產品包裝方面做了一些巧妙的工作。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。