• 下载数据-19.3 MB
  • 下载模型-43.5 MB
  • 下载结果-36.66 MB

在本系列的上一篇文章中,我们选择了两种SSD模型进行进一步工作,一种基于MobileNet,另一种基于SqueezeNet。在本文中,我们将开发一些Python代码,这些代码使我们能够使用这些模型检测图像中的人物。

选定的DNN被实现为Caffe模型。Caffe模型由两部分组成:模型结构(.prototxt)文件和训练后的模型(.caffemodel)。Caffe模型结构以类似于JSON的格式编写。训练后的模型是CNN内核和其他训练后数据的二进制序列化。在本系列的第一篇文章中,我们提到了将Caffe与Python OpenCV结合使用。这是什么意思?我们应该同时安装两个框架,OpenCV和Caffe吗?幸运的是,没有,只有OpenCV库。该框架包括DNN模块,该模块直接支持使用TensorFlow,Caffe,Torch,Darknet等开发的网络模型。所以——幸运的我们!—— OpenCV框架允许同时使用计算机视觉算法和深度神经网络。这就是我们所需要的。

让我们从两个实用程序类开始我们的Python代码:

import cv2
import numpy as np
import osclass CaffeModelLoader:    @staticmethoddef load(proto, model):net = cv2.dnn.readNetFromCaffe(proto, model)return netclass FrameProcessor:   def __init__(self, size, scale, mean):self.size = sizeself.scale = scaleself.mean = meandef get_blob(self, frame):img = frame(h, w, c) = frame.shapeif 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)return blob

CaffeModelLoader类具有一个静态方法来加载来自磁盘的Caffe模型。之后的FrameProcessor类旨在将数据从图像转换为DNN的特定格式。该类的构造函数接收三个参数。size参数定义用于DNN处理的输入数据的大小。用于图像处理的卷积网络几乎总是使用正方形图像作为输入,因此我们仅为宽度和高度指定一个值。scale和mean参数用于将数据缩放到训练SSD所用的值范围。该类的唯一方法是get_blob,它接收图像并返回blob——神经网络处理的一种特殊结构。为了接收blob,首先将图像调整为指定的正方形。然后,使用OpenCV的DNN模块中的blobFromImage方法使用指定的scale、size和mean值,从调整大小后的图像创建Blob 。

注意get_blob方法开头的代码。该代码实现了一些“技巧”:我们修剪非正方形图像以仅获取图像的中心正方形部分,如下图所示:

此技巧旨在使图像的纵横比保持恒定。如果宽高比改变,图像将变形,并且物体检测的精度将降低。此技巧的一个缺点是,我们只会在图像的中央正方形部分(上图中以蓝色显示)检测到人员。

现在让我们看一下使用SSD模型进行人检测的主要类别:

class SSD: def __init__(self, frame_proc, ssd_net):self.proc = frame_procself.net = ssd_netdef detect(self, frame):blob = self.proc.get_blob(frame)self.net.setInput(blob)detections = self.net.forward()# detected object countk = detections.shape[2]obj_data = []for i in np.arange(0, k):obj = detections[0, 0, i, :]obj_data.append(obj)return obj_datadef get_object(self, frame, data):confidence = int(data[2]*100.0)(h, w, c) = frame.shaper_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+dxobj_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

上面的类的构造函数有两个参数:frame_proc用于将图像转换为blob而ssd_net用于检测对象。主要方法detect接收帧(图像)作为输入,并使用指定的帧处理器从该帧获取blob。该blob用作网络的输入,我们使用该forward方法获得检测结果。这些检测结果显示为4级数组(张量)。我们不会分析整个张量。我们只需要数组的第二维。我们将从检测结果中提取出来并返回结果——对象数据列表。

对象数据是一个实数组。这是一个例子:

[array([ 0.        , 15.       ,  0.90723044,  0.56916684,  0.6017439 ,0.68543154,  0.93739873], dtype=float32)]

该数组包含七个数字:

  1. 检测到的物体数
  2. 类数量
  3. 对象属于给定类的置信度
  4. 对象ROI的四个左上角和右下角坐标(这些坐标相对于Blob大小)

