生産技術者サラリーマンの日々

社畜サラリーマンが生産技術やお金の悩みを徒然と書くブログです。私の備忘録が共有できるとうれしいです

【PYTHON +OPENCV】物体検出の基礎 背景差分を実装する

画像処理

1.やりたいこと

以前、対象の物体抽出を色特徴量を使って対象物体の抽出を行った。

inusan0424.hatenablog.com

色情報以外にも、対象物体を抽出する方法として背景差分をやってみました。色抽出と組み合わせて対象領域を絞りこみやすくなります。

2.画像処理の方法

2.1 背景差分

 背景差分は、移動物体を検出/抽出する方法として有名な方法のひとつです。特に定点(固定)カメラでよく用いられています。
具体的な方法として、背景画像を事前に用意しておき、検出したい画像と差分(引き算)し、その差分値が閾値以上であれば、移動物体として検出できます。

 今回の実装では画像処理の結果としては、二値化処理とするので今回の場合であれば、移動物体を白画素(255)とし、それ以外(背景)を黒画素(0)としています。

OPENCVチュートリアルを参考にしました。
他にも高度な背景差分があるようですが、まずは基本からやってみます。

labs.eecs.tottori-u.ac.jp

2.2 ノイズ処理

 背景差分の結果、抜き出したい領域(白画素)とした場合、完全には吹き出せず、白い点々が点在する。これらは以降の画像処理で不要な情報となるため、背景差分による二値化処理にはノイズ処理を実施する必要があります。今回は、基本的な処理として、収縮膨張処理を行い、これらノイズ処理を実施していきます。

収縮

収縮(contraction)とは、注目している画素を中心として、その近傍(今回の例だと、縦3画素、横3画素)の中で、黒画素(0)がひとつでもあれば、注目画素を黒画素にする。逆に、注目画素の近傍すべて白画素であれば、注目画素は白画素(255)とする

#カーネルの設定(7×7ピクセルの近傍処理用)
kernel = np.ones((7, 7), np.uint8)
#収縮処理
mask = cv2.erode(mask, kernel)

膨張

膨張(dilation)とは、収縮の逆で、注目している画素を中心として、その近傍(今回の例だと、縦3画素、横3画素)の中で、白画素(255)がひとつでもあれば、注目画素を白画(255)にする。逆に、注目画素の近傍に白がひとつもなけえれば、注目画素を黒画素(0)にする。

#カーネルの設定(7×7ピクセルの近傍処理用)
kernel = np.ones((7, 7), np.uint8)
#膨張処理
mask = cv2.dilate(mask, kernel)

こちらのサイト様を参考にさせて頂きました。
図が色々とあって直観的にわかりやすいです。

imagingsolution.net

3.実装してみる

今回は、ゴーストさんを抽出してみます。
抽出結果は末尾に添付していますが、微妙な感じです。
もう少し、いろいろと前処理が必要な感じがします。

入力画像
入力画像
import numpy as np
import cv2

def ExImg(mask, input,output):
	h = mask.shape[0] #画像の縦画素数を取得
	w = mask.shape[1] #画像の横画素数を取得

	for j in range(h):
		for i in range(w):
			if mask[j,i] == 255:                    #画素に白があったら
				output[j,i,0] = input[j,i,0]   #入力画像のR値を格納
				output[j,i,1] = input[j,i,1] #入力画像のG値を格納
				output[j,i,2] = input[j,i,2] #入力画像のB値を格納
			else:
				output[j,i,0] = 255
				output[j,i,1] = 255
				output[j,i,2] = 255

def BackGroundDetect():
	kernel = np.ones((7, 7), np.uint8)  #カーネルの指示
        th = 40               #背景差分の閾値を40ピクセルとする
	imgIn = cv2.imread("input.jpg")  #入力画像の読み込み
	imgOut = imgIn
	imgBk = cv2.imread("bak.jpg")   #背景画像の読み込み
	gray = cv2.cvtColor(imgIn, cv2.COLOR_BGR2GRAY)
	bg = cv2.cvtColor(imgBk, cv2.COLOR_BGR2GRAY)
	mask = cv2.absdiff(gray, bg)    #背景差分
	mask[mask < th] = 0        #二値化処理
        mask[mask >= th] = 255       #二値化処理
	d_mask = cv2.dilate(mask, kernel)      #膨張処理
        e_mask = cv2.erode(d_mask, kernel)  #収縮処理
	ExImg(e_mask, imgIn,imgOut)    #物体の抽出画像を生成

	cv2.imwrite("diff.jpg",mask) 
	cv2.imwrite("erode.jpg",e_mask)
	cv2.imwrite("diration.jpg",d_mask)
	cv2.imwrite("output.jpg",imgOut)

pythonを立ち上げ、実行は以下のように記載します。

import BackGroundDetect as bg
bg.BackGroundDetect()
入力画像
入力画像
背景画像
背景画像
差分画像
差分画像
膨張画像
膨張画像
収縮画像
収縮画像
出力結果
出力結果

inusan0424.hatenablog.com

inusan0424.hatenablog.com

https://blog.hatena.ne.jp/inusan0424/inusan0424.hatenablog.com/config/design/detail