ニューロチキンハウス:パート1. Raspberry Piとカメラをチキンハウスに設置してセットアップする

画像

兄貴があなたを見ています、鳥!





ニューロチキンハウスに関する記事

ネタバレ見出し
  1. ニューラルネットワークでのトレーニングの概要
  2. 鶏を監視するための鉄、ソフトウェア、および構成
  3. ニワトリの生涯のイベントを投稿するボット -ニューラルネットワークなし
  4. データセットのレイアウト
  5. 鶏小屋での鶏の認識の作業モデル
  6. 結果-鶏小屋で鶏を認識する作業用ボット








このアイデアはかなり前に出てきました。 ビデオカード(暗号通貨の家)を使用して採掘された暗号通貨で鶏小屋を加熱することを考えている人はいますが、間違いなく、画像、音声、ニューラルネットワークおよびその実際のアプリケーションを認識することについて考えている人がいます。







むかしむかし、父親がきゅうりを選別するのを手伝った日本人についての記事を読みました。 彼らは鶏が両親にどのように突進するかを分析し、メッセンジャーにレポートを送信することを決めました-楽しみからのアイデア。









一般的に、多くの計画があります。 巣の近くで攪拌が行われたという事実は、鳥が巣に登ったか、巣からledい出したことを意味します。 これはopenCVを使えば簡単に理解でき、すでにその方法を知っています。 このブログで簡単に。







しかし、各鳥を認識し、どの鳥が飛んでいないかを分析したらどうでしょうか? 個々の鶏の生産性を評価しますか? 鳥が急ぐことなく、休息する他の正当な理由がない場合(たとえば、日照時間が短い、脱皮)、鶏肉のスープを調理する時間でしょうか?







「鳥ch11は理由もなく急いでいないように思えます。おそらく、さらなる運命を検討する必要があります。」 それから、ch11の鳥は古い猫のクランベリーで、鶏と一緒に住んでいるだけです。







ハッカソン



これがすべて素晴らしいと思うのは忘れられないことでした。 ( 窓の外の車で )動きを検出する最初の経験はうまくいきましたが、今では機器はアイドル状態でした。 いつもすべてが突然起こるので、木曜日のある晴れた日に両親に金曜日の夜にチケットを買って週末に飛び、ニューロチキンハウスのデータ収集をセットアップしました。







主な困難は、有線インターネットの欠如とそれを実行することの根本的な不可能性(荒野、何をすべきか)でした。 しかし、あなたが何に登録しているのかわからないとき、あなたは最善を望みます、はい。







さらに、鶏小屋には出口がありませんでした。 もちろん、両親は、光とアラームを供給することにより、自宅から直接ナイフのスイッチを制御します。 私の父は鶏小屋にソケットを実装する要求に応答し、一般的に彼女は非常に迅速に実現しました。







機器の主要部分は、Raspberry Pi 3とそのカメラボード、電源、USBファンです(ファンなしの画像処理によりプロセッサが最大80度加熱されるため)。 さらに、誰かがpiにインターネットを提供する必要がありました。







だから、ホットスポットの代替品-3g / 4gモデムhuavei、Android上の古いxperia。 このモデムは、別の電源を必要としないという点で優れていますが、Windowsでのみ動作するという点で悪いです。 もちろん、Linuxでそれを入手する方法についての記事はありますが、私は何かが欲しくありませんでした。







厳密に限られた時間の条件(出発の前日が残っていた)では、電話が選ばれました。

プロバイダーは、この地域で静的IPサービスを提供しませんでした。 IPは動的であることが判明し、動的DNSサービスを使用して修正することが決定されました。







そして突然(誰が疑うか)、うまくいきませんでした。 結局のところ、IPは単なる動的ではなく、灰色の動的です。 これは、外部からアクセスすることが不可能であり、ポートが閉じていることを意味します。







同時に、画像サーバーをキャプチャして送信するためのPythonスクリプトは見られましたが、まだ生のままでした。







その間、利用可能な時間の半分はすでに費やされています。







友人は、ssh back connectという素晴らしいものがあることを提案しました。これにより、一般的に失望から救われました。 時間がほとんど残っていなかったので、すべてがどのように機能するかを完全に理解できませんでした。少なくとも何らかの形で機能することが必要でした。







出発の直前に、王冠にはsshトンネル、温度測定、郵便局のアラームが設置されました。その場合、セットアップ全体が鶏小屋に行きました。 インターネットではまだ悪いことがありますが、そうです。 それは十分に暗く、写真には何も見えないことが判明しました。 父はできるだけ早く照明を設置することを約束しました。 当分の間、カメラはオフになりました。







主なことは、インターネットがあった場所ならどこからでもpiに接続できるということです。







設定の詳細



ハッカソンから少し離れて-行進で、この問題をさらに調整することを約束しました。 (永続的なautosshキーワードを使用して) ガイドを読んだ後、逆sshの代わりにautosshをセットアップしようとしました。これは不安定に動作し、クラウンを使用してサポートされていました。 最初はautosshで何も起こりませんでしたが、クラウンで最初のソリューションを使い続けましたが、肥沃な接続の問題により、とにかくautosshで友達を作ることを余儀なくされました。







