Today I got the v0.2 code completed. So we take a photo on PIR=HIGH, run inference using TFLITE, and then annotate it with the top class, using Pillow! We also take a video, but we are not doing any video classification or object detection at the moment, and it seems a cheat to label it with the species name from the still image!
What's to-do next per software?
- We can run a web server, and SQL database on the Pi, so we can store all the images with their associated species classifications. Then we can show a list with images of all the species identified. Add a thumbs up/down to see if user agrees with the CNN classification. Side bar for total species seen, how many in last hr/day. Also stick the videos on the web server too (although remain unclassified)
- Update so we can add sound to the video recordings from the USB mic
- Make some kind of Android app that pulls data from the SQL database, so images and videos can be viewed easily
import RPi.GPIO as GPIO
import time
from PIL import Image, ImageDraw, ImageFont
import numpy as np
import tflite_runtime.interpreter as tflite
import subprocess
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(7, GPIO.IN) #Read output from PIR motion sensor
# Load class labels
class_labels = ["Blackbird", "Bluetit", "Carrion Crow", "Chaffinch", "Coal Tit", "Collared Dove",
"Dunnock", "Feral Pigeon", "Goldfinch", "Great Tit", "Greenfinch", "House Sparrow", "Jackdaw",
"Long Tailed Tit", "Magpie", "Robin", "Song Thrush", "Starling", "Wood Pigeon", "Wren"] # class labels here
# Load the TFLite model
interpreter = tflite.Interpreter(model_path="birds4.tflite")
interpreter.allocate_tensors()
# Get input & output tensor details
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
IMG_SIZE = (224, 224) # make sure these are made to correct size for model!
# Load and preprocess image
def preprocess_image(image_path):
image = Image.open(image_path)
image = image.resize(IMG_SIZE)
img_array = np.array(image, dtype=np.float32)
img_array = img_array / 255.0 # Normalize if needed
img_array = np.expand_dims(img_array, axis=0) # Add batch dimension
return img_array
# Run inference
def predict(image_path):
image = preprocess_image(image_path)
# Set input tensor
interpreter.set_tensor(input_details[0]['index'], image)
# Run inference
interpreter.invoke()
predictions = interpreter.get_tensor(output_details[0]['index'])[0]
# Get predictions
predicted_class_idx = np.argmax(predictions)
predicted_class_label = class_labels[predicted_class_idx]
confidence_score = float(predictions[predicted_class_idx])
# Return predicted class & probabilities
return{
"predicted_class": predicted_class_label,
"confidence": round(confidence_score * 100,2)
}
def annotate_photo(image_path, species):
image = Image.open(image_path)
draw = ImageDraw.Draw(image)
font_size = int(image.height *0.06)
try:
font = ImageFont.truetype("usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", font_size)
except:
font = ImageFont.load_default()
#add text
text = f"Detected: {species}"
text_width, text_height = draw.textsize(text, font=font)
padding = 10
box_x = 10
box_y = image.height - text_height - 100
box_width = text_width +2 * padding
box_height = text_height +2 * padding
draw.rectangle(
[box_x, box_y, box_x + box_width, box_y + box_height],
fill="black"
)
draw.text(
(box_x + padding, box_y + padding),
text,
font=font,
fill="white"
)
annotated_path = image_path.replace(".jpg", "_labeled.jpg")
image.save(annotated_path)
print(f"Annotateed image saved as {annotated_path}")
def take_photo():
timestamp = time.strftime("%Y%m%d-%H%M%S")
image_path = f"/home/whosthatbird/photos/photo_{timestamp}.jpg"
subprocess.run([
"libcamera-still",
"-o", image_path,
"-t", "2000"
])
return image_path
def record_video():
timestamp = time.strftime("%Y%m%d-%H%M%S")
filename = f"/home/whosthatbird/Videos/video_{timestamp}.h264"
subprocess.run([
"libcamera-vid",
"-o", filename,
"-t", "10000"
])
while True:
i=GPIO.input(7)
if i==0: #When output from motion sensor is LOW
print("No birds")
time.sleep(0.1)
elif i==1: #When output from motion sensor is HIGH
print("bird detected")
image_path = take_photo()
print(image_path)
species = predict(image_path)
print(species)
annotated_img = annotate_photo(image_path, species)
#record_video()
time.sleep(2)
time.sleep(0.1)
Neil K. Sheridan
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.