3

スキャンした画像の黒いノイズのある境界線を自動的に検出して切り取るコードを書いています。私のアルゴリズムは2つの変数に基づいています:灰色の平均値(行/列のピクセルの)と位置(画像の行/列の)。

グレー
平均値画像はグレースケールです。これは、任意のピクセルのグレー値が0(黒)から255(白)の範囲であることを意味します。
ピクセルの各行/列について、その行/列のすべてのピクセルの平均グレー値を推定します。
結果が暗い場合、現在の行/列は切り取られる境界線の一部です。

位置
位置は、画像の左上隅からの行/列のピクセル単位の距離です。

より良いアイデアについては、次の画像をご覧ください。
スキャンした画像のサムネイル:
スキャンした画像のサムネイル
結果のチャート:
結果の文字

チャートを見ると、次のルールにより、トリミングポイントがどこにあるかを推定するのは非常に簡単です。ほとんどのサンプルは、実際の紙である白い狭い範囲(150〜200)にあり、次にテールにあります。暗い値にすばやく変更されます。
これらの迅速な変更はトリミングポイントです(テールの実際の端では、数ピクセルの場合でも白が残る可能性がありますが、これはめったに発生しません)。

自動的にやりたいのですが、役立つ統計はありますか?
PS:私はコンピューターエンジニアです。統計を調べましたが...何年も前です!!

最良のシナリオでは、コードは黒枠の問題の影響を受けたスキャン画像で機能するはずですが、実際には、次のサンプルで機能するように満足しています:
https ://docs.google.com/folder/ d /0B8ubCWBwsuOON3d1VVo4Z1AxWDA/編集

4

1 に答える 1

4

画像を前処理すると、統計が簡単になります。あなたの場合、幅の広い水平線とそれに続く大津しきい値(統計的に最適)による形態学的クロージングにより、タスクがはるかに簡単になります。形態学的な開口部はここで興味深いものです。なぜなら、は特に紙の領域をはるかに軽くするからです。境界領域がぼやけている2つの例があります。つまり、明るい部分も含まれていますが、この手順が役に立たないわけではありません。その後は、列ごとと行ごとに合計し、平均と標準偏差に基づいて境界線を区切るだけです。値が以下の場合mean - x*stddev、それからそれは紙の外にあります。このようにして、画像のトリミングに使用する用紙の左上隅と右下隅を定義できます。このようなコーナーを定義する最も簡単な方法は、見つかった合計を前後に直線的にトラバースし、以前の条件が満たされないときに停止することです。

あなたの画像でxは、[-1.5、-1]の範囲で機能します(他の画像も同様に、私はそのあたりでテストしました)。クロージングオペレーターの横線のサイズを101ポイントに固定しました。結果は次のとおりです(比較のために必要な場合は、コーナー座標を含めることができます)。

ここに画像の説明を入力してください ここに画像の説明を入力してください

ここに画像の説明を入力してください ここに画像の説明を入力してください

問題は、指摘されているように、これらの画像の一部には、次の場合(紙に接続されている)のように白い境界線も含まれていることです。これを処理するには、画像がバイナリになった後、コンポーネントを切断することを期待して、形態学的な開口部を適用することを検討してください。大きな構造要素を使用できます。私は51x51のサイズのいずれかを使用しましたが、これは画像のサイズとしてはそれほど大きくありません。主な制限は、使用しているライブラリの実装です。実装が悪い場合は遅くなる可能性があります(特に、scipyには高速な実装がありません)。その後、最大のコンポーネントのみを保持し、通常どおりに続行します。

ここに画像の説明を入力してください ここに画像の説明を入力してください

サンプルコード:

import sys
import numpy
import cv2 as cv
from PIL import Image, ImageOps, ImageDraw
from scipy.ndimage import morphology, label


img = ImageOps.grayscale(Image.open(sys.argv[1]))
im = numpy.array(img, dtype=numpy.uint8)

im = morphology.grey_closing(img, (1, 101))
t, im = cv.threshold(im, 0, 1, cv.THRESH_OTSU)

# "Clean noise".
im = morphology.grey_opening(im, (51, 51))
# Keep largest component.
lbl, ncc = label(im)
largest = 0, 0
for i in range(1, ncc + 1):
    size = len(numpy.where(lbl == i)[0])
    if size > largest[1]:
        largest = i, size
for i in range(1, ncc + 1):
    if i == largest[0]:
        continue
    im[lbl == i] = 0


col_sum = numpy.sum(im, axis=0)
row_sum = numpy.sum(im, axis=1)
col_mean, col_std = col_sum.mean(), col_sum.std()
row_mean, row_std = row_sum.mean(), row_sum.std()

row_standard = (row_sum - row_mean) / row_std
col_standard = (col_sum - col_mean) / col_std

def end_points(s, std_below_mean=-1.5):
    i, j = 0, len(s) - 1
    for i, rs in enumerate(s):
        if rs > std_below_mean:
            break
    for j in xrange(len(s) - 1, i, -1):
        if s[j] > std_below_mean:
            break
    return (i, j)

# Bounding rectangle.
x1, x2 = end_points(col_standard)
y1, y2 = end_points(row_standard)

#img.crop((x1, y1, x2, y2)).save(sys.argv[2]) # Crop.
result = img.convert('RGB')
draw = ImageDraw.Draw(result)
draw.line((x1, y1, x2, y1, x2, y2, x1, y2, x1, y1),
        fill=(0, 255, 255), width=15)
result.save(sys.argv[2]) # Save with the bounding rectangle.
于 2013-01-13T05:27:13.443 に答える