Kornia Filtering API 深度指南:用 filter2d / filter2d_separable / filter3d 自定义图像滤波算子
2026/9/24 14:25:48 网站建设 项目流程
  • 计算机视觉
  • 人工智能
  • 深度学习
  • 图像处理

【免费下载链接】kornia

🐍 Geometric Computer Vision Library for Spatial AI

项目地址:https://gitcode.com/gh_mirrors/ko/kornia
点击查看免费下载

本文是 Kornia 几何计算机视觉库中Filtering API的完整技术指南。Filtering API 是 Kornia 滤波子系统(模糊、边缘检测等算子)的底层原语层,提供filter2dfilter2d_separablefilter3d三个核心函数,让开发者用自己的卷积核直接对批量张量做滤波。读完本文,你将掌握这三个原语的完整参数语义、底层实现原理、与相关别名函数(convolve2dcorrelate2dfft_conv等)的关系,以及它们在 Kornia 内部(盒式模糊、高斯模糊、拉普拉斯算子)的真实调用方式,从而能基于这些原语构建自己的可微图像处理算子。

1. 什么是 Filtering API

在 docs/source/filters.rst 中,kornia.filters模块被划分为五大部分:模糊(blurring)、边缘检测(edge detection)、阈值分割(segmentation)、Filtering API 与核生成(kernels)。其中 Filtering API 的官方定位是:

"Apply your own 2D, separable or 3D kernels withfilter2d,filter2d_separableandfilter3d."

对应的 docs/source/filters.filtering_api.rst 中明确写道:

"Convolve an image with your own kernel. These are the primitives the blur and edge operators are built on."

这两句话定义了本 API 的使命:它是所有模糊(blur)与边缘(edge)算子的构建基石(primitives)。也就是说,Kornia 里更上层的box_blurgaussian_blur2dlaplacian等算子,最终都会落到这三个函数上执行卷积。

三个核心函数一览:

函数输入形状卷积核形状维度
filter2d(B, C, H, W)(1, kH, kW)(B, kH, kW)2D
filter2d_separable(B, C, H, W)kernel_x: (1, kW)(B, kW)kernel_y: (1, kH)(B, kH)2D(可分离)
filter3d(B, C, D, H, W)(1, kD, kH, kW)(B, kD, kH, kW)3D

所有函数都遵循 Kornia 的统一约定:输入必须是批量化的(B, C, ...)形状张量,卷积核独立作用于每个通道,输出与输入保持相同的通道数与空间形状(在padding='same'时)。

2. filter2d:二维卷积原语

filter2d是 Filtering API 中最核心的函数,其完整签名定义在 kornia/filters/filter.py:

def filter2d( input: torch.Tensor, kernel: torch.Tensor, border_type: str = "reflect", normalized: bool = False, padding: str = "same", behaviour: str = "corr", ) -> torch.Tensor:

2.1 参数语义

参数默认值含义
input必填输入张量,形状(B, C, H, W),批次数为 B、通道数为 C
kernel必填卷积核,形状(1, kH, kW)(所有批次共享)或(B, kH, kW)(每批次独立核)
border_type'reflect'卷积前对输入施加的边界填充模式,可选'constant''reflect''replicate''circular'
normalizedFalse若为True,核在应用前会被 L1 归一化
padding'same'填充策略,'same'保持输出与输入同尺寸,'valid'不做隐式填充
behaviour'corr'卷积模式,'corr'为互相关(默认,等价于 PyTorchconv2d),'conv'为真卷积(核先翻转)

2.2 官方文档示例:均值滤波

filter2d的 docstring 中给出的标准示例(源于 kornia/filters/filter.py)演示了用3x3全 1 核做窗口求和:

import torch from kornia.filters import filter2d input = torch.tensor([[[ [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 5., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], ]]]) kernel = torch.ones(1, 3, 3) filter2d(input, kernel, padding='same') # tensor([[[[0., 0., 0., 0., 0.], # [0., 5., 5., 5., 0.], # [0., 5., 5., 5., 0.], # [0., 5., 5., 5., 0.], # [0., 0., 0., 0., 0.]]]])

