本篇博客记录学习OpenCV中的图像金字塔。
一般情况下,我们要处理的是一副具有固定分辨率的图像。但是有些情况下,我们需要对同一图像的不同分辨率的子图像进行处理。比如,我们要在一幅图像中查找某个目标,比如脸,我们不知道目标在图像中的尺寸大小。这种情况下,我们需要创建一组具有不同分辨率的图像,我们把这组图像叫做图像金字塔(简单来说就是同一图像的不同分辨率的子图集合)。如果我们把最大的图像放在底部,最小的放在顶部,看起来就像一座金字塔,故而得名图像金字塔。
图像金字塔有两类:高斯金字塔和拉普拉斯金字塔。
高斯金字塔的顶部是通过将底部图像中连续的行和列去除得到的。顶部图像中的每个像素值等于下一层图像中 5 个像素的高斯加权平均值。这样操作一次一个 MxN 的图像就变成了一个 M/2xN/2 的图像。所以这幅图像的面积就变为原来图像面积的四分之一。这被称为 Octave。连续进行这样的操作我们就会得到一个分辨率不断下降的图像金字塔。我们可以使用函cv2.pyrDown() 和 cv2.pyrUp() 构建图像金字塔。函数 cv2.pyrDown() 从一个高分辨率大尺寸的图像向上构建一个金子塔(尺寸变小,分辨率降低)。
操作分为两步:
操作同样分为两步:
例如:
接下来我们看一下各自的效果:
上采样:
代码:
# -*- coding: utf-8 -*-
# @Time : 2019/10/19 21:32
# @Author : MMagicLoren
# @Email : [email protected]
# @File : 图像金字塔.py
# @Software: PyCharm
import cv2 as cv
import numpy as np
if __name__ == '__main__':
src = cv.imread("F:/Pycharm/opencv_exercises-master/images/CrystalLiu4.jpg") # 读入图片放进src中
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE) # 创建窗口, 窗口尺寸自动调整
cv.imshow("input image", src)
print(src.shape) # 原始图像大小
up = cv.pyrUp(src)
cv.imshow("up image", up)
print(up.shape)
cv.waitKey(0) # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
cv.destroyAllWindows()
下采样:
代码:
# -*- coding: utf-8 -*-
# @Time : 2019/10/19 21:32
# @Author : MMagicLoren
# @Email : [email protected]
# @File : 图像金字塔.py
# @Software: PyCharm
import cv2 as cv
import numpy as np
if __name__ == '__main__':
src = cv.imread("F:/Pycharm/opencv_exercises-master/images/CrystalLiu4.jpg") # 读入图片放进src中
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE) # 创建窗口, 窗口尺寸自动调整
cv.imshow("input image", src)
print(src.shape) # 原始图像大小
# up = cv.pyrUp(src)
# cv.imshow("up image", up)
# print(up.shape)
down = cv.pyrDown(src)
cv.imshow("down image", down)
print(down.shape)
cv.waitKey(0) # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
cv.destroyAllWindows()
我们再用更形象的一种方法进行展示。
# -*- coding: utf-8 -*-
# @Time : 2019/10/19 21:32
# @Author : MMagicLoren
# @Email : [email protected]
# @File : 图像金字塔.py
# @Software: PyCharm
import cv2 as cv
import numpy as np
def pyramids_demo(image):
level = 3
temp = image.copy()
pyramid_images = [] # 定义一个图像list
for i in range(level):
dst = cv.pyrDown(temp)
pyramid_images.append(dst)
cv.imshow("pyramid_down_"+str(i+1), dst)
temp = dst.copy()
return pyramid_images
if __name__ == '__main__':
src = cv.imread("F:/Pycharm/opencv_exercises-master/images/CrystalLiu4.jpg") # 读入图片放进src中
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE) # 创建窗口, 窗口尺寸自动调整
cv.imshow("input image", src)
print(src.shape) # 原始图像大小
# up = cv.pyrUp(src)
# cv.imshow("up image", up)
# print(up.shape)
# down = cv.pyrDown(src)
# cv.imshow("down image", down)
# print(down.shape)
pyramids_demo(src)
cv.waitKey(0) # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
cv.destroyAllWindows()
同理,我们也可以得到上采样的图像。
注意,当我们对一幅图像先做上采样再做下采样(或者先做下采样后做上采样)后得到的图像与原图像是不相等的。
接下来我们再看拉普拉斯金字塔:
拉普拉斯金字塔由高斯金字塔形成。没有专用功能。拉普拉斯金字塔图像仅像边缘图像。它的大部分元素为零。它们用于图像压缩。拉普拉斯金字塔的层由高斯金字塔的层与高斯金字塔的上层的扩展版本之间的差形成。计算公式为:
# -*- coding: utf-8 -*-
# @Time : 2019/10/19 21:32
# @Author : MMagicLoren
# @Email : [email protected]
# @File : 图像金字塔.py
# @Software: PyCharm
import cv2 as cv
import numpy as np
def laplace_demo(image): # 注意:图片必须是满足2^n这种分辨率
down = cv.pyrDown(image)
down_up = cv.pyrUp(down)
lpls = image - down_up
cv.imshow("lpls image", lpls)
if __name__ == '__main__':
src = cv.imread("F:/Pycharm/opencv_exercises-master/images/messi5.jpg") # 读入图片放进src中
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE) # 创建窗口, 窗口尺寸自动调整
cv.imshow("input image", src)
print(src.shape) # 原始图像大小
# up = cv.pyrUp(src)
# cv.imshow("up image", up)
# print(up.shape)
# down = cv.pyrDown(src)
# cv.imshow("down image", down)
# print(down.shape)
# pyramids_demo(src)
laplace_demo(src)
cv.waitKey(0) # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
cv.destroyAllWindows()
# -*- coding: utf-8 -*-
# @Time : 2019/10/19 21:32
# @Author : MMagicLoren
# @Email : [email protected]
# @File : 图像金字塔.py
# @Software: PyCharm
import cv2 as cv
import numpy as np
def laplace_demo(image): # 注意:图片必须是满足2^n这种分辨率
pyramid_images = pyramids_demo(image)
level = len(pyramid_images)
for i in range(level-1, -1, -1):
if i-1 < 0:
expand = cv.pyrUp(pyramid_images[i], dstsize=image.shape[:2])
lpls = cv.subtract(image, expand)
cv.imshow("laplace_demo"+str(i), lpls)
else:
expand = cv.pyrUp(pyramid_images[i], dstsize=pyramid_images[i-1].shape[:2])
lpls = cv.subtract(pyramid_images[i-1], expand)
cv.imshow("laplace_demo"+str(i), lpls)
if __name__ == '__main__':
src = cv.imread("F:/Pycharm/opencv_exercises-master/images/lena.jpg") # 读入图片放进src中
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE) # 创建窗口, 窗口尺寸自动调整
cv.imshow("input image", src)
print(src.shape) # 原始图像大小
# up = cv.pyrUp(src)
# cv.imshow("up image", up)
# print(up.shape)
# down = cv.pyrDown(src)
# cv.imshow("down image", down)
# print(down.shape)
# pyramids_demo(src)
laplace_demo(src)
cv.waitKey(0) # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
cv.destroyAllWindows()
完整工程代码:
# -*- coding: utf-8 -*-
# @Time : 2019/10/19 21:32
# @Author : MMagicLoren
# @Email : [email protected]
# @File : 图像金字塔.py
# @Software: PyCharm
import cv2 as cv
import numpy as np
def pyramids_demo(image):
level = 3
temp = image.copy()
pyramid_images = [] # 定义一个图像list
for i in range(level):
dst = cv.pyrDown(temp)
pyramid_images.append(dst)
cv.imshow("pyramid_down_"+str(i+1), dst)
temp = dst.copy()
return pyramid_images
def laplace_demo(image): # 注意:图片必须是满足2^n这种分辨率
pyramid_images = pyramids_demo(image)
level = len(pyramid_images)
for i in range(level-1, -1, -1):
if i-1 < 0:
expand = cv.pyrUp(pyramid_images[i], dstsize=image.shape[:2])
lpls = cv.subtract(image, expand)
cv.imshow("laplace_demo"+str(i), lpls)
else:
expand = cv.pyrUp(pyramid_images[i], dstsize=pyramid_images[i-1].shape[:2])
lpls = cv.subtract(pyramid_images[i-1], expand)
cv.imshow("laplace_demo"+str(i), lpls)
if __name__ == '__main__':
src = cv.imread("F:/Pycharm/opencv_exercises-master/images/lena.jpg") # 读入图片放进src中
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE) # 创建窗口, 窗口尺寸自动调整
cv.imshow("input image", src)
print(src.shape) # 原始图像大小
# up = cv.pyrUp(src)
# cv.imshow("up image", up)
# print(up.shape)
# down = cv.pyrDown(src)
# cv.imshow("down image", down)
# print(down.shape)
# pyramids_demo(src)
laplace_demo(src)
cv.waitKey(0) # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
cv.destroyAllWindows()