web-dev-qa-db-ja.com

テキスト画像が上下逆になっているかどうかを検出する

私は数百枚の画像(スキャンしたドキュメント)を持っていますが、それらのほとんどは歪んでいます。 Pythonを使用してそれらを歪めたいと思っていました。
これが私が使用したコードです:

import numpy as np
import cv2

from skimage.transform import radon


filename = 'path_to_filename'
# Load file, converting to grayscale
img = cv2.imread(filename)
I = cv2.cvtColor(img, COLOR_BGR2GRAY)
h, w = I.shape
# If the resolution is high, resize the image to reduce processing time.
if (w > 640):
    I = cv2.resize(I, (640, int((h / w) * 640)))
I = I - np.mean(I)  # Demean; make the brightness extend above and below zero
# Do the radon transform
sinogram = radon(I)
# Find the RMS value of each row and find "busiest" rotation,
# where the transform is lined up perfectly with the alternating dark
# text and white lines
r = np.array([np.sqrt(np.mean(np.abs(line) ** 2)) for line in sinogram.transpose()])
rotation = np.argmax(r)
print('Rotation: {:.2f} degrees'.format(90 - rotation))

# Rotate and save with the original resolution
M = cv2.getRotationMatrix2D((w/2,h/2),90 - rotation,1)
dst = cv2.warpAffine(img,M,(w,h))
cv2.imwrite('rotated.jpg', dst)

このコードは、いくつかの角度を除いて、ほとんどのドキュメントでうまく機能します:(180と0)と(90と270)は同じ角度として検出されることがよくあります(つまり、(180と0)と(90と270))。だから私は多くの逆さまの文書を受け取ります。

次に例を示します。
enter image description here

私が得る結果の画像は、入力画像と同じです。

OpencvとPythonを使用して画像が上下逆になっているかどうかを検出するための提案はありますか?
PS:EXIFデータを使用して方向を確認しようとしましたが、解決策はありませんでした。


編集:
Tesseract(Pythonの場合はpytesseract)を使用して向きを検出できますが、画像に多くの文字が含まれている場合にのみ可能です。
これを必要とする可能性のある人のために:

import cv2
import pytesseract


print(pytesseract.image_to_osd(cv2.imread(file_name)))

ドキュメントに十分な文字が含まれている場合、Tesseractが方向を検出する可能性があります。ただし、画像に線が少ない場合、Tesseractによって提案される方向角度は通常間違っています。したがって、これは100%のソリューションにはなりません。

36
singrium

Python3/OpenCV4スクリプト スキャンしたドキュメントを揃えます。

ドキュメントを回転し、行を合計します。ドキュメントの回転角度が0度と180度の場合、画像には多くの黒いピクセルが含まれます。

rotate to find maximum zebra

スコアを維持する方法を使用します。ゼブラパターンに似ているため、各画像にスコアを付けます。最高のスコアの画像は正しい回転をしています。リンクした画像は0.5度ずれていました。読みやすくするために一部の関数を省略しました。完全なコードは ここにあります です。

# Rotate the image around in a circle
angle = 0
while angle <= 360:
    # Rotate the source image
    img = rotate(src, angle)    
    # Crop the center 1/3rd of the image (roi is filled with text)
    h,w = img.shape
    buffer = min(h, w) - int(min(h,w)/1.15)
    roi = img[int(h/2-buffer):int(h/2+buffer), int(w/2-buffer):int(w/2+buffer)]
    # Create background to draw transform on
    bg = np.zeros((buffer*2, buffer*2), np.uint8)
    # Compute the sums of the rows
    row_sums = sum_rows(roi)
    # High score --> Zebra stripes
    score = np.count_nonzero(row_sums)
    scores.append(score)
    # Image has best rotation
    if score <= min(scores):
        # Save the rotatied image
        print('found optimal rotation')
        best_rotation = img.copy()
    k = display_data(roi, row_sums, buffer)
    if k == 27: break
    # Increment angle and try again
    angle += .75
