首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

YOLO11 图像缩放 | 图像填充 | 自适应不同尺寸的图片

  • 25-02-19 04:01
  • 4562
  • 7927
blog.csdn.net

本文分享YOLO中的图像缩放、填充,实现任意图像训练和推理的基础,是图像预处理中的工作。

本文的代码和示例,适合YOLO11、YOLOv8和YOLOv5等版本。

目录

1、思路流程

2、示例1 默认灰色填充,图像尺寸为640*640

3、示例2 黑色填充,图像尺寸为640*640

4、示例3 白色填充,图像尺寸为1280*1280


1、思路流程

我们首先分析一下letterbox函数

  • 功能:对输入图像进行缩放和填充,使其适应指定的目标尺寸 new_shape(默认640x640),并保持图像的纵横比。
  • 步骤:
    • 获取原始图像的宽高尺寸 shape。
    • 计算缩放比例 r,以确保图像不会拉伸变形。
    • 根据缩放比例 r 计算新尺寸 new_unpad。
    • 计算图像在目标尺寸中的填充大小 dw 和 dh,使图像居中。
    • 如果 auto 为 True,填充的宽高会被调整为步长的倍数;如果 scale_fill 为 True,则直接拉伸图像到目标尺寸,不做填充。
    • 使用 cv2.copyMakeBorder 根据填充宽高添加指定颜色(默认黑色)的边框。
    • 返回处理后的图像、缩放比例 ratio 以及填充宽高 (dw, dh)。

然后分析一下process_images_in_folder函数

  • 功能:对指定文件夹中的所有图像文件进行 letterbox 处理,并保存到输出文件夹。
  • 步骤:
    • 检查输出文件夹是否存在,不存在则创建。
    • 遍历输入文件夹中的所有图像文件,确保仅处理指定格式(.jpg, .png, .jpeg)。
    • 读取每个图像文件的字节数据,将其传入 save_letterboxed_image 函数,处理并保存到输出文件夹。

2、示例1 默认灰色填充,图像尺寸为640*640

这里默认填充灰色颜色,设置图像尺寸为640*640

