Kornia Image Container 详解:用 Image、ImageLayout 与 PixelFormat 管理图像张量
【免费下载链接】kornia🐍 空间人工智能的几何计算机视觉库项目地址: https://gitcode.com/kornia/kornia
导读
本文围绕 Kornia 图像容器模块(kornia.image)展开,系统讲解Image类及其配套的元数据数据结构ImageSize、PixelFormat、ChannelsOrder、ImageLayout。这些类型为图像数据提供了自描述的元信息,让一段torch.Tensor在任意通道顺序(CHW/HWC)、任意色彩空间(RGB/BGR/Gray)、任意位深下都能被正确解释和转换。读完本文,你将掌握如何从 numpy / DLPack / 文件构造Image对象、如何在不同色彩空间与通道布局之间无损转换、如何校验张量形状是否符合声明布局,以及如何把图像打印到终端或写出文件——并深入理解其底层源码实现与测试验证。
说明:
kornia.image是一个独立、自洽的图像容器子模块,API 与 Kornia 其他模块(如kornia.color、kornia.io)协同工作。本文以 image.container.rst 的 API 文档为骨架,结合 kornia/image/base.py、kornia/image/image.py 等源码逐一展开。
一、模块概览:kornia.image提供什么
kornia.image是 Kornia 的图像数据结构子模块,公开 API 定义在 kornia/image/init.py,主要包括三类能力:
- 图像元数据与容器:
ImageSize、PixelFormat、ChannelsOrder、ImageLayout、Image,它们全部定义在 kornia/image/base.py 与 kornia/image/image.py 中,正是本文的核心; - 张量与图像互转工具:
image_to_tensor、tensor_to_image、image_list_to_tensor、make_grid、perform_keep_shape_image等,定义在 kornia/image/utils.py; - 终端打印与绘制:
image_to_string、print_image(定义在 kornia/image/image_print.py)以及draw_line、draw_rectangle等绘图函数(定义在 kornia/image/draw.py)。
本文聚焦第一类(容器与元数据),并在必要时引入第二、三类工具来佐证Image的完整工作流。
Image类在文档中自带两条重要声明(见 kornia/image/image.py):
- 最小功能原则:它只提供图像操作的最小功能,一旦你需要高级的
torch.Tensor多态操作,可能需要自行扩展; - 实验性 API:该 API 处于实验阶段,未来可能发生变化。
这意味着它适合作为“带元数据的图像载体”在 pipeline 中传递,而不承诺与torch.Tensor完全一致的行为。
二、四个元数据结构:为张量补上“语义”
Image之所以能自描述,靠的是四个基础类型(全部为frozen dataclass或Enum,定义在 kornia/image/base.py):
2.1 ImageSize:高与宽
ImageSize是冻结数据类(@dataclass(frozen=True)),仅包含两个字段:
| 字段 | 类型 | 含义 |
|---|---|---|
height | int \| torch.Tensor | 图像高度 |
width | int \| torch.Tensor | 图像宽度 |
字段允许是torch.Tensor,说明它也能表达批量/动态尺寸。构造与读取示例(与源码 docstring 一致):
from kornia.image import ImageSize size = ImageSize(3, 4) size.height # 3 size.width # 42.2 ColorSpace 与 PixelFormat:色彩空间 + 位深
PixelFormat描述“像素格式”,由两个字段组成:
| 字段 | 类型 | 含义 |
|---|---|---|
color_space | ColorSpace | 色彩空间枚举 |
bit_depth | int | 每个通道的位数 |
其中ColorSpace是Enum(源码 kornia/image/base.py):
UNKNOWN = 0——用于多波段图像的占位值;GRAY = 1;RGB = 2;BGR = 3。
构造示例:
from kornia.image import ColorSpace, PixelFormat pixel_format = PixelFormat(color_space=ColorSpace.RGB, bit_depth=8) pixel_format.color_space # <ColorSpace.RGB: 2> pixel_format.bit_depth # 8bit_depth与张量元素字节数存在直接约束:Image构造函数会用KORNIA_CHECK(data.element_size() == pixel_format.bit_depth // 8, "Invalid bit depth.")校验两者一致(见 kornia/image/image.py)。例如torch.uint8的element_size()为 1,对应 8 位;torch.float32为 4,对应 32 位。
2.3 ChannelsOrder:通道在前还是在后
ChannelsOrder是二值枚举(kornia/image/base.py):
CHANNELS_FIRST = 0——CHW 布局(PyTorch 惯例,如(3, H, W));CHANNELS_LAST = 1——HWC 布局(OpenCV / numpy 惯例,如(H, W, 3))。
这个枚举是整个容器模块的“枢纽”:Image内部所有色彩转换都先判断通道顺序,必要时先permute再计算,最后再转回原布局。
2.4 ImageLayout:把三者组合成完整布局
ImageLayout把尺寸、通道数、通道顺序组合成一个整体(kornia/image/base.py):
| 字段 | 类型 | 含义 |
|---|---|---|
image_size | ImageSize | 图像尺寸 |
channels | int | 通道数 |
channels_order | ChannelsOrder | 通道顺序 |
from kornia.image import ChannelsOrder, ImageLayout, ImageSize layout = ImageLayout(ImageSize(3, 4), 3, ChannelsOrder.CHANNELS_LAST) layout.image_size # ImageSize(height=3, width=4) layout.channels # 3 layout.channels_order # <ChannelsOrder.CHANNELS_LAST: 1>2.5 布局校验函数 KORNIA_CHECK_IMAGE_LAYOUT
与四个数据结构配套的还有一个校验函数KORNIA_CHECK_IMAGE_LAYOUT(x, layout, msg=None, raises=True)(kornia/image/base.py),它根据布局生成期望形状并调用KORNIA_CHECK_SHAPE:
CHANNELS_FIRST期望形状为[channels, height, width];CHANNELS_LAST期望形状为[height, width, channels];raises=False时不抛异常而返回布尔值。
测试用例 tests/image/test_image.py 验证了四种情形:两种布局各有一例合法校验返回True,另有raises=True时抛ShapeError、raises=False时返回False的两例。
三、核心类 Image:带元数据的图像张量
Image类是本节的主角。它的构造函数签名与校验逻辑如下(kornia/image/image.py):
def __init__(self, data: torch.Tensor, pixel_format: PixelFormat, layout: ImageLayout) -> None: KORNIA_CHECK_IMAGE_LAYOUT(data, layout) KORNIA_CHECK(data.element_size() == pixel_format.bit_depth // 8, "Invalid bit depth.") self._data = data self._pixel_format = pixel_format self._layout = layout构造时即做两件事:形状是否符合布局、位深是否与张量 dtype 匹配。非法输入在构造阶段就被拦截。
3.1 从 torch.Tensor 构造
import torch from kornia.image import ChannelsOrder, ColorSpace, Image, ImageLayout, ImageSize, PixelFormat data = torch.randint(0, 255, (3, 4, 5), dtype=torch.uint8) # CxHxW pixel_format = PixelFormat(color_space=ColorSpace.RGB, bit_depth=8) layout = ImageLayout( image_size=ImageSize(4, 5), channels=3, channels_order=ChannelsOrder.CHANNELS_FIRST, ) img = Image(data, pixel_format, layout) assert img.channels == 3 assert img.height == 4 and img.width == 5 assert img.shape == (3, 4, 5)3.2 属性一览
Image提供一系列只读属性(kornia/image/image.py):
| 属性 | 返回 | 说明 |
|---|---|---|
data | torch.Tensor | 底层张量 |
shape | tuple[int, ...] | 张量形状 |
dtype/device | torch.dtype/torch.device | 数据类型与设备 |
pixel_format | PixelFormat | 像素格式 |
layout | ImageLayout | 完整布局 |
channels | int | 通道数 |
image_size | ImageSize | 图像尺寸 |
height/width | int | 高 / 宽 |
channels_order | ChannelsOrder | 通道顺序 |
此外还有to(device, dtype)(支持把torch.dtype直接作为第一个参数传入的便捷写法)、clone()、float()等实例方法(kornia/image/image.py)。
3.3 色彩空间转换:to_gray / to_rgb / to_bgr
这是Image最核心的能力。三个方法在源码中遵循同一套流程(以 to_gray 为例):
- 若已是目标色彩空间,直接返回
self; - 若布局为
CHANNELS_LAST,先permute为通道在前; - 调用
kornia.color模块的转换函数(如rgb_to_grayscale、bgr_to_grayscale); - 若原布局是通道在后,再
permute回去; - 用新色彩空间构造新
PixelFormat(位深不变),并用channels=1(灰度)或channels=3(RGB/BGR)构造新ImageLayout,返回新的Image。
to_rgb/to_bgr的实现细节(kornia/image/image.py):
- 灰度 → RGB:
kornia.color.grayscale_to_rgb,把亮度值复制到三个通道; - RGB ↔ BGR:直接在通道维翻转,如
data[:, [2, 1, 0], ...](4D 批量)或data[[2, 1, 0], ...](3D); - 灰度 → BGR:先转 RGB 再翻转通道。
测试 tests/image/test_image.py 对 CHW 与 HWC 两种通道顺序分别验证了 RGB→Gray→RGB、BGR→Gray→BGR、RGB↔BGR 三种往返转换,并断言灰度重建的 RGB 是亮度值的三通道复制,BGR 重建结果是其翻转。
3.4 多种数据源构造与导出
Image通过类方法支持四种数据来源(kornia/image/image.py):
| 类方法 | 输入 | 说明 |
|---|---|---|
from_numpy(data, color_space=ColorSpace.RGB, channels_order=ChannelsOrder.CHANNELS_LAST) | numpy 数组 | 自动从形状推断ImageSize与通道数,bit_depth = data.itemsize * 8;默认按 OpenCV 惯例HWC处理 |
from_dlpack(data) | DLPack capsule | 从 numpy、TVM、JAX 等共享内存交换格式构造,默认按 CHW 处理 |
from_file(file_path) | 文件路径 | 内部调用kornia.io.load_image(file_path, desired_type=ImageLoadType.RGB8, device="cpu"),固定得到 RGB、CHW |
| 直接构造 | torch.Tensor | 需手动提供PixelFormat与ImageLayout |
对应导出方法:
to_numpy():self.data.cpu().detach().numpy()(kornia/image/image.py);to_dlpack():返回 DLPack capsule,与from_dlpack互逆,测试见 tests/image/test_image.py;write(file_path):写出图像文件。
import numpy as np from kornia.image import ColorSpace, Image # 从 numpy(模拟 cv2.imread 结果,HxWxC) data = np.ones((4, 5, 3), dtype=np.uint8) img = Image.from_numpy(data, color_space=ColorSpace.RGB) assert img.channels == 3 and img.height == 4 and img.width == 5 # 写回 numpy np_img = np.asarray(img.to_numpy())测试 tests/image/test_image.py 验证了from_numpy → to_numpy的往返一致性,以及clone()/to(device)/to(dtype)链式调用的行为。
3.5 文件读写:from_file 与 write
from_file通过load_image读取,write通过write_image写出(kornia/image/image.py)。写出的核心逻辑是:若布局为CHANNELS_LAST先permute(2, 0, 1)转为 CHW,再交给kornia.io.write_image。
底层 IO 实现位于 kornia/io/io.py,要点如下:
- 解码:基于
kornia_rs(Kornia 的 Rust 后端)。JPEG 走read_image_jpegturbo,PNG 会读取文件头判断色彩类型(灰度/索引/灰度+Alpha/RGBA)选择对应解码路径(kornia/io/io.py); - 类型转换:
ImageLoadType枚举(UNCHANGED/GRAY8/RGB8/RGBA8/GRAY32/RGB32)通过_convert_image_type完成灰度↔RGB↔RGBA 与 8 位↔32 位的组合转换([kornia/io/io.py](https://link.gitcode.com/i/e19eb43b5b0f4ec481ebf6f123607b0f#L37-L45, L125-L171)); - 编码:
write_image支持.jpg/.jpeg/.png/.tiff,dtype 为uint8/uint16/float32,JPEG 可用quality参数控制质量(默认 80,png/tiff 忽略该参数)(kornia/io/io.py)。
因此Image.from_file("panda.png")得到的是(3, H, W)的uint8RGB 图像,img.write("out.jpg")则按 JPEG 编码写出。相关读写测试见 tests/image/test_image.py,其中含 JPeg 压缩导致像素误差的容差断言与标注。
四、终端打印:print / print_image / image_to_string
Image.print(max_width=256)能把图像以 ANSI 颜色块形式打印到终端(kornia/image/image.py),实现位于 kornia/image/image_print.py:
image_to_string(image, max_width=256):接受(C, H, W)的 RGB 张量,先做KORNIA_CHECK_IS_IMAGE与形状校验;非浮点 dtype 先除以 255 归一化;宽度超过max_width时调用kornia.geometry.resize等比缩放;逐像素经rgb2short映射为 xterm-256 颜色码,生成\033[48;5;{short}m背景色块;rgb2short(rgb):在 256 色调色板(源码内置完整CLUT查找表)中查找最接近的颜色;print_image(image, max_width=96):模块级函数,接受文件路径字符串或torch.Tensor,路径会先经kornia.io.load_image读取。
img = Image.from_file("panda.png") img.print() # 在支持 xterm-256 的终端中显示缩略图 from kornia.image import print_image print_image("panda.png", max_width=96)注意:该方法依赖终端对 ANSI 背景色转义序列的支持,普通日志文件或不支持 ANSI 的终端上无法还原效果。
五、配套工具:张量与图像的互转
虽然Image是本文主角,但kornia.image.utils提供的一批“无元数据”互转工具与其互补,值得一并掌握(kornia/image/utils.py):
image_to_tensor(image, keepdim=True):numpy(H,W)/(H,W,C)/(B,H,W,C)→(C,H,W)/(B,C,H,W);tensor_to_image(tensor, keepdim=False, force_contiguous=False):反向转换,GPU 张量自动拷回 CPU,灰度单通道自动 squeeze;image_list_to_tensor(images):形状一致的(H,W,C)列表 →(B,C,H,W);make_grid(tensor, n_row=None, padding=2):(B,C,H,W)批量张量拼成一张大图(自动补零到矩形网格);ImageToTensor(keepdim=False):nn.Module包装版,可直接嵌入nn.Sequential;perform_keep_shape_image(f)/perform_keep_shape_video(f):装饰器,把任意前导维度的(*,C,H,W)/(*,C,D,H,W)输入压成(B,C,H,W)/(B,C,D,H,W)交给函数处理后还原形状,常用于让卷积等算子支持任意批量维度。
from kornia.image import image_to_tensor, tensor_to_image, make_grid img = np.ones((4, 4, 3)) # HxWxC t = image_to_tensor(img, keepdim=False) # (1, 3, 4, 4) back = tensor_to_image(t) # (4, 4, 3) grid = make_grid(torch.rand(8, 3, 32, 32)) # 2x4 网格拼图这些函数对应测试见 tests/image/test_image_utils.py,print相关测试见 tests/image/test_print.py。
六、实战流程串联:从文件到转换再到写出
把上述知识串成一个典型工作流:
import torch from kornia.image import ColorSpace, Image # 1. 读取:得到 RGB8、CHW、uint8 的 Image img = Image.from_file("photo.jpg") print(img.pixel_format, img.layout) # 查看元数据 # 2. 转到 GPU、转 float(与深度学习 pipeline 衔接) img = img.to("cuda").float() # 3. 转灰度用于预处理 gray = img.to_gray() # 4. 转回 RGB 并克隆一份 rgb = gray.to_rgb().clone() # 5. 写出(JPEG,默认质量 80) rgb.to(torch.uint8).write("out.jpg")实际使用中请注意:
to_gray()/to_rgb()后返回的是新的Image对象,通道数与PixelFormat已同步更新,无需手动维护元数据;- 色彩空间转换不改变位深,若从
uint8输入出发,转换结果仍为uint8; write目前文档标注“仅保证 JPEG 格式输出”,但底层kornia.io.write_image已支持.png/.tiff,且from_file固定按RGB8读取,读出的图像色彩空间标记为 RGB。
七、源码结构速查与延伸阅读
- 元数据结构与布局校验:kornia/image/base.py(
ImageSize/ColorSpace/PixelFormat/ChannelsOrder/ImageLayout/KORNIA_CHECK_IMAGE_LAYOUT) - 核心容器类:kornia/image/image.py(
Image全部属性、色彩转换、from_numpy/from_dlpack/from_file/write) - 终端打印:kornia/image/image_print.py(
image_to_string/print_image/rgb2short) - 互转与批处理工具:kornia/image/utils.py(
image_to_tensor/tensor_to_image/make_grid等) - 文件 IO 底层:kornia/io/io.py(
load_image/write_image/ImageLoadType) - 测试用例:tests/image/test_image.py(构造、numpy 往返、DLPack、色彩转换、读写)、tests/image/test_image_utils.py、tests/image/test_print.py
- 模块导出清单:kornia/image/init.py
- 本文对应的 API 文档页:docs/source/image.container.rst(
autoclass生成的ImageSize/PixelFormat/ChannelsOrder/ImageLayout/Image完整成员文档)
八、已知边界与注意事项
- 实验性 API:
Image明确标注“experimental and might suffer changes in the future”,升级 Kornia 时需关注迁移说明(仓库 changelog.d 目录记录了各版本的 breaking / fixed 变更); - 最小功能原则:
Image不承诺完整模拟torch.Tensor的多态行为(如魔法方法、广播),需要灵活张量操作时应取出.data操作后再包回; - 多波段图像:
ColorSpace.UNKNOWN目前只是占位值,源码中标注了TODO: define CompressedImage,压缩图像容器尚未实现; - 位深校验严格:
bit_depth必须与data.element_size() * 8一致,声明 8 位却传入float32张量会在构造时报 “Invalid bit depth.”; - 打印依赖终端能力:
print()需要 xterm-256 色支持,且会按max_width自动缩放,超大图在普通终端上无法完整呈现。
综上,Kornia 的 Image Container 以“张量 + 元数据”的组合,为几何计算机视觉 pipeline 提供了一种类型安全、自描述的图像表示方式:构造即校验、转换即更新元数据、读写即复用kornia.io的 Rust 加速后端。无论是对接 OpenCV 的 HWC 数据、跨框架的 DLPack 交换,还是在深度学习前处理中统一通道布局,这套容器都值得作为图像数据层的首选载体。
【免费下载链接】kornia🐍 空间人工智能的几何计算机视觉库项目地址: https://gitcode.com/kornia/kornia
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考