cv2.destroyAllWindows()

best rotation

文書が上下逆になっているかどうかを確認するにはどうすればよいですか?ドキュメントの上部から画像内の最初の黒以外のピクセルまでの領域を塗りつぶします。黄色で面積を測定します。最小面積の画像は、右側が上になる画像になります。

rightside upupside down

# Find the area from the top of page to top of image
_, bg = area_to_top_of_text(best_rotation.copy())
right_side_up = sum(sum(bg))
# Flip image and try again
best_rotation_flipped = rotate(best_rotation, 180)
_, bg = area_to_top_of_text(best_rotation_flipped.copy())
upside_down = sum(sum(bg))
# Check which area is larger
if right_side_up < upside_down: aligned_image = best_rotation
else: aligned_image = best_rotation_flipped
# Save aligned image
cv2.imwrite('/home/stephen/Desktop/best_rotation.png', 255-aligned_image)
cv2.destroyAllWindows()
24
Stephen Meschke

画像で既に角度補正を実行したと仮定すると、次のようにして、画像が反転しているかどうかを確認できます。

  1. 補正された画像をy軸に投影して、各線の「ピーク」を取得します。重要:実際にはほとんど常に2つのサブピークがあります!
  2. 細かい構造やノイズなどを取り除くために、ガウスとのたたみ込みによってこの投影をスムーズにします。
  3. 各ピークについて、より強いサブピークが上または下にあるかどうかを確認します。
  4. 下側にサブピークがあるピークの割合を計算します。これは、画像が正しく方向付けられているという確信を与えるスカラー値です。

ステップ3でのピークの検出は、平均値を超えるセクションを検出することによって行われます。次に、サブピークはargmaxを介して検出されます。

これは、アプローチを説明する図です。あなたの数行のサンプル画像

  • 青:オリジナルの投影
  • オレンジ:滑らかな投影
  • 水平線:画像全体の平滑化された投影の平均。

bla

これを行うコードは次のとおりです。

import cv2
import numpy as np

# load image, convert to grayscale, threshold it at 127 and invert.
page = cv2.imread('Page.jpg')
page = cv2.cvtColor(page, cv2.COLOR_BGR2GRAY)
page = cv2.threshold(page, 127, 255, cv2.THRESH_BINARY_INV)[1]

# project the page to the side and smooth it with a gaussian
projection = np.sum(page, 1)
gaussian_filter = np.exp(-(np.arange(-3, 3, 0.1)**2))
gaussian_filter /= np.sum(gaussian_filter)
smooth = np.convolve(projection, gaussian_filter)

# find the pixel values where we expect lines to start and end
mask = smooth > np.average(smooth)
edges = np.convolve(mask, [1, -1])
line_starts = np.where(edges == 1)[0]
line_endings = np.where(edges == -1)[0]

# count lines with peaks on the lower side
lower_peaks = 0
for start, end in Zip(line_starts, line_endings):
    line = smooth[start:end]
    if np.argmax(line) < len(line)/2:
        lower_peaks += 1

print(lower_peaks / len(line_starts))

これは指定された画像に対して0.125を印刷するため、これは正しい方向を向いておらず、反転する必要があります。

このアプローチは、画像または画像内に整理されていないもの(数学や画像など)がある場合、うまく機能しない可能性があることに注意してください。もう1つの問題は、行が少なすぎて、統計が不良になることです。

また、フォントが異なると、ディストリビューションも異なる可能性があります。いくつかの画像でこれを試して、アプローチが機能するかどうかを確認できます。データが足りません。

6
Obay

Alyn モジュールを使用できます。それをインストールするには:

pip install alyn

次に、画像をデスキューするために使用します(ホームページから取得):

from alyn import Deskew
d = Deskew(
    input_file='path_to_file',
    display_image='preview the image on screen',
    output_file='path_for_deskewed image',
    r_angle='offest_angle_in_degrees_to_control_orientation')`
d.run()

Alynはテキストのデスキュー専用です。

1
Xilpex