2017-08-08 17 views
1

私はPythonとOpenCVを使ってスクリプトを開発し、スキャンされた計装図上のハイライトされた領域を検出し、TesseractのOCR関数を使ってテキストを出力しようとしています。私のワークフローではまず関心領域の一般的な周辺を検出し、処理ブロックを適用してテキストのブロック(線、枠線、ノイズ)以外のすべてを削除します。処理された画像は、TesseractのOCRエンジンに送られます。円の枠の内側からテキストを抽出する

このワークフローはイメージの約半分で動作しますが、残りのテキストは境界線に触れるために残ります。

ステップ1:InRangeを使用してハイライトの色範囲でマスクを作成し、関心領域を見つけます。

手順2:関心のある輪郭を描き、切り抜き、ファイルに保存します。

---参考コードは---ここで始まる

ステップ3:閾値画像とキャニーエッジ検出を適用

ステップ4:エッジを輪郭と、cv2.approxPolyDPを使用して見て円形の形状にそれらをフィルタリングします頂点が8より大きい頂点で実行されます。第1または第2の最大の輪郭を取ることは、通常、内側のエッジに対応します。

ステップ5:マスクとビット単位の操作を使用して、輪郭内のすべてが白い背景イメージに転送されます。画像をノイズ除去し、OCRエンジンに供給される最終的な画像を作成するために、膨張および侵食が適用される。

import cv2 
import numpy as np 
import pytesseract 
pytesseract.pytesseract.tesseract_cmd = 'C:/Program Files (x86)/Tesseract-OCR/tesseract' 

d_path = "Test images\\" 

img_name = "cropped_12.jpg" 

img = cv2.imread(d_path + img_name) # Reads the image 

## Resize image before calculating contour 
height, width = img.shape[:2] 
img = cv2.resize(img,(2*width,2*height),interpolation = cv2.INTER_CUBIC) 

img_orig = img.copy()   # Makes copy of original image 

img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # Convert to grayscale 

# Apply threshold to get binary image and write to file 
_, img = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU) 


# Edge detection 
edges = cv2.Canny(img,100,200) 

# Find contours of mask threshold 
_, contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) 

# Find contours associated w/ polygons with 8 sides or more 
cnt_list = [] 
area_list = [cv2.contourArea(c) for c in contours] 
for j in contours: 
    poly_pts = cv2.approxPolyDP(j,0.01*cv2.arcLength(j,True),True) 
    area = cv2.contourArea(j) 
    if (len(poly_pts) > 8) & (area == max(area_list)): 
     cnt_list.append(j) 

cv2.drawContours(img_orig, cnt_list, -1, (255,0,0), 2) 

# Show contours 
cv2.namedWindow('Show',cv2.WINDOW_NORMAL) 
cv2.imshow("Show",img_orig) 
cv2.waitKey() 
cv2.destroyAllWindows() 

# Zero pixels outside circle 
mask = np.zeros(img.shape).astype(img.dtype) 
cv2.fillPoly(mask, cnt_list, (255,255,255)) 
mask_inv = cv2.bitwise_not(mask) 

a = cv2.bitwise_and(img,img,mask = mask) 
wh_back = np.ones(img.shape).astype(img.dtype)*255 
b = cv2.bitwise_and(wh_back,wh_back,mask = mask_inv) 

res = cv2.add(a,b) 

# Get rid of noise 
kernel = np.ones((2, 2), np.uint8) 
res = cv2.dilate(res, kernel, iterations=1) 
res = cv2.erode(res, kernel, iterations=1) 

# Show final image 
cv2.namedWindow('result',cv2.WINDOW_NORMAL) 
cv2.imshow("result",res) 
cv2.waitKey() 
cv2.destroyAllWindows() 

コードが動作する場合、これらは、出力取得画像である: Working

しかし、テキストは円形の境界に触れる場合において、テキストのコード前提部分が大きいの一部であります最後の文字は無視されます。例: Not working

この問題を回避するための処理手順はありますか?それとも別のアプローチですか?私は境界線を検出しようとするためにハフ・サークル・トランスフォームを使用しようとしましたが、かなり複雑で、輪郭線として機能しません。

私はOpenCVとPythonにはかなり新しいので、どんな助けにも感謝します。

答えて

0

ハフ・サークル・トランスフォームがうまく行かなかった場合は、ボーダーシェイプを近似することをお勧めします。私が知っている最善の方法は、ダグラス・ピーッカー(Douglas-Peucker)のアルゴリズムで、写真の周囲を減らして輪郭を単純化する方法です。

この参照ファイルをOpenCVからチェックすると、あなたのボーダーに適用できる後処理のタイプを確認できます。彼らはまた、ダグラス・ピーッカーを言及している: OpenCV boarder processing

+0

Douglas-Peuckerアルゴリズムのパラメータで再生すると、元の結果が出力されるか、結果が出力されません。しかし、境界線の形状を近似する最も簡単な方法は、輪郭にcv2.minEnclosingCircle()関数を使用することでした。 –

+0

ダグラス・ピーッカーがこのユースケースに限定されている理由を知りましたか? – hackela

0

ちょうどハンチング。 OTSUしきい値処理後。腐ってイメージを広げる。これにより、非常に薄い接合部が消失する。同じコードは以下の通りです。

kernel = np.ones((5,5),np.uint8) 
th3 = cv2.erode(th3, kernel,iterations=1) 
th3 = cv2.dilate(th3, kernel,iterations=1) 

どうすればいいか教えてください。これがうまくいかない場合、私はカップル以上のアイデアを持っています。

+0

これまでのところ、この特定の画像には形態学的操作が行われていません。 Bを円に結ぶジョイントは、文字よりも比較的厚い。画像を単に壊すだけでも、ジョイント自体の手前の文字が分割されます。 –

関連する問題