示例代码如下:

  1. import os
  2. import cv2
  3. import numpy as np
  4. # 定义letterbox函数,用于对图像进行缩放和填充,使其适应指定尺寸
  5. def letterbox(img, new_shape=(640, 640), color=(0, 0, 0), auto=False, scale_fill=False, scale_up=False, stride=32):
  6. shape = img.shape[:2] # 获取图像的原始高度和宽度
  7. if isinstance(new_shape, int):
  8. new_shape = (new_shape, new_shape) # 如果new_shape是整数,则将其转换为方形尺寸
  9. # 计算缩放比例r,确保图像不会拉伸变形
  10. r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])
  11. if not scale_up:
  12. r = min(r, 1.0) # 如果scale_up为False,则缩放比例不大于1,避免放大
  13. ratio = r, r # 记录宽高的缩放比例
  14. new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) # 根据比例计算缩放后的尺寸
  15. dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # 计算需要填充的宽度和高度
  16. if auto:
  17. dw, dh = np.mod(dw, stride), np.mod(dh, stride) # 如果auto为True,将填充尺寸调整为步长的倍数
  18. elif scale_fill:
  19. dw, dh = 0.0, 0.0 # 如果scale_fill为True,则不进行填充,直接拉伸到目标尺寸
  20. new_unpad = (new_shape[1], new_shape[0])
  21. ratio = new_shape[1] / shape[1], new_shape[0] / shape[0] # 重新计算缩放比例
  22. dw /= 2 # 左右填充的宽度
  23. dh /= 2 # 上下填充的高度
  24. if shape[::-1] != new_unpad: # 如果原始尺寸和缩放后的尺寸不同,进行图像缩放
  25. img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR) # 线性插值进行图像缩放
  26. top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) # 上下填充像素数
  27. left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) # 左右填充像素数
  28. img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # 使用指定颜色填充
  29. return img, ratio, (dw, dh) # 返回处理后的图像、缩放比例以及填充的宽高
  30. # 保存经过letterbox处理的图像
  31. def save_letterboxed_image(image_bytes, output_filename, new_shape=(640, 640)):
  32. im0 = cv2.imdecode(np.frombuffer(image_bytes, np.uint8), cv2.IMREAD_COLOR) # 从字节数据解码出图像
  33. if im0 is None:
  34. raise ValueError("Failed to decode image from image_bytes") # 如果图像解码失败,抛出异常
  35. img, _, _ = letterbox(im0, new_shape=new_shape) # 对图像进行letterbox处理
  36. # 保存处理后的图像
  37. cv2.imwrite(output_filename, img) # 将处理后的图像写入文件
  38. print(f"Saved letterboxed image to {output_filename}") # 输出保存成功的信息
  39. # 处理文件夹中的所有图像
  40. def process_images_in_folder(folder_path, output_folder, new_shape=(640, 640)):
  41. if not os.path.exists(output_folder):
  42. os.makedirs(output_folder) # 如果输出文件夹不存在,则创建
  43. # 遍历文件夹中的所有图像文件
  44. for filename in os.listdir(folder_path):
  45. if filename.endswith(('.jpg', '.png', '.jpeg')): # 仅处理特定格式的图像文件
  46. image_path = os.path.join(folder_path, filename) # 获取图像的完整路径
  47. with open(image_path, 'rb') as f:
  48. image_bytes = f.read() # 读取图像文件的字节数据
  49. output_filename = os.path.join(output_folder, filename) # 构建输出文件的完整路径
  50. save_letterboxed_image(image_bytes, output_filename, new_shape=new_shape) # 保存处理后的图像
  51. # 使用示例
  52. if __name__ == "__main__":
  53. folder_path = 'raw_pic' # 替换为你的图片文件夹路径
  54. output_folder = 'raw_pic-bai-640' # 替换为保存处理后图片的文件夹路径
  55. process_images_in_folder(folder_path, output_folder, new_shape=(640, 640)) # 处理文件夹中的图像

看一下原图:

经过图像缩放和填充后,填充灰色颜色,设置图像尺寸为640*640

3、示例2 黑色填充,图像尺寸为640*640

这里填充颜色设置为黑色,即color=(0, 0, 0),,图像尺寸还是640*640

