如何使用Faster R-CNN来计算对象个数
准确地在给定的图像或视频帧中计算对象个数的实例是机器学习中很难解决的问题。尽管许多解决方案已经被开发出来,用来计算人、汽车和其他物体的数量,但是没有一个是完美的办法。当然,我们这里讨论的是图像处理,所以神经网络对于这项工作来说似乎是一个很好的工具。
你可以在下面的神经网络对象计数域中找到不同方法、常见问题、挑战和最新解决方案的描述。作为概念的证明,Faster R-CNN网络的现有模型将被用来计算街道上的物体数量,并在文章的最后给出视频示例。
挑战
对于计算对象个数的问题,找到一个合适的解决方案取决于许多因素。除了一些与神经网络图像处理有关的挑战,例如训练数据的大小,它的质量等等。下面是对计数对象个数问题的具体挑战:
- 要计算的对象类型
- 重叠
- 透视图
- 检测到的对象的最小尺寸
- 训练和测试速度
用来计算公路上的汽车数量或是体育场上的人群的这些方法,通常大多数对象重叠,并且透视图通常也是允许遥远距离中很小的对象的。
同时,在一个单一图片中计算对象数量的解决方案可以不同于在一个实时视频中计算对象数量的解决方案。
简单的需求,简单的解决方案
在这篇文章中,我将尝试解决在街道上计算对象数量的问题,使用多个对象同时可见的示例视频。为了处理拥挤场景的图像或交通堵塞,以准确地计算物体数量的实例,我建议深入研究该领域的最新研究:“Towards perspective-free object counting with deep learning(利用深度学习进行无透视对象的数量计算)”。这篇论文的结果可以用GitHub上的代码进行复制。
在上述的论文中,像CCNN和Hydra CNN这样的方法在给定不同类型的对象的情况下表现不佳,因此需要采取不同的方法。
在机器学习领域(特别是卷积神经网络的深度学习)中,有一种非常有趣的方法,叫做基于区域的卷积神经网络(R-CNN),我们可以在一个给定的图像上识别多个物体及其位置。
为了我们的概念验证工作,我将使用“Faster R-CNN”的Keras实现来处理视频文件,并使用给定类的检测对象来对图像进行注释。
FAST和FASTER
有许多方法可以把找到对象位置和识别对象的方法结合起来,以提高速度和准确性。多年来,我们已经从使用标准的RCNN网络,通过Fast R-CNN,到Faster R-CNN,来解决我们简单的计算问题。 Fast R-CNN建立在之前的工作上,以有效地利用深度卷积网络对对象提议进行分类。与R-CNN相比,Fast R-CNN引入了一些改进训练和测试速度的创新,以及检测的准确性。
在多阶段管道(multi-stage pipelines)中使用R-CNN训练模型的方法(首先检测对象边界,然后执行识别)是相当慢的,不适合实时处理。这种方法的缺点主要是它的速度,无论是在训练过程中,还是在实际测试期间。当对象检测被执行的时候, 使用著名的VGG16,一个标准的R-CNN的训练过程:GPU需要花费两天半的时间来完成5000张的图像,并且需要几百GB的存储空间。在测试时检测对象使用一个GPU来花费47s处理出一张图片。这主要是由于在没有共享计算的情况下,对每个对象提议进行了卷积网络的正向传递。
Fast R-CNN通过引入一种单阶段训练算法来改进R-CNN,该算法将对象和它们的空间位置在一个处理阶段进行分类。Fast R-CNN的改进是:
- 更高的检测质量
- 在单一阶段使用多任务损失进行训练
- 训练可以更新所有网络层
- 特性缓存不需要磁盘存储
Faster R-CNN引入了一个区域提议网络(RPN),它与检测网络共享完整图像的卷积特性,支持几乎没有成本的区域建议。这个解决方案的RPN组件指出了统一的网络在哪里可以查看。对于同样的VGG-16模型, Faster R-CNN在GPU上的帧速率为5 fps,同时达到了最先进的目标检测精度。RPN是一种完全的卷积网络,可以针对生成检测方案的任务进行端到端训练,并被设计用来有效地预测具有广泛范围和纵横比的区域提议。
Faster R-CNN在去年被Pinterest用作一种解决方案,可以在他们的网站上进行视觉搜索,可以在下面的PoC描述中看到我们检测和计算样本视频中的对象。
概念验证
为了解决我们的想象问题,我们将使用前面提到的Faster R-CNN模型,和在一个GPU可行的AWS实例上的Keras。我们处于一个舒适的位置,可以下载已经预先训练好的模型,最适合我们的需求和选择的框架。当然,你可以使用所提供的Python脚本对模型进行训练,请记住,它可能需要花费许多时间。
对于Faster R-CNN来说,它存在多重实现,包括Caffe,TensorFlow等等。我们将在后端使用TensorFlow和Keras(v.2.0.3)。这段代码可以作为GitHub上最初的Keras F R-CNN实现的一个复刻(fork)。
测试网络的脚本被修改,这样它就可以处理视频文件,并为检测到的对象(有可能性)添加适当的数据,并对已计数对象的摘要进行注释。我使用opencv来处理视频和已经训练过的模型(可在这里下载),同时处理帧。
有许多用于处理视频的实用方法,例如:
def convert_to_images():
cam = cv2.VideoCapture(input_video_file)
counter = 0
while True:
flag, frame = cam.read()
if flag:
cv2.imwrite(os.path.join(img_path, str(counter) + '.jpg'),frame)
counter = counter + 1
else:
break if cv2.waitKey(1) == 27:
break
# press esc to quit
cv2.destroyAllWindows()
并将视频从经过处理的帧中保存:
def save_to_video(): list_files = sorted(get_file_names(output_path), key=lambda var:[int(x) if x.isdigit() else x for x in re.findall(r'[^0-9]|[0-9]+', var)])
img0 = cv2.imread(os.path.join(output_path,'0.jpg'))
height , width , layers = img0.shape
# fourcc = cv2.cv.CV_FOURCC(*'mp4v') fourcc = cv2.VideoWriter_fourcc(*'mp4v')
#fourcc = cv2.cv.CV_FOURCC(*'XVID') videowriter = cv2.VideoWriter(output_video_file,fourcc, frame_rate, (width,height))
for f in list_files:
print("saving..." + f)
img = cv2.imread(os.path.join(output_path, f)) videowriter.write(img)
videowriter.release()
cv2.destroyAllWindows()
当对象检测在测试期间进行时,我正在创建一个带有检测对象类和第1号的元组列表,这一列表在之后会减少为特定对象类的出现次数:
for jk in range(new_boxes.shape[0]):
(x1, y1, x2, y2) = new_boxes[jk,:]
cv2.rectangle(img_scaled,(x1, y1), (x2, y2), class_to_color[key],2)
textLabel = '{}: {}'.format(key,int(100*new_probs[jk]))
all_dets.append((key,100*new_probs[jk]))
all_objects.append((key, 1))
减少的方法:
def accumulate(l): it = itertools.groupby(l, operator.itemgetter(0))
for key, subiter in it:
yield key, sum(item[1] for item in subiter)
脚本参数是自描述型的
- “–input_file”,输入视频文件的路径。
- “–output_file”,输出视频文件的路径。
- “–input_dir”, 输入工作目录的路径,在该目录中存储了经过处理的帧。
- “–output_dir” 路径到输出工作目录,其中有带注释的处理框架存储。
- “–frame_rate” 帧率在构建视频输出时使用帧率。
使用示例:
python test_frcnn_count.py --input_file ~/videos/MVI_6848.mp4 --output_file ~/output4.mp4 --frame_rate=25
脚本处理的几个例子:
视频地址
https://www.youtube.com/watch?v=z2wQBNDYRXg
https://www.youtube.com/watch?v=n4vQxAFncKA
https://www.youtube.com/watch?v=YqoGPpFfQi
- PixelBender(着色器)初体验
- Centos下堡垒机Jumpserver V3.0环境部署完整记录(1)-安装篇
- CSS好看的按钮
- Metaball(元球)效果学习
- ASP.NET MVC 4 RC的JS/CSS打包压缩功能
- 表格可在线编辑效果
- CSS侧边栏宽度不动(更改页面宽度时),内容区宽度自适应
- JS网页顶部弹出可关闭广告图层
- 未来会不会出现人类大脑与人工智能进行链接,而产生的超级大脑?
- android布局文件中android:icon="?attr/menuIconCamera"找不到对应图标路径
- 无限级分类(非递归算法/存储过程版/GUID主键)完整数据库示例_(1)表结构
- Centos7修改默认网卡名(改为eth0)以及网卡启动报错RTNETLINK answers: File exists处理
- 通过企业分布式缓存共享运行时数据
- 移植SlidingMenu Android library,和安装example出现的问题解决
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 使用Python实现微信拍一拍功能的思路代码
- Laravel5.7 Eloquent ORM快速入门详解
- 微信公众号用户与网站用户的绑定解决方案分析
- laravel使用Faker数据填充的实现方法
- PHP开发实现快递查询功能详解
- Laravel5.7 数据库操作迁移的实现方法
- PHP7引入的"??"和"?:"的区别讲解
- Python自动化操作实现图例绘制
- ThinkPHP5.0框架使用build 自动生成模块操作示例
- PHP远程连接oracle数据库操作实现方法图文详解
- 微信公众平台开发教程②微信端分享功能图文详解
- 微信公众平台开发教程⑥ 微信开发集成类的使用图文详解
- keras分类之二分类实例(Cat and dog)
- 详解Python 循环嵌套
- PHP中quotemeta()函数的用法讲解