![]() |
動いた痕跡 |
![]() |
うわわわわ |
農業試験場の研究員の方からCoconalaにて「条件を変えたときに害虫の行動にどのような影響があるかを記録したい」というご相談をいただきました。
当初のご相談は「(フォトインタラプタを使用して)通路を遮る動きをカウントしたい」ということでしたが、ラズパイを用いた画像による動体検知を提案しました。
赤外線LED、IR Picamera、Raspberry Piだけという大変シンプルな構成です。起動すると指定秒数ごとに差分を求め、全画素のうち何%が変化したかを標準出力に書き出します。オプションとしてウィンドウに画像を表示するか画像ファイルを出力するか、を指定できるようにしました。
プログラムはPython + OpenCVで書きました。当初、よくある動体検知としてBackgroundSubtractorMOGとapplyを使うタイプで試していただいたのですが、結果は少し意図と違っていました。
![]() |
虫ではなく坊主頭中年体型のわたくし |
冒頭の画像が演算結果です。害虫がケースの中で動いているところを捉えた画像と飼育環境の写真です。
依頼者の方からは、新しい知見も含めて期待以上の結果が得られたとのご報告をいただきました。日本の農業のために微力ながらお手伝いができて何よりです。
今回のように「こういう観察がしたい」というテーマがあればご相談ください。相談だけなら500円、実装についても公的な研究機関からの公益性のあるテーマであればできるだけお力になりたいと思っています。お気軽にどうぞ。
一応ソースです…間隔指定ではなくwait指定だ、とか、いろいろ突っ込みどころはあると思いますがpython初心者ということでご寛恕いただきたく存じますm(_ _)m
【追記4月11日】
公開当初のソースは背景との差分検知をするものでした。
フレーム間差分に書き換えました。
【追記4月11日】
公開当初のソースは背景との差分検知をするものでした。
フレーム間差分に書き換えました。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
import io | |
import picamera | |
import sys | |
import time | |
import datetime | |
import numpy as np | |
import cv2 | |
# フレーム差分の計算 | |
def frame_sub(img1, img2, img3, th): | |
# フレームの絶対差分 | |
diff1 = cv2.absdiff(img1, img2) | |
diff2 = cv2.absdiff(img2, img3) | |
# 2つの差分画像の論理積 | |
diff = cv2.bitwise_and(diff1, diff2) | |
# 二値化処理 | |
diff[diff < th] = 0 | |
diff[diff >= th] = 255 | |
# メディアンフィルタ処理(ゴマ塩ノイズ除去) | |
mask = cv2.medianBlur(diff, 3) | |
return mask | |
# | |
# 画像取得 | |
# | |
def get_gray_image(): | |
# USB Camera | |
# ret, frame = cap.read() | |
# picamera | |
stream = io.BytesIO() | |
camera.capture(stream, format='jpeg') | |
data = np.fromstring(stream.getvalue(), dtype=np.uint8) | |
frame = cv2.imdecode(data, 1) | |
return cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY) | |
# | |
# 初期化、パラメータ読み込みなど | |
# | |
seconds = 1 | |
showImage = False | |
fileImage = False | |
args = sys.argv | |
for i in args: | |
if i == "image": | |
showImage = True | |
if i == "file": | |
fileImage = True | |
if i.isdigit(): | |
seconds = int(i) | |
print(showImage, seconds) | |
# | |
# カメラの準備 | |
# | |
# USB Camera | |
# cap = cv2.VideoCapture(0) | |
# picamera | |
CAMERA_WIDTH = 320 | |
CAMERA_HEIGHT = 240 | |
camera = picamera.PiCamera() | |
camera.resolution = (CAMERA_WIDTH, CAMERA_HEIGHT) | |
# カメラ動作テスト : camera.capture('my_picture.jpg') | |
# | |
# フレーム先読み | |
# | |
frame1 = get_gray_image() | |
frame2 = get_gray_image() | |
frame3 = get_gray_image() | |
while(1): | |
mask = frame_sub(frame1, frame2, frame3, th=3) | |
# Aが押されたら終了、するはずなのですが | |
k = cv2.waitKey(30) & 0xff | |
if k == 65: | |
break | |
now = datetime.datetime.now() | |
wCount = np.count_nonzero(mask) | |
aCount = mask.size | |
filename = now.strftime("%Y-%m-%dT%H:%M:%S") | |
print filename, wCount, aCount, float(wCount) / float(aCount) | |
if showImage: | |
cv2.imshow('mask', mask) | |
cv2.imshow('frame2', frame2) | |
if fileImage: | |
cv2.imwrite('sabun/'+filename+'org.jpg', frame2) | |
cv2.imwrite('sabun/'+filename+'dif.jpg', mask) | |
frame1 = frame2 | |
frame2 = frame3 | |
frame3 = get_gray_image() | |
time.sleep(seconds) | |
cap.release() | |
cv2.destroyAllWindows() | |
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。