示例代码如下:

  1. import os
  2. import cv2
  3. import numpy as np
  4. # 定义letterbox函数,用于对图像进行缩放和填充,使其适应指定尺寸
  5. def letterbox(img, new_shape=(640, 640), color=(0, 0, 0), auto=False, scale_fill=False, scale_up=False, stride=32):
  6. shape = img.shape[:2] # 获取图像的原始高度和宽度
  7. if isinstance(new_shape, int):
  8. new_shape = (new_shape, new_shape) # 如果new_shape是整数,则将其转换为方形尺寸
  9. # 计算缩放比例r,确保图像不会拉伸变形
  10. r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])
  11. if not scale_up:
  12. r = min(r, 1.0) # 如果scale_up为False,则缩放比例不大于1,避免放大
  13. ratio = r, r # 记录宽高的缩放比例
  14. new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) # 根据比例计算缩放后的尺寸
  15. dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # 计算需要填充的宽度和高度
  16. if auto:
  17. dw, dh = np.mod(dw, stride), np.mod(dh, stride) # 如果auto为True,将填充尺寸调整为步长的倍数
  18. elif scale_fill:
  19. dw, dh = 0.0, 0.0 # 如果scale_fill为True,则不进行填充,直接拉伸到目标尺寸
  20. new_unpad = (new_shape[1], new_shape[0])
  21. ratio = new_shape[1] / shape[1], new_shape[0] / shape[0] # 重新计算缩放比例
  22. dw /= 2 # 左右填充的宽度
  23. dh /= 2 # 上下填充的高度
  24. if shape[::-1] != new_unpad: # 如果原始尺寸和缩放后的尺寸不同,进行图像缩放
  25. img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR) # 线性插值进行图像缩放
  26. top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) # 上下填充像素数
  27. left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) # 左右填充像素数
  28. img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # 使用指定颜色填充
  29. return img, ratio, (dw, dh) # 返回处理后的图像、缩放比例以及填充的宽高
  30. # 保存经过letterbox处理的图像
  31. def save_letterboxed_image(image_bytes, output_filename, new_shape=(640, 640)):
  32. im0 = cv2.imdecode(np.frombuffer(image_bytes, np.uint8), cv2.IMREAD_COLOR) # 从字节数据解码出图像
  33. if im0 is None:
  34. raise ValueError("Failed to decode image from image_bytes") # 如果图像解码失败,抛出异常
  35. img, _, _ = letterbox(im0, new_shape=new_shape) # 对图像进行letterbox处理
  36. # 保存处理后的图像
  37. cv2.imwrite(output_filename, img) # 将处理后的图像写入文件
  38. print(f"Saved letterboxed image to {output_filename}") # 输出保存成功的信息
  39. # 处理文件夹中的所有图像
  40. def process_images_in_folder(folder_path, output_folder, new_shape=(640, 640)):
  41. if not os.path.exists(output_folder):
  42. os.makedirs(output_folder) # 如果输出文件夹不存在,则创建
  43. # 遍历文件夹中的所有图像文件
  44. for filename in os.listdir(folder_path):
  45. if filename.endswith(('.jpg', '.png', '.jpeg')): # 仅处理特定格式的图像文件
  46. image_path = os.path.join(folder_path, filename) # 获取图像的完整路径
  47. with open(image_path, 'rb') as f:
  48. image_bytes = f.read() # 读取图像文件的字节数据
  49. output_filename = os.path.join(output_folder, filename) # 构建输出文件的完整路径
  50. save_letterboxed_image(image_bytes, output_filename, new_shape=new_shape) # 保存处理后的图像
  51. # 使用示例
  52. if __name__ == "__main__":
  53. folder_path = 'raw_pic' # 替换为你的图片文件夹路径
  54. output_folder = 'raw_pic-bai-640' # 替换为保存处理后图片的文件夹路径
  55. process_images_in_folder(folder_path, output_folder, new_shape=(640, 640)) # 处理文件夹中的图像

看一下原图:

经过图像缩放和填充后,填充黑色颜色,设置图像尺寸为640*640

4、示例3 白色填充,图像尺寸为1280*1280

这里填充颜色设置为白色,即color=(2, 0, 0),,图像尺寸还是640*640

