4

私は現在、作業中のボックスでopenCVにアクセスできません. 'やりたいことは、ピクセルのグループ化の周りのボックスの 4 つのリストのタプルを取得する方法を見つけることです。

元のしきい値画像元のしきい値画像

現在、私はこのコードを使用しています:

box = image.getbbox()
draw = ImageDraw.Draw(area) # Create a draw object
draw.rectangle(area.getbbox(), outline="red")

結果画像結果画像

しかし、私が本当にやりたいのは、上部の白い領域または中央の灰色の領域の周りにボックスを描くことです. これを自動化された関数として書きたいのですが、しきい値がどこにあるのかわからないので、トリミングを避けたいと思います。これは、花火で達成したい状況画像の例です。

新しい夢の結果新しい夢の結果 うまくいけば、それは明らかです!二日寝てない!ポインタやガイダンスは非常に高く評価されています!

4

2 に答える 2

6

このタスクに必要な基本的なツール/値は次のとおりです。

  • 連結成分のラベル付け方法。
  • 接続されたコンポーネントを破棄するか保持するかを決定するためのしきい値。
  • 接続されたコンポーネント間の距離を計算するためのメトリックと、それらを結合するかどうかを決定するためのしきい値 (これは、実際にそのようなことをしたい場合にのみ必要です。これはまだ不明です)。

1 つ目は では使用できませんがPILscipy提供されます。使用したくない場合は、 https://stackoverflow.com/a/14350691/1832154scipyの回答を検討してください。私はその答えでコードを使用し、プレーンリストの代わりに画像を使用するように適応させ、そこにある関数が というモジュールに配置されていると想定しました。3 番目のステップでは、単純なチェス盤の距離を使用しました。PILwu_cclO(n^2)

次に、200 ピクセル未満のコンポーネントを破棄し、100 ピクセルより近いコンポーネントは同じバウンディング ボックスにある必要があることを考慮し、バウンディング ボックスを 10 ピクセルでパディングすると、次のようになります。

ここに画像の説明を入力

最大のものだけを保持するために、コンポーネントのしきい値をより高い値に変更するだけです。また、この画像の前に示した 2 つの手順を逆の順序で実行することもできます。最初に閉じたコンポーネントを結合し、次に破棄します (ただし、これは以下のコードでは実行されません)。

これらは比較的単純なタスクですが、タスクを実行するためにライブラリに依存していないため、コードはそれほど短くありません。以下は、上記のイメージを実現するコードの例です。接続されたコンポーネントのマージは特に大きく、急いで書いたために必要以上に大きなコードになったと思います。

import sys
from collections import defaultdict
from PIL import Image, ImageDraw

from wu_ccl import scan, flatten_label


def borders(img):
    result = img.copy()
    res = result.load()
    im = img.load()
    width, height = img.size

    for x in xrange(1, width - 1):
        for y in xrange(1, height - 1):
            if not im[x, y]: continue
            if im[x, y-1] and im[x, y+1] and im[x-1, y] and im[x+1, y]:
                res[x, y] = 0
    return result

def do_wu_ccl(img):
    label, p = scan(img)
    ncc = flatten_label(p)
    # Relabel.
    l = label.load()
    for x in xrange(width):
        for y in xrange(height):
            if l[x, y]:
                l[x, y] = p[l[x, y]]
    return label, ncc

def calc_dist(a, b):
    dist = float('inf')
    for p1 in a:
        for p2 in b:
            p1p2_chessboard = max(abs(p1[0] - p2[0]), abs(p1[1] - p2[1]))
            if p1p2_chessboard < dist:
                dist = p1p2_chessboard
    return dist


img = Image.open(sys.argv[1]).convert('RGB')
width, height = img.size
# Pad image.
img_padded = Image.new('L', (width + 2, height + 2), 0)
width, height = img_padded.size
# "discard" jpeg artifacts.
img_padded.paste(img.convert('L').point(lambda x: 255 if x > 30 else 0), (1, 1))

# Label the connected components.
label, ncc = do_wu_ccl(img_padded)

# Count number of pixels in each component and discard those too small.
minsize = 200
cc_size = defaultdict(int)
l = label.load()
for x in xrange(width):
    for y in xrange(height):
        cc_size[l[x, y]] += 1
cc_filtered = dict((k, v) for k, v in cc_size.items() if k > 0 and v > minsize)

# Consider only the borders of the remaining components.
result = Image.new('L', img.size)
res = result.load()
im = img_padded.load()
l = label.load()
for x in xrange(1, width - 1):
    for y in xrange(1, height - 1):
        if im[x, y] and l[x, y] in cc_filtered:
            res[x-1, y-1] = l[x, y]
result = borders(result)
width, height = result.size
result.save(sys.argv[2])
# Collect the border points for each of the remainig components.
res = result.load()
cc_points = defaultdict(list)
for x in xrange(width):
    for y in xrange(height):
        if res[x, y]:
            cc_points[res[x, y]].append((x, y))
cc_points_l = list(cc_points.items())

# Perform a dummy O(n^2) method to determine whether two components are close.
grouped_cc = defaultdict(set)
dist_threshold = 100 # pixels
for i in xrange(len(cc_points_l)):
    ki = cc_points_l[i][0]
    grouped_cc[ki].add(ki)
    for j in xrange(i + 1, len(cc_points_l)):
        vi = cc_points_l[i][1]
        vj = cc_points_l[j][1]
        kj = cc_points_l[j][0]
        dist = calc_dist(vi, vj)
        if dist < dist_threshold:
            grouped_cc[ki].add(kj)
            grouped_cc[kj].add(ki)
# Flatten groups.
flat_groups = defaultdict(set)
used = set()
for group, v in grouped_cc.items():
    work = set(v)
    if group in used:
        continue
    while work:
        gi = work.pop()
        if gi in flat_groups[group] or gi in used:
            continue
        used.add(gi)
        flat_groups[group].add(gi)
        new = grouped_cc[gi]
        if not flat_groups[group].issuperset(new):
            work.update(new)

# Draw a bounding box around each group.
draw = ImageDraw.Draw(img)
bpad = 10
for cc in flat_groups.values():
    data = []
    for vi in cc:
        data.extend(cc_points[vi])
    xsort = sorted(data)
    ysort = sorted(data, key=lambda x: x[1])
    # Padded bounding box.
    bbox = (xsort[0][0] - bpad, ysort[0][1] - bpad,
            xsort[-1][0] + bpad, ysort[-1][1] + bpad)
    draw.rectangle(bbox, outline=(0, 255, 0))
img.save(sys.argv[2])

繰り返しますが、関数wu_ccl.scanを調整する必要があります (前述の回答から取得)。そのため'I'には、ネストされた Python リストを使用する代わりに、モードを使用してイメージを作成することを検討してください。また、接続されたコンポーネントの数を返すように少し変更しましflatten_labelた (ただし、この最終的なコードでは実際には使用されていません)。

于 2013-02-13T18:58:46.507 に答える
0

それでも役立つ場合はscipy.ndimage.measurements.label、画像内のブロブを見つけ、境界ボックスを見つけるために使用できる があります。

于 2013-03-07T02:53:53.533 に答える