ここにアイデアがあります。この問題をいくつかのステップに分けます。
平均的な長方形の輪郭領域を決定します。次に、等高線を検出し、等高線の外接する四角形領域を使用してフィルター処理します。これを行う理由は、典型的な特性は非常に大きくなるだけで、大きなノイズはより大きな長方形の領域に広がるという観察のためです。次に、平均面積を決定します。
大きな外れ値の輪郭を削除します。等高線を繰り返し処理5x
し、等高線を塗りつぶして平均等高線領域よりも大きい場合は、大きい等高線を削除します。固定されたしきい値領域を使用する代わりに、この動的しきい値を使用してロバスト性を高めています。
垂直カーネルで拡張して文字を接続します。このアイデアは、文字が列に配置されているという観察を利用しています。垂直カーネルで拡張することにより、テキストを結合して、ノイズがこの結合された輪郭に含まれないようにします。
小さなノイズを取り除きます。保持するテキストが接続されたので、輪郭を見つけ4x
、平均輪郭領域よりも小さい輪郭を削除します。
ビット単位-および画像を再構成します。マスクを維持するために必要な輪郭のみがあるため、ビット単位でテキストを保持し、結果を取得します。
これはプロセスの視覚化です:
我々大津の閾値バイナリ画像を得るための輪郭を見つける平均矩形の輪郭領域を決定するために。ここから、輪郭を塗りつぶして、緑色で強調表示された大きな外れ値の輪郭を削除します
我々が構築次の垂直カーネルをして拡張文字を接続します。この手順では、保持する必要なすべてのテキストを接続し、ノイズを個々のブロブに分離します。
次に、輪郭を見つけ、輪郭領域を使用してフィルタリングして、小さなノイズを除去します
削除されたすべてのノイズ粒子が緑色で強調表示されています
結果
コード
import cv2
# Load image, grayscale, and Otsu's threshold
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# Determine average contour area
average_area = []
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
x,y,w,h = cv2.boundingRect(c)
area = w * h
average_area.append(area)
average = sum(average_area) / len(average_area)
# Remove large lines if contour area is 5x bigger then average contour area
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
x,y,w,h = cv2.boundingRect(c)
area = w * h
if area > average * 5:
cv2.drawContours(thresh, [c], -1, (0,0,0), -1)
# Dilate with vertical kernel to connect characters
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2,5))
dilate = cv2.dilate(thresh, kernel, iterations=3)
# Remove small noise if contour area is smaller than 4x average
cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
area = cv2.contourArea(c)
if area < average * 4:
cv2.drawContours(dilate, [c], -1, (0,0,0), -1)
# Bitwise mask with input image
result = cv2.bitwise_and(image, image, mask=dilate)
result[dilate==0] = (255,255,255)
cv2.imshow('result', result)
cv2.imshow('dilate', dilate)
cv2.imshow('thresh', thresh)
cv2.waitKey()
注:従来の画像処理は、しきい値処理、モルフォロジー演算、および輪郭フィルタリング(輪郭近似、面積、アスペクト比、またはブロブ検出)に限定されています。入力画像は文字テキストのサイズに基づいて変化する可能性があるため、特異解を見つけることは非常に困難です。動的ソリューションの機械/ディープラーニングを使用して独自の分類子をトレーニングすることを検討したい場合があります。