该类的第二种方法将检测数据转换为更简单的格式,以备将来使用。它将相对置信度转换为百分比值,并将相对ROI坐标转换为整数数据——原始图像中的像素坐标。该方法考虑了从原始帧的中心正方形提取blob数据的事实。

最后, get_objects方法仅从检测数据中提取具有指定类别和足够置信度的对象。由于DNN模型可以检测到二十个不同类别 的person对象,因此我们仅对该类别的检测进行过滤,以确保检测到的对象确实是人类,因此我们指定了高置信度阈值。

另一个实用程序类——用于将检测到的对象绘制到图像中以可视化结果:

class Utils:   @staticmethoddef draw_object(obj, label, color, frame):(confidence, (x1, y1, w, h)) =  objx2 = x1+wy2 = y1+hcv2.rectangle(frame, (x1, y1), (x2, y2), color, 2)y3 = y1-12text = label + " " + str(confidence)+"%"cv2.putText(frame, text, (x1, y3), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 1, cv2.LINE_AA)@staticmethoddef draw_objects(objects, label, color, frame):for (i, obj) in enumerate(objects):Utils.draw_object(obj, label, color, frame)

现在我们可以编写代码来启动人检测算法:

proto_file = r"C:\PI_RPD\mobilenet.prototxt"
model_file = r"C:\PI_RPD\mobilenet.caffemodel"
ssd_net = CaffeModelLoader.load(proto_file, model_file)
print("Caffe model loaded from: "+model_file)proc_frame_size = 300
# frame processor for MobileNet
ssd_proc = FrameProcessor(proc_frame_size, 1.0/127.5, 127.5)
person_class = 15ssd = SSD(ssd_proc, ssd_net)im_dir = r"C:\PI_RPD\test_images"
im_name = "woman_640x480_01.png"
im_path = os.path.join(im_dir, im_name)
image = cv2.imread(im_path)
print("Image read from: "+im_path)obj_data = ssd.detect(image)
persons = ssd.get_objects(image, obj_data, person_class, 0.5)
person_count = len(persons)
print("Person count on the image: "+str(person_count))
Utils.draw_objects(persons, "PERSON", (0, 0, 255), image)res_dir = r"C:\PI_RPD\results"
res_path = os.path.join(res_dir, im_name)
cv2.imwrite(res_path, image)
print("Result written to: "+res_path)

该代码实现了一个size= 300的帧处理器,因为我们使用的模型适用于300 x 300像素的图像。scale和mean参数都被用于MobileNet模型训练,同样的值。这些值必须始终分配给模型的训练值,否则模型的精度会降低。person_class的值是15,因为人体是模型上下文中的第15个类。

在示例图像上运行代码会产生以下结果:

我们使用非常简单的案例来检测人员。目的只是检查我们的代码是否正确工作,并且DNN模型可以预测人在图像中的存在。而且有效!

下一步

下一步是在Raspberry Pi设备上启动我们的代码。在接下来的文章中,我们将看看如何在设备上安装Python的OpenCV的和运行代码。

