2017-03-28 15 views
3

私は、正面から透明なボックスを持っています。前面の透明パネルにカメラを配置して、内部の画像をキャプチャします。ほとんどの時間はボックスが空ですが、誰かがこのボックスの中にオブジェクトを置いたとしたら、キャプチャされた画像からこのオブジェクトを抽出するだけです。オブジェクトを持つボックスの画像からオブジェクトを抽出する

(私の本当の目的は、ボックス内に配置されたオブジェクトを認識することですが、最初にオブジェクトを抽出してトレーニングモデルを生成するためのフィーチャを抽出します。 )

私はOpenCVを初めて使っていて、Pythonでそれを使用しています。私はいくつかのOpenCV関数を見つけてくれました。

  • GrabCutが、これは私が、ちょうど オブジェクトを抽出することができるよ、私はオブジェクトの上に長方形をマークすることを提供し、私のために完璧に動作しますが、 オブジェクトとしてのため、そのことはできませんボックス内の任意の場所することができオブジェクトの正確なサイズの矩形 を描画し、方法がある場合は私にお勧めします。
  • 画像の違いは空のキャビティーボックスの画像があり、 オブジェクトが存在すると、画像間で の違いを計算するのにcv2.absdiff関数を使うことができますが、ほとんどが正しく動作しません。 場合によっては、ピクセルごとの差分計算を使用するので、 はこの結果が奇妙であり、光条件の変更もプラス は困難になります。
  • バックグラウンドの減算、私はこれにいくつかの記事を読んで、これは 私は必要なものだと思われるが、私はビデオのためのものだと私はしなかった それはちょうど2つの画像空のボックスとオブジェクトの別のボックス。

は、背景差分のためのコードであっても、それは誰もがこのトピックに助けてくださいすることができ、短い距離

cap = cv2.VideoCapture(0) 
fgbg = cv2.createBackgroundSubtractorMOG2() 
fgbg2 = cv2.createBackgroundSubtractorKNN() 

while True: 
    ret, frame = cap.read() 
    cv2.namedWindow('Real', cv2.WINDOW_NORMAL) 
    cv2.namedWindow('MOG2', cv2.WINDOW_NORMAL) 
    cv2.namedWindow('KNN', cv2.WINDOW_NORMAL) 
    cv2.namedWindow('MOG2_ERODE', cv2.WINDOW_NORMAL) 
    cv2.namedWindow('KNN_ERODE', cv2.WINDOW_NORMAL) 
    cv2.imshow('Real', frame) 
    fgmask = fgbg.apply(frame) 
    fgmask2 = fgbg2.apply(frame) 
    kernel = np.ones((3,3), np.uint8) 
    fgmask_erode = cv2.erode(fgmask,kernel,iterations = 1) 
    fgmask2_erode = cv2.erode(fgmask2,kernel,iterations = 1) 

    cv2.imshow('MOG2',fgmask) 
    cv2.imshow('KNN',fgmask2) 
    cv2.imshow('MOG2_ERODE',fgmask_erode) 
    cv2.imshow('KNN_ERODE',fgmask2_erode) 
    k = cv2.waitKey(30) & 0xff 
    if k == 27: 
     break 
cap.release() 
cv2.destroyAllWindows() 

のためにそれほど正しく動作しない、また、上記の変更方法を、以下の通りであります私は空の画像を取得しようとすると、2つの画像を使用するコード。おかげで、事前にカメラから

サンプル画像は以下の通りです: (私は画像サイズが大きい理由です8MPカメラを使用しています、私はサイズを縮小して、ここでそれをアップロードする)

Empty Box

Object-1

Object-2

+0

GrabCutのパフォーマンスを向上させるには、エッジ検出を実行してボックスのエッジを取得します。あなたが長方形にぴったり合ってGrabCutを実行することができたら、 –

+0

イメージを提供していない場合、どのように人々がイメージ処理タスクを手伝うことを期待していますか? – m3h0w

+0

@JeruLuke:ありがとう、私はいくつかのサンプル画像を更新し、あなたが示唆しているものを試してみます。 –

答えて

4

あなたは減算について言及しましたが、私はこのケースでは最良のアプローチだと考えています。私は、あなたが私たちに提供したケースを処理する非常に単純なアルゴリズムを実装しました。私はコメントでコードを説明しました。画像上では、問題の最も重要なステップ、すなわちアルゴリズムの手がかりを提示します。画像間

差: enter image description here

差分閾値逆: enter image description here

上記組み合わせの両方: enter image description here

結果その1: enter image description here

結果がNO 。2:説明と enter image description here

コード:

import cv2 
import numpy as np 

# load the images 
empty = cv2.imread("empty.jpg") 
full = cv2.imread("full_2.jpg") 

# save color copy for visualization 
full_c = full.copy() 

