2018年4月6日金曜日

動物の活動状態を記録する@ココナラ

動いた痕跡

うわわわわ

農業試験場の研究員の方からCoconalaにて「条件を変えたときに害虫の行動にどのような影響があるかを記録したい」というご相談をいただきました。

当初のご相談は「(フォトインタラプタを使用して)通路を遮る動きをカウントしたい」ということでしたが、ラズパイを用いた画像による動体検知を提案しました。

赤外線LED、IR Picamera、Raspberry Piだけという大変シンプルな構成です。起動すると指定秒数ごとに差分を求め、全画素のうち何%が変化したかを標準出力に書き出します。オプションとしてウィンドウに画像を表示するか画像ファイルを出力するか、を指定できるようにしました。

プログラムはPython + OpenCVで書きました。当初、よくある動体検知としてBackgroundSubtractorMOGとapplyを使うタイプで試していただいたのですが、結果は少し意図と違っていました。
虫ではなく坊主頭中年体型のわたくし
ということで「背景からどのぐらい変化したか」ではなく単純に前フレームと差分を求めるプログラムに変更しました。とはいえPython不慣れ+OpenCV初心者なので、こちらのコードを参考にさせていただきました。ありがとうございます。

冒頭の画像が演算結果です。害虫がケースの中で動いているところを捉えた画像と飼育環境の写真です。

依頼者の方からは、新しい知見も含めて期待以上の結果が得られたとのご報告をいただきました。日本の農業のために微力ながらお手伝いができて何よりです。

今回のように「こういう観察がしたい」というテーマがあればご相談ください。相談だけなら500円、実装についても公的な研究機関からの公益性のあるテーマであればできるだけお力になりたいと思っています。お気軽にどうぞ。

一応ソースです…間隔指定ではなくwait指定だ、とか、いろいろ突っ込みどころはあると思いますがpython初心者ということでご寛恕いただきたく存じますm(_ _)m

【追記4月11日】
公開当初のソースは背景との差分検知をするものでした。
フレーム間差分に書き換えました。
# -*- 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 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。