边缘设备上的实时AI人员检测:使用预先训练的SSD模型检测人员相关推荐

  1. 边缘设备上的实时AI虫害消除:入门

    目录 介绍 选择器与检测器 实时性呢? 下一步 在这里,我们从使用AI和DNN的角度阐述了害虫消除的问题.然后,我们提出两种可能的解决方案:1--使用预训练的SSD模型检测猫.羊和其他动物:2--使用 ...

  2. 边缘设备上的实时AI人员检测:以实时模式检测视频中的人员

    下载数据-19.3 MB 下载模型-43.5 MB 下载结果-36.66 MB 这是七篇系列文章中的最后一篇.到目前为止,我们已经有了用于人员检测的DNN模型和用于在Raspberry Pi设备上启动 ...

  3. 边缘设备上的实时AI人员检测:检测视频中的人员

    下载数据-19.3 MB 下载模型-43.5 MB 下载结果-36.66 MB 从本系列的前几篇文章中,我们获得了使用SSD DNN模型检测图像中人物的Python代码.而且我们已经展示了该代码可以在 ...

  4. 边缘设备上的实时AI人员检测:入门

    下载数据-19.3 MB 下载模型-43.5 MB 下载结果-36.66 MB 得益于深度学习(DL),实时视频流中的人的实时检测几年前就已经解决了.但是,在边缘和物联网设备上并不总是那么容易,因为它 ...

  5. 边缘设备上的实时AI人员检测:在Raspberry Pi上启动SSD

    下载数据-19.3 MB 下载模型-43.5 MB 下载结果-36.66 MB 在本系列的最后一篇文章中,我们编写了Python代码,用于使用SSD模型检测图像中的人物.在本文中,我们将介绍在Rasp ...

  6. 使用预先训练的SSD模型检测害虫

    目录 介绍 选择网络架构 害虫检测代码 它能运行吗? 它可以在边缘设备上工作吗? 下一步 在这里,我们给出了有关如何使用预训练的MobileSSD模型检测对象的简短说明.然后,我们提供并解释用于使用S ...

  7. 边缘设备上的实时AI人员检测:在Raspberry Pi上测试SSD模型

    下载数据-19.3 MB 下载模型-43.5 MB 下载结果-36.66 MB 在本系列的上一篇文章中,我们已经在Raspberry Pi设备上启动了人体检测软件.在这一本文中,我们将比较Raspbe ...

  8. 边缘设备上的实时AI人员检测:选择深度学习模型

    下载数据-19.3 MB 下载模型-43.5 MB 下载结果-36.66 MB 在本系列的介绍性文章中,我们讨论了为边缘设备创建DL人员检测器的简单方法,该方法是找到合适的DNN模型并编写代码以在设备 ...

  9. 170 FPS!YolactEdge:边缘设备上的实时实例分割,已开源!

    点击上方"CVer",选择加"星标"置顶 重磅干货,第一时间送达 本文转载自:AI人工智能初学者 论文:https://arxiv.org/abs/2012.1 ...

最新文章

  1. Kubernetes(五) - Service
  2. My97DatePicker日历插件
  3. 弱电工程网络视频监控系统联网方式及接地要求
  4. 科大星云诗社动态20210331
  5. LeetCode —— 1554. 只有一个不同字符的字符串(Python)
  6. 2021年中国乙酸异冰片酯市场趋势报告、技术动态创新及2027年市场预测
  7. C#.Net 使用 JsonReader/JsonWriter 高性能解析/生成 Json 文档
  8. nagios 流量监控和报警的shell脚本
  9. 漫谈 Clustering (追忆篇): Regularized GMM
  10. 模拟https类型的get,post请求时,碰到证书不信任,无法正常获取返回内容的异常
  11. 计算机组成原理中ID是什么,计算机组成原理
  12. 《妈妈是孩子最好的老师》读后感
  13. Linux设置串口波特率等参数
  14. 电子计算机的指令是由什么和什么组成的,吴承亮问:计算机指令由两部分组成它们是 计算机指令由哪两个字段组成,各自的作用是什么?...
  15. C++编程 杨辉三角
  16. 古马其顿国王-亚历山大
  17. 大翻盘!超80亿美元Java侵权案落槌,谷歌胜诉!
  18. 今日头条怎么申请开通原创,怎么快速过新手期
  19. Personalized Re-ranking for Recommendation
  20. 从入门到精通,计算机er如何快速掌握机器学习(ML)?

热门文章

  1. qthread run结束了算销毁吗_Java线程的run()方法和start()方法有什么区别?
  2. spring3.0 aop 获取 ibatis 执行的语句_Mybatis 源码分析:执行器
  3. mysql master线程 fork_多线程中fork的坑
  4. promise用法_【JavaScript 教程】异步操作——Promise 对象
  5. 设计灵感|信息图表海报竟然能设计的这么有趣!
  6. 手绘水彩卡通插画 | 艺术品因有灵魂而珍藏
  7. 「PPT模板」 商务UI风格
  8. Linux内存管理:内存寻址之分段机制与分页机制
  9. Linux内存管理:分页机制
  10. FD.io VPP:vlib buffer pool(vlib_buffer) 内存初始化