小土堆——常见的Transforms

小土堆——常见的Transforms 1.ToTensor 创建一个「PIL 图片 / NumPy 数组 → PyTorch Tensor 格式」的转换工具2.Normalize「归一化」调整图片像素值的分布让模型训练更稳定3.Resize (图片放缩)4.Compose Compose是 “工具打包机”把多个转换工具按顺序打包成一个新工具5. RandomCrop (随机裁剪)Resize和RandomCrop传单值的区别1.ToTensor 创建一个「PIL 图片 / NumPy 数组 → PyTorch Tensor 格式」的转换工具tensor_trans transforms.ToTensor() # 调用 tensor_trans 这个转换工具把 PIL 格式的 img 转换成 Tensor 格式结果存到 tensor_img 里。 tensor_img tensor_trans(img) print(tensor_img) # 0图片的 “步数 / 索引”比如后续想加第 2 张图就写 1TensorBoard 会按数字顺序展示。 writer.add_image(ants_image, tensor_img, 0)为什么必须用 ToTensorPIL 图片的本质用Image.open()打开的图片是「PIL.Image.Image」类型本质是 “图片查看器格式”只有 “展示图片” 的能力没有 “数值计算” 的能力比如无法做矩阵运算、梯度下降Tensor 的本质Tensor 是 PyTorch 的核心数据结构可以理解为 “带计算功能的多维数组”PyTorch 的模型、优化器、GPU 加速等功能只认 Tensor 格式ToTensor 的核心工作把 PIL 图片或 NumPy 数组转换成torch.Tensor类型把图片像素值从「0-255 的整数」转换成「0.0-1.0 的浮点数」模型训练时浮点数计算更稳定调整维度顺序PIL 图片的维度是(高度H, 宽度W, 通道C)比如 224×224×3转换成 Tensor 后变成(通道C, 高度H, 宽度W)3×224×224—— 这是 PyTorch 要求的维度顺序。2.Normalize「归一化」调整图片像素值的分布让模型训练更稳定trans_norm transforms.Normalize([1,3,3],[1,2,3]) img_norm trans_norm(tensor_img) writer.add_image(ants_norm, img_norm, 2)核心代码transforms.Normalize(mean[均值1, 均值2, 均值3], std[标准差1, 标准差2, 标准差3])这里的[1,3,3]是均值mean[1,2,3]是标准差std为什么是 3 个数因为图片是「RGB 三通道」红、绿、蓝第一个数对应红色通道第二个对应绿色通道第三个对应蓝色通道这里写的[1,3,3]和[1,2,3]是自定义的测试值实际项目中会用数据集的真实均值 / 标准差比如 ImageNet 的mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]为什么要做归一化原始图片的像素值范围是 0-1Tensor 格式不同通道的像素值分布可能差异很大比如红色通道均值 0.6绿色通道均值 0.2模型训练时数值分布差异大会导致收敛慢、精度低归一化能把各通道的像素值调整到「均值为 0、标准差为 1」的标准分布让模型学得更快更好你这里用的[1,3,3]是测试值实际项目中一定要用对应数据集的真实均值 / 标准差比如训练自己的图片集要先计算所有图片的 RGB 均值和标准差。3.Resize (图片放缩)# Resize 图片放缩 print(img.size) trans_resize transforms.Resize((512,512)) # img PIL(W,H) - resize - img_resize PIL(H,W) img_resize trans_resize(img) # img_resize PIL - totensor - img_resize tensor img_resize transforms.ToTensor()(img_resize) print(img_resize) writer.add_image(resize, img_resize, 0)4.Compose Compose是 “工具打包机”把多个转换工具按顺序打包成一个新工具# 和第一段的Resize((512,512))不同这里只传一个数512表示「保持图片宽高比将最短边缩放到 512 像素」 trans_resize_2 transforms.Resize(512) # 第一步用trans_resize_2缩放 PIL 图片输出 PIL # 第二步用transforms.ToTensor()把缩放后的 PIL 转成 Tensor输出 Tensor trans_compose transforms.Compose([trans_resize_2, transforms.ToTensor()]) img_resize_2 trans_compose(img_lake) writer.add_image(resize, img_resize_2, 1)Compose的优势不用像第一段那样手动分步转换代码更简洁尤其是需要多个转换步骤时比如 “裁剪→缩放→归一化→转 Tensor”Compose 能大幅简化代码。注意列表里的工具必须按「PIL 处理工具在前Tensor 处理工具在后」的顺序且前一个工具的输出要能匹配后一个工具的输入比如 Resize 输出 PILToTensor 输入 PIL顺序不能反。5. RandomCrop (随机裁剪)# !!!RandomCrop只处理 PIL 图片输入必须是 PIL 格式输出也还是 PIL 格式。 trans_random transforms.RandomCrop(512) trans_compose_2 transforms.Compose([trans_random, transforms.ToTensor()]) for i in range(10): img_crop trans_compose_2(img_lake) writer.add_image(crop, img_crop, i)作用初始化 PyTorch 的RandomCrop工具功能是从 PIL 图片中随机选一个位置裁剪出一个 512×512 的正方形区域参数说明传单个数值512表示裁剪出「512×512」的正方形和Resize(512)的单参数逻辑类似如果传(H, W)比如(300, 500)表示裁剪出「高 300、宽 500」的矩形和固定裁剪的区别RandomCrop每次裁剪的位置是随机的比如这次裁左上角下次裁中间下次裁右下角而如果是固定裁剪比如CenterCrop每次都裁正中间为什么要用 RandomCrop实战意义在深度学习训练中随机裁剪是一种数据增强手段目的让模型看到同一张图片的不同局部比如蚂蚁图片有时裁到头部有时裁到身体避免模型 “死记硬背” 图片位置提升模型的泛化能力比如换一张蚂蚁图片哪怕蚂蚁在图片角落模型也能识别场景训练时常用测试 / 预测时一般不用测试时用固定裁剪或完整图片。Resize和RandomCrop传单值的区别1.Resize 的核心目的是调整整张图片的大小但尽量保留图片原貌不拉伸变形。举个例子假设你的原始图片是800×600宽 800高 600最短边是高度 600。用Resize(512)代码会计算缩放比例512/600 ≈ 0.853宽度跟着缩放800×0.853 ≈ 682最终图片尺寸是682×512宽 682高 512宽高比和原图一致800:600 682:512图片不会变形。如果 Resize 只传一个数却强制切正方形会导致图片拉伸比如把 800×600 的图硬缩成 512×512这违背了 Resize “保留图片原貌” 的设计初衷。2.Crop裁剪的核心目的是从整张图里 “切一块小区域”和 Resize 的 “调整整张图” 完全不同裁剪需要明确 “切多大的区域”如果你只传一个数比如 512代码默认你想要正方形区域最常用的裁剪需求如果你想要矩形就传两个数RandomCrop((300, 500))表示切 “高 300、宽 500” 的矩形。裁剪不需要保持比例裁剪是 “舍弃部分区域”不是 “拉伸整张图”所以直接指定裁剪区域的尺寸即可不存在 “变形” 的问题。易记的 “区分口诀”Resize缩放传 1 个数 按比例缩保原貌传 2 个数 强制缩成指定尺寸可能变形Crop裁剪传 1 个数 切正方形传 2 个数 切指定尺寸的矩形和比例无关。···#打开Tensorboardtensorboard --logdirlogs默认端口号为6006如果想防止在一台服务器上和别人发生端口冲突可以更改端口号tensorboard --logdirlogs --port6008 r“绝对路径”r路径r是 “原始字符串”避免 Windows 路径里的\被识别成转义字符比如\n是换行···完整的代码文件from PIL import Image from torch.utils.tensorboard import SummaryWriter from torchvision import transforms from torchvision.transforms import Compose, RandomCrop # python - tensor数据类型 # 通过transforms.ToTensor去解决两个问题 # 1.transforms该如何使用python # 2.为什么我们需要Tensor数据类型 writer SummaryWriter(logs) img_path rE:\PycharmProjects\PythonProject1\hymenoptera_data\train\ants_image\0013035.jpg # 或img_path hymenoptera_data/train/ants_image/0013035.jpg img Image.open(img_path) # ToTensor 转换数据类型 # 1.把 PIL 图片或 NumPy 数组转换成 torch.Tensor 类型原始图片img是 PIL 格式PyTorch/TensorBoard 不直接支持这种格式 # 2.把图片像素值从「0-255 的整数」转换成「0.0-1.0 的浮点数」模型训练时浮点数计算更稳定 # 3.调整维度顺序PIL 图片的维度是 (高度H, 宽度W, 通道C)比如 224×224×3转换成 Tensor 后变成 (通道C, 高度H, 宽度W)3×224×224—— 这是 PyTorch 要求的维度顺序。 tensor_trans transforms.ToTensor() # 调用 tensor_trans 这个转换工具把 PIL 格式的 img 转换成 Tensor 格式结果存到 tensor_img 里。 tensor_img tensor_trans(img) print(tensor_img) # 0图片的 “步数 / 索引”比如后续想加第 2 张图就写 1TensorBoard 会按数字顺序展示。 writer.add_image(ants_image, tensor_img, 0) img_lake Image.open(imgs/lake.jpg) tensor_lake tensor_trans(img_lake) writer.add_image(lake_image, tensor_lake, 0) # Normalize「归一化」调整图片像素值的分布让模型训练更稳定 trans_norm transforms.Normalize([1,3,3],[1,2,3]) img_norm trans_norm(tensor_img) writer.add_image(ants_norm, img_norm, 2) # Resize 图片放缩 print(img.size) trans_resize transforms.Resize((512,512)) # img PIL(W,H) - resize - img_resize PIL(H,W) img_resize trans_resize(img) # img_resize PIL - totensor - img_resize tensor img_resize transforms.ToTensor()(img_resize) print(img_resize) writer.add_image(resize, img_resize, 0) # Compose - resize - 2 Compose是 “工具打包机”把多个转换工具按顺序打包成一个新工具 # 和第一段的Resize((512,512))不同这里只传一个数512表示「保持图片宽高比将最短边缩放到 512 像素」 trans_resize_2 transforms.Resize(512) # 第一步用trans_resize_2缩放 PIL 图片输出 PIL # 第二步用transforms.ToTensor()把缩放后的 PIL 转成 Tensor输出 Tensor trans_compose transforms.Compose([trans_resize_2, transforms.ToTensor()]) img_resize_2 trans_compose(img_lake) writer.add_image(resize, img_resize_2, 1) # RandomCrop 随机裁剪 # !!!RandomCrop只处理 PIL 图片输入必须是 PIL 格式输出也还是 PIL 格式。 # Resize (单值) 按比例缩最短边 (保比例Resize (H,W) 强制缩成指定尺寸 # RandomCrop (单值) 切正方形RandomCrop (H,W) 切矩形 trans_random transforms.RandomCrop(512) trans_compose_2 transforms.Compose([trans_random, transforms.ToTensor()]) for i in range(10): img_crop trans_compose_2(img_lake) writer.add_image(crop, img_crop, i) writer.close()