# convert to grayscale 
empty_g = cv2.cvtColor(empty, cv2.COLOR_BGR2GRAY) 
full_g = cv2.cvtColor(full, cv2.COLOR_BGR2GRAY) 

# blur to account for small camera movement 
# you could try if maybe different values will maybe 
# more reliable for broader cases 
empty_g = cv2.GaussianBlur(empty_g, (41, 41), 0) 
full_g = cv2.GaussianBlur(full_g, (41, 41), 0) 

# get the difference between full and empty box 
diff = full_g - empty_g 
cv2.imwrite("diff.jpg", diff) 

# inverse thresholding to change every pixel above 190 
# to black (that means without the bag) 
_, diff_th = cv2.threshold(diff, 190, 255, 1) 
cv2.imwrite("diff_th.jpg", diff_th) 

# combine the difference image and the inverse threshold 
# will give us just the bag 
bag = cv2.bitwise_and(diff, diff_th, None) 
cv2.imwrite("just_the_bag.jpg", bag) 

# threshold to get the mask instead of gray pixels 
_, bag = cv2.threshold(bag, 100, 255, 0) 

# dilate to account for the blurring in the beginning 
kernel = np.ones((15, 15), np.uint8) 
bag = cv2.dilate(bag, kernel, iterations=1) 

# find contours, sort and draw the biggest one 
_, contours, _ = cv2.findContours(bag, cv2.RETR_TREE, 
            cv2.CHAIN_APPROX_SIMPLE) 
contours = sorted(contours, key=cv2.contourArea, reverse=True)[:3] 
cv2.drawContours(full_c, [contours[0]], -1, (0, 255, 0), 3) 

# show and save the result 
cv2.imshow("bag", full_c) 
cv2.imwrite("result2.jpg", full_c) 
cv2.waitKey(0) 

さて、もちろんアルゴリズムを向上させることができ、あなたが対処する必要がありますどのような条件に調整する必要があります。たとえば、ライティングの違いについて言及しました。これを処理して、減算された画像の背景が似ていることを確認する必要があります。これを行うには、おそらく、いくつかのコントラスト向上アルゴリズムを見なければならないかもしれません。もしカメラが動くなら、それは全く別の問題かもしれません。

私は、JeruLukeが私のアプローチで見つけた輪郭の境界矩形で言及したGrabCutも考慮する。オブジェクトがその中に含まれていることを確認するには、矩形を展開するだけです。

+0

これで、空のボックスを参照画像として使用しました。ニース!!! @ m3h0w –

2

私が代わりにラフなソリューションを持っています。あなたはそれをさらに欲しがる場合に備えて、あなたのニーズに合わせてそれを洗練しなければなりません。私はそれらをより作るためにエッジを膨張

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) #---convert image to gray--- 
blur = cv2.GaussianBlur(gray, (5, 5), 0) #---blurred the image--- 
edges = cv2.Canny(blur, lower, upper) #---how to find perfect edges see link below--- 

enter image description here

enter image description here

まず、私はエッジを行うには、グレースケール画像のぼやけたバージョンにcv2.Canny()を用い検出しました表示:

kernel = np.ones((3, 3), np.uint8) 
dilated = cv2.morphologyEx(edges, cv2.MORPH_DILATE, kernel) 

次に、エッジ検出画像に存在する輪郭が見つかりました。

_, contours, hierarchy = cv2.findContours(king, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) 

私だけ

は、その後、私は輪郭がその周りにバウンディングボックスを置くA最大の面積を持つ見つけ外側輪郭を取得するためにcv2.RETR_EXTERNALを使用。

enter image description here

enter image description here

今、私はセグメントにお弁当をGrabCutアルゴリズムを使用。

enter image description here:そうするために、私はGrabCutアルゴリズム

最終出力のための入力として輪郭を発見した後、私が得た境界の矩形の座標を使用し、私はTHIS LINK HERE

から必要なすべての助けを得ました

enter image description here

は、あなたが見ることができるように、それは完璧ではないが、これは私が得ることができる最善の方法です。

希望します。あなたがより良い解決策を得たら投稿してください! :D

+0

私は投稿した回答を見てください。/questions/18194870/canny-edge-image-noise-removal/42344599#42344599) –

+0

ニース!私は "弱点"が "最大の輪郭検出"にあると感じます。オブジェクトの輪郭がCannyの検出によって閉じられない場合、最大の輪郭は箱の輪郭の1つになる可能性があります。たぶんあなたのオブジェクトが決して "ボックスカラー"でない場合、あなたはまた、カラーセグメンテーションのためにcountourを検出するために行くことができますか? Canny + findContourが失敗した場合でも、これはおそらくかなり騒がしく、最大の輪郭を選択する必要がありますが、別のアプローチになる可能性があります。 – Soltius

+0

@ソルティウス私も同じことを考えました。この場合、K-Meansクラスタリングが役立ちます。バックグラウンドは一定であるので、適応閾値も考えました。 –

関連する問題