目录
介绍
选择网络架构
害虫检测代码
它能运行吗?
它可以在边缘设备上工作吗?
下一步
在这里,我们给出了有关如何使用预训练的MobileSSD模型检测对象的简短说明。然后,我们提供并解释用于使用SSD模型检测视频中动物的Python代码。最后,我们在视频文件上演示了某种动物类型(SSD模型能够检测到)的检测结果。
- 下载源34.8 KB
- 下载模型-26 MB(外部链接)
野蛮的野生生物可能给企业和房主带来痛苦。鹿、驼鹿甚至猫等动物都会对花园、庄稼和财产造成破坏。
在本系列文章中,我们将演示如何在Raspberry Pi上实时(或近实时)检测有害生物(例如驼鹿),然后采取措施消除有害生物。由于我们不想造成任何伤害,我们将通过播放巨大的噪音来吓跑害虫。
欢迎您下载该项目的源代码。我们假设您熟悉Python并且对神经网络的工作原理有基本的了解。
在该系列的上一篇文章中,我们比较了可用于检测有害生物的两种DNN类型:检测器和分类器。检测器赢了。在本文中,我们将开发使用预先训练的检测DNN来检测有害生物的Python代码。
选择网络架构有几种常见的对象检测网络架构,例如Faster-RCNN,单发检测器(SSD)和“只看一次”(YOLO)。
由于我们的网络需要在内存和CPU受限的边缘设备上运行,因此我们将使用MobileNet单发检测器(SSD)架构。MobileNet SSD是一种轻量级的对象检测器网络,可以在移动设备和边缘设备上很好地运行。在Pascal VOC 2012数据集上对其进行了训练,该数据集包含一些可能代表害虫的类别,例如猫、牛、狗、马和羊。
我们将使用与该先前的文章系列中用于人类检测的算法相同的算法来检测视频中的害虫。
害虫检测代码首先,我们需要修改MobileNet代码以使其检测到有害生物。
让我们从创建一些实用程序类开始,以简化此任务:
import cv2
import numpy as np
import os
class CaffeModelLoader:
@staticmethod
def load(proto, model):
net = cv2.dnn.readNetFromCaffe(proto, model)
return net
class FrameProcessor:
def __init__(self, size, scale, mean):
self.size = size
self.scale = scale
self.mean = mean
def get_blob(self, frame):
img = frame
(h, w, c) = frame.shape
if w>h :
dx = int((w-h)/2)
img = frame[0:h, dx:dx+h]
resized = cv2.resize(img, (self.size, self.size), cv2.INTER_AREA)
blob = cv2.dnn.blobFromImage(resized, self.scale, (self.size, self.size), self.mean, False, False)
return blob
class Utils:
@staticmethod
def draw_object(obj, label, color, frame):
(confidence, (x1, y1, w, h)) = obj
x2 = x1+w
y2 = y1+h
cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2)
y3 = y1-12
text = label + " " + str(confidence)+"%"
cv2.putText(frame, text, (x1, y3), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 1, cv2.LINE_AA)
@staticmethod
def draw_objects(objects, label, color, frame):
for (i, obj) in enumerate(objects):
Utils.draw_object(obj, label, color, frame)
CaffeModelLoader类使用为原型和模型文件提供的路径从磁盘加载Caffe模型。
下一个实用程序类FrameProcessor,将帧转换为Blob(用作CNN输入的特殊结构化数据)。
最后,Utils类在框架中检测到的所有对象周围绘制边界矩形。我们的实用程序类使用的大多数方法来自OpenCV库的Python版本。让我们详细看看这些。
对于我们的实用程序类就是这样。接下来,我们将编写实际检测有害生物的代码。
从SSD类开始,它可以检测框架中指定类的对象:
class SSD:
def __init__(self, frame_proc, ssd_net):
self.proc = frame_proc
self.net = ssd_net
def detect(self, frame):
blob = self.proc.get_blob(frame)
self.net.setInput(blob)
detections = self.net.forward()
# detected object count
k = detections.shape[2]
obj_data = []
for i in np.arange(0, k):
obj = detections[0, 0, i, :]
obj_data.append(obj)
return obj_data
def get_object(self, frame, data):
confidence = int(data[2]*100.0)
(h, w, c) = frame.shape
r_x = int(data[3]*h)
r_y = int(data[4]*h)
r_w = int((data[5]-data[3])*h)
r_h = int((data[6]-data[4])*h)
if w>h :
dx = int((w-h)/2)
r_x = r_x+dx
obj_rect = (r_x, r_y, r_w, r_h)
return (confidence, obj_rect)
def get_objects(self, frame, obj_data, class_num, min_confidence):
objects = []
for (i, data) in enumerate(obj_data):
obj_class = int(data[1])
obj_confidence = data[2]
if obj_class==class_num and obj_confidence>=min_confidence :
obj = self.get_object(frame, data)
objects.append(obj)
return objects
该类中的关键方法是detect和get_objects。
该detect方法将加载的DNN模型应用于每个帧,以检测所有可能类别的对象。
该get_objects方法查看检测到的对象,并仅选择那些既属于指定类又具有被正确检测到的高概率(置信度)的对象。
然后,我们将使用VideoSSD类,该类在整个视频剪辑上运行有害生物检测:
class VideoSSD:
def __init__(self, ssd):
self.ssd = ssd
def detect(self, video, class_num, min_confidence, class_name):
detection_num = 0;
capture = cv2.VideoCapture(video)
img = None
dname = 'Pest detections'
cv2.namedWindow(dname, cv2.WINDOW_NORMAL)
cv2.resizeWindow(dname, 1280, 960)
# Capture all frames
while(True):
(ret, frame) = capture.read()
if frame is None:
break
obj_data = self.ssd.detect(frame)
class_objects = self.ssd.get_objects(frame, obj_data, class_num, min_confidence)
p_count = len(class_objects)
detection_num += p_count
if len(class_objects)>0:
Utils.draw_objects(class_objects, class_name, (0, 0, 255), frame)
# Display the resulting frame
cv2.imshow(dname,frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
capture.release()
cv2.destroyAllWindows()
return detection_num
该类中唯一的方法是detect。它处理从视频文件提取的所有帧。在每个框架中,它检测由class_num参数指定的类的所有对象,然后在检测到的对象周围显示带有边界矩形的框架。
让我们启动代码,看看它如何处理视频文件。以下代码加载视频文件并尝试检测狗:
proto_file = r"C:\PI_PEST\net\mobilenet.prototxt"
model_file = r"C:\PI_PEST\net\mobilenet.caffemodel"
ssd_net = CaffeModelLoader.load(proto_file, model_file)
mobile_proc_frame_size = 300
ssd_proc = FrameProcessor(mobile_proc_frame_size, 1.0/127.5, 127.5)
pest_class = 12
pest_name = "DOG"
ssd = SSD(ssd_proc, ssd_net)
video_file = r"C:\PI_PEST\video\dog_1.mp4"
video_ssd = VideoSSD(ssd)
detections = video_ssd.detect(video_file, pest_class, 0.2, pest_name)
我们将pest_class值设置为12,因为“dog”是MobileNet SSD模型中的第12类。这是运行上述代码时捕获的视频。
https://youtube.com/embed/V7efecRb8Lo
它可以在边缘设备上工作吗?如您所见,当在PC上运行时,我们的SSD检测器成功检测到视频中的狗。边缘设备呢?检测器是否会足够快地处理提要以实时检测物体?我们可以通过测试以每秒帧数(FPS)衡量的帧速率来找出。
在我们之前引用的文章中,我们借用的模型在Raspberry Pi 3设备上的运行速度约为1.25 FPS。这足以检测到害虫吗?我们可以假设平均而言,动物会在相机上捕获至少2到3秒。这意味着我们将拥有2到3个帧来检测有害生物并对其做出反应。听起来很有可能。
下一步到目前为止,对于野生动植物的检测结果还不是很有希望。但是我们不要放弃!
在接下来的文章中,我们将讨论一些想法检测“异国情调”的害虫,如驼鹿和犰狳。
https://www.codeproject.com/Articles/5289748/Detecting-Pests-Using-Pre-Trained-SSD-Models