質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.99%

  • Python

    5565questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • OpenCV

    831questions

    OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

PythonとOpenCVを用いて物体を白色で抽出したい

解決済

回答 1

投稿

  • 評価
  • クリップ 3
  • VIEW 361

takekoko

score 7

前提・実現したいこと

最近、趣味でプログラミングを始めました。
PythonとOpenCVを用いて何も映っていない背景と物体を映した前景で差分をとり、物体だけを白色で抽出したいです。

発生している問題

しかし、背景や物体の色によって物体の色が黒になってしまうことがあり、うまくいきません。

diff = cv2.absdiff(pic,gray)


この命令でうまく物体だけを抽出できるかなと思い、使ってみたのですが、2値化するときの閾値によって色が変化してしまい、黒くなってしまうことが多々あります。

<<画像>>
これは手のみで、色のおかげか白で抽出できています。
イメージ説明

服の白い部分の一部と影になっている部分が黒くなっているのがわかると思います。
イメージ説明

該当のソースコード

#coding:utf-8

import os.path
import numpy as np
import cv2

cam = cv2.VideoCapture(0)
cam.set(3, 960)          #width
cam.set(4, 540)          #heigh
cam.set(5,25)            #fps

while True:
        ret2,image = cam.read()

        Key = cv2.waitKey(10)
        if Key == 32:                     #space
                cv2.imwrite("base.png",image)

        if os.path.isfile("base.png"):
                pic = cv2.imread('base.png',cv2.IMREAD_GRAYSCALE)               #読み込み
                gray = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)                   #現在
                diff = cv2.absdiff(pic,gray)                                    #比較画像生成
                diff2 = cv2.medianBlur(diff,ksize=3)                            #ブラー
                twoc = cv2.threshold(diff2,40,255,cv2.THRESH_BINARY)[1]         #2値化
                cv2.imshow("base",diff)
                cv2.imshow("image",diff2)
                cv2.imshow("result",twoc)
        else:
                cv2.imwrite("base.png",image)

        if Key == 27:      #Esc
                break
cv2.destroyAllWindows()

質問項目

  1. この方法、考え方で目的は達成できるのか
  2. もっと効率的だったり、簡単な方法はないのか
  3. その他、このプログラムにおかしいところはないか

最近始めたばかりで、おかしなところが多くあると思いますが、回答よろしくお願い致します。

補足情報(言語/FW/ツール等のバージョンなど)

Raspberry Pi 3
Python 2.7.9
OpenCV 3.1.0

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+3

この回答は、この方針のまま改良する手段に関するものです。


隙間を埋めたいというなら、典型的にはクロージング処理を行うのかと思います。
OpenCV-Pythonチュートリアル >> OpenCVを使った画像処理 >> モルフォロジー変換

クロージング処理はオープニング処理の逆の処理を指し, 膨張の後に収縮 をする処理です.前景領域中の小さな(黒い)穴を埋めるのに役立ちます

カーネルサイズなどを実際の状況に応じて調整する必要があります。
適当にコードを書いてみました。

#coding:utf-8

import os.path
import numpy as np
import cv2

cam = cv2.VideoCapture(0)
cam.set(cv2.CAP_PROP_FPS, 25)

BASE_FILE_NAME = 'base.png'
if os.path.isfile(BASE_FILE_NAME):
    base = cv2.imread(BASE_FILE_NAME, cv2.IMREAD_GRAYSCALE)
else:
    _, base = cam.read()
    cv2.imwrite(BASE_FILE_NAME, base)

while True:
    _, image = cam.read()

    key = cv2.waitKey(10)
    if key == 27:  #Esc
        break
    if key == 32:  #space
        cv2.imwrite(BASE_FILE_NAME, image)
        base = cv2.imread(BASE_FILE_NAME, cv2.IMREAD_GRAYSCALE)

    gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)          
    result = cv2.absdiff(base, gray)                                 
    result = cv2.medianBlur(result, ksize=3)                 
    _, result = cv2.threshold(result, *(40, 255), cv2.THRESH_BINARY)    

    # ノイズ除去(closing)
    result = cv2.morphologyEx(result, cv2.MORPH_CLOSE, kernel=np.ones((5,5),np.uint8))

    cv2.imshow('base', base)
    cv2.imshow('image', image)
    cv2.imshow('result', result)

cv2.destroyAllWindows()

書き換えた点は、次の通りです。
・言うまでもないですが、ノイズ除去の処理を追加しています。
・base.pngの読み取りを一回に抑えています。毎回所在を確認するのは無駄です。
・(おそらく)camのフレームサイズを指定する必要はありません。
・その他、適当に変数の数を減らす工夫をしています。

実はPython2.7の環境にOpenCVを落とすのが面倒で、Python3.xでコーディングしています。
おそらく2.7でも問題なく動作すると思いますが、もし違ったらごめんなさいね。

あと、改善できるとしたら二値化の手法でしょう。
いろいろな手法が使えますので、試してみてください。
こちらが参考になるかと思います。Python版ではないですが、基本は一緒です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/09 23:18

    返信遅れて申し訳ないです。
    プログラムとご指摘ありがとうございます。
    これを参考にいろいろ試してみたいと思います。
    申し訳ないのですが、いろいろな考え方を参考にしたいので、もう少しベストアンサーを先延ばしにさせてください。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.99%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Python

    5565questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • OpenCV

    831questions

    OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。