├── app ├── run.py ├── labels.txt ├── __init__.py ├── deer │ ├── 2.jpg │ ├── thumbnail │ │ └── 2.jpg │ └── .thumbnail │ │ └── 2.jpg ├── views.pyc ├── __init__.pyc ├── static │ ├── logo.png │ ├── images │ │ └── 2.jpg │ ├── style.css │ └── stylesheets │ │ └── style.css ├── __pycache__ │ ├── harpu.cpython-35.pyc │ ├── views.cpython-35.pyc │ ├── views.cpython-38.pyc │ ├── __init__.cpython-35.pyc │ ├── __init__.cpython-38.pyc │ ├── process.cpython-35.pyc │ └── process.cpython-38.pyc ├── templates │ ├── photo.html │ ├── layout.html │ ├── photo_dir.html │ ├── confirm.html │ ├── template.html │ ├── name.html │ ├── timer.html │ ├── deleteall.html │ ├── restore.html │ ├── mode.html │ ├── species.html │ ├── index.html │ └── recentactivity.html ├── demomode.py ├── process.py ├── harpu.py └── views.py ├── run.py ├── params.json ├── README.md ├── boarbuster.py └── harpu.py /app/run.py: -------------------------------------------------------------------------------- 1 | from app import app 2 | app.run(debug=True) 3 | -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | from app import app 2 | app.run(host='', port=80) 3 | -------------------------------------------------------------------------------- /app/labels.txt: -------------------------------------------------------------------------------- 1 | sheep 2 | hog 3 | turkey 4 | whitetail deer 5 | aoudad 6 | black bear 7 | raccoon 8 | -------------------------------------------------------------------------------- /app/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | app = Flask(__name__) 4 | from app import views 5 | 6 | -------------------------------------------------------------------------------- /app/deer/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supernova1024/PhotoView-Raspberrypi-Flask-master/HEAD/app/deer/2.jpg -------------------------------------------------------------------------------- /app/views.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supernova1024/PhotoView-Raspberrypi-Flask-master/HEAD/app/views.pyc -------------------------------------------------------------------------------- /app/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supernova1024/PhotoView-Raspberrypi-Flask-master/HEAD/app/__init__.pyc -------------------------------------------------------------------------------- /app/static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supernova1024/PhotoView-Raspberrypi-Flask-master/HEAD/app/static/logo.png -------------------------------------------------------------------------------- /params.json: -------------------------------------------------------------------------------- 1 | {"name": "Wifi", "timer": "12", "never_feed": ["Whitetail Deer", "Hogs"], "feed": ["Whitetail Deer", "Hogs"]} -------------------------------------------------------------------------------- /app/deer/thumbnail/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supernova1024/PhotoView-Raspberrypi-Flask-master/HEAD/app/deer/thumbnail/2.jpg -------------------------------------------------------------------------------- /app/static/images/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supernova1024/PhotoView-Raspberrypi-Flask-master/HEAD/app/static/images/2.jpg -------------------------------------------------------------------------------- /app/deer/.thumbnail/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supernova1024/PhotoView-Raspberrypi-Flask-master/HEAD/app/deer/.thumbnail/2.jpg -------------------------------------------------------------------------------- /app/__pycache__/harpu.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supernova1024/PhotoView-Raspberrypi-Flask-master/HEAD/app/__pycache__/harpu.cpython-35.pyc -------------------------------------------------------------------------------- /app/__pycache__/views.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supernova1024/PhotoView-Raspberrypi-Flask-master/HEAD/app/__pycache__/views.cpython-35.pyc -------------------------------------------------------------------------------- /app/__pycache__/views.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supernova1024/PhotoView-Raspberrypi-Flask-master/HEAD/app/__pycache__/views.cpython-38.pyc -------------------------------------------------------------------------------- /app/__pycache__/__init__.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supernova1024/PhotoView-Raspberrypi-Flask-master/HEAD/app/__pycache__/__init__.cpython-35.pyc -------------------------------------------------------------------------------- /app/__pycache__/__init__.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supernova1024/PhotoView-Raspberrypi-Flask-master/HEAD/app/__pycache__/__init__.cpython-38.pyc -------------------------------------------------------------------------------- /app/__pycache__/process.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supernova1024/PhotoView-Raspberrypi-Flask-master/HEAD/app/__pycache__/process.cpython-35.pyc -------------------------------------------------------------------------------- /app/__pycache__/process.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supernova1024/PhotoView-Raspberrypi-Flask-master/HEAD/app/__pycache__/process.cpython-38.pyc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Flask Web Control System for Raspberry Pi 4 2 | 3 | This is the real-time animal detection algorithm. It is restoring the images and information to mysql database. -------------------------------------------------------------------------------- /app/templates/photo.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | {{image}} 4 | DELETE 5 | {% endblock %} 6 | -------------------------------------------------------------------------------- /app/demomode.py: -------------------------------------------------------------------------------- 1 | import os 2 | from shutil import copyfile 3 | 4 | 5 | os.system('sudo pkill -9 -f harpu.py') 6 | copyfile('/home/pi/demo/demo.py', '/home/pi/harpu.py') 7 | os.system('lxterminal -e python /home/pi/harpu.py') 8 | demomessage = "Machine Now in Demo Mode" 9 | print ("Done") 10 | -------------------------------------------------------------------------------- /app/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | Species Specific Download and View your Photos 3 | 4 |
5 | 6 |
Your Images
7 |
8 |
9 | {% for message in get_flashed_messages() %} 10 |
{{ message }}
11 | {% endfor %} 12 | {% block body %}{% endblock %} 13 |
14 | -------------------------------------------------------------------------------- /app/templates/photo_dir.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | 4 | 10 |
11 | 20 | 21 | {% endblock %} 22 | -------------------------------------------------------------------------------- /app/templates/confirm.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Control Panel 5 | 6 | 7 | 8 |
Control Panel
9 |
10 |
11 |
{{ message }}
12 |
13 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/templates/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Control Panel 5 | 6 | 7 | 8 |
Control Panel
9 |
10 |
11 |
12 | 13 |
14 |
15 | 16 |
17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/templates/name.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Control Panel 5 | 6 | 7 | 8 |
Control Panel
9 |
10 |
11 |
{{ message }}
12 |
13 | 14 |
15 | 16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /app/templates/timer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Control Panel 5 | 6 | 7 | 8 |
Control Panel
9 |
10 |
11 |
{{ message }}
12 |
13 |
14 | 15 |
16 | 17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /app/templates/deleteall.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Control Panel 5 | 6 | 7 | 8 |
Control Panel
9 |
10 |
11 |
{{ message }}
12 |
13 | 14 |
15 |
16 | 17 |
18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/templates/restore.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Control Panel 5 | 6 | 7 | 8 |
Control Panel
9 |
10 |
11 |
{{ message }}
12 |
13 | 14 |
15 |
16 | 17 |
18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/static/style.css: -------------------------------------------------------------------------------- 1 | body { font-family: sans-serif; background: #eee; } 2 | a, h1, h2 { color: #FF6600; } 3 | h1, h2 { font-family: 'impact', sans-serif; margin: 0; text-align: center; } 4 | h1 { border-bottom: 1px solid #6b8e23; } 5 | h2 { font-size: 1.2em; } 6 | 7 | .page { margin: 2em auto; width: 100; 8 | padding: 0.8em; background: black; } 9 | .entries { list-style: none; margin: 0; padding: 0; text-align: center; } 10 | .entries li { margin: 0.8em 1.2em; } 11 | .entries li h2 { margin: -1em; } 12 | .add-entry { font-size: 0.9em; border-bottom: 1px solid #ccc; } 13 | .add-entry dl { font-weight: bold; } 14 | .metanav { text-align: right; font-size: 0.8em; padding: 0.3em; 15 | margin-bottom: 1em; background: #fafafa; } 16 | .flash { background: #cee5F5; padding: 0.5em; 17 | border: 1px solid #aacbe2; } 18 | .error { background: #f0d6d6; padding: 0.5em; } 19 | -------------------------------------------------------------------------------- /app/templates/mode.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Control Panel 5 | 6 | 7 | 8 |
Control Panel
9 |
10 |
11 |
{{ message }}
12 |
13 | 14 |
15 |
16 | 17 |
18 |
19 | 20 |
21 |
22 | 23 |
24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/process.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import re 4 | from collections import defaultdict 5 | from os import fsync 6 | 7 | def read(): 8 | try: 9 | with open('/home/pi/params.json', 'r') as file: 10 | # with open('../params.json', 'r') as file: 11 | accounts = json.load(file) 12 | return accounts 13 | except (OSError, ValueError): # file does not exist or is empty/invalid 14 | accounts = {} 15 | 16 | def read_conf(): 17 | myvars = {} 18 | # with open("../hostapd.conf") as myfile: 19 | with open("/etc/hostapd/hostapd.conf") as myfile: 20 | for line in myfile: 21 | name, var = line.partition("=")[::2] 22 | if name.strip() == 'ssid': 23 | return var; 24 | 25 | def fixup(key, value): 26 | data = read() 27 | data[key] = value 28 | 29 | # write the changed value into file 30 | with open("/home/pi/params.json","w") as f: 31 | # with open("../params.json","w") as f: 32 | json.dump(data, f, ensure_ascii=False) 33 | f.close() 34 | 35 | 36 | def updating(filename,dico): 37 | 38 | 39 | 40 | RE = '(('+'|'.join(dico.keys())+')\s*=)[^\r\n]*?(\r?\n|\r)' 41 | 42 | pat = re.compile(RE) 43 | 44 | def jojo(mat,dic = dico ): 45 | 46 | return dic[mat.group(2)].join(mat.group(1,3)) 47 | 48 | with open(filename,'rb') as f: 49 | 50 | content = f.read() 51 | 52 | with open(filename,'wb') as f: 53 | 54 | f.write(pat.sub(jojo,content)) 55 | return 56 | 57 | def nested_dict(n, type): 58 | if n == 1: 59 | return defaultdict(type) 60 | else: 61 | return defaultdict(lambda: nested_dict(n-1, type)) -------------------------------------------------------------------------------- /app/templates/species.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Control Panel 5 | 6 | 7 | 8 |
Control Panel
9 |
10 |
11 |
{{ message }}
12 |
13 |
14 |
15 | Species that you wish for the machine to feed 16 |
17 |
18 | 23 |
24 |
25 | Species that wish the machine to never feed 26 |
27 |
28 | 35 |
36 | 37 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Control Panel 5 | 6 | 7 | 8 |
Control Panel
9 |
10 |
11 |
{{ message }}
12 |
13 | 14 |
15 |
16 | 17 |
18 |
19 | 20 |
21 |
22 | 23 |
24 |
25 | 26 |
27 |
28 | 29 |
30 |
31 | 32 |
33 |
34 | 35 |
36 |
37 | 38 |
39 | 40 | 41 | -------------------------------------------------------------------------------- /app/templates/recentactivity.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Control Panel 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 |
Recent Activity
17 | {% if dates %} 18 |
19 | 20 |
21 | {% endif %} 22 | {% if not dates %} 23 |
There is no record
24 | {% else %} 25 | {% for date in dates %} 26 | 27 | 28 | 29 | 30 | {% for zone in timezones %} 31 | 32 | {% endfor %} 33 | 34 | 35 | 36 | {% for animal in animals %} 37 | 38 | 39 | {% for timezone in timezones %} 40 | 41 | {% endfor%} 42 | 43 | {% endfor %} 44 | 45 |
{{ date }}{{ zone }}
{{ animal }}{{ message[date][animal][timezone] }}
46 | {% endfor %} 47 | {% endif %} 48 |
49 | 50 | 51 | -------------------------------------------------------------------------------- /app/static/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | .button{ 2 | background-color: #6b8e23; 3 | border: none; 4 | color: white; 5 | padding: 15px 20px; 6 | text-align: center; 7 | text-decoration: none; 8 | display: inline-block; 9 | font-size: 16px; 10 | width: 100%; 11 | } 12 | 13 | .message{ 14 | color: #FF6600; 15 | text-align: center; 16 | font-size: 16px; 17 | } 18 | 19 | .heading{ 20 | padding-top: 20px; 21 | font: 24px arial, sans-serif; 22 | text-align: center; 23 | color: #808080; 24 | } 25 | 26 | hr { 27 | display: block; 28 | margin-left: auto; 29 | margin-right: auto; 30 | border-style: inset; 31 | border-width: 1px; 32 | color: #D3D3D3; 33 | } 34 | 35 | body { 36 | color: #000000; 37 | font: 16px arial, sans-serif; 38 | text-align: center; 39 | } 40 | 41 | 42 | /* -------------------- Page Styles (not required) */ 43 | div { margin: 20px; } 44 | 45 | button.submit, a.submit { 46 | background-color: #4CAF50; /* Green */ 47 | border: none; 48 | color: white; 49 | padding: 15px 32px; 50 | text-align: center; 51 | text-decoration: none; 52 | display: inline-block; 53 | font-size: 16px; 54 | } 55 | 56 | form#form2 input[type="text"], form#form3 input[type="number"] { 57 | padding: 10px; 58 | border: solid 1px gainsboro; 59 | -webkit-transition: box-shadow 0.3s, border 0.3s; 60 | -moz-transition: box-shadow 0.3s, border 0.3s; 61 | -o-transition: box-shadow 0.3s, border 0.3s; 62 | transition: box-shadow 0.3s, border 0.3s; 63 | display: block; 64 | margin: 0; 65 | width: 200px; 66 | font-family: "Open Sans", sans-serif; 67 | font-size: 18px; 68 | -webkit-appearance: none; 69 | -moz-appearance: none; 70 | appearance: none; 71 | -webkit-box-shadow: none; 72 | -moz-box-shadow: none; 73 | box-shadow: none; 74 | -webkit-border-radius: none; 75 | -moz-border-radius: none; 76 | -ms-border-radius: none; 77 | -o-border-radius: none; 78 | border-radius: none; 79 | } 80 | form#form2 input[type="text"]:focus, form#form2 input[type="text"].focus, 81 | form#form3 input[type="number"]:focus, form#form3 input[type="number"].focus { 82 | border: solid 1px #707070; 83 | -webkit-box-shadow: 0 0 5px 1px #969696; 84 | -moz-box-shadow: 0 0 5px 1px #969696; 85 | box-shadow: 0 0 5px 1px #969696; 86 | } 87 | form#form3 input[type="number"] { 88 | text-align: right; 89 | } 90 | 91 | div.recent_div { 92 | margin-top: 2%; 93 | } 94 | div.recent_title { 95 | font-size: 20px; 96 | } 97 | table th { 98 | background-color: #D5D5D5; 99 | } 100 | table tbody tr{ 101 | background-color: #EB2620; 102 | } 103 | table tbody tr:first-child{ 104 | background-color: #68D643; 105 | } 106 | table thead tr th { 107 | border-bottom: 1px solid black; 108 | } 109 | table thead tr th:first-child { 110 | background-color: #929292; 111 | } 112 | table tbody tr td:first-child { 113 | border-right: 1px solid black; 114 | } -------------------------------------------------------------------------------- /boarbuster.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import tensorflow as tf 4 | import os 5 | os.environ['TF_CPP_MIN_LOG_LEVEL']='2' 6 | import time 7 | import json 8 | import RPi.GPIO as GPIO 9 | import glob 10 | 11 | #Set Up GPIO 12 | GPIO.setwarnings(False) 13 | GPIO.setmode(GPIO.BOARD) 14 | 15 | #Save Photos of Trapped Animals 16 | files = glob.glob("trapped/photo*.jpg") 17 | if files == []: 18 | print "No Previous Image Found: Resetting Image Counter" 19 | hognum = 1000000 20 | else: 21 | files = sorted(files) 22 | hognum = int(os.path.basename(files[-1])[5:-4]) 23 | hognum += 1 24 | print "Previous Image Found and Counted - Current Image Number is:" 25 | print hognum 26 | 27 | #Save Photos of Detected Motion 28 | files2 = glob.glob("detected/photo*.jpg") 29 | if files2 == []: 30 | print "No Previous Image Found: Resetting Image Counter" 31 | num = 1000000 32 | else: 33 | files2 = sorted(files2) 34 | num = int(os.path.basename(files2[-1])[5:-4]) 35 | num += 1 36 | print "Previous Image Found and Counted - Current Image Number is:" 37 | print num 38 | 39 | #Load Parameters 40 | params = {} 41 | with open('/home/pi/params.json') as data_file: 42 | params = json.load(data_file) 43 | 44 | #print ('=== params ===', params) 45 | 46 | if (params['starttime']) == 'Small': 47 | numcts = 5 48 | if (params['starttime']) == 'Medium': 49 | numcts = 10 50 | if (params['starttime']) == 'Large': 51 | numcts = 15 52 | 53 | # switch camera to video streaming 54 | #cap = cv2.VideoCapture("bbvid1.mpg") 55 | cap = cv2.VideoCapture(0) 56 | a = [] 57 | model_dir = '' 58 | #bgsMOG = cv2.createBackgroundSubtractorMOG2(detectShadows = False) 59 | bgsMOG = cv2.createBackgroundSubtractorMOG2(history = 300, varThreshold = 50, detectShadows = False) 60 | 61 | label_lines = [line.rstrip() for line 62 | in tf.gfile.GFile("labels.txt")] 63 | 64 | def create_graph(): 65 | 66 | # Creates graph from saved graph_def.pb. 67 | with tf.gfile.FastGFile(os.path.join( 68 | model_dir, 'graph.pb'), 'rb') as f: 69 | graph_def = tf.GraphDef() 70 | graph_def.ParseFromString(f.read()) 71 | _ = tf.import_graph_def(graph_def, name='') 72 | 73 | # Download and create graph 74 | create_graph() 75 | 76 | def detect(frame): 77 | with tf.Session() as sess: 78 | softmax_tensor = sess.graph.get_tensor_by_name('final_result:0') 79 | cv2.imwrite("current_frame.jpg",frame) 80 | 81 | image_data = tf.gfile.FastGFile("./current_frame.jpg", 'rb').read() 82 | predictions = sess.run(softmax_tensor,{'DecodeJpeg/contents:0': image_data}) 83 | 84 | predictions = np.squeeze(predictions) 85 | 86 | # change n_pred for more predictions 87 | n_pred=1 88 | top_k = predictions.argsort()[-n_pred:][::-1] 89 | for node_id in top_k: 90 | human_string_n = label_lines[node_id] 91 | score = predictions[node_id] 92 | print ('The animal is {} and score is {}'.format(human_string_n, score)) 93 | result = 0 94 | if human_string_n in ('Hog') and score > .55: 95 | result = Hog 96 | return result 97 | hog = 0 98 | 99 | # Take Sample Image to Send to Wifi Interface to check camera placement 100 | sample = 0 101 | framecount = 0 102 | while sample == 0: 103 | ret, frame = cap.read() 104 | framecount += 1 105 | if framecount > 400 and sample < 1: 106 | cv2.imwrite("deer/sample.jpg", frame) 107 | print "Sample Image Collected" 108 | sample += 1 109 | 110 | # Motion Detection Portion 111 | while hog < 1: 112 | print "delay start timer 2 min" 113 | GPIO.setup(37, GPIO.OUT) 114 | GPIO.cleanup(37) 115 | time.sleep(10) 116 | GPIO.setup(37, GPIO.OUT) 117 | print "starting control system" 118 | hog = 0 119 | fct = 0 120 | timeout = time.time() + 60 121 | #cap = cv2.VideoCapture(0) 122 | time.sleep(2) 123 | while (hog < 1) and (time.time() < timeout): 124 | ret, frame = cap.read() 125 | fct += 1 126 | if ret and fct > 300: 127 | fgmask = bgsMOG.apply(frame) 128 | # To find the contours of the objects 129 | _, contours, hierarchy = cv2.findContours(fgmask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) 130 | #cv2.drawContours(frame,contours,-1,(0,255,0),cv2.cv.CV_FILLED,32) 131 | try: hierarchy = hierarchy[0] 132 | except: hierarchy = [] 133 | a = [] 134 | for contour, hier in zip(contours, hierarchy): 135 | if (hog < 2) and (time.time() < timeout): 136 | (x, y, w, h) = cv2.boundingRect(contour) 137 | if w > 30 and h > 30: 138 | width = str(w) 139 | height = str(h) 140 | dimension = width + ", " + height 141 | dimension1 = dimension 142 | cv2.rectangle(frame, (x, y), (x + w, y + h), (147, 20, 255), 1) 143 | cv2.putText(frame, dimension1, (x, y + h + 12), 0, 0.5, (147, 20, 255)) 144 | (x, y, w, h) = cv2.boundingRect(contour) 145 | 146 | x1 = w / 2 147 | y1 = h / 2 148 | cx = x + x1 149 | cy = y + y1 150 | a.append([cx, cy]) 151 | area = cv2.contourArea(contour) 152 | if (len(a) >= numcts) and (hog < 1): 153 | 154 | cv2.imwrite("detected/photo%s.jpg" % num, frame) 155 | num += 1 156 | if detect(frame) == 'Hog': 157 | print ('Alarm! A group of Hogs was detected. please trigger the trap!') 158 | cv2.imwrite("trapped/photo%s.jpg" % hognum, frame) 159 | hognum +=1 160 | #hog += 1 161 | break 162 | else: 163 | break 164 | #cv2.imshow('BGS', fgmask) 165 | cv2.imshow('Ori+Bounding Box', frame) 166 | key = cv2.waitKey(100) 167 | if key == ord('q'): 168 | break 169 | #cap.release() 170 | cv2.destroyAllWindows() 171 | if hog >= 2: 172 | GPIO.setup(13, GPIO.OUT) 173 | print "Releasing Trap" 174 | time.sleep(3) 175 | GPIO.cleanup(13) 176 | print "Done" 177 | -------------------------------------------------------------------------------- /app/harpu.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import re 3 | import sys 4 | import cv2 5 | import numpy as np 6 | import tensorflow as tf 7 | import time 8 | import os 9 | os.environ['TF_CPP_MIN_LOG_LEVEL']='2' 10 | from threading import Thread 11 | import RPi.GPIO as GPIO 12 | import glob 13 | from PIL import Image 14 | from shutil import copyfile 15 | 16 | # Threaded class for performance improvement 17 | class VideoStream: 18 | def __init__(self, src=0): 19 | self.stream = cv2.VideoCapture(src) 20 | (self.grabbed, self.frame) = self.stream.read() 21 | self.stopped = False 22 | 23 | def start(self): 24 | Thread(target=self.update, args=()).start() 25 | return self 26 | 27 | def update(self): 28 | while True: 29 | if self.stopped: 30 | self.stream.release() 31 | return 32 | 33 | (self.grabbed, self.frame) = self.stream.read() 34 | 35 | def read(self): 36 | # Return the latest frame 37 | return self.frame 38 | 39 | def stop(self): 40 | self.stopped = True 41 | 42 | def create_graph(): 43 | 44 | # Creates graph from saved graph_def.pb. 45 | with tf.gfile.FastGFile(os.path.join( 46 | model_dir, 'graph.pb'), 'rb') as f: 47 | graph_def = tf.GraphDef() 48 | graph_def.ParseFromString(f.read()) 49 | _ = tf.import_graph_def(graph_def, name='') 50 | 51 | def run(animals_feed='Whitetail Deer', animals_not_feed='Aoudad', timer="5"): 52 | # Define num variable 53 | 54 | files = glob.glob(animals_feed + "/" + animals_feed + "*.jpg") 55 | if files == []: 56 | print ("No Previous Image Found: Resetting Image Counter") 57 | num = 1000000 58 | else: 59 | files = sorted(files) 60 | num = int(os.path.basename(files[-1])[4:-4]) 61 | num += 1 62 | print ("Previous Image Found and Counted - Current Image Number is:") 63 | print (num) 64 | 65 | model_dir='' 66 | 67 | label_lines = [line.rstrip() for line 68 | in tf.gfile.GFile("labels.txt")] 69 | 70 | #Set up Pins for Motion Sensors 71 | GPIO.setwarnings(False) 72 | GPIO.setmode(GPIO.BOARD) 73 | GPIO.setup(29, GPIO.IN) 74 | GPIO.setup(31, GPIO.IN) 75 | GPIO.setup(33, GPIO.IN) 76 | GPIO.setup(35, GPIO.IN) 77 | 78 | # Download and create graph 79 | create_graph() 80 | 81 | # Variables declarations 82 | frame_count=0 83 | score=0 84 | start = time.time() 85 | pred=0 86 | last=0 87 | human_string=None 88 | doors=0 89 | #Doors Closing 90 | print ("Doors Closing") 91 | GPIO.setup(16, GPIO.OUT) 92 | GPIO.setup(18, GPIO.OUT) 93 | time.sleep(15) 94 | GPIO.cleanup(16) 95 | GPIO.cleanup(18) 96 | print ("Doors Closed") 97 | 98 | ### THE TIMER VARIABLE FROM THE WEB CONTROL SHOULD BE ENTERED BELOW WHERE THE 5 IS CURRENTLY 99 | timeout = time.time() + timer*60 100 | 101 | # Start tensorflow session 102 | while True: 103 | 104 | #Set up motion sensor variables 105 | ms1=0 106 | ms2=0 107 | ms3=0 108 | ms4=0 109 | 110 | #clean up cameras 111 | GPIO.setup(36, GPIO.OUT) 112 | GPIO.cleanup(36) 113 | GPIO.setup(37, GPIO.OUT) 114 | GPIO.cleanup(37) 115 | GPIO.setup(38, GPIO.OUT) 116 | GPIO.cleanup(38) 117 | GPIO.setup(40, GPIO.OUT) 118 | GPIO.cleanup(40) 119 | print ("Monitoring Motion Sensors") 120 | while ms1 < 5 and ms2 < 5 and ms3 < 5 and ms4 < 5: 121 | if GPIO.input(29): 122 | print("Motion Detected MS1") 123 | ms1 += 1 124 | time.sleep(.2) 125 | if ms1 == 5: 126 | GPIO.setup(37, GPIO.OUT) 127 | print ("Camera 1 Started") 128 | time.sleep(2) 129 | break 130 | if GPIO.input(31): 131 | print("Motion Detected MS2") 132 | ms2 += 1 133 | time.sleep(.2) 134 | if ms2 == 5: 135 | GPIO.setup(36, GPIO.OUT) 136 | print ("Camera 2 Started") 137 | time.sleep(2) 138 | break 139 | if GPIO.input(33): 140 | print("Motion Detected MS3") 141 | ms3 += 1 142 | time.sleep(.2) 143 | if ms3 == 5: 144 | GPIO.setup(38, GPIO.OUT) 145 | print ("Camera 3 Started") 146 | time.sleep(2) 147 | break 148 | if GPIO.input(35): 149 | print("Motion Detected MS4") 150 | ms4 += 1 151 | time.sleep(.2) 152 | if ms4 == 5: 153 | GPIO.setup(40, GPIO.OUT) 154 | print ("Camera 4 Started") 155 | time.sleep(2) 156 | break 157 | if time.time() > timeout and doors == 1: 158 | print ("Timer Expired: Securing Machine - Resetting Timer") 159 | print ("Closing Doors") 160 | GPIO.setup(16, GPIO.OUT) 161 | GPIO.setup(18, GPIO.OUT) 162 | time.sleep(10) 163 | GPIO.cleanup(16) 164 | GPIO.cleanup(18) 165 | print ("Doors Closed") 166 | GPIO.cleanup(36) 167 | GPIO.cleanup(37) 168 | GPIO.cleanup(38) 169 | GPIO.cleanup(40) 170 | print ("Resetting Timer") 171 | doors = 0 172 | 173 | vs = VideoStream(src=0) 174 | vs.start() 175 | print ("Camera Started") 176 | with tf.Session() as sess: 177 | softmax_tensor = sess.graph.get_tensor_by_name('final_result:0') 178 | scans = 0 179 | while scans < 5: 180 | frame = vs.read() 181 | frame_count+=1 182 | # Only run every 5 frames 183 | if frame_count%10==0: 184 | 185 | # Save the image as the fist layer of inception is a DecodeJpeg 186 | cv2.imwrite("current_frame.jpg",frame) 187 | 188 | image_data = tf.gfile.FastGFile("./current_frame.jpg", 'rb').read() 189 | predictions = sess.run(softmax_tensor,{'DecodeJpeg/contents:0': image_data}) 190 | 191 | predictions = np.squeeze(predictions) 192 | 193 | # change n_pred for more predictions 194 | n_pred=1 195 | top_k = predictions.argsort()[-n_pred:][::-1] 196 | for node_id in top_k: 197 | human_string_n = label_lines[node_id] 198 | score = predictions[node_id] 199 | 200 | print (scans) 201 | scans += 1 202 | print('%s (score = %.2f)' % (human_string_n, score)) 203 | 204 | ### BELOW IS WHERE THE TARGET SPECIES VARIABLE SHOULD IN A SERIES 205 | if human_string_n in (animals_feed) and score > .8: 206 | copyfile("/home/pi/current_frame.jpg", "/home/pi/" + animals_feed + "/" + animals_feed + "%s.jpg" % num) 207 | try: 208 | im = Image.open("/home/pi/" + animals_feed + "/" + animals_feed + "%s.jpg" % num) 209 | except IOError: 210 | print ("File Corrupted") 211 | os.remove("/home/pi/" + animals_feed + "/" + animals_feed + "%s.jpg" % num) 212 | print (animals_feed + " Detected") 213 | print ('Confidence %.2F%%' % (score * 100)) 214 | num += 1 215 | scans = 0 216 | ##### THE TIMER VARIABLE FROM THE WEB CONTROL SHOULD BE ENTERED BELOW WHERE THE 5 IS CURRENTLY 217 | timeout = time.time() + timer*60 218 | if doors == 0: 219 | print ("Doors Opening") 220 | GPIO.setup(13, GPIO.OUT) 221 | GPIO.setup(15, GPIO.OUT) 222 | time.sleep(10) 223 | GPIO.cleanup(13) 224 | GPIO.cleanup(15) 225 | print ("Doors Open") 226 | doors = 1 227 | ### BELOW IS WHERE THE NON TARGET SPECIES VARIABLE SHOULD IN A SERIES 228 | if human_string_n in (animals_not_feed) and score > .8: 229 | #print "Shocker Activated" 230 | #Turn On Shocker 231 | #GPIO.setup(32, GPIO.OUT) 232 | #GPIO.setup(22, GPIO.OUT) 233 | print ("Doors Closing") 234 | GPIO.setup(16, GPIO.OUT) 235 | GPIO.setup(18, GPIO.OUT) 236 | time.sleep(10) 237 | GPIO.cleanup(16) 238 | GPIO.cleanup(18) 239 | time.sleep(180) 240 | #GPIO.cleanup(22) 241 | #GPIO.cleanup(32) 242 | doors = 0 243 | os.remove("/home/pi/current_frame.jpg") 244 | # if the 'q' key is pressed, stop the loop 245 | if cv2.waitKey(1) & 0xFF == ord("q"):break 246 | 247 | vs.stop() 248 | print ("Closing Camera") 249 | time.sleep(2) 250 | 251 | if __name__ == '__main__': 252 | run() -------------------------------------------------------------------------------- /app/views.py: -------------------------------------------------------------------------------- 1 | from flask_mysqldb import MySQL 2 | from flask import Flask, request, session, g, redirect, url_for, \ 3 | abort, render_template, flash, send_from_directory 4 | from contextlib import closing 5 | from app import app 6 | import os 7 | from shutil import copyfile 8 | from os import listdir, mkdir 9 | from os.path import isdir, join, dirname, exists, splitext 10 | from PIL import Image 11 | import subprocess 12 | from app.process import read, fixup, updating, read_conf, nested_dict 13 | import time 14 | 15 | # app = Flask(__name__) 16 | mysql = MySQL() 17 | # MySQL Configuration 18 | app.config['MYSQL_USER'] = 'root' 19 | app.config['MYSQL_PASSWORD'] = 'password' 20 | app.config['MYSQL_DB'] = 'raspberrypi' 21 | app.config['MYSQL_HOST'] = 'localhost' 22 | mysql.init_app(app) 23 | 24 | # from app.harpu import run 25 | 26 | app.config.update(dict( 27 | PHOTO_DIR='/home/pi/deer/', 28 | #PHOTO_DIR='static/images/', 29 | THUMB_SIZE=(300, 300) 30 | )) 31 | app.config.from_envvar('PHOTOVIEWER_SETTINGS', silent=True) 32 | 33 | 34 | @app.route('/') 35 | @app.route('/index') 36 | @app.route('/index/', methods=['POST']) 37 | def index(): 38 | return render_template('index.html') 39 | 40 | 41 | @app.route('/mode/', methods=['POST']) 42 | def mode(): 43 | data = read() 44 | modelist = ["Demo Mode", "Demo Mode with Shocker", "Standard Mode", "Standard Mode with Shocker"] 45 | modemessage = 'Please select the machine mode below. Demo mode only operates one camera for demonstration purposes. Standard mode is normal operation of all cameras and sensors.' 46 | return render_template('mode.html', modelist=modelist, mode=data['mode'], message=modemessage); 47 | 48 | @app.route('/machinemode/', methods=['POST']) 49 | def machinemode(): 50 | mode = request.form["mode"] 51 | fixup('mode', mode) 52 | time.sleep(1) 53 | modewarning = "Machine Mode Confirmed" 54 | os.system('sudo pkill -9 -f harpu.py') 55 | subprocess.Popen(['lxterminal', '-e', 'sudo', 'python', 'harpu.py']) 56 | return render_template('savesettings.html', message=modewarning) 57 | 58 | @app.route('/delete_activities/', methods=['POST']) 59 | def delete_activities(): 60 | cur = mysql.connection.cursor() 61 | cur.execute('''DELETE FROM `records` WHERE 1''') 62 | mysql.connection.commit() 63 | deletemessage = 'All Records were Deleted.' 64 | return render_template('confirm.html', message=deletemessage) 65 | 66 | @app.route('/species/', methods=['POST']) 67 | def species(): 68 | speciesmessage = "Please Select the Species that you wish for the machine to feed and the Species that wish the machine to never feed." 69 | feed = ["Whitetail Deer", "Hog", "Aoudad"] 70 | never_feed = ["Aoudad", "Whitetail Deer", "Hog", "Raccoon", "Black Bear"] 71 | data = read() 72 | return render_template('species.html', fdata=feed, ndata=never_feed, feed=data['feed'], never_feed=data['never_feed'], message=speciesmessage) 73 | 74 | @app.route('/activity/', methods=['POST']) 75 | def activity(): 76 | recentactivity = "Recent Activity" 77 | animals = ['Whitetail Deer', 'Hog', 'Black Bear'] 78 | timezones = [ 79 | '12AM - 3AM', 80 | '3AM - 6AM', 81 | '6AM - 9AM', 82 | '9AM - 12PM', 83 | '12PM - 3PM', 84 | '3PM - 6PM', 85 | '6PM - 9PM', 86 | '9PM - 12AM' 87 | ] 88 | data_item = [[0 for k in range(3)] for j in range(8)] 89 | cur = mysql.connection.cursor() 90 | print ('connected !!') 91 | cur.execute('''SELECT * FROM records''') 92 | results = [dict(animal=row[1], date=row[3], timezone=row[4]) for row in cur.fetchall()] 93 | datelist = [] 94 | for item in results: 95 | if item['date'] in datelist: 96 | pass 97 | else: 98 | datelist.append(item['date']) 99 | 100 | recentactivity = nested_dict(3, int) 101 | for date in datelist: 102 | for animal in animals: 103 | for timezone in timezones: 104 | recentactivity[date][animal][timezone] = 0 105 | for item in results: 106 | recentactivity[item['date']][item['animal']][item['timezone']] += 1 107 | print ("recentactivity", recentactivity) 108 | 109 | return render_template('recentactivity.html', 110 | dates=datelist, 111 | timezones=timezones, 112 | animals=animals, 113 | message=recentactivity) 114 | 115 | @app.route('/name/', methods=['POST']) 116 | def name(): 117 | name = read_conf() 118 | print ('======= data ======', name) 119 | namemessage = "Please enter a name for the machine, this will also be your WIFI Network Name. After Clicking Save your machine will reboot." 120 | return render_template('name.html', name=name, message=namemessage) 121 | 122 | @app.route('/timer/', methods=['POST']) 123 | def timer(): 124 | data = read() 125 | timermessage = "Please enter the number of whole minutes that you wish the machine to stay open after seeing a target animal." 126 | return render_template('timer.html', timer=data['timer'], message=timermessage) 127 | 128 | @app.route('/ftime/', methods=['POST']) 129 | def ftime(): 130 | data = read() 131 | sTime = ["24HR", "4AM", "5AM", "6AM", "7AM", "8AM", "9AM", "10AM"] 132 | eTime = ["24HR", "4PM", "5PM", "6PM", "7PM", "8PM", "9PM", "10PM"] 133 | ftimemessage = "Please select when you would like the feeder to start and stop feeding. If you would like it to always feed, select 24HR on both options." 134 | return render_template('feedtime.html', sTime=sTime, eTime=eTime, startTime=data['starttime'], endTime=data['endtime'], message=ftimemessage) 135 | 136 | @app.route('/feedtime/', methods=['POST']) 137 | def feedtime(): 138 | starttime = request.form["starttime"] 139 | endtime = request.form["endtime"] 140 | start = str(starttime) 141 | end = str(endtime) 142 | fixup('starttime', starttime) 143 | fixup('endtime', endtime) 144 | time.sleep(1) 145 | if start == '24HR' and end == '24HR': 146 | feedtimewarning = "Machine will feed 24 hours per day." 147 | else: 148 | feedtimewarning = "Machine will Feed from "+ start + ":00 to " + end + ":00" 149 | os.system('sudo pkill -9 -f harpu.py') 150 | subprocess.Popen(['lxterminal', '-e', 'sudo', 'python', 'harpu.py']) 151 | return render_template('savesettings.html', message=feedtimewarning) 152 | 153 | @app.route('/restore/', methods=['POST']) 154 | def restore(): 155 | restorewarning = 'The Factory Restore will reset the machine completely to factory settings this includes your WIFI name. This will also reboot your machine.' 156 | return render_template('restore.html', message=restorewarning) 157 | 158 | @app.route('/confirmrestore/', methods=['POST']) 159 | def confirmrestore(): 160 | os.system('sudo pkill -9 -f harpu.py') 161 | os.system('sudo rm -rf deer') 162 | os.system('mkdir deer') 163 | os.system('sudo cp /home/pi/paramsdefault.json /home/pi/params.json') 164 | name = 'SpeciesSpecific' 165 | var_key = ['ssid'] 166 | var_value = [name] 167 | what_to_change = dict(zip(var_key, var_value)) 168 | print ('what', what_to_change) 169 | updating('/etc/hostapd/hostapd.conf', what_to_change) 170 | time.sleep(2) 171 | os.system('sudo reboot') 172 | 173 | @app.route('/cancelrestore/', methods=['POST']) 174 | def cancelrestore(): 175 | cancelmessage = 'Restoration Cancelled, Machine not Restored' 176 | return render_template('index.html', message=cancelmessage) 177 | 178 | @app.route('/imgdelete/', methods=['POST']) 179 | def imgdelete(): 180 | deletewarning = 'This will delete all photos from the machine. Please either Confirm or Cancel below' 181 | return render_template('deleteall.html', message=deletewarning) 182 | 183 | @app.route('/canceldelete/', methods=['POST']) 184 | def canceldelete(): 185 | candelmessage = 'Delete Cancelled, No Images Were Deleted' 186 | return render_template('index.html', message=candelmessage) 187 | 188 | @app.route('/deleteall/', methods=['POST']) 189 | def deleteall(): 190 | os.system('sudo pkill -9 -f harpu.py') 191 | os.system('sudo rm -rf deer') 192 | os.system('mkdir deer') 193 | os.system('sudo pkill -9 -f harpu.py') 194 | subprocess.Popen(['lxterminal', '-e', 'sudo', 'python', 'harpu.py']) 195 | deletemessage = 'All Images were Deleted, Please allow time for machine to restart' 196 | return render_template('confirm.html', message=deletemessage) 197 | 198 | # Added by Lee Yam Keng - 09/19/2017 199 | @app.route('/define_feeds/', methods=['POST']) 200 | def define_feeds(): 201 | animals_feed = request.form.getlist("feed") 202 | animals_not_feed = request.form.getlist("never_feed") 203 | print ('animals_not_feed', animals_not_feed) 204 | fixup('feed', animals_feed) 205 | fixup('never_feed', animals_not_feed) 206 | time.sleep(1) 207 | os.system('sudo pkill -9 -f harpu.py') 208 | subprocess.Popen(['lxterminal', '-e', 'sudo', 'python', 'harpu.py']) 209 | return render_template('savesettings.html') 210 | 211 | @app.route('/define_name/', methods=['POST']) 212 | def define_name(): 213 | name = request.form["name"] 214 | print ('name', name) 215 | fixup('name', name) 216 | var_key = ['ssid'] 217 | var_value = [name] 218 | what_to_change = dict(zip(var_key, var_value)) 219 | print ('what', what_to_change) 220 | updating('/etc/hostapd/hostapd.conf', what_to_change) 221 | time.sleep(2) 222 | os.system('sudo reboot') 223 | 224 | @app.route('/define_timer/', methods=['POST']) 225 | def define_timer(): 226 | timer = request.form["timer"] 227 | fixup('timer', timer) 228 | time.sleep(1) 229 | os.system('sudo pkill -9 -f harpu.py') 230 | subprocess.Popen(['lxterminal', '-e', 'sudo', 'python', 'harpu.py']) 231 | return render_template('savesettings.html') 232 | @app.route('/delete/') 233 | def delete(filename): 234 | print ('filename', filename) 235 | os.remove('/home/pi/deer/' + filename) 236 | return render_template('index.html') 237 | 238 | @app.route('/thumb/') 239 | def thumb(path): 240 | # print ('--- path----', path) 241 | return send_from_directory('/home/pi/deer/.thumbnail/', path) 242 | 243 | # End of plugin by Lee Yam Keng 244 | 245 | @app.route('/settime/', methods=['POST']) 246 | def settime(): 247 | settimewarning = 'Please Set the Time Below' 248 | return render_template('form.html', message=settimewarning) 249 | 250 | @app.route('/getresults/', methods=['POST']) 251 | def getsresults(): 252 | year1 = request.form['year'] 253 | month = request.form['month'] 254 | date1 = request.form['date'] 255 | hour1 = request.form['hour'] 256 | minute1 = request.form['minute'] 257 | year = str(year1).zfill(4) 258 | date = str(date1).zfill(2) 259 | hour = str(hour1).zfill(2) 260 | minute = str(minute1).zfill(2) 261 | td = date + " " + month + " " + year + " " + hour + ":" + minute + ":00" 262 | td2 = str(td) 263 | os.system('date -s "%s" '%(td2)) 264 | os.system('sudo hwclock -w') 265 | os.system('sudo pkill -9 -f harpu.py') 266 | subprocess.Popen(['lxterminal', '-e', 'sudo', 'python', 'harpu.py']) 267 | resultswarning = 'Date and Time set to: ' + month + " " + date + " " + year +" " + hour + ":" + minute + ":00" 268 | return render_template('savesettings.html', message=resultswarning) 269 | 270 | @app.route('/images/', defaults={'path': ''}, methods=['POST']) 271 | @app.route('/') 272 | def photo_dir(path): 273 | DEBUG=True, 274 | pd = app.config['PHOTO_DIR'] 275 | dir_entries = [] 276 | image_entries = [] 277 | up = None 278 | 279 | # Only add 'up' if not in the root 280 | if path != '': 281 | up = dirname(join('/',path)) 282 | 283 | # One thing that flask does not have by default is regualar expression 284 | # matching in the routing. Can be added on: 285 | # http://stackoverflow.com/questions/5870188/does-flask-support-regular-expressions-in-its-url-routing 286 | # Just handle it here by checking if the current path is a directory or not 287 | 288 | nav = join(pd, path) 289 | print ('==== nav ===', nav) 290 | # If it's a directory, show the listing 291 | if isdir(nav): 292 | 293 | # TODO There is no safety here, a user could potentially navigate 294 | # outside of where they should be allowed 295 | 296 | # If there is no thumbnail directory for this directory, create it 297 | thumb_dir = join(nav, '.thumbnail') 298 | if not exists(thumb_dir): 299 | mkdir(thumb_dir) 300 | 301 | 302 | list_all = listdir(nav) 303 | for list_item in list_all: 304 | if isdir(join(nav,list_item)) and list_item != '.thumbnail': 305 | dir_entries.append(list_item) 306 | # Primitive check for image files, only for jpg and png 307 | elif list_item.endswith('.png') or list_item.endswith('.jpg'): 308 | image_entries.append(list_item) 309 | 310 | # Generate thumbnails for any that are missing 311 | thumb = join(thumb_dir,list_item) 312 | if not exists(thumb): 313 | # Open primary image 314 | im = Image.open(join(nav,list_item)) 315 | # Convert mode on paletted image formats 316 | if im.mode != "RGB": 317 | im = im.convert("RGB") 318 | im.thumbnail(app.config['THUMB_SIZE'], Image.ANTIALIAS) 319 | im.save(thumb, "JPEG") 320 | print ('dir_entries', dir_entries) 321 | print ('image_entries', image_entries) 322 | print ('path', path) 323 | print ('up', up) 324 | 325 | return render_template('photo_dir.html', dir_entries=dir_entries, image_entries=image_entries, path=path, up=up) 326 | 327 | # Otherwise it must be a file (assuming an image file, but again, unsafe) 328 | # So display the photo 329 | else: 330 | return render_template('photo.html', image=url_for("static", filename=join('images', path)), file=path) -------------------------------------------------------------------------------- /harpu.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import re 3 | import sys 4 | import cv2 5 | import json 6 | import numpy as np 7 | import tensorflow as tf 8 | import time 9 | import os 10 | os.environ['TF_CPP_MIN_LOG_LEVEL']='2' 11 | from threading import Thread 12 | import RPi.GPIO as GPIO 13 | import glob 14 | from PIL import Image 15 | from shutil import copyfile 16 | import datetime as dt 17 | 18 | #Load Parameters 19 | params = {} 20 | with open('/home/pi/params.json') as data_file: 21 | params = json.load(data_file) 22 | 23 | print ('=== params ===', params) 24 | 25 | # Define num variable 26 | 27 | files = glob.glob("deer/photo*.jpg") 28 | if files == []: 29 | print "No Previous Image Found: Resetting Image Counter" 30 | num = 1000000 31 | else: 32 | files = sorted(files) 33 | num = int(os.path.basename(files[-1])[5:-4]) 34 | num += 1 35 | print "Previous Image Found and Counted - Current Image Number is:" 36 | print num 37 | 38 | model_dir='' 39 | 40 | label_lines = [line.rstrip() for line 41 | in tf.gfile.GFile("labels.txt")] 42 | 43 | #Set up Pins for Motion Sensors 44 | GPIO.setwarnings(False) 45 | GPIO.setmode(GPIO.BOARD) 46 | GPIO.setup(29, GPIO.IN) 47 | GPIO.setup(31, GPIO.IN) 48 | GPIO.setup(33, GPIO.IN) 49 | GPIO.setup(35, GPIO.IN) 50 | 51 | #Clean up earlier pins 52 | GPIO.setup(13, GPIO.OUT) 53 | GPIO.cleanup(13) 54 | GPIO.setup(15, GPIO.OUT) 55 | GPIO.cleanup(15) 56 | GPIO.setup(16, GPIO.OUT) 57 | GPIO.cleanup(16) 58 | GPIO.setup(18, GPIO.OUT) 59 | GPIO.cleanup(18) 60 | GPIO.setup(22, GPIO.OUT) 61 | GPIO.cleanup(22) 62 | GPIO.setup(32, GPIO.OUT) 63 | GPIO.cleanup(32) 64 | GPIO.setup(36, GPIO.OUT) 65 | GPIO.cleanup(36) 66 | GPIO.setup(37, GPIO.OUT) 67 | GPIO.cleanup(37) 68 | GPIO.setup(38, GPIO.OUT) 69 | GPIO.cleanup(38) 70 | GPIO.setup(40, GPIO.OUT) 71 | GPIO.cleanup(40) 72 | 73 | #Set Mode 74 | if params['mode'] == 'Demo Mode': 75 | mode = "demo" 76 | print "Demo Mode" 77 | elif params['mode'] == 'Demo Mode with Shocker': 78 | mode = "demoshock" 79 | print "Demo Mode Shocker" 80 | elif params['mode'] == 'Standard Mode': 81 | mode = "standard" 82 | print "Standard Mode" 83 | else: 84 | mode = "standardshock" 85 | print "Standard Mode Shocker" 86 | 87 | #Set Feed Time Start Variable 88 | if params['starttime'] == '24HR': 89 | feedstart = 00 90 | elif params['starttime'] == '4AM': 91 | feedstart = 4 92 | elif params['starttime'] == '5AM': 93 | feedstart = 5 94 | elif params['starttime'] == '6AM': 95 | feedstart = 6 96 | elif params['starttime'] == '7AM': 97 | feedstart = 7 98 | elif params['starttime'] == '8AM': 99 | feedstart = 8 100 | elif params['starttime'] == '9AM': 101 | feedstart = 9 102 | else: 103 | feedstart = 10 104 | 105 | #Set Feed Time Start Variable 106 | if params['endtime'] == '24HR': 107 | feedstop = 23 108 | elif params['endtime'] == '4PM': 109 | feedstop = 16 110 | elif params['endtime'] == '5PM': 111 | feedstop = 17 112 | elif params['endtime'] == '6PM': 113 | feedstop = 18 114 | elif params['endtime'] == '7PM': 115 | feedstop = 19 116 | elif params['endtime'] == '8PM': 117 | feedstop = 20 118 | elif params['endtime'] == '9PM': 119 | feedstop = 21 120 | else: 121 | feedstop = 22 122 | 123 | #Set Feed Animal 124 | if params['feed'] == 'Whitetail Deer': 125 | feed = "deer" 126 | elif params['feed'] == 'Black Bear': 127 | feed = "bear" 128 | elif params['feed'] == 'Hogs' or params['feed'] == 'Hog': 129 | feed = "hog" 130 | elif params['feed'] == 'Raccoon': 131 | feed = "raccoon" 132 | else: 133 | feed = 'aoudad' 134 | 135 | print feedstart 136 | print feedstop 137 | print feed 138 | 139 | # Threaded class for performance improvement 140 | class VideoStream: 141 | def __init__(self, src=0): 142 | self.stream = cv2.VideoCapture(src) 143 | (self.grabbed, self.frame) = self.stream.read() 144 | self.stopped = False 145 | 146 | def start(self): 147 | Thread(target=self.update, args=()).start() 148 | return self 149 | 150 | def update(self): 151 | while True: 152 | if self.stopped: 153 | self.stream.release() 154 | return 155 | 156 | (self.grabbed, self.frame) = self.stream.read() 157 | 158 | def read(self): 159 | # Return the latest frame 160 | return self.frame 161 | 162 | def stop(self): 163 | self.stopped = True 164 | 165 | def create_graph(): 166 | 167 | # Creates graph from saved graph_def.pb. 168 | with tf.gfile.FastGFile(os.path.join( 169 | model_dir, 'graph.pb'), 'rb') as f: 170 | graph_def = tf.GraphDef() 171 | graph_def.ParseFromString(f.read()) 172 | _ = tf.import_graph_def(graph_def, name='') 173 | 174 | # Download and create graph 175 | create_graph() 176 | 177 | # Variables declarations 178 | frame_count=0 179 | score=0 180 | start = time.time() 181 | pred=0 182 | last=0 183 | human_string=None 184 | doors=0 185 | nontarget=0 186 | #Doors Closing 187 | print "Doors Closing" 188 | GPIO.setup(16, GPIO.OUT) 189 | GPIO.setup(18, GPIO.OUT) 190 | time.sleep(15) 191 | GPIO.cleanup(16) 192 | GPIO.cleanup(18) 193 | print "Doors Closed" 194 | 195 | timeout = time.time() + int(params['timer'])*60 196 | target = 0 197 | # Start tensorflow session 198 | while True: 199 | 200 | #Set up motion sensor variables 201 | ms1=0 202 | ms2=0 203 | ms3=0 204 | ms4=0 205 | 206 | #clean up cameras 207 | GPIO.setup(36, GPIO.OUT) 208 | GPIO.cleanup(36) 209 | GPIO.setup(37, GPIO.OUT) 210 | GPIO.cleanup(37) 211 | GPIO.setup(38, GPIO.OUT) 212 | GPIO.cleanup(38) 213 | GPIO.setup(40, GPIO.OUT) 214 | GPIO.cleanup(40) 215 | if nontarget == 1 and mode in ('demo') and doors ==1: 216 | print "Doors Closing" 217 | GPIO.setup(16, GPIO.OUT) 218 | GPIO.setup(18, GPIO.OUT) 219 | time.sleep(10) 220 | GPIO.cleanup(16) 221 | GPIO.cleanup(18) 222 | doors = 0 223 | target = 0 224 | if nontarget == 1 and mode == 'demoshock': 225 | print "Shocker Activated" 226 | GPIO.setup(22, GPIO.OUT) 227 | print "Doors Closing" 228 | GPIO.setup(16, GPIO.OUT) 229 | GPIO.setup(18, GPIO.OUT) 230 | time.sleep(10) 231 | GPIO.cleanup(16) 232 | GPIO.cleanup(18) 233 | time.sleep(60) 234 | GPIO.cleanup(22) 235 | doors = 0 236 | target = 0 237 | if target == 0 and nontarget == 1 and mode == 'standardshock': 238 | print "Shocker Activated" 239 | #Turn On Shocker 240 | GPIO.setup(32, GPIO.OUT) 241 | GPIO.setup(22, GPIO.OUT) 242 | print "Doors Closing" 243 | GPIO.setup(16, GPIO.OUT) 244 | GPIO.setup(18, GPIO.OUT) 245 | time.sleep(10) 246 | GPIO.cleanup(16) 247 | GPIO.cleanup(18) 248 | time.sleep(180) 249 | GPIO.cleanup(22) 250 | GPIO.cleanup(32) 251 | doors = 0 252 | target = 0 253 | if time.time() > timeout and doors == 1: 254 | print "Timer Expired: Securing Machine - Resetting Timer" 255 | print "Closing Doors" 256 | GPIO.setup(16, GPIO.OUT) 257 | GPIO.setup(18, GPIO.OUT) 258 | time.sleep(10) 259 | GPIO.cleanup(16) 260 | GPIO.cleanup(18) 261 | print "Doors Closed" 262 | GPIO.cleanup(36) 263 | GPIO.cleanup(37) 264 | GPIO.cleanup(38) 265 | GPIO.cleanup(40) 266 | print "Resetting Timer" 267 | doors = 0 268 | target = 0 269 | 270 | print("Monitoring Motion Sensors") 271 | hour = dt.datetime.now().hour 272 | while feedstart > hour or hour > feedstop: 273 | print "Checking Time" 274 | time.sleep(300) 275 | while ms1 < 5 and ms2 < 5 and ms3 < 5 and ms4 < 5: 276 | if GPIO.input(29): 277 | print("Motion Detected MS1") 278 | ms1 += 1 279 | time.sleep(.2) 280 | if ms1 == 5: 281 | GPIO.setup(37, GPIO.OUT) 282 | print "Camera 1 Started" 283 | time.sleep(2) 284 | break 285 | if GPIO.input(31) and mode in ('standard', 'standardshock'): 286 | print("Motion Detected MS2") 287 | ms2 += 1 288 | time.sleep(.2) 289 | if ms2 == 5: 290 | GPIO.setup(36, GPIO.OUT) 291 | print "Camera 2 Started" 292 | time.sleep(2) 293 | break 294 | if GPIO.input(33) and mode in ('standard', 'standardshock'): 295 | print("Motion Detected MS3") 296 | ms3 += 1 297 | time.sleep(.2) 298 | if ms3 == 5: 299 | GPIO.setup(38, GPIO.OUT) 300 | print "Camera 3 Started" 301 | time.sleep(2) 302 | break 303 | if GPIO.input(35) and mode in ('standard', 'standardshock'): 304 | print("Motion Detected MS4") 305 | ms4 += 1 306 | time.sleep(.2) 307 | if ms4 == 5: 308 | GPIO.setup(40, GPIO.OUT) 309 | print "Camera 4 Started" 310 | time.sleep(2) 311 | break 312 | if time.time() > timeout and doors == 1: 313 | print "Timer Expired: Securing Machine - Resetting Timer" 314 | print "Closing Doors" 315 | GPIO.setup(16, GPIO.OUT) 316 | GPIO.setup(18, GPIO.OUT) 317 | time.sleep(10) 318 | GPIO.cleanup(16) 319 | GPIO.cleanup(18) 320 | print "Doors Closed" 321 | GPIO.cleanup(36) 322 | GPIO.cleanup(37) 323 | GPIO.cleanup(38) 324 | GPIO.cleanup(40) 325 | print "Resetting Timer" 326 | doors = 0 327 | target = 0 328 | 329 | vs = VideoStream(src=0) 330 | vs.start() 331 | print "Camera Started" 332 | with tf.Session() as sess: 333 | softmax_tensor = sess.graph.get_tensor_by_name('final_result:0') 334 | if mode in ('standard', 'standardshock'): 335 | scanmax = 5 336 | if mode in ('demo', 'demoshock'): 337 | scanmax = 25 338 | scans = 0 339 | while scans < scanmax: 340 | frame = vs.read() 341 | frame_count+=1 342 | # Only run every 5 frames 343 | if frame_count%10==0: 344 | 345 | # Save the image as the fist layer of inception is a DecodeJpeg 346 | cv2.imwrite("current_frame.jpg",frame) 347 | 348 | image_data = tf.gfile.FastGFile("./current_frame.jpg", 'rb').read() 349 | predictions = sess.run(softmax_tensor,{'DecodeJpeg/contents:0': image_data}) 350 | 351 | predictions = np.squeeze(predictions) 352 | 353 | # change n_pred for more predictions 354 | n_pred=1 355 | top_k = predictions.argsort()[-n_pred:][::-1] 356 | for node_id in top_k: 357 | human_string_n = label_lines[node_id] 358 | score = predictions[node_id] 359 | 360 | print (scans) 361 | scans += 1 362 | print('%s (score = %.2f)' % (human_string_n, score)) 363 | 364 | if human_string_n in (params['feed']) and score > .75: 365 | now = time.strftime("%c") 366 | font = cv2.FONT_HERSHEY_SIMPLEX 367 | img = cv2.imread("/home/pi/current_frame.jpg") 368 | machinename = params['name'] 369 | text = machinename + " - " + now 370 | text2 = str(text) 371 | text3 = "hello" 372 | cv2.putText(frame, text2, (20,20), font, 0.8,(0,102,255), 2, cv2.LINE_AA) 373 | cv2.imwrite("/home/pi/detected.jpg", frame) 374 | time.sleep(2) 375 | copyfile("/home/pi/detected.jpg", "/home/pi/deer/photo%s.jpg" % num) 376 | try: 377 | im = Image.open("/home/pi/deer/photo%s.jpg" % num) 378 | except IOError: 379 | print "File Corrupted" 380 | os.remove("/home/pi/deer/photo%s.jpg" % num) 381 | print "Target Detected" 382 | print ('Confidence %.2F%%' % (score * 100)) 383 | num += 1 384 | scans = 0 385 | os.remove("/home/pi/detected.jpg") 386 | timeout = time.time() + int(params['timer'])*60 387 | target = 1 388 | if doors == 0: 389 | print "Doors Opening" 390 | GPIO.setup(13, GPIO.OUT) 391 | GPIO.setup(15, GPIO.OUT) 392 | time.sleep(10) 393 | GPIO.cleanup(13) 394 | GPIO.cleanup(15) 395 | print "Doors Open" 396 | doors = 1 397 | if human_string_n in (params['never_feed']) and score >.75: 398 | print "Non Target Detected" 399 | nontarget=1 400 | scans = scanmax 401 | os.remove("/home/pi/current_frame.jpg") 402 | # if the 'q' key is pressed, stop the loop 403 | if cv2.waitKey(1) & 0xFF == ord("q"):break 404 | 405 | vs.stop() 406 | print "Closing Camera" 407 | time.sleep(2) 408 | --------------------------------------------------------------------------------