可以看到,位于中心的像素值 5 被扩散到3x3邻域中;由于padding='same',输出形状与输入一致,仍是(1, 1, 5, 5)

2.3 归一化与均值滤波

normalized=True时,核会先经过 L1 归一化(即除以核内所有元素绝对值之和),归一化实现见 kornia/filters/kernels.py:

def normalize_kernel2d(input: torch.Tensor) -> torch.Tensor: norm = input.abs().sum(dim=-1).sum(dim=-1) return input / (norm[..., None, None])

因此torch.ones(1, 3, 3)normalized=True时会变成每个元素为1/9的核,等价于标准均值滤波。在测试 tests/filters/test_filters.py 中,test_normalized_mean_filter验证了这一点:中心值 5 经归一化后邻域值为5.0 / 9(注释中写明的nv: float = 5.0 / 9),并断言该结果在padding='same'padding='valid'两种模式下均成立。

2.4 校验与异常

函数内部通过 Kornia 的类型/形状检查体系(KORNIA_CHECK_IS_TENSORKORNIA_CHECK_SHAPEKORNIA_CHECK)对输入做严格校验:

  • input必须是张量且形状为["B", "C", "H", "W"]
  • kernel必须是张量且形状为["B", "H", "W"]
  • border_type必须属于{'constant', 'reflect', 'replicate', 'circular'}
  • padding必须属于{'valid', 'same'}
  • behaviour必须属于{'conv', 'corr'}

测试 tests/filters/test_filters.py 的test_exception验证了这些失败路径:传入非张量会抛TypeCheckError("Type mismatch: expected Tensor"),形状不符抛ShapeError,非法border_type/padding则分别抛出 "Invalid border, a. Ex..." 与 "Invalid padding mode, a. Ex..." 错误信息。

3. filter2d_separable:可分离卷积原语

filter2d_separable提供**可分离(separable)**卷积:将一个二维核分解为水平方向核kernel_x与垂直方向核kernel_y,先后各做一次一维滤波。签名见 kornia/filters/filter.py:

def filter2d_separable( input: torch.Tensor, kernel_x: torch.Tensor, kernel_y: torch.Tensor, border_type: str = "reflect", normalized: bool = False, padding: str = "same", ) -> torch.Tensor:
  • kernel_x形状为(1, kW)(B, kW),沿 W 方向作用;
  • kernel_y形状为(1, kH)(B, kH),沿 H 方向作用。

3.1 实现原理:两次一维滤波

其实现非常简洁,本质上是两次filter2d的组合(见 kornia/filters/filter.py):

out_x = filter2d(input, kernel_x[..., None, :], border_type, normalized, padding) return filter2d(out_x, kernel_y[..., None], border_type, normalized, padding)

即先把kernel_x变成形状(1, 1, kW)的二维核沿水平方向滤波,再把kernel_y变成(1, kH, 1)沿垂直方向滤波。对可分核(如高斯核、盒式核),这种两次一维卷积的计算量与二维直接卷积相比大幅降低,是 Kornia 中许多模糊算子的默认路径。

3.2 与 filter2d 的等价性验证

测试 tests/filters/test_filters.py 的test_separable专门验证了可分路径与直接二维路径的一致性:

kernel_x = torch.ones(1, 3) kernel_y = torch.ones(1, 3) kernel = kernel_y.t() @ kernel_x # 由两个一维核外积构造二维核 out = filter2d(inp, kernel[None], padding=padding) out_sep = filter2d_separable(inp, kernel_x, kernel_y, padding=padding) self.assert_close(out, out_sep) # 两种路径输出一致

该测试覆盖了padding='same'padding='valid'两种模式,是理解可分离卷积正确性的最佳佐证。

4. filter3d:三维卷积原语

