计算机视觉----opencv高级操作(上采样,下采样,拉普拉斯金字塔,图像数值的统计)
一、准备工作
1、前置代码:
import cv2
import numpy as np
from matplotlib import pyplot as pltdef cv_show(name, img):"""显示图像"""cv2.imshow(name, img)cv2.waitKey(0)
2、图片准备
mm.jpg
motor.jpg
oidman.jpg
二、图片的上采样下采样
1、下采样(Downsampling)
下采样是降低图像分辨率的过程,通过减少图像像素数量,缩小图像尺寸,核心目的是减少计算量、节省存储,或为多尺度分析提供低分辨率图像。
核心步骤
预处理(抗混叠滤波):先对原始图像进行低通滤波(如高斯滤波),抑制高频信号。若跳过此步,直接丢弃像素会导致混叠失真(如细线条变成 “摩尔纹”)。
像素采样:按固定间隔选取像素,生成低分辨率图像。最常用的是 “隔行隔列采样”(如 2 倍下采样时,保留图像中坐标为 (2i,2j) 的像素,i、j 为整数)。
示例
一张 1024×1024 的图像,经 2 倍下采样后,尺寸变为 512×512,像素数量减少为原来的 1/4。
2、上采样(Upsampling)
上采样是提升图像分辨率的过程,通过增加像素数量,放大图像尺寸,核心用于恢复低分辨率图像的细节,或配合下采样实现多尺度操作。
核心步骤
像素插值:在原有像素之间插入新像素,常用插值算法有:
nearest neighbor(最近邻插值):直接复制相邻像素值,速度快但易产生 “块状失真”;
bilinear(双线性插值):基于相邻 4 个像素的加权平均计算新像素,效果更平滑;
bicubic(双三次插值):基于相邻 16 个像素的非线性加权计算,细节保留更优,但计算量更大。
后处理(可选):部分场景会对插值后的图像进行滤波,进一步优化边缘平滑度。
示例
一张 512×512 的图像,经 2 倍上采样后,尺寸变为 1024×1024,但新增像素由插值生成,并非真实细节(需超分辨率算法进一步优化)。
3、拉普拉斯金字塔(Laplacian Pyramid)
拉普拉斯金字塔是一种多尺度图像表示结构,通过 “下采样 + 上采样” 的差值计算,存储图像的 “细节信息”,与存储 “低频轮廓” 的高斯金字塔配合使用。
核心原理
拉普拉斯金字塔(记为 L)的每一层,由高斯金字塔的当前层与上一层上采样后的图像的差值构成,公式可简化为:
L(i) = G(i) - UpSample(G(i+1))
其中:
G(i)
:高斯金字塔的第 i 层(高分辨率,含轮廓 + 细节);G(i+1)
:高斯金字塔的第 i+1 层(G (i) 下采样后的低分辨率图像,仅含轮廓);UpSample(G(i+1))
:将 G (i+1) 上采样到与 G (i) 相同尺寸,仅恢复轮廓,无细节;差值
L(i)
:即 G (i) 中独有的 “细节信息”(如边缘、纹理)。
核心作用
- 图像重建:若保留拉普拉斯金字塔的细节层(L (0)~L (n))和高斯金字塔的最顶层(G (n),最粗轮廓),可通过 “上采样 + 叠加细节” 恢复原始高分辨率图像;
- 图像融合 / 编辑:在不同尺度下处理细节(如融合两张图像的边缘、修复图像瑕疵),避免直接处理高分辨率图像的冗余计算;
- 图像压缩:拉普拉斯金字塔的细节层多为高频信号,可通过量化压缩,减少存储量。
示例代码:
motor = cv2.imread('oldman.jpg',cv2.IMREAD_GRAYSCALE)
# motor = cv2.resize(motor,(400,300))
cv_show('motor',motor)
motor_down_1 = cv2.pyrDown(motor)
cv_show('down_1',motor_down_1)
motor_down_2 = cv2.pyrDown(motor_down_1)
cv_show('down_2',motor_down_2)#上采样
motor_up_1 = cv2.pyrUp(motor)
cv_show('up_1',motor)
motor_up_2 = cv2.pyrUp(motor_up_1)
cv_show('up_2',motor_up_2)#下采样后上采样
motor_down_1_up = cv2.pyrUp(motor_down_1)
motor_down_2_up = cv2.pyrUp(motor_down_2)cv_show('down_1_up',motor_down_1_up)
cv_show('down_2_up',motor_down_2_up)#拉普拉斯金字塔
L0 = motor - motor_down_1_up
L1 = motor_down_1 - motor_down_2_upfuyuan = motor_down_1_up + L0
cv_show('L0',L0)
cv_show('L1',L1)
cv_show('fuyuan',fuyuan)
cv_show('fuyuan',fuyuan)
这里用的是oldman.jpg而不是motor.jpg,用motor.jpg会报错,因为在图像像素值为奇数时,下采样后再过采样的结果会添加一个像素,和原图不同
三、图像的数值统计
cv2.calcHist(images,channels,mask,histSize,ranges)
计算图像的直方图,用于表示图像中像素灰度级别的分布情况。
images: 原图像图像格式为 uint8 或 float32。当传入函数时应 用中括号 [ ] 括来例如[img]
channels: 表示传入的图像通道数。如果输入图像是灰度图它的值就是 [0]。
如果是彩色图像 的传入的参数可以是 [0][1][2] 它们分别对应着 BGR。
mask: 掩模图像。统计整幅图像的直方图就把它为None。但是如果你想统计图像某一部分的直方图,你就制作一个掩模图像并使用它。
histSize:BINS的数目,也需用中括号括来 (分成多少个区间)
BINS :上面的直方图显示了每个像素值的像素数,即从0到255。即您需要256个值才能显示上述直方图。
但是请考虑一下,如果您不需要单独地查找所有像素值的像素数,而是在像素值间隔内查找像素数,
该怎么办?例如,您需要找到介于 0 到 15 之间的像素数,然后是 16 到 31、32到47....、240 到 255。
您只需要 16 个值来表示直方图。
因此,只需将整个直方图拆分为 16 个子部分,每个子部分的值就是其中所有像素计数的总和。
这个子部分都称为“BIN”。在第一种情况下,条形数为256(每个像素一个),而在第二种情况下,它只有16。BINS 在 OpenCV 文档中由术语histSize表示。
ranges:像素值范围[0 256]
示例代码:
img = cv2.imread('mm.jpg',cv2.IMREAD_GRAYSCALE)
#转化为一堆数据
a= img.ravel()
#将多维数组转化为一维数组
plt.hist(a,bins=256)#使用bins绘制直方图
#a:一维数组,bins=256:指定直方图的条数
plt.show()
img_hist = cv2.calcHist([img],[0],None,[16],[0,256])
plt.plot(img_hist)#使用calchist绘制曲线图
plt.show()img = cv2.imread('mm.jpg')
color = ('b','g','r')
for i,col in enumerate(color):histr = cv2.calcHist([img],[i],None,[256],[0,256])plt.plot(histr,color=col)
plt.show()
RGB三个通道的数值不同颜色绘图: