OpenCV:08图像金字塔

目录

图像金字塔

图像金字塔介绍

图像金字塔是图像中多尺度表达的一种,最主要用于图像的分割,是一种以多分辨率来解释图像的有效且概念简单的结构。 简单来说,图像金字塔是同一图像不同分辨率的子图集合(有800×800、480×640…)

图像金字塔最初用于 机器视觉图像压缩,一幅图像的金字塔是一系列以金字塔形状排列的 分辨率逐渐降低、且 来源于同一张原始图图像集合。其通过梯次向下采样获得,直到达到某个终止条件才停止采样。

金字塔的底部是待处理图像的高分辨率表示,而顶部是低分辨率的近似。我们将一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低

高斯金字塔固定了缩放比,即如果你是800×800的图,无法缩放成500×500

我们将要学习用什么方法,如何去生成这些图像金字塔

OpenCV:08图像金字塔

常见两类图像金字塔:

  • 高斯金字塔(Gaussian pyramid):用来向下/降采样(分辨率减小,图片变小,向上走),是主要的图像金字塔;
  • 拉普拉斯金字塔(Laplacian pyramid):用来从金字塔低层图像重建上层未采样图像,在数字图像处理中也就是预测残差,可以对图像进行最大程度的还原,配合高斯金字塔一起使用

; 高斯金字塔(Gaussian pyramid)

高斯金字塔是通过高斯平滑和亚采样(一个图形中取出一小块)获得的一系列 下采样图像

向下采样

原理非常简单:如下图所示

OpenCV:08图像金字塔
原始图像分辨率 M*N ——> 处理图像后分辨率 M/2 * N/2;即每次处理后, 结果是原来的1/4(不要求是偶数,会自动四舍五入)
OpenCV:08图像金字塔
注意:向下采样(分辨率减小,在上图中表现为 方向向上 )会丢失信息

关键API: cv2.pyrDown(src[, dst[, dstsize[, borderType]]])
其中:

  • src:需要操作的图片
  • dst:返回值,不用写,我们用一个参数接受即可
  • dstsize:返回图片的大小
  • *图片会变成原来的1/4

import cv2
import numpy as np

img = cv2.imread('./lena.png')

dst = cv2.pyrDown(img)

dst2 = cv2.pyrDown(dst)

cv2.imshow('img',img)
cv2.imshow('dst',dst)
cv2.imshow('dst2',dst2)

cv2.waitKey(0)
cv2.destroyAllWindows()

结果:

OpenCV:08图像金字塔

其实清晰度几乎没变,这就是图像金字塔的厉害之处:虽然丢掉了偶数行和偶数列,但是 经过了高斯核函数卷积后,相当于把一个像素点匀到周围了,因此变化不大

向上采样

向上采样是向下采样的相反过程,指图片从小变大的过程

OpenCV:08图像金字塔
  1. 将图像在每个方向扩大为原来的两倍,新增的行和列以0填充
  2. 使用先前同样的内核(乘以4)于放大后的图像卷积,获取近似值 ——> 假设四个一组,相当于把有数值的地方向周围三个0的位置填充(以左上角为例,相当于把10分成四份,一份2.5;但是由于整体值变小了,图像会偏暗,为了解决这个问题,我们乘4,相当于”复制”四份)

操作和向下采样一样!

关键API: cv2.pyrUp(src[, dst[, dstsize[, borderType]]])
其中:

  • src:需要操作的图片
  • dst:返回值,不用写,我们用一个参数接受即可
  • dstsize:返回图片的大小
  • *图片会变成原来的4倍

import cv2
import numpy as np

img = cv2.imread('./Hello.jpeg')

dst = cv2.pyrUp(img)

cv2.imshow('img',img)
cv2.imshow('dst',dst)

cv2.waitKey(0)
cv2.destroyAllWindows()

结果:

OpenCV:08图像金字塔

拉普拉斯金字塔

OpenCV:08图像金字塔
拉普拉斯金字塔图像 = 原始图像 - 上采操作函数(下采操作函数(原始图像))

将降采样之后的图像在进行上采样操作,然后与之前还没降采样的原图进行做差得到残差图!为还原图像做信息的准备!

也就是说, 拉普拉斯金字塔是通用 原图像减去 先缩小后再放大的图像(高斯金字塔) 的一系列图像构成的, 减去后得到的结果就是拉普拉斯金字塔的图像。保留的是残差!

拉普拉斯金字塔是由高斯金字塔构成的,没有专门的函数

OpenCV:08图像金字塔

import cv2
import numpy as np

img = cv2.imread('./lena.png')

temp = cv2.pyrDown(img)

dst = cv2.pyrUp(temp)

lap0 = img - dst

cv2.imshow('dst',dst)
cv2.imshow('lap0',lap0)

cv2.waitKey(0)
cv2.destroyAllWindows()

结果:

OpenCV:08图像金字塔

图像直方图

图像直方图的基本概念

在统计学中,直方图是一种对数据分布情况的图形表示,是一种二维统计图表

图像直方图是用于表示数字图像中亮度分布的直方图,标绘了 图像中每个亮度值的像素数

可以借助观察该直方图了解需要如何调整亮度分布的直方图。这种直方图中, 横坐标的左侧为纯黑、较暗的区域,而 右侧为较亮、纯白的区域

因此,一张较暗图片的图像直方图的数据多集中于左侧和中间部分,而整体明亮,只有少量阴影的图像则相反

  • 横坐标:图像中各个像素点的 灰度级(灰度值0-255每一个数字都是一个灰度级)
  • 纵坐标:具有该灰度级的 *像素个数