filter3d将滤波扩展到三维体数据(如 CT 体数据、视频序列、光场),签名见 kornia/filters/filter.py:

def filter3d( input: torch.Tensor, kernel: torch.Tensor, border_type: str = "replicate", normalized: bool = False, behaviour: str = "corr", ) -> torch.Tensor:
  • input形状为(B, C, D, H, W),D 为深度维;
  • kernel形状为(1, kD, kH, kW)(B, kD, kH, kW)
  • border_type支持'constant''reflect''replicate''circular'(默认值为'replicate',与 2D 版本的'reflect'不同);
  • 注意filter3d没有padding参数,输出始终与输入保持相同形状(B, C, D, H, W)(始终等价于padding='same');
  • behaviour同样支持'corr''conv'

4.1 官方文档示例

docstring 中的示例(kornia/filters/filter.py)构造了一个5x5x5的三维张量,中心切片上有一个值为 5 的体素,用3x3x3全 1 核滤波后,该值在三个深度切片的3x3邻域中都被扩散为 5:

import torch from kornia.filters import filter3d input = torch.tensor([[[ [[0., 0., 0., 0., 0.], ...], # 深度切片 0:全 0 [[0., 0., 0., 0., 0.], [0., 0., 5., 0., 0.], ...], # 深度切片 1:中心值为 5 [[0., 0., 0., 0., 0.], ...] # 深度切片 2:全 0 ]]]) kernel = torch.ones(1, 3, 3, 3) filter3d(input, kernel) # 输出在三个切片上都出现 5 的 3x3 扩散块

4.2 三维归一化

filter2d不同,filter3dnormalized=True时先做维度重整再复用normalize_kernel2d(见 kornia/filters/filter.py):

if normalized: bk, dk, hk, wk = kernel.shape tmp_kernel = normalize_kernel2d(tmp_kernel.view(bk, dk, hk * wk)).view_as(tmp_kernel)

即把三维核展平为(B, D, H*W)后逐行做 L1 归一化。测试 tests/filters/test_filters.py 的test_normalized_mean_filter验证了3x3x3全 1 核归一化后中心值 5 变为5.0 / 27(27 个元素之和)。

5. 核心参数深挖:padding、border_type 与 behaviour

5.1 padding:'same' 与 'valid'

padding='same'是默认模式:在卷积前先对输入做填充,使输出与输入空间形状一致。填充量由内部函数_compute_padding计算(kornia/filters/filter.py):

def _compute_padding(kernel_size: list[int]) -> list[int]: computed = [k - 1 for k in kernel_size] # 每维需要填充的总量 out_padding = 2 * len(kernel_size) * [0] for i in range(len(kernel_size)): computed_tmp = computed[-(i + 1)] pad_front = computed_tmp // 2 # 前侧(上/左) pad_rear = computed_tmp - pad_front # 后侧(下/右) out_padding[2 * i + 0] = pad_front out_padding[2 * i + 1] = pad_rear return out_padding

关键细节:对偶数尺寸的核,填充是不对称的pad_rear = pad_front + 1),因为奇数尺寸核的k-1是偶数可以对称平分,而偶数尺寸核只能通过"前少后多"的方式保持输出尺寸。测试 tests/filters/test_filters.py 的test_even_sized_filter专门覆盖了2x2偶数核在'same''valid'下的行为,test_mix_sized_filter_padding_same(tests/filters/test_filters.py)则覆盖了5x6这种宽高不对称的核。

padding='valid'不做填充,输出尺寸变为(B, C, H - kH + 1, W - kW + 1),在源码中由 kornia/filters/filter.py 的output.view(b, c, h - height + 1, w - width + 1)体现。

5.2 border_type:四种边界模式

模式行为
'constant'用常数(0)填充边界
'reflect'镜像反射填充(不含边界像素本身)
'replicate'复制最边缘像素值填充
'circular'环形循环填充

这些模式直接透传给torch.nn.functional.padmode参数(见 kornia/filters/filter.py),因此行为与 PyTorch 完全一致。测试中test_smoke(tests/filters/test_filters.py)对四种 border 类型 × 归一化开关 × 两种 padding 模式做了全组合冒烟验证。

5.3 behaviour:'corr' 与 'conv' 的区别

这是本 API 最值得注意的细节之一。深度学习框架中的conv2d实际执行的是互相关(cross-correlation),而数学意义上的真卷积需要先将核翻转 180°。filter2d通过behaviour参数显式区分两者:

  • 'corr'(默认):核不翻转,行为等价于 PyTorchconv2d
  • 'conv':执行真卷积,源码中通过kernel.flip((-2, -1))翻转核(见 kornia/filters/filter.py)。

测试 tests/filters/test_filters.py 的test_conv1..9排列的3x3核验证了两者差异:对中心为 1 的输入,'corr'输出核的原始排列(9 在左上),而'conv'输出核翻转后的排列(1 在左上)。

6. 便捷别名与 FFT 加速后端

filter2d/filter3d之外,kornia/filters/filter.py 还提供了一系列语义化别名与高性能实现,全部通过 kornia/filters/init.py 对外导出:

6.1 语义化别名

函数等价调用
correlate2d(input, kernel, ...)filter2d(..., behaviour='corr')
convolve2d(input, kernel, ...)filter2d(..., behaviour='conv')
correlate3d(input, kernel, ...)filter3d(..., behaviour='corr')
convolve3d(input, kernel, ...)filter3d(..., behaviour='conv')

例如convolve2d的实现就是一行(kornia/filters/filter.py):

return filter2d(input, kernel, border_type=border_type, normalized=normalized, padding=padding, behaviour="conv")

当你的算法在语义上需要"真卷积"而非互相关时,使用这些别名可以显著提升代码可读性。

6.2 fft_conv:大核加速

fft_conv(kornia/filters/filter.py)提供基于 FFT 的二维卷积后端,利用卷积定理在频域做逐元素乘法。其 docstring 明确指出适用场景:

"This function is recommended when the kernel size is larger than approximately (20 x 20). For large kernels, FFT-based convolution is computationally more efficient than direct spatial convolution, reducing complexity from O(H * W * kH * kW) to approximately O(H * W log(H * W))."

实现细节:内部使用torch.fft.rfftn/torch.fft.irfftn,通过共轭(torch.conj)实现互相关,并在频域计算前做空间域填充以避免循环卷积伪影;CPU 上的 float16 / bfloat16 输入会先用 float32 计算再转回原精度。测试 tests/filters/test_filters.py 的test_matches_spatial_filter验证了fft_convfilter2d在所有 padding / behaviour / normalized 组合下输出一致。

7. 源码级应用:模糊与边缘算子如何构建在 Filtering API 之上

回到文档的核心定位——"the primitives the blur and edge operators are built on"——我们可以在源码中逐一印证这些原语在 Kornia 内部的实际调用:

7.1 box_blur(盒式模糊)

kornia/filters/blur.py 中,box_blur的卷积路径分别使用filter2d_separable(可分离模式,默认)与filter2d(不可分离模式):

if separable: ky, kx = _unpack_2d_ks(kernel_size) kernel_y = get_box_kernel1d(ky, device=input.device, dtype=input.dtype) kernel_x = get_box_kernel1d(kx, device=input.device, dtype=input.dtype) out = filter2d_separable(input, kernel_x, kernel_y, border_type) else: kernel = get_box_kernel2d(kernel_size, device=input.device, dtype=input.dtype) out = filter2d(input, kernel, border_type)

7.2 gaussian_blur2d(高斯模糊)

kornia/filters/gaussian.py 中,gaussian_blur2dget_gaussian_kernel1d生成水平/垂直一维高斯核后走filter2d_separable(可分离路径),或用get_gaussian_kernel2d生成二维高斯核走filter2d

if separable: kernel_x = get_gaussian_kernel1d(kx, sigma[:, 1].view(bs, 1)) kernel_y = get_gaussian_kernel1d(ky, sigma[:, 0].view(bs, 1)) out = filter2d_separable(input, kernel_x, kernel_y, border_type) else: kernel = get_gaussian_kernel2d(kernel_size, sigma) out = filter2d(input, kernel, border_type)

7.3 laplacian(拉普拉斯算子)

kornia/filters/laplacian.py 直接导入filter2d,并用get_laplacian_kernel2d生成的核调用它(kornia/filters/laplacian.py):return filter2d(input, kernel, border_type)

此外,filter2d系列还被广泛用于其他子模块,例如kornia/metrics/ssim.pykornia/geometry/transform/pyramid.pykornia/geometry/transform/elastic_transform.pykornia/contrib/distance_transform.py等。这充分说明 Filtering API 确实是整个 Kornia 滤波与几何变换体系的公共底座。

8. 实战:构建自定义算子

基于以上知识,你可以用 Filtering API 快速实现任意线性滤波算子。以锐化(unsharp 风格)为例:

import torch from kornia.filters import filter2d def sharpen(image: torch.Tensor, strength: float = 1.0) -> torch.Tensor: """用自定义核实现锐化:identity + strength * (identity - box)""" kernel = torch.tensor([[[ [0.0, -1.0, 0.0], [-1.0, 5.0, -1.0], [0.0, -1.0, 0.0], ]]], device=image.device, dtype=image.dtype) return filter2d(image, kernel, border_type="replicate", padding="same")

几个来自源码与测试的最佳实践:

  • 核形状:单核用(1, kH, kW);需要按批次使用不同核时用(B, kH, kW),此时每个批次元素独立滤波;
  • 可分离优先:只要核能写成两个一维核的外积(高斯、盒式、Sobel 类),就用filter2d_separable提升效率,且输出与二维路径一致(有test_separable保证);
  • 大核用 FFT:核尺寸超过约20x20时,考虑fft_conv以换取更低复杂度;
  • 边界语义:边缘处理敏感的任务(如梯度估计)优先考虑'replicate''reflect',避免'constant'引入的边界跳变;
  • 可微性:整个 API 完全由 PyTorch 算子组成(F.pad+F.conv2d/F.conv3d),梯度可以正常反向传播。测试test_gradcheck(tests/filters/test_filters.py)对filter2dfilter3d均做了梯度检查,test_dynamo还验证了与torch.compile的兼容性;
  • 输入约束:所有输入必须是(B, C, ...)形状的张量,维度不足或类型错误会立即抛异常(TypeCheckError/ShapeError),便于尽早发现 bug。

9. 小结

Filtering API 是 Kornia 滤波系统的核心原语层:filter2d提供二维互相关/卷积,filter2d_separable通过两次一维滤波实现高效的可分离卷积,filter3d将同一套设计扩展到三维体数据。配合normalizedpaddingborder_typebehaviour四个开关,这组函数可以表达几乎所有的线性图像滤波操作,而convolve2d/correlate2d/fft_conv等辅助函数进一步丰富了表达力与性能选项。Kornia 自身的box_blurgaussian_blur2dlaplacian等算子全部构建在这些原语之上——理解了 Filtering API,就掌握了 Kornia 滤波体系的根基,也为自定义可微图像算子打下了坚实基础。

  • 计算机视觉
  • 人工智能
  • 深度学习
  • 图像处理

【免费下载链接】kornia

🐍 Geometric Computer Vision Library for Spatial AI

项目地址:https://gitcode.com/gh_mirrors/ko/kornia
点击查看免费下载

相关推荐

上一篇:从 .bundle 到可导入的工程:AssetRipper 跨平台资产提取手记
下一篇:GitHub_Trending/de/developer-portfolios项目国际化:多语言作品集网站的实现方法

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询