目录
一、目标检测简介
- 目标检测是计算机视觉中一个重要的研究方向。
- 人眼可以轻松、准确地识别出图片中的物体是什么、这个物体在图片中的哪个位置。
- 对于计算机来说,在以数字形式表示的图片中寻找目标物体,并判断这个物体是什么,这是一件困难的事情。
目标检测的发展
可以分为两个阶段:传统检测算法和基于深度学习的检测算法。
- 传统的目标检测算法是通过将人为设计的目标特征和机器学习的分类器相结合来实现的。
- 基于深度学习的检测算法可分为两类:
- 一类是使用基于候选区域(Region Proposal)的方法先找出图片中可能存在目标的区域,然后通过卷积神经网络对该区域进行分类;
- 另一类是直接使用卷积神经网络预测目标所属类别的概率和其在图片中的位置坐标。
由于深度学习的崛起,推动了目标检测的快速发展和应用,如今目标检测已经广泛的应用于我们的日常生活中,如自动驾驶、安保监控、医疗影像、机器视觉等领域。
虽然目标检测在发展过程中取得了很多成果,但同时也面临很多挑战,例如目标检测在实时性、抗干扰性、工业的大规模应用等方面还存在很多阻碍。
二、相关的工具的介绍
OpenCV
OpenCV
:
- 是一个基于 C++ 编写的轻量级高效的开源许可发行的跨平台计算机视觉库,可运行在多种操作系统上:Windows、Mac OS、Linux、Android。
- 由于其具有友好的可读性和运行的效率,故获得大量开发者的青睐,同时其还提供 Python、Ruby 等语言的接口方便开发者调用。本教程将使用 Python 语言对 OpenCV 的库函数进行调用。
NumPy
NumPy
- 是一个支持处理多维度大型矩阵的 Python 科学计算包。
- 在对图像进行处理时经常会用到 NumPy,OpenCV 中读取存储图片都是以 NumPy 形式完成的。
- 利用 NumPy 我们可以轻松的以多维数据的形式呈现图片,并对图片进行重组、计算、数值分析等操作。
TensorFlow
TensorFlow
- 是一个开源的机器学习平台,其广泛应用于机器学习和深度学习算法实现上。
- 其可运行在多种平台上,如 PC、移动和分布式平台。支持多种计算机语言:C++、Python、Java、Go等。
- 由于其灵活、便捷、高性能以及活跃的社区等因素使得 TensorFlow 成为目前最受欢迎的机器学习开源框架之一。
scikit-learn
scikit-learn
- 基于 Python 的开源机器学习工具
- 其涵盖大部分机器学习算法,包括分类、回归、非监督分类、数据降维、数据预处理等,是一款高效的数据挖掘和分析的工具。
- 其通过NumPy、SciPy 和 Matplotlib 等实现多种算法并且可在各种环境中使用。
scikit-image
scikit-image
- 基于 Python 的开源图像处理工具
- 其将图片作为 NumPy 数组,并包括分割、几何变换、过滤等处理方法。
只需要在使用的时候直接调用就行了
三、滑动窗口(Sliding Windows)
3.1 简介
传统的目标检测方法:
- 首先需要提供待检测图片
- 然后将**滑动窗口(Sliding Windows)和图像金字塔(Image Pyramid)**这两种方法相结合
- 从图片中选择出一些区域。
- 通过一些算法提取出这些区域的特征信息
- 然后通过机器学习的分类器对提取的特征分类。
- 目标检测的输出结果一般是使用矩形框标记出要检测的目标
- 但是使用滑动窗口和图像金字塔时在同一个目标上会标记出多个矩形框
- 所以我们需要使用非极大值抑制(Non-maxima suppression)来剔除多余的矩形框
滑动窗口(Sliding Windows)在目标检测过程中的作用
- 定位目标(物体、动物等)在图片中的位置。
- 在计算机视觉中滑动窗口是一个矩形框
- 它沿着从左向右、从上向下的方向在图片上滑动
- 以达到提取出图片中每一个区域的目的。
3.2 代码来实现这个方法
首先在脚本中我们导入需要用到的模块
- 这里我们导入 cv2 模块用于处理图片。
- 分别从 matplotlib 导入
pyplot
和从 IPython 中导入display
模块用于显示图片。 - 然后我们使用
%matplotlib inline
魔法函数让图片在页面中显示。
import cv2
from matplotlib import pyplot as plt
from IPython import display
%matplotlib inline
3.2.1 定义函数获取滑动窗口
定义一个函数 sliding_window
用于获取滑动窗口。
- 这个函数有三个参数
image
、window
和step
。
- 第一个参数
image
是输入函数的图片,我们将用矩形框在这个图片上滑动。 - 第二个参数
window
是一个元组,表示滑动的矩形框的高和宽。 - 第三个参数
step
表示矩形框间隔多少个像素移动一次,这里我们可以称之为步长。
def sliding_window(image, window, step):
for y in range(0, image.shape[0] - window[1], step):
for x in range(0, image.shape[1] - window[0], step):
yield (x, y, image[y:y + window[1], x:x + window[0]])
- 图中的
n
就表示矩形框每次移动n
个像素的距离 step
设置的太小或太大都会对目标检测造成负面的影响,一般这个值会设置在 4 到 8 之间。
我们使用两个 for
循环获取矩形框的所有坐标位置。
- 第一个
for
循环控制矩形框以step
的步长在图片中上下移动 - 第二个
for
循环控制矩形框以step
的步长在图中左右移动。 - 最后通过
yield
生成器返回一个元组
- 其中元组的第一个元素
x
和第二个元素y
表示矩形框左上角的坐标 - 元组的第三个元素
image[y:y + window[1], x:x + window[0]]
就是处在图片中不同位置的矩形框。
- 使用
cv2.imread
函数读取图片
pets.jpg 是要读取的图片名。
- 然后我们定义滑动窗口的宽
window_w
为 400 个像素,滑动窗口的高window_h
为 400 个像素。 - 我们使用
n
来表示滑动窗口的数量。
image = cv2.imread("pets.jpg")
(window_w, window_h) = (400, 400)
3.2.2 遍历每一个滑动窗口
-
接下来使用一个
for
循环来遍历每一个滑动窗口 -
我们需要传递三个参数给
sliding_window
。 -
第一个参数
image
是我们读取的图片。 -
第二个参数
(window_w, window_h)
表示滑动窗口的宽和高。 -
第三个参数
200
表示滑动窗口将每次滑动的步长为200
个像素
(注意这里为了演示方便将滑动窗口和步长的值设置得都很大,在实际使用中不建议将其设置过大或过小)。
for (x, y, window) in sliding_window(image, (window_w, window_h), 200):
if window.shape[0] != window_w or window.shape[1] != window_h:
continue
clone = image.copy()
cv2.rectangle(clone, (x, y), (x + window_w, y + window_h), (0, 255, 0), 2)
clone = clone[:,:,::-1]
plt.imshow(clone)
plt.pause(0.1)
display.clear_output(wait=True)
- 然后我们使用一个
if
语句来判断获得的滑动窗口和我们设定的滑动窗口大小是否一致 - 如果滑动窗口截取的区域与设定的
(window_w, window_h)
中任意一个元素不同,则执行continue
跳过该滑动窗口。
在循环内我们绘制出图片中每一个滑动窗口了:
- 在绘制前使用
copy
函数复制输入函数的图片,因为接下来的画图操作将会修改源图片 - 接着我们使用
cv2.rectangle
在clone
上绘制出每个滑动窗口。 - 因为在 OpenCV 图片是以 B,G,R(蓝,绿,红)的通道顺序存储的,而在 Matplotlib 中图片是以 R,G,B 的通道顺序存储,所以我们使用
clone[:,:,::-1]
切片方法来跳转图片通道的顺序 - 然后使用
plt.imshow
在页面中呈现绘图后的结果。
因为我们在 for 循环内要绘制多张图片
- 所以使用
plt.pause(0.1)
让每张图片显示暂停一段时间,函数的参数 0.1 表示暂停 0.1 秒。 - 最后我们使用 display 的
clear_output(wait=True)
方法清除已经显示的图片为下一张图片显示做准备。
执行代码后绘制的滑动窗口的结果如下所示:
从图中我们可以看到滑动窗口按照从左向右、从上向下在图片上滑动。
四、实验总结
- 学习了目标检测的基本概念
- 在传统检测算法中常用的滑动窗口方法,该方法是用来定位目标(物体、动物等)在图片中的位置的。