目录
- 一、图像金字塔的作用及实现
- 二、代码来实现图像金字塔
- 三、图像金字塔结合滑动窗口
- 3.1 代码实现
- 四、实验总结
- 介绍图像金字塔。
- 使用图像金字塔结合滑动窗口的方法
- 标记出图像中不同尺寸的物体。
一、图像金字塔的作用及实现
- 简单来说就是用多个不同的尺寸来表示一张图片。
- 最左边的图片是原始图片
- 然后从左向右图片的尺寸依次缩小直到图片的尺寸达到一个阈值,这个阈值就是多次缩小图片的最小尺寸,不会有比这更小尺寸的图片了
- 像这种图片的尺寸逐步递增或递减的多张图层就是图像金字塔
- 每张不同尺寸的图片都称为图像金字塔的一层。
- 图像金字塔的目的就是寻找图片中出现的不同尺寸的目标(物体、动物等)。
二、代码来实现图像金字塔
- 导入
cv2
模块用于处理图片 - 分别从
matplotlib
导入pyplot
和从IPython
中导入display
模块用于显示图片 - 然后我们使用
%matplotlib inline
魔法函数让图片在页面中显示
import cv2
from matplotlib import pyplot as plt
from IPython import display
%matplotlib inline
- 创建了一个名为
pyramid
函数,这个函数将用来生成图像金字塔
这个函数有三个参数:
- 第一个参数
image
是要进行图像金字塔操作的原始图片。 - 第二个参数
top
是图像将会被缩小的最小尺寸,我们将这个参数设置一个默认值为(128, 128)
,第一个128
表示图片的高,第二个128
表示图片的宽。 - 第三个参数
ratio
表示每次图像将会被缩小ratio
倍,我们给这个参数设置了一个默认值为1.2
。
def pyramid(image, top = (128, 128), ratio = 1.2):
yield image
while True:
(w, h) = (int(image.shape[1] / ratio), int(image.shape[0] / ratio))
image = cv2.resize(image, (w, h), interpolation = cv2.INTER_AREA)
if w < top[1] or h < top[0]:
break
yield image
- 在函数内我们首先使用
yield
生成器返回原始图片
因为在图像金字塔的最底端我们需要一张原始图片。 - 然后使用
while
循环来不断缩小图片尺寸。
直到缩小后图片的尺寸比前面的top
参数小为止。 - 在循环内
(w, h)
表示图像金字塔前一层的图像缩小ratio
倍的宽和高。
我们使用cv2.resize
方法将前一层图片进行缩放,我们将(w, h)
作为函数的第二个参数,表示缩放后图片的宽和高的值。 - 我们使用
if
语句判断图片的尺寸是否已经到达了设定的最小尺寸
将每次图片缩放后的宽和高与设定的最小尺寸top
进行对比
如果小于最小尺寸则使用break
结束循环 - 最后使用
yield
生成器返回每次缩放后的图片
至此图像金字塔的函数就构建完成了。
调用这个函数看下结果
- 首先我们使用
cv2.imread
函数读取图片。
image = cv2.imread("pets.jpg")
然后我们使用一个 for
循环获取每次缩放的图片
- 这里
pyramid
的第一个参数image
就是需要逐层缩小的图片。 - 第二个参数
top
不传入值,表示使用默认的最小尺寸。 - 第三个参数
ratio
表示每次将图片缩小1.5
倍。
- 接下来我们使用切片方法
i[:,:,::-1]
调整图片的通道顺序以便使用plt.imshow
方法显示图片 - 然后使用
plt.pause(0.3)
让每张图片显示暂停 0.3 秒 - 最后使用
display
的clear_output(wait=True)
方法清除当前显示的图片为显示下一张图片做准备。
for i in pyramid(image, ratio = 1.5):
i = i[:,:,::-1]
plt.imshow(i)
plt.pause(0.3)
display.clear_output(wait=True)
执行上面代码可以看到坐标轴上的数字在不断缩小
- 说明图片的尺寸已经按照我们传递给
pyramid
函数的参数来缩小了。
三、图像金字塔结合滑动窗口
在传统的目标检测方法中:
- 使用图像金字塔和滑动窗口相结合的方式来检测出图片中不同位置和不同尺寸的目标。
- 用滑动窗口的方法时,在图片上滑动的矩形框尺寸是固定的,这就导致了如果目标的尺寸相对于矩形框太大或太小都会导致我们无法检测到目标。
我们可以在图像金字塔的每层图片上进行滑动窗口的操作来解决这个问题。
- 左边的图片,狗并不能完全被矩形框包围,矩形框只能包住狗的部分面部区域;
- 右边的图片,通过运用图像金字塔和滑动窗口相结合的方法,矩形框的尺寸没有变化,但是在经过缩小后的图片中狗完全被矩形框包裹住了。
3.1 代码实现
- 创建中前面学习过的
sliding_window
函数
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]])
- 定义滑动窗口的宽
window_w
为 128 个像素,滑动窗口的高window_h
为 128 个像素
(window_w, window_h) = (128, 128)
- 使用一个
for
循环获取每层缩放的图片,其中pyramid
函数的每个参数上一节已经解释过了,这里就不做赘述了。
for i in pyramid(image, ratio = 1.5):
for (x, y, window) in sliding_window(i, (window_w, window_h), 100):
if window.shape[0] != window_w or window.shape[1] != window_h:
continue
clone = i.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.01)
display.clear_output(wait=True)
在循环内再使用一个 for
循环进行滑动窗口的操作
- 其中
sliding_window
函数的参数意义如下
- 第一个参数
i
是图像金字塔每层的图片。 - 第二个参数
(128, 128)
表示滑动窗口的宽和高都是128
。 - 第三个参数
100
表示滑动窗口将每次滑动的步长为100
个像素。
我们使用一个if
语句:
- 判断获得的滑动窗口和我们设定的滑动窗口大小是否一致。
- 如果滑动窗口截取的区域与设定的
(window_w, window_h)
中任意一个元素不同,则执行continue
跳过该滑动窗口。 - 最后就是在图片上绘制出滑动窗口。
下图就是我们运行脚本后得到的部分图片
- 可以看到我们在图像金字塔的每一层都使用滑动窗口
- 虽然矩形框的尺寸保持不变,但是随着图片地不断缩小,矩形框逐渐包裹住目标。
四、实验总结
本节实验我们学习了图像金字塔方法
- 图像金字塔就是用多个不同的尺寸来表示一张图片。
- 通常图像金字塔会和滑动窗口相结合来实现检测出图片中不同位置和不同尺寸的目标。