示例代码如下:

  1. import os
  2. import cv2
  3. import numpy as np
  4. # 定义letterbox函数,用于对图像进行缩放和填充,使其适应指定尺寸
  5. def letterbox(img, new_shape=(1280, 1280), color=(255, 255, 255), auto=False, scale_fill=False, scale_up=False, stride=32):
  6. shape = img.shape[:2] # 获取图像的原始高度和宽度
  7. if isinstance(new_shape, int):
  8. new_shape = (new_shape, new_shape) # 如果new_shape是整数,则将其转换为方形尺寸
  9. # 计算缩放比例r,确保图像不会拉伸变形
  10. r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])
  11. if not scale_up:
  12. r = min(r, 1.0) # 如果scale_up为False,则缩放比例不大于1,避免放大
  13. ratio = r, r # 记录宽高的缩放比例
  14. new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) # 根据比例计算缩放后的尺寸
  15. dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # 计算需要填充的宽度和高度
  16. if auto:
  17. dw, dh = np.mod(dw, stride), np.mod(dh, stride) # 如果auto为True,将填充尺寸调整为步长的倍数
  18. elif scale_fill:
  19. dw, dh = 0.0, 0.0 # 如果scale_fill为True,则不进行填充,直接拉伸到目标尺寸
  20. new_unpad = (new_shape[1], new_shape[0])
  21. ratio = new_shape[1] / shape[1], new_shape[0] / shape[0] # 重新计算缩放比例
  22. dw /= 2 # 左右填充的宽度
  23. dh /= 2 # 上下填充的高度
  24. if shape[::-1] != new_unpad: # 如果原始尺寸和缩放后的尺寸不同,进行图像缩放
  25. img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR) # 线性插值进行图像缩放
  26. top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) # 上下填充像素数
  27. left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) # 左右填充像素数
  28. img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # 使用指定颜色填充
  29. return img, ratio, (dw, dh) # 返回处理后的图像、缩放比例以及填充的宽高
  30. # 保存经过letterbox处理的图像
  31. def save_letterboxed_image(image_bytes, output_filename, new_shape=(1280, 1280)):
  32. im0 = cv2.imdecode(np.frombuffer(image_bytes, np.uint8), cv2.IMREAD_COLOR) # 从字节数据解码出图像
  33. if im0 is None:
  34. raise ValueError("Failed to decode image from image_bytes") # 如果图像解码失败,抛出异常
  35. img, _, _ = letterbox(im0, new_shape=new_shape) # 对图像进行letterbox处理
  36. # 保存处理后的图像
  37. cv2.imwrite(output_filename, img) # 将处理后的图像写入文件
  38. print(f"Saved letterboxed image to {output_filename}") # 输出保存成功的信息
  39. # 处理文件夹中的所有图像
  40. def process_images_in_folder(folder_path, output_folder, new_shape=(1280, 1280)):
  41. if not os.path.exists(output_folder):
  42. os.makedirs(output_folder) # 如果输出文件夹不存在,则创建
  43. # 遍历文件夹中的所有图像文件
  44. for filename in os.listdir(folder_path):
  45. if filename.endswith(('.jpg', '.png', '.jpeg')): # 仅处理特定格式的图像文件
  46. image_path = os.path.join(folder_path, filename) # 获取图像的完整路径
  47. with open(image_path, 'rb') as f:
  48. image_bytes = f.read() # 读取图像文件的字节数据
  49. output_filename = os.path.join(output_folder, filename) # 构建输出文件的完整路径
  50. save_letterboxed_image(image_bytes, output_filename, new_shape=new_shape) # 保存处理后的图像
  51. # 使用示例
  52. if __name__ == "__main__":
  53. folder_path = 'raw_pic' # 替换为你的图片文件夹路径
  54. output_folder = 'raw_pic-bai-1280' # 替换为保存处理后图片的文件夹路径
  55. process_images_in_folder(folder_path, output_folder, new_shape=(1280, 1280)) # 处理文件夹中的图像

看一下原图:

经过图像缩放和填充后,填充白色颜色,设置图像尺寸为1280*1280

YOLO11系列文章推荐:

一篇文章快速认识YOLO11 | 关键改进点 | 安装使用 | 模型训练和推理-CSDN博客

一篇文章快速认识 YOLO11 | 实例分割 | 模型训练 | 自定义数据集-CSDN博客

一篇文章快速认识 YOLO11 | 目标检测 | 模型训练 | 自定义数据集-CSDN博客

一篇文章快速认识YOLO11 | 旋转目标检测 | 原理分析 | 模型训练 | 模型推理-CSDN博客

YOLO11模型推理 | 目标检测与跟踪 | 实例分割 | 关键点估计 | OBB旋转目标检测-CSDN博客

YOLO11模型训练 | 目标检测与跟踪 | 实例分割 | 关键点姿态估计-CSDN博客

YOLO11 实例分割 | 自动标注 | 预标注 | 标签格式转换 | 手动校正标签-CSDN博客

YOLO11 实例分割 | 导出ONNX模型 | ONNX模型推理-CSDN博客

YOLO11 目标检测 | 导出ONNX模型 | ONNX模型推理-CSDN博客

YOLO11 目标检测 | 自动标注 | 预标注 | 标签格式转换 | 手动校正标签_yolo11 标注平台-CSDN博客

分享完成,欢迎交流学习~

注:本文转载自blog.csdn.net的一颗小树x的文章"https://blog.csdn.net/qq_41204464/article/details/143249851"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top