by Adrian Rosebrock on August 20, 2018 in Deep Learning, Optical Character Recognition (OCR), Tutorials
點擊這裏下載這篇文章的源代碼python
在本教程中,您將學習如何使用EAST文本檢測器使用OpenCV檢測天然場景圖像中的文本。
OpenCV的EAST文本檢測器是一種基於新穎架構和訓練模式的深度學習模型。它可以(1)在720p圖像上以13 FPS接近實時運行,而且(2)得到最早進的文本檢測精度。
在本教程的其他部分,您將學習如何使用OpenCV的EAST檢測器自動檢測圖像和視頻流中的文本。算法
在本教程中,您將學習如何使用EAST文本檢測器使用OpenCV檢測圖像中的文本。
EAST文本檢測器要求咱們在咱們的系統上運行OpenCV 3.4.2或OpenCV 4 - 若是您尚未安裝OpenCV 3.4.2或更高版本,請參閱個人OpenCV安裝指南並按照各自的操做系統進行操做。
在今天的教程的第一部分中,我將討論爲何在天然場景圖像中檢測文本會如此具備挑戰性。
從那裏我將簡要討論EAST文本檢測器,咱們爲何使用它,以及使算法如此新穎的緣由 - 我還將包含原始論文的連接,以便您能夠閱讀詳細信息,若是您如此傾向。
最後,我將提供個人Python + OpenCV文本檢測實現,以便您能夠開始在本身的應用程序中應用文本檢測。安全
爲何天然場景文本檢測如此具備挑戰性網絡
圖1:天然場景圖像的示例,其中文本檢測因爲光照條件,圖像質量和非平面物體而具備挑戰性(Mancas-Thillou和Gosselin的圖1)。架構
在受約束的受控環境中檢測文本一般能夠經過使用基於啓發式的方法來完成,例如利用梯度信息或者文本一般被分組成段落而且字符出如今直線上的事實。在我以前關於檢測護照圖像中的機器可讀區域的博客文章中能夠看到這種基於啓發式的文本檢測器的示例。
天然場景文本檢測雖然不一樣 - 並且更具挑戰性。
因爲廉價數碼相機的普及,更不用說幾乎每部智能手機如今都有攝像頭這一事實,咱們須要高度關注拍攝圖像的條件 - 此外,咱們能作什麼和不能作什麼假設。我已經包含了Celine Mancas-Thillou和Bernard Gosselin在2017年優秀論文「天然場景文本理解」中描述的天然場景文本檢測挑戰的總結版本:
.圖像/傳感器噪聲:手持式攝像機的傳感器噪聲一般高於傳統掃描儀的噪聲。此外,低價相機一般會插入原始傳感器的像素以產生真實的顏色。
.視角:天然場景文本天然能夠具備與文本不平行的視角,使文本更難識別。
.模糊:不受控制的環境每每會模糊,特別是若是最終用戶使用的智能手機沒有某種形式的穩定性。
.照明條件:咱們沒法對天然場景圖像中的照明條件作出任何假設。它可能接近黑暗,相機上的閃光燈可能會亮起,或者太陽可能會發出明亮的光線,使整個圖像飽和。
.分辨率:並不是全部攝像機都是相同的 - 咱們可能在處理分辨率低於標準的相機。
.非紙質對象:大多數(但不是所有)紙張都不是反光的(至少在您嘗試掃描的紙張環境中)。天然場景中的文字多是反光的,包括徽標,標誌等。
.非平面物體:考慮當您將文本環繞在瓶子周圍時會發生什麼 - 表面上的文本變得扭曲和變形。雖然人類仍然能夠輕鬆地「檢測」並閱讀文本,但咱們的算法會很困難。咱們須要可以處理這樣的用例。
.未知佈局:咱們不能使用任何先驗信息來爲咱們的算法提供關於文本所在位置的「線索」。app
正如咱們將要了解的那樣,OpenCV的EAST文本檢測器實現很是強大,即便文本模糊,反射或部分模糊,也可以對文本進行本地化:框架
圖2:OpenCV的EAST場景文本檢測器即便在模糊和模糊的圖像中也能檢測到。ide
EAST深度學習文本檢測器函數
圖3:EAST文本檢測全卷積網絡的結構(Zhou等人的圖3)。oop
隨着OpenCV 3.4.2和OpenCV 4的發佈,咱們如今可使用一種名爲EAST的基於深度學習的文本檢測器,它基於Zhou等人的2017年論文「EAST:一種高效精確的場景文本檢測器」。
咱們將算法稱爲「EAST」,由於它是:高效且準確的場景文本檢測管道。
據做者說,EAST管道可以在720p圖像上以任意方向預測文本的單詞和行,而且可以以13 FPS運行。
也許最重要的是,因爲深度學習模型是端到端的,所以能夠迴避其餘文本檢測器一般應用的計算上昂貴的子算法,包括候選聚合和字分區。
爲了構建和訓練這樣一種深度學習模型,EAST方法採用了新穎,精心設計的損失函數。
有關EAST的更多詳細信息,包括架構設計和培訓方法,請務必參考做者的出版物。
項目結構
首先,請訪問「下載」部分,確保將源代碼+圖像抓取到今天的帖子。從那裏,只需使用tree terminal命令查看項目結構:
$ tree --dirsfirst . ├── images │ ├── car_wash.png │ ├── lebron_james.jpg │ └── sign.jpg ├── frozen_east_text_detection.pb ├── text_detection.py └── text_detection_video.py 1 directory, 6 files
請注意,我在images /目錄中提供了三張示例圖片。您可能但願添加本身使用智能手機收集的圖像或在線查找的圖像。
咱們今天將審查兩個.py文件:
text_detection.py:檢測靜態圖像中的文本。
text_detection_video.py:經過網絡攝像頭或輸入視頻文件檢測文本。
這兩個腳本都使用了序列化的EAST模型(frozen_east_text_detection.pb),以便在「下載」中提供。
實施說明
我今天包含的文本檢測實現基於OpenCV的官方C ++示例;可是,我必須認可在將其轉換爲Python時遇到了一些麻煩。
首先,Python中沒有Point2f和RotatedRect函數,所以,我沒法100%模仿C ++實現。 C ++實現能夠生成旋轉的邊界框,但不幸的是,我今天與你分享的那個不能。
其次,NMSBoxes函數不返回Python綁定的任何值(至少對於個人OpenCV 4預發佈安裝),最終致使OpenCV拋出錯誤。 NMSBoxes函數能夠在OpenCV 3.4.2中工做,但我沒法對其進行詳盡的測試。
我解決了這個問題,我在imutils中使用我本身的非最大值抑制實現,但一樣,我不相信這兩個是100%可互換的,由於看起來NMSBoxes接受其餘參數。
鑑於這一切,我盡力使用個人工做功能和資源爲您提供最好的OpenCV文本檢測實現。若是您對方法有任何改進,請隨時在下面的評論中分享。
使用OpenCV實現咱們的文本檢測器
在咱們開始以前,我想指出您至少須要在系統上安裝OpenCV 3.4.2(或OpenCV 4)才能使用OpenCV的EAST文本檢測器,所以若是您還沒有安裝OpenCV 3.4.2或更高版本在您的系統上,請參閱個人OpenCV安裝指南。
接下來,確保您的系統上還安裝/升級了imutils:
pip install --upgrade imutils
此時您的系統已配置好,所以打開text_detection.py並插入如下代碼:
首先,咱們在第2-6行導入咱們所需的包和模塊。值得注意的是,咱們從imutils.object_detection導入NumPy,OpenCV和個人non_max_suppression實現。
而後咱們繼續解析第9-20行的五個命令行參數:
--image:輸入圖像的路徑。
--east:EAST場景文本檢測器模型文件路徑。
--min-confidence:肯定文本的機率閾值。可選,默認值= 0.5。
--width:調整後的圖像寬度 - 必須是32的倍數。可選,默認值= 320。
--height:調整後的圖像高度 - 必須是32的倍數。可選,默認值= 320。
重要提示:EAST文本要求輸入圖像尺寸爲32的倍數,所以若是您選擇調整--width和--height值,請確保它們是32的倍數!
從那裏,讓咱們加載咱們的圖像並調整它的大小:
在第23和24行,咱們加載並複製輸入圖像。
從那裏,第30行和第31行肯定原始圖像尺寸與新圖像尺寸的比率(基於爲--width和--height提供的命令行參數)。
而後咱們調整圖像大小,忽略縱橫比(第34行)。
爲了使用OpenCV和EAST深度學習模型執行文本檢測,咱們須要提取兩層的輸出特徵映射:
咱們在40-42行構建一個layerNames列表:
第一層是咱們的輸出sigmoid激活,它給出了包含文本或不包含文本的區域的機率。
第二層是表示圖像「幾何」的輸出要素圖 - 咱們將可以使用此幾何來導出輸入圖像中文本的邊界框座標
讓咱們加載OpenCV的EAST文本檢測器:
咱們使用cv2.dnn.readNet將神經網絡加載到內存中,方法是將路徑傳遞給EAST檢測器(包含在咱們的命令行args字典中)做爲第46行的參數。
而後咱們經過將其轉換爲第50行和第51行的blob來準備咱們的圖像。要了解有關此步驟的更多信息,請參閱深度學習:OpenCV的blobFromImage如何工做。
要預測文本,咱們能夠簡單地將blob設置爲輸入並調用net.forward(第53和54行)。這些行被抓取時間戳包圍,以便咱們能夠在第58行打印通過的時間。
經過將layerNames做爲參數提供給net.forward,咱們正在指示OpenCV返回咱們感興趣的兩個特徵映射:
輸出幾何圖用於導出輸入圖像中文本的邊界框座標
相似地,分數圖包含包含文本的給定區域的機率
咱們須要逐個遍歷每一個值:
咱們首先抓住得份量的維度(第63行),而後初始化兩個列表:
rects:存儲文本區域的邊界框(x,y) - 座標
置信度:存儲與rects中每一個邊界框關聯的機率
咱們稍後將對這些區域應用非最大值抑制。
在第68行開始循環。
第72-77行提取當前行的分數和幾何數據y。
接下來,咱們遍歷當前所選行的每一個列索引:
對於每一行,咱們開始循環第80行的列。
咱們須要經過忽略不具備足夠高几率的區域來過濾掉弱文本檢測(第82和83行)。
當文本經過網絡時,EAST文本檢測器天然地減少了體積大小 - 咱們的體積大小實際上比輸入圖像小4倍,因此咱們乘以4使座標回到原始圖像的方向。
我已經介紹瞭如何在第91-93行提取角度數據;可是,正如我在上一節中所提到的,我沒法像在C ++實現中那樣構建一個旋轉的邊界框 - 若是你想要處理任務,從第91行的角度開始將是你的第一個步。
從那裏,第97-105行導出文本區域的邊界框座標。
而後,咱們分別更新咱們的rects和confidences列表(第109和110行)。
咱們差很少完成了!
最後一步是將非最大值抑制應用於咱們的邊界框以抑制弱重疊邊界框,而後顯示結果文本預測:
正如我在上一節中提到的,我沒法在個人OpenCV 4安裝(cv2.dnn.NMSBoxes)中使用非最大值抑制,由於Python綁定沒有返回值,最終致使OpenCV錯誤輸出。我沒法徹底在OpenCV 3.4.2中進行測試,所以它能夠在v3.4.2中運行。
相反,我使用了imutils包中提供的非最大值抑制實現(第114行)。結果仍然很好;可是,我沒法將輸出與NMSBoxes函數進行比較,看看它們是否相同。
第117-126行環繞咱們的邊界框,將座標縮放回原始圖像尺寸,並將輸出繪製到咱們的原始圖像。顯示原始圖像,直到按下一個鍵(第129和130行)。
做爲最後的實現說明,我想提一下,咱們的兩個嵌套for循環用於循環第68-110行的分數和幾何體積,這將是一個很好的例子,你能夠利用Cython來大大加速你的管道。我已經展現了Cython在Fast中的強大功能,使用OpenCV和Python優化了'for'像素循環。
OpenCV文本檢測結果
你準備好對圖像應用文本檢測了嗎?
首先抓住此博客文章的「下載」並解壓縮文件。
從那裏,您能夠在終端中執行如下命令(記下兩個命令行參數):
$ python text_detection.py --image images/lebron_james.jpg \ --east frozen_east_text_detection.pb [INFO] loading EAST text detector... [INFO] text detection took 0.142082 seconds
您的結果應相似於如下圖像:
圖4:着名的籃球運動員,Lebron James的球衣文字經過OpenCV和EAST文本檢測成功識別。
勒布朗詹姆斯肯定了三個文本區域。
如今讓咱們嘗試檢測商業標誌的文字:
$ python text_detection.py --image images/car_wash.png \ --east frozen_east_text_detection.pb [INFO] loading EAST text detector... [INFO] text detection took 0.142295 seconds
圖5:在洗車站的這個天然場景中使用EAST和Python以及OpenCV能夠輕鬆識別文本。
最後,咱們將嘗試一個路標:
$ python text_detection.py --image images/sign.jpg \ --east frozen_east_text_detection.pb [INFO] loading EAST text detector... [INFO] text detection took 0.141675 seconds
圖6:使用Python + OpenCV進行場景文本檢測,EAST文本檢測器成功檢測到此西班牙語中止標誌上的文本。
此場景包含西班牙停車標誌。 OpenCV和EAST正確檢測到「ALTO」這個詞。
正如您所知,EAST很是準確且相對較快,每張圖像的平均時間約爲0.14秒。
使用OpenCV在視頻中進行文本檢測
如今咱們已經看到了如何檢測圖像中的文本,讓咱們繼續使用OpenCV檢測視頻中的文本。
這個解釋很是簡短;有關詳細信息,請參閱上一節。
打開text_detection_video.py並插入如下代碼:
# import the necessary packages from imutils.video import VideoStream from imutils.video import FPS from imutils.object_detection import non_max_suppression import numpy as np import argparse import imutils import time import cv2
咱們首先導入咱們的包。咱們將使用VideoStream訪問網絡攝像頭和FPS以對此腳本的每秒幀數進行基準測試。其餘全部內容與上一節中的相同。
爲方便起見,讓咱們定義一個新函數來解碼咱們的預測函數 - 它將被重用於每一個幀並使咱們的循環更清晰
def decode_predictions(scores, geometry): # grab the number of rows and columns from the scores volume, then # initialize our set of bounding box rectangles and corresponding # confidence scores (numRows, numCols) = scores.shape[2:4] rects = [] confidences = [] # loop over the number of rows for y in range(0, numRows): # extract the scores (probabilities), followed by the # geometrical data used to derive potential bounding box # coordinates that surround text scoresData = scores[0, 0, y] xData0 = geometry[0, 0, y] xData1 = geometry[0, 1, y] xData2 = geometry[0, 2, y] xData3 = geometry[0, 3, y] anglesData = geometry[0, 4, y] # loop over the number of columns for x in range(0, numCols): # if our score does not have sufficient probability, # ignore it if scoresData[x] < args["min_confidence"]: continue # compute the offset factor as our resulting feature # maps will be 4x smaller than the input image (offsetX, offsetY) = (x * 4.0, y * 4.0) # extract the rotation angle for the prediction and # then compute the sin and cosine angle = anglesData[x] cos = np.cos(angle) sin = np.sin(angle) # use the geometry volume to derive the width and height # of the bounding box h = xData0[x] + xData2[x] w = xData1[x] + xData3[x] # compute both the starting and ending (x, y)-coordinates # for the text prediction bounding box endX = int(offsetX + (cos * xData1[x]) + (sin * xData2[x])) endY = int(offsetY - (sin * xData1[x]) + (cos * xData2[x])) startX = int(endX - w) startY = int(endY - h) # add the bounding box coordinates and probability score # to our respective lists rects.append((startX, startY, endX, endY)) confidences.append(scoresData[x]) # return a tuple of the bounding boxes and associated confidences return (rects, confidences)
咱們定義了decode_predictions函數。此函數用於提取:
文本區域的邊界框座標
以及文本區域檢測的機率
這個專用函數將使代碼在之後的腳本中更易於閱讀和管理。
# construct the argument parser and parse the arguments ap = argparse.ArgumentParser() ap.add_argument("-east", "--east", type=str, required=True, help="path to input EAST text detector") ap.add_argument("-v", "--video", type=str, help="path to optinal input video file") ap.add_argument("-c", "--min-confidence", type=float, default=0.5, help="minimum probability required to inspect a region") ap.add_argument("-w", "--width", type=int, default=320, help="resized image width (should be multiple of 32)") ap.add_argument("-e", "--height", type=int, default=320, help="resized image height (should be multiple of 32)") args = vars(ap.parse_args())
咱們的命令行參數解析:
--east:EAST場景文本檢測器模型文件路徑。
--video:輸入視頻的路徑。可選 - 若是提供了視頻路徑,則不會使用網絡攝像頭。
--min-confidence:肯定文本的機率閾值。可選,默認值= 0.5。
--width:調整後的圖像寬度(必須是32的倍數)。可選,默認值= 320。
--height:調整後的圖像高度(必須是32的倍數)。可選,默認值= 320。
上一節中僅使用圖像的腳本(就命令行參數而言)的主要變化是我用--video替換了--image參數。
重要提示:EAST文本要求輸入圖像尺寸爲32的倍數,所以若是您選擇調整--width和--height值,請確保它們是32的倍數!
接下來,咱們將執行模仿前一個腳本的重要初始化:
第84-86行的高度/寬度和比率初始化將容許咱們稍後正確地縮放咱們的邊界框。
定義了輸出層名稱,咱們在第91-97行加載了預訓練的EAST文本檢測器。
如下塊設置咱們的視頻流和每秒幀數計數器:
咱們的視頻流設置爲:
網絡攝像頭(100-103行)
或視頻文件(第106-107行)
從那裏咱們初始化咱們在第110行的每秒幀數,並開始循環傳入幀:
咱們開始在113行的視頻/網絡攝像頭幀上循環。
咱們的框架調整大小,保持縱橫比(第124行)。從那裏,咱們抓住尺寸並計算比例比(第129-132行)。而後咱們再次調整框架的大小(必須是32的倍數),此次忽略縱橫比,由於咱們已經存儲了安全保持的比率(第135行)。
預測和繪圖文本區域邊界框發生在如下行:
在這個塊中咱們:
使用EAST經過建立blob並將其傳遞經過網絡來檢測文本區域(第139-142行)
解碼預測並應用NMS(第146和147行)。咱們使用此腳本中先前定義的decode_predictions函數和個人imutils non_max_suppression便利函數。
環繞邊界框並在框架上繪製它們(第150-159行)。這涉及經過先前收集的比率來縮放框。
從那裏咱們將關閉幀處理循環以及腳本自己:
咱們在循環的每次迭代中更新咱們的fps計數器(第162行),以便在咱們突破循環時計算並顯示計時(第173-175行)。
咱們在165行顯示EAST文本檢測的輸出並處理按鍵(第166-170行)。若是按「q」進行「退出」,咱們就會跳出循環並繼續清理並釋放指針。
視頻文本檢測結果
要使用OpenCV將文本檢測應用於視頻,請務必使用此博客文章的「下載」部分。
從那裏,打開一個終端並執行如下命令(這將啓動你的網絡攝像頭,由於咱們沒有經過命令行參數提供--video):
$ python text_detection_video.py --east frozen_east_text_detection.pb [INFO] loading EAST text detector... [INFO] starting video stream... [INFO] elasped time: 59.76 [INFO] approx. FPS: 8.85
咱們的OpenCV文本檢測視頻腳本可實現7-9 FPS。
這個結果並不像做者報道的那麼快(13 FPS);可是,咱們使用的是Python而不是C ++。經過使用Cython優化for循環,咱們應該可以提升文本檢測管道的速度。
摘要
在今天的博客文章中,咱們學習瞭如何使用OpenCV的新EAST文本檢測器來自動檢測天然場景圖像中是否存在文本。
文本檢測器不只準確,並且可以在720p圖像上以近似實時的速度運行,大約13 FPS。
爲了提供OpenCV的EAST文本檢測器的實現,我須要轉換OpenCV的C ++示例;然而,我遇到了許多挑戰,例如:
沒法使用OpenCV的NMSBox進行非最大值抑制,而是必須使用imutils的實現。
因爲缺乏RotatedRect的Python綁定,沒法計算真正的旋轉邊界框。
我試圖讓個人實現儘量接近OpenCV,但請記住,個人版本與C ++版本沒有100%徹底相同,而且可能會有一兩個小問題須要隨着時間的推移而解決。
不管如何,我但願你喜歡今天的OpenCV文本檢測教程!