web-dev-qa-db-ja.com

OCRのクリーニング画像

OCRの画像をクリアしようとしています:(行)

enter image description here

時々画像をさらに処理するためにこれらの行を削除する必要があり、かなり近づいていますが、多くの場合、しきい値がテキストから取りすぎています。

    copy = img.copy()
    blur = cv2.GaussianBlur(copy, (9,9), 0)
    thresh = cv2.adaptiveThreshold(blur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,11,30)

    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9))
    dilate = cv2.dilate(thresh, kernel, iterations=2)

    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 > 300:
            x,y,w,h = cv2.boundingRect(c)
            cv2.rectangle(copy, (x, y), (x + w, y + h), (36,255,12), 3)

編集:さらに、フォントが変更された場合、定数を使用しても機能しません。これを行う一般的な方法はありますか?

9
K41F4r

ここにアイデアがあります。この問題をいくつかのステップに分けます。

  1. 平均長方形の輪郭領域を決定します。次に、輪郭を検出し、の境界長方形領域を使用して輪郭をフィルタリングします。輪郭。これを行う理由は、一般的な特性は非常に大きくなるのに対して、大きなノイズはより大きな長方形の領域に広がるという観察のためです。次に、平均面積を決定します。

  2. 大きな外れ値の等高線を削除します。等高線を繰り返し処理し、塗りつぶして平均等高線領域より大きい5xの場合は、大きな等高線を削除します輪郭。固定されたしきい値領域を使用する代わりに、この動的しきい値を使用してロバスト性を高めています。

  3. 垂直カーネルで拡張して文字を接続します。このアイデアは、文字が列に配置されているという観察を利用しています。垂直カーネルで拡張することにより、テキストを結合して、ノイズがこの結合された輪郭に含まれないようにします。

  4. 小さなノイズを取り除きます。保持するテキストが接続されたので、コンターを見つけ、平均コンター領域4xより小さいコンターをすべて削除します。

  5. ビット単位で画像を再構成します。マスクを維持するために必要な輪郭のみがあるため、ビット単位でテキストを保持し、結果を取得します。


これはプロセスの視覚化です:

大津のしきい値 バイナリイメージを取得するには、次に 輪郭を見つける を使用して、平均的な長方形の輪郭領域を決定します。ここから、緑色で強調表示されている大きな外れ値の輪郭を filling contours で削除します。

enter image description hereenter image description here

次に、文字を接続するために vertical kernel および dilate を作成します。この手順では、保持する必要なすべてのテキストを接続し、ノイズを個々のブロブに分離します。

enter image description here

次に、輪郭を見つけて、 輪郭領域 を使用してフィルタリングし、小さなノイズを削除します

enter image description here

削除されたすべてのノイズ粒子が緑色で強調表示されています

enter image description here

結果

enter image description here

コード

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()

注:従来の画像処理は、しきい値処理、モルフォロジー演算、および輪郭フィルタリング(輪郭近似、面積、アスペクト比、またはブロブ検出)に制限されています。入力画像は文字テキストのサイズに基づいて変化する可能性があるため、特異解を見つけることは非常に困難です。動的ソリューションの機械/ディープラーニングを使用して独自の分類子をトレーニングすることを検討したい場合があります。

14
nathancy