尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

图像金字塔原理与实战:从多尺度分析到OpenCV实现

图像金字塔原理与实战:从多尺度分析到OpenCV实现 1. 从“多尺度”说起为什么我们需要图像金字塔如果你处理过图像无论是做计算机视觉、图像编辑还是简单的缩放大概率都听过“图像金字塔”这个词。听起来挺高大上但它的核心思想其实非常朴素用不同的分辨率去看同一张图。这就像你站在一幅巨大的壁画前为了看清细节你得凑近看为了看清整体布局你得退远看。图像金字塔就是帮你系统性地完成这个“凑近”和“退远”过程的数学工具。我第一次真正理解它的威力是在做一个车牌识别的项目里。当时直接用原始的高清图像去检测车牌算法要么跑得慢要么在小车牌上漏检。后来引入了图像金字塔先在一张缩小的图上快速找到车牌可能存在的区域再回到原图的对应位置进行精确定位和识别效果和效率都提升了一个量级。这让我意识到它绝不是一个课本里的数学玩具而是解决实际工程问题的利器。简单来说图像金字塔通过一系列下采样缩小和上采样放大操作生成一组分辨率逐层降低或升高的图像集合。最底层是原始的高分辨率图像越往上走图像尺寸越小看起来越“模糊”但保留的全局信息越强。这个结构之所以叫“金字塔”就是因为从底到顶图像尺寸越来越小堆叠起来就像一个金字塔。它的应用场景远比你想象的广泛从最经典的SIFT、ORB特征点检测到目标检测中的多尺度滑动窗口比如早期的DPM、HOG检测器再到图像融合如拉普拉斯金字塔融合、超分辨率重建甚至在现代深度学习的某些预处理或后处理环节中你都能看到它的身影。理解图像金字塔是打通传统图像处理和现代视觉算法任督二脉的关键一步。2. 金字塔的构建基石高斯与拉普拉斯图像金字塔主要有两大类高斯金字塔和拉普拉斯金字塔。前者是基础后者是前者的“微分”形式蕴含了更多的细节信息。要搞懂它们得先理解两个核心操作高斯模糊和下采样。2.1 高斯模糊不是简单的平均下采样前为什么一定要先模糊这是新手最容易忽略的关键。想象一下你有一张画满密集细线的图。如果你直接每隔一个像素扔掉一个像素最简单的下采样那些高频的细线可能会因为采样点错过线条而产生严重的“摩尔纹”或“混叠”效应导致下采样后的图像出现原本不存在的奇怪图案。高斯模糊的目的就是充当一个“低通滤波器”平滑掉这些高频细节只保留图像中变化平缓的低频信息。这样在下采样时就不会有高频信号“混”进来捣乱了。高斯模糊不是简单的均值滤波它用一个二维的高斯函数钟形曲线作为权重核对图像进行卷积。离中心像素越近的像素权重越大这使得平滑效果更自然能更好地保持边缘过渡。一个常见的5x5高斯核可能长这样数值已归一化[[1, 4, 6, 4, 1], [4, 16, 24, 16, 4], [6, 24, 36, 24, 6], [4, 16, 24, 16, 4], [1, 4, 6, 4, 1]] / 256在实际构建金字塔时OpenCV等库通常会使用一个小的、可分离的高斯核如5x5进行迭代卷积而不是直接用一个巨大的核这样效率更高。2.2 高斯金字塔的构建迭代的“缩小”过程高斯金字塔的构建是一个迭代过程分为两个方向向下采样构建金字塔从第i层记为G_i生成第i1层G_{i1}。步骤1高斯模糊。对G_i进行高斯模糊使用上述高斯核卷积得到模糊后的图像Blur(G_i)。这一步是为了抗混叠。步骤2降采样。将Blur(G_i)的尺寸缩小为原来的一半通常长宽各减半。最简单的做法是直接隔行隔列采样。这样得到的图像就是G_{i1}。重复这个过程直到图像尺寸小到无法继续比如小于某个阈值如4x4像素。向上采样重建过程这是向下采样的逆过程用于从高层图像G_{i1}近似重建低层图像G_i。步骤1上采样。将G_{i1}的尺寸放大一倍长宽各乘2。新增的像素位置通常先填充0零值。步骤2高斯模糊。对放大后的图像再次进行高斯模糊通常使用与向下采样时相同或相似的高斯核。这一步是为了插值使图像变得平滑填补上采样引入的“空洞”。需要注意的是向上采样再模糊得到的图像并不是原始的G_i而是一个丢失了高频细节的、模糊化的G_i我们称之为Expand(G_{i1})。高频细节去哪了这就引出了拉普拉斯金字塔。2.3 拉普拉斯金字塔存储“丢失的细节”拉普拉斯金字塔不是独立构建的它直接来源于高斯金字塔。它的每一层定义为当前层的高斯图像与上一层高斯图像经上采样重建后的差值L_i G_i - Expand(G_{i1})这里的L_i就是第i层的拉普拉斯图像。因为Expand(G_{i1})是G_i的低频近似所以它们的差值L_i捕捉的正是G_i中那些被高斯平滑和下采样过程“丢掉”的高频边缘和纹理细节。你可以把拉普拉斯金字塔的每一层看作是一张“残差图”或“细节图”。拉普拉斯金字塔的精妙之处在于它的无损性在理想的无损计算下。因为G_i L_i Expand(G_{i1})通过这个公式我们可以从金字塔顶层的那个最小的高斯图像G_top开始结合每一层的拉普拉斯细节L_i逐层向上完美地重建出原始图像G_0。这为图像压缩和多分辨率编辑提供了理论基础。注意在实际的数值计算特别是使用8位无符号整型uint8时做减法G_i - Expand(G_{i1})可能会产生负值。因此通常会将拉普拉斯金字塔的像素值存储为有符号整型如int16或者先进行偏移如加128再存储为uint8在重建时再减回去。这是实现时的一个小坑。3. 手把手实现用OpenCV和NumPy构建你的金字塔理论说再多不如动手写一遍。这里我用Python和OpenCV带你完整实现高斯和拉普拉斯金字塔并解释每一步的意图。3.1 环境准备与基础函数首先确保你安装了必要的库。我们主要用OpenCV和NumPy。import cv2 import numpy as np import matplotlib.pyplot as plt def display_images(images, titles, rows, cols): 一个简单的多图显示函数 fig, axes plt.subplots(rows, cols, figsize(15, rows*3)) axes axes.flatten() for ax, img, title in zip(axes, images, titles): if len(img.shape) 2: # 灰度图 ax.imshow(img, cmapgray) else: # 彩色图 # OpenCV默认是BGRmatplotlib显示需要转为RGB img_rgb cv2.cvtColor(img, cv2.COLOR_BGR2RGB) ax.imshow(img_rgb) ax.set_title(title) ax.axis(off) plt.tight_layout() plt.show()3.2 实现高斯金字塔OpenCV提供了现成的函数cv2.pyrDown()和cv2.pyrUp()但为了理解原理我们先自己实现一个简化版。def my_gaussian_blur(image, ksize5, sigma1.0): 手动实现一个简单的高斯模糊效率较低仅用于教学 # 生成一维高斯核 kernel_1d cv2.getGaussianKernel(ksize, sigma) # 通过外积得到二维可分核 kernel_2d kernel_1d * kernel_1d.T # 应用卷积 blurred cv2.filter2D(image, -1, kernel_2d, borderTypecv2.BORDER_REFLECT) return blurred def my_pyr_down(image): 向下采样一层先高斯模糊再隔点采样 # 1. 高斯模糊 (抗混叠) blurred my_gaussian_blur(image) # 2. 降采样取所有偶数行和偶数列 downsampled blurred[::2, ::2] return downsampled def my_pyr_up(image): 向上采样一层先插零再高斯模糊模拟插值 h, w image.shape[:2] # 1. 创建两倍大小的空矩阵并在偶数位置填充原图像素 upsampled np.zeros((h*2, w*2) image.shape[2:], dtypeimage.dtype) upsampled[::2, ::2] image # 2. 高斯模糊进行插值。注意这里模糊的强度需要调整以匹配pyrDown的效果。 # 通常上采样时的高斯核权重应是下采样时的4倍因为像素数变为4倍 # 但更常见的做法是直接用相同的核进行卷积然后乘以4对于8位图要小心溢出。 # 这里我们使用一个简单的5x5高斯核并乘以4。 kernel cv2.getGaussianKernel(5, 1) * 2 # 乘以2是为了近似补偿 kernel_2d kernel * kernel.T upsampled cv2.filter2D(upsampled, -1, kernel_2d, borderTypecv2.BORDER_REFLECT) # 由于我们插零后模糊能量像素值总和会损失乘以4是一个常见的近似补偿。 # 但对于严格的拉普拉斯金字塔重建这个因子必须与pyrDown的核精确匹配。 return upsampled def build_gaussian_pyramid_opencv(image, levels): 使用OpenCV内置函数构建高斯金字塔推荐更稳定高效 pyramid [image] for i in range(levels-1): pyramid.append(cv2.pyrDown(pyramid[-1])) # 对列表最后一张图进行下采样 return pyramid # 读取一张示例图像 img cv2.imread(your_image.jpg) # 请替换为你的图片路径 if img is None: # 如果没图片创建一个简单的测试图 img np.zeros((256, 256, 3), dtypenp.uint8) cv2.rectangle(img, (50, 50), (150, 150), (0, 255, 0), -1) cv2.circle(img, (200, 100), 30, (0, 0, 255), -1) gray_img cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 为简化我们用灰度图演示 # 构建4层高斯金字塔 gaussian_pyramid build_gaussian_pyramid_opencv(gray_img, 4) # 显示 display_images(gaussian_pyramid, [fGaussian Level {i}: {gaussian_pyramid[i].shape} for i in range(len(gaussian_pyramid))], rows1, cols4)运行这段代码你会看到图像尺寸逐层减半例如 256x256 - 128x128 - 64x64 - 32x32图像内容也越来越模糊但大致的形状和结构依然清晰可辨。3.3 实现拉普拉斯金字塔拉普拉斯金字塔需要高斯金字塔作为输入。def build_laplacian_pyramid(gaussian_pyramid): 根据高斯金字塔构建拉普拉斯金字塔 laplacian_pyramid [] num_levels len(gaussian_pyramid) for i in range(num_levels - 1): # 获取当前层 Gi 和上一层 Gi1 gi gaussian_pyramid[i] gi_plus1 gaussian_pyramid[i 1] # 将 Gi1 上采样使其尺寸与 Gi 相同 # 注意cv2.pyrUp 的尺寸是 2倍所以需要指定目标尺寸为 gi 的尺寸 # 但更标准的做法是pyrUp(gi_plus1) 的尺寸应该是 gi_plus1*2这不一定等于 gi。 # 实际上由于下采样可能舍入gi 的尺寸可能是奇数pyrUp后尺寸可能差1。 # 因此我们需要调整尺寸。 upsampled cv2.pyrUp(gi_plus1, dstsize(gi.shape[1], gi.shape[0])) # 计算拉普拉斯层Li Gi - upsampled(Gi1) # 注意图像是 uint8相减可能产生负数需要转为有符号类型 laplacian cv2.subtract(gi.astype(np.int16), upsampled.astype(np.int16)) # 或者为了显示可以将其缩放到0-255范围 # laplacian_display cv2.normalize(laplacian, None, 0, 255, cv2.NORM_MINMAX, dtypecv2.CV_8U) laplacian_pyramid.append(laplacian) # 金字塔的顶层最小那张高斯图没有上一层可以减通常直接作为拉普拉斯金字塔的顶层 # 但严格来说拉普拉斯金字塔顶层就是高斯金字塔顶层因为它是低频信息的最终保留地。 laplacian_pyramid.append(gaussian_pyramid[-1].astype(np.int16)) return laplacian_pyramid # 构建拉普拉斯金字塔 laplacian_pyramid build_laplacian_pyramid(gaussian_pyramid) # 准备显示将int16转换为可显示的uint8注意拉普拉斯层有正有负中心在128附近 display_list [] titles [] for i, lap in enumerate(laplacian_pyramid): # 将值域线性映射到0-255以便显示 lap_display cv2.normalize(lap, None, 0, 255, cv2.NORM_MINMAX, dtypecv2.CV_8U) display_list.append(lap_display) titles.append(fLaplacian Level {i}: {lap.shape}) display_images(display_list, titles, rows1, colslen(laplacian_pyramid))观察拉普拉斯金字塔的图像你会发现它们看起来像“边缘检测”图。最底层Level 0包含了最精细的边缘和纹理细节越往上细节越粗糙主要剩下一些大的轮廓。中间灰度128左右的区域代表变化平缓的低频区域在差值中接近0。3.4 从拉普拉斯金字塔重建图像这是验证我们金字塔构建是否正确、理解其无损性的关键一步。def reconstruct_from_laplacian_pyramid(laplacian_pyramid): 从拉普拉斯金字塔重建原始图像 # 从顶层开始顶层就是最后一张高斯图 reconstructed laplacian_pyramid[-1].astype(np.float32) # 从顶层开始用浮点避免精度损失 # 从顶层向下从倒数第二层开始向上迭代 for i in range(len(laplacian_pyramid)-2, -1, -1): # 将当前重建图低频部分上采样 upsampled cv2.pyrUp(reconstructed, dstsize(laplacian_pyramid[i].shape[1], laplacian_pyramid[i].shape[0])) # 加上当前层的拉普拉斯细节高频部分 reconstructed upsampled laplacian_pyramid[i].astype(np.float32) # 将结果转换回uint8并确保值域在0-255 reconstructed np.clip(reconstructed, 0, 255).astype(np.uint8) return reconstructed # 重建图像 reconstructed_img reconstruct_from_laplacian_pyramid(laplacian_pyramid) # 比较原始图像和重建图像 print(fOriginal shape: {gray_img.shape}, Reconstructed shape: {reconstructed_img.shape}) print(fAre they identical? {np.array_equal(gray_img, reconstructed_img)}) # 由于浮点运算和OpenCV的pyrUp/pyrDown内部实现可能有微小差异完全相等很难我们看差异 diff cv2.absdiff(gray_img, reconstructed_img) print(fMax difference: {np.max(diff)}) print(fMean difference: {np.mean(diff)}) # 显示原始、重建和差异图 display_images([gray_img, reconstructed_img, diff], [Original Image, Reconstructed Image, fDifference (max{np.max(diff)})], rows1, cols3)如果实现正确重建的图像应该与原始图像几乎完全相同最大像素差异通常只有1或2这是由于计算过程中的舍入误差造成的。这个实验完美地证明了拉普拉斯金字塔是一种无损或近乎无损的图像表示方式。4. 不止于理论图像金字塔的实战应用剖析理解了原理和实现我们来看看它在实际项目中如何大显身手。这里我分享三个最经典也最实用的应用场景。4.1 应用一多尺度特征检测以SIFT为例SIFT尺度不变特征变换算法是图像金字塔应用的典范。它的核心思想是真正的关键点不仅要在空间位置x, y上稳定还要在尺度空间σ上稳定。图像金字塔在这里是高斯差分金字塔DoG就是用来构建这个“尺度空间”的。过程简述构建高斯尺度空间对原始图像不断进行高斯模糊增加σ生成一系列不同尺度的图像这构成了一个“八度”Octave的尺度空间。然后将图像下采样一半作为下一个八度的起始重复这个过程。这就形成了一个高斯金字塔但每一层内还有多个不同σ的尺度。构建高斯差分金字塔在同一八度内将相邻尺度的高斯图像相减得到DoG图像。DoG是拉普拉斯算子LoG的近似对边缘和角点响应强烈且计算效率更高。关键点检测在DoG金字塔的三维空间x, y, σ中寻找极值点。每个像素需要和它同一尺度的8个邻居以及上下相邻尺度的各9个邻居共26个进行比较只有当它是这26个点中的最大值或最小值时才被认为是一个候选关键点。关键点定位通过三维二次函数拟合来精确定位关键点的位置和尺度并消除低对比度和边缘响应不稳定的点。为什么金字塔在这里不可或缺尺度不变性通过在多个尺度上搜索找到的特征点不受图像缩放影响。一个在放大图像中清晰可见的角点在缩小图像中可能只是一个像素块但通过金字塔我们能在合适的尺度上找到它。效率在低分辨率图像上搜索特征速度远快于直接在全分辨率图像上搜索。SIFT通过先在下采样图像上找到大致区域再映射回原图精修平衡了精度和速度。实操心得在使用OpenCV的SIFT检测器时nOctaveLayers和contrastThreshold是两个关键参数。nOctaveLayers控制每个八度内的尺度层数增加它会检测到更多尺度连续的特征但计算量也更大。contrastThreshold过滤低对比度的点在纹理丰富的场景可以调高以减少噪点。我通常会在目标图像上做一个小网格搜索找到适合当前任务的最佳参数组合。4.2 应用二图像融合拉普拉斯金字塔融合这是拉普拉斯金字塔最“魔法”的应用之一用于实现无缝的图像拼接或混合。经典例子是“苹果和橘子”的融合或者将一张图的天空与另一张图的地面完美结合。原理与步骤分别构建金字塔对源图像A和源图像B分别构建高斯金字塔和拉普拉斯金字塔。构建掩模金字塔对定义融合区域的二值掩模图像比如左边是1右边是0构建高斯金字塔。注意掩模也需要下采样以匹配每一层拉普拉斯金字塔的尺寸。逐层融合在每一层拉普拉斯金字塔上按照对应层的掩模进行加权融合L_fused_i mask_i * L_A_i (1 - mask_i) * L_B_i。掩模经过高斯模糊后边缘是平滑过渡的这保证了融合边界在不同尺度上都是平滑的。重建从融合后的拉普拉斯金字塔顶层开始逐层向上采样并加上融合后的细节层最终重建出融合后的图像。为什么比直接融合好如果直接在原图上用模糊的掩模进行融合在颜色或纹理差异大的边界仍然可能看到一条模糊但突兀的接缝。这是因为一次性处理了所有频率的信息。拉普拉斯金字塔融合将图像分解到不同频率带低频层高层金字塔决定了图像的整体结构和颜色过渡高频层低层金字塔决定了细节纹理。我们让低频信息在较大的区域上平滑过渡掩模模糊半径大而让高频信息在较小的区域上快速切换掩模模糊半径小。这样最终重建的图像在所有尺度上都实现了平滑过渡接缝在视觉上就“消失”了。def laplacian_pyramid_blend(img_a, img_b, mask, levels6): 拉普拉斯金字塔融合 # 生成A和B的高斯金字塔 gp_a [img_a.astype(np.float32)] gp_b [img_b.astype(np.float32)] gp_m [mask.astype(np.float32) / 255.0] # 归一化到0-1 for i in range(levels): gp_a.append(cv2.pyrDown(gp_a[-1])) gp_b.append(cv2.pyrDown(gp_b[-1])) gp_m.append(cv2.pyrDown(gp_m[-1])) # 生成A和B的拉普拉斯金字塔 lp_a [gp_a[levels-1]] # 顶层是高斯金字塔的顶层 lp_b [gp_b[levels-1]] for i in range(levels-1, 0, -1): # 拉普拉斯层 高斯层 - 上层高斯的上采样 size (gp_a[i-1].shape[1], gp_a[i-1].shape[0]) ge_a cv2.pyrUp(gp_a[i], dstsizesize) ge_b cv2.pyrUp(gp_b[i], dstsizesize) lp_a.append(gp_a[i-1] - ge_a) lp_b.append(gp_b[i-1] - ge_b) lp_a.reverse() # 反转使第0层是原图尺寸的细节层 lp_b.reverse() # 融合拉普拉斯金字塔 lp_fused [] for la, lb, gm in zip(lp_a, lp_b, gp_m[::-1]): # gp_m需要反转顺序以匹配lp lp_fused.append(gm * la (1 - gm) * lb) # 从融合金字塔重建 reconstructed lp_fused[0] for i in range(1, levels): size (lp_fused[i].shape[1], lp_fused[i].shape[0]) reconstructed cv2.pyrUp(reconstructed, dstsizesize) reconstructed reconstructed lp_fused[i] # 裁剪到0-255并转换类型 reconstructed np.clip(reconstructed, 0, 255).astype(np.uint8) return reconstructed4.3 应用三加速目标检测与图像匹配在深度学习统治目标检测之前基于滑动窗口和手工特征如HOGSVM的方法是主流。直接在数百万像素的大图上用固定大小的窗口滑动计算量是灾难性的。图像金字塔提供了优雅的解决方案。工作流程构建输入图像金字塔对输入图像进行多尺度下采样。构建检测窗口金字塔可选如果你的检测器窗口大小固定那么在不同尺度的图像上这个固定窗口实际上对应着原始图像中不同大小的区域。例如在缩小一半的图像上一个64x64的窗口对应原图中128x128的区域。这样一个固定大小的检测器就能检测不同大小的目标。逐尺度检测从金字塔顶层最小图开始用检测器进行滑动窗口检测。因为图像小计算非常快可以快速排除大片不可能存在目标的区域。映射与精修将在小图上检测到的目标框根据下采样的比例映射回原始图像的大致区域。然后可以在这个区域内用更精细的尺度或直接在原图进行二次检测或边界框回归得到精确的位置。在现代深度学习中的应用 虽然CNN本身具有一定尺度不变性但图像金字塔思想依然以其他形式存在特征金字塔网络FPNFeature Pyramid Network可以看作是深度学习版的“特征金字塔”。它通过自顶向下和横向连接将深层网络的高层语义特征与浅层网络的高分辨率特征融合让检测器能在不同尺度的特征图上检测不同大小的目标。多尺度测试在模型推理时将输入图像缩放到多个不同尺寸分别进行预测然后综合所有尺度的结果。这能显著提升对小目标和超大目标的检测精度是刷高比赛指标时的常用技巧当然也增加了计算成本。5. 避坑指南实现与应用中的常见问题纸上得来终觉浅在实际编码和应用图像金字塔时有几个坑我几乎每次都会遇到这里总结一下。5.1 尺寸对齐与舍入误差这是最恼人的问题之一。图像的长宽不一定是2的整数次幂或者可能是奇数。cv2.pyrDown和cv2.pyrUp对尺寸的处理遵循一个近似公式pyrDown:dst_width (src_width 1) // 2,dst_height (src_height 1) // 2pyrUp:dst_width src_width * 2,dst_height src_height * 2这意味着对一个(99, 99)的图像做pyrDown会得到(50, 50)的图像。再对它做pyrUp会得到(100, 100)的图像。尺寸对不上了解决方案指定目标尺寸cv2.pyrUp(src, dstsize(target_width, target_height))。在重建拉普拉斯金字塔时必须精确指定目标尺寸为上一层的尺寸。保持一致在构建和重建金字塔的整个循环中始终使用同一套尺寸计算逻辑。最好写一个辅助函数来管理每一层的尺寸。预先裁剪对于要求严格的场景如需要完美重建可以先将图像裁剪或填充至长宽为2^n的尺寸。5.2 数据类型与数值溢出图像通常是uint8类型0-255。但在构建拉普拉斯金字塔时做减法G_i - Expand(G_{i1})会产生负数。如果用uint8直接计算负数会下溢变成很大的正数如-1变成255导致重建完全错误。解决方案在计算拉普拉斯层前先将高斯图像转换为有符号类型如np.int16或np.float32。存储拉普拉斯金字塔时也使用有符号类型。重建时最后一步再将结果用np.clip截断并转回uint8。5.3 模糊核的选择与“频带分离”效果高斯金字塔的质量很大程度上取决于高斯模糊核的大小ksize和标准差sigma。OpenCV的pyrDown使用一个固定的、不可配置的核。如果你自己实现需要小心选择。核太小抗混叠效果不足下采样后图像可能出现锯齿。核太大过度模糊导致细节丢失严重上层金字塔图像过于平滑信息损失大。经验值通常sigma设为0.5 * ((ksize-1)*0.5 - 1) 0.8。OpenCV默认的pyrDown行为大致相当于一个5x5的核。对于拉普拉斯金字塔融合有时会使用更大的核如7x7来获得更平滑的低频过渡。5.4 在深度学习 pipeline 中的集成将图像金字塔集成到现代深度学习框架如PyTorch, TensorFlow中时需要注意数据加载效率实时构建多尺度图像金字塔可能成为数据加载的瓶颈。通常的做法是在预处理阶段预先计算好多个尺度的图像或者使用支持torchvision.transforms.Resize等操作的DataLoader进行在线缩放。批处理一个批次batch内的图像必须尺寸相同。因此多尺度训练通常是以“图像中心裁剪缩放”或“随机缩放后填充到固定尺寸”的方式实现的而不是在一个batch里放不同尺度的图。梯度流如果你在自定义层中实现了金字塔操作例如一个可微分的图像金字塔采样需要确保所有操作都是可微的以便梯度能够反向传播。标准的cv2.pyrDown是不可微的你需要用torch.nn.functional.interpolate配合高斯滤波来实现可微版本。图像金字塔是一个古老而强大的工具它的思想穿透了传统图像处理和现代深度学习。理解它不仅能帮你解决很多实际的工程问题更能让你对“多尺度”这个计算机视觉的核心概念有更深刻的体会。下次当你面对一个需要处理不同大小目标的视觉任务时不妨先想想这里是不是可以用金字塔来优雅地解决
返回列表