作業を開始するには、動的グレーIPを使用してリモートデバイスに実行可能ファイル(方法はわかりませんが、googleは実行可能ファイルlinuxを作成します)を作成し、次の行を追加するだけです。







/usr/bin/autossh -M 0 -o ServerAliveInterval=50 -o ServerAliveCountMax=2 -nNTf -R 2222:localhost:22 userB@hostB -p bbbb
      
      





この行では、2222は必要のないポートに置き換えることができます。userBをホームサーバー上のユーザー(つまり、鶏小屋にないもの)に、hostBをホームサーバー上のホストに、bbbbをホームサーバーのポートに置き換える必要があります。標準(22)とは異なります。







興味がある場合、または何か変更したい場合は、コマンドパラメータについて自分で読むことができます。 次に、このような行をクローナー(crontab -e)に追加します(クローナーに慣れていない場合は、 1 2 3 4の友人が入力を収集しました)。再起動時にautosshが実行されます。







 @reboot /path/to/script/autosshtunnel.sh
      
      





したがって、別のリモートマシンからホームサーバーにアクセスしている場合は、セッションが中断しないようにしてください。 つまり、私はラップトップからサーバーにアクセスし、既にサーバーから鶏小屋をノックしています。この場合、サーバーに接続するときと鶏小屋(ラズベリー)に接続するときの永遠のセッションのパラメーターを処方します。







これは、次のパターンに従って行われます。







 ssh -o TCPKeepAlive=yes -o ServerAliveInterval=50 user@box.example.com
      
      





鶏小屋のシステムに次のように接続します。







 ssh -o TCPKeepAlive=yes -o ServerAliveInterval=50 sshuser@localhost -p 2222
      
      





リモート接続の可能性がすべてでした。次に、温度アラームについて簡単に説明します。 ubuntuやraspbanなどのdebianシステムでメールのアラームを設定するには、このガイドに従ってください 。ssmtpをインストールし、設定を修正するだけです。 raspbanのメールの過熱に関するアラームの最も簡単なスクリプトは次のようになります。







 TEMPERATURE="$(/opt/vc/bin/vcgencmd measure_temp)" NTEMPERATURE="$(echo $TEMPERATURE | tr -dc '0-9.')" LIMIT="61.0" if [ $(echo "$NTEMPERATURE > $LIMIT" | bc) -ne 0 ]; then echo "The critical CPU temperature has been reached $NTEMPERATURE" | sudo /usr/bin/ssmtp -vvv somename@somehost.com fi
      
      





その後、このスクリプトを実行可能ファイルにパックし、クラウンにドロップします。 暑くなるまで、2分ごとにスクリプトを実行します。







次に、画像を収集するメインスクリプトについて説明します。 動きに気付いた場合に条件付きで有用と考える画像。 これらの画像については、すでに分析と認識を強化します。 有用なブログは上記で言及されており、そこからスクリプトをベースとして、少し書き直しました。







ガイド自体は、あなたが動作するために必要なことをすでに述べていますが、私はあなたがOpenCVビルドを作成する必要があることを繰り返します。 これには長い時間がかかる場合があります(私の場合は5時間かかりました)。 これに加えて、numpy、imutilsなど、他のライブラリもインストールする必要があります。落とし穴はありませんでした。







メインスクリプトをニーズに合わせて書き直し、次の変更を行いました。







  • Python 2をPython 3に変更
  • Dropboxの代わりにサーバーを使用しました。
  • 元のフレームと圧縮されたフレームが保存されます。







pi_surveillance.pyの完成バージョンは次のようになります(構成内のスクリプトから定数を削除する必要がない限り)。







 # import the necessary packages import sys sys.path.append('/usr/local/lib/python2.7/site-packages') from pyimagesearch.tempimage import TempImage from picamera.array import PiRGBArray from picamera import PiCamera import argparse import warnings import datetime import imutils import json import time import cv2 import os # construct the argument parser and parse the arguments ap = argparse.ArgumentParser() ap.add_argument("-c", "--conf", required=True, help="path to the JSON configuration file") args = vars(ap.parse_args()) # filter warnings, load the configuration and check if we are going to use server warnings.filterwarnings("ignore") conf = json.load(open(args["conf"])) client = None if conf["use_server"]: #we do not use Dropbox print("[INFO] you are using server") # initialize the camera and grab a reference to the raw camera capture camera = PiCamera() camera.resolution = tuple(conf["resolution"]) camera.framerate = conf["fps"] rawCapture = PiRGBArray(camera, size=tuple(conf["resolution"])) # allow the camera to warmup, then initialize the average frame, last # uploaded timestamp, and frame motion counter print("[INFO] warming up...") time.sleep(conf["camera_warmup_time"]) avg = None lastUploaded = datetime.datetime.now() motionCounter = 0 # capture frames from the camera for f in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True): # grab the raw NumPy array representing the image and initialize # the timestamp and occupied/unoccupied text frame = f.array timestamp = datetime.datetime.now() text = "Unoccupied" # resize the frame, frame = imutils.resize(frame, width=1920) frameorig = imutils.resize(frame, width=1920) # convert it to grayscale, and blur it gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) gray = cv2.GaussianBlur(gray, (21, 21), 0) # if the average frame is None, initialize it if avg is None: print("[INFO] starting background model...") avg = gray.copy().astype("float") rawCapture.truncate(0) continue # accumulate the weighted average between the current frame and # previous frames, then compute the difference between the current # frame and running average cv2.accumulateWeighted(gray, avg, 0.5) frameDelta = cv2.absdiff(gray, cv2.convertScaleAbs(avg)) # threshold the delta image, dilate the thresholded image to fill # in holes, then find contours on thresholded image thresh = cv2.threshold(frameDelta, conf["delta_thresh"], 255, cv2.THRESH_BINARY)[1] thresh = cv2.dilate(thresh, None, iterations=2) cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = cnts[0] if imutils.is_cv2() else cnts[1] # loop over the contours # check if there is at least one contour, which is large enough # I know this isn't the best practice # I know about bool variables # I know about other things too. I just don't actually care # Yes, I am a liar, 'cause if I did not care, # I wouldn't write anything of those ^ for c in cnts: # if the contour is too small, ignore it if cv2.contourArea(c) < conf["min_area"]: continue text = "Occupied" print("[INFO] room is occupied, motion counter is {mc}".format(mc=motionCounter)) # initiate timestamp ts = timestamp.strftime("%A-%d-%B-%Y-%I:%M:%S%p") ts1 = timestamp.strftime("%A-%d-%B-%Y") # let's create paths on a server pathorig = "{base_path}/{timestamp}/origs".format( base_path=conf["server_base_path"], timestamp=ts1) pathres = "{base_path}/{timestamp}/res".format( base_path=conf["server_base_path"], timestamp=ts1) os.system('ssh -p bbbb "%s" "%s %s"' % ("userB@hostB", "sudo mkdir -p", pathorig)) os.system('ssh -p bbbb "%s" "%s %s"' % ("userB@hostB", "sudo mkdir -p", pathres)) # upload images on a server if (text == "Occupied"): motionCounter += 1 if motionCounter >= conf["min_motion_frames"] and (timestamp - lastUploaded).seconds >= conf["min_upload_seconds"]: print("[INFO] time to upload, motion counter is {mc}".format(mc=motionCounter)) # upload original t = TempImage() cv2.imwrite(t.path, frameorig) os.system('scp -P bbbb "%s" "%s:%s"' % (t.path, "userB@hostB", pathorig)) t.cleanup() # upload resized image of 512 px framec = imutils.resize(frame, width=512) tc = TempImage() cv2.imwrite(tc.path, framec) os.system('scp -P bbbb "%s" "%s:%s"' % (tc.path, "userB@hostB", pathres)) tc.cleanup() #reset motionCounter motionCounter = 0 lastUploaded = datetime.datetime.now() # otherwise, the room is not occupied else: motionCounter = 0 # check to see if the frames should be displayed to screen if conf["show_video"]: # display the security feed cv2.imshow("Security Feed", frame) key = cv2.waitKey(1) & 0xFF # if the `q` key is pressed, break from the loop if key == ord("q"): break # clear the stream in preparation for the next frame rawCapture.truncate(0)
      
      





構成は次のようになります。







 { "show_video": false, "use_server": true, "server_base_path": "/media/server/PIC_LOGS", "min_upload_seconds": 1.0, "min_motion_frames": 3, "camera_warmup_time": 2.5, "delta_thresh": 5, "resolution": [1920, 1080], "fps": 16, "min_area": 6000 }
      
      





そして-tempimage.py:







 # import the necessary packages import uuid import os import datetime class TempImage: def __init__(self, basePath="./temps", ext=".jpg"): # construct the file path timestamp = datetime.datetime.now() ts = timestamp.strftime("-%I:%M:%S%p") self.path = "{base_path}/{rand}{tmstp}{ext}".format(base_path=basePath, rand=str(uuid.uuid4())[:8], tmstp=ts, ext=ext) def cleanup(self): # remove the file os.remove(self.path)
      
      





最初に受け取った画像は、巣の中の鶏の尾の画像でした。 天気の良い日にはコンソールを凝視する、人生を通して内向的な5月の素晴らしい贈り物。 暗闇、フレーム内の鳥の頭の欠如、およびスクリプトのカスタマイズの欠如にもかかわらず、画像は本当に喜んでいました。 これは鶏のしっぽです( あなたから千キロ離れたところにいる鶏が巣の中にrawいだと思ってください。







画像

それから照明が設定され、私はもっと感動的な写真を撮った。







画像

画像



スクリプトは、OpenCVが次のように仮想作業環境cvにインストールされているという事実を考慮して起動されます(これをバックグラウンドに正しく送信する方法を理解する必要もあります)。







 source ~/.profile workon cv cd ~/chickencoop python3 /home/sshuser/chickencoop/pi_surveillance.py --conf conf.json
      
      





画像



継続するには...



All Articles