OpenCV:08图像金字塔
我们从图像直方图可以看出:该幅图像存在较多很暗或者很亮的点( 具有这些灰度级的像素个数较多),反而亮暗平衡的点较少(具有这些灰度级的像素个数较少)

看懂了之后我们就可以自主分析下面三张图啦(懒得写了…)

OpenCV:08图像金字塔

举个🌰:
有个3×3的图片,其中

  • 像素的灰度级表示 ——> 图片中有什么数字
  • 具有该灰度级的像素个数表示 ——> *这个数字在图片中出现了几次

OpenCV:08图像金字塔

画出上图的直方图,直方图可以有很多种。比如:
折线图:

OpenCV:08图像金字塔

柱状图:

OpenCV:08图像金字塔

归一化图:

  • 横坐标:图像中各个像素点的 灰度级(图像中出现的像素值)
  • 纵坐标:出现这个灰度级的 概率(图像中每一个出现的像素值次数/像素值个数)
    OpenCV:08图像金字塔

; 直方图术语

  • dims:直方图中需要统计的特征的数目,也就是需要统计的项目。如dims = 1,表示我们只用统计灰度值
  • bins:直方图中每个小区间(每个特征空间子区段)的数目,较常操作
    OpenCV:08图像金字塔

range:我们统计灰度值的范围,一般为0-255

总的来说:直方图就是图像中各种灰度级出现的次数而画出的图

使用 OpenCV 统计直方图

关键API: cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])

  • images:原始图像(可以不是黑白图),加 s表示可以同时对多张图片进行直方图统计 ——> 此处要加中括号,表示是一个图像集合
  • channels:指定通道,需要用中括号” [ ]“括起来
  • 如果输入的图像是灰度图,那么就只有一个通道,则[ ]内写0: [0]
  • 彩色图像可以是 [ 0 ], [ 1 ], [ 2 ],分别对应 B,G,R
  • mask:掩码图像
  • 统计整幅图像的直方图:设为 None
  • 统计图像某个区域的直方图:需要掩码图像
  • histSizeBINS(柱状图中的柱子)的数量
  • 需要用中括号括起来,如 [256](因为是从0开始,因此有256个数字)
  • ranges:像素值范围,例如 [0,255]
  • accumulate:累积标识
  • 默认值为 False(一般我们只操作一个图)
  • 如果被设置为 True,则 直方图在开始分配时不会被清零
  • 该参数允许从多个对象中计算单个直方图,或者用于实时更新直方图
  • 多个直方图的累积结果,用于对一组图像计算直方图
  • *该函数会返回直方图的数据,可以直接用 plt.plot(返回值) 进行绘图!

import cv2
import numpy as np

img = cv2.imread('./lena.png')

hist = cv2.calcHist([img],[0],None,[256],[0,255])
print(hist)

结果:

OpenCV:08图像金字塔
从上到下分别是 灰度级0、1、2......

使用 OpenCV 绘制直方图


import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('./lena.png')

hist_B = cv2.calcHist([img],[0],None,[256],[0,255])
hist_G = cv2.calcHist([img],[1],None,[256],[0,255])
hist_R = cv2.calcHist([img],[2],None,[256],[0,255])

plt.plot(hist_B,color = 'b',label = 'Blue')
plt.plot(hist_G,color = 'g',label = 'Green')
plt.plot(hist_R,color = 'r',label = 'Red')
plt.legend()

plt.show()

结果:
对应横轴是灰度值转化来的(我们没有给定横轴的值,matplotlib自动索引的,相当于 cv2.cvtColor(img,cv2.COLOR_GRAY2BRR)

我们可以发现:整个图都是偏红色(红色低频较少,在高频区较多),蓝色在偏低的位置(只有帽子上有一点),绿色在高频区较少(整幅图几乎没有绿色)

OpenCV:08图像金字塔

使用掩膜的直方图

如果你只对图片中的某一部分感兴趣(例如图像中的人脸、手…),就可以用 掩膜进行操作,选出图中的 roi区域,对该区域使用 cv2.calcHist(mask)进行直方图计算

  • 掩膜
    OpenCV:08图像金字塔
    掩膜的特点:想要显示的区域是纯白的,其他不想让它显示的区域是纯黑的
  • 如何生成掩膜
  • 先生成一个和原始图片大小一样( img.shape)的全黑图片: mask = np.zeros(image.shape,np.uint8)
  • 将想要的区域通过索引的方式设置为255: mask[100:200,200:300] = 355

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('./lena.png')

gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

mask = np.zeros(gray.shape,np.uint8)

mask[200:400,200:400] = 255

hist_gray = cv2.calcHist([gray],[0],None,[256],[0,255])
hist_mask = cv2.calcHist([gray],[0],mask,[256],[0,255])

plt.plot(hist_gray,label = 'gray',color = 'g')
plt.plot(hist_mask,label = 'mask',color = 'r')
plt.legend()
plt.show()

cv2.imshow('gray',gray)
cv2.imshow('mask',mask)

cv2.imshow('gray&mask',cv2.bitwise_and(gray,gray,mask = mask))

cv2.waitKey(0)
cv2.destroyAllWindows()

结果:

OpenCV:08图像金字塔
OpenCV:08图像金字塔

Original: https://blog.csdn.net/m0_59466249/article/details/125909895
Author: Lionetxx
Title: OpenCV:08图像金字塔

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/645591/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球