OpenCV 图像缩放实验报告
一、实验目的
- 完成 OpenCV 在本地(WSL2 + VSCode)的部署。
- 利用 OpenCV 对手机拍摄图像进行尺寸变换,掌握
cv2.resize的基本用法。 - 分析直接缩放导致的几何失真问题,实现等比缩放 + 黑边填充(letterbox)方案,使图像在指定画布中无失真居中显示。
二、实验环境
| 项目 | 配置 |
|---|---|
| 操作系统 | Windows 11 + WSL2 (Ubuntu 22.04) |
| Python | 3.11 (conda 虚拟环境 cv_env) |
| OpenCV | 4.10.0 (opencv-python + opencv-contrib-python) |
| 编辑器 | VS Code + WSL Remote 扩展 |
| 其他依赖 | NumPy ≥ 1.26 |
部署命令摘要:
bash
conda create -n cv_env python=3.11 -y
conda activate cv_env
pip install opencv-python opencv-contrib-python numpy
三、原理分析
3.1 直接缩放(任务 2)
直接调用 cv2.resize(img, (W_dst, H_dst)) 会独立对水平和垂直方向做线性映射:
x′=x⋅WdstWsrc,y′=y⋅HdstHsrc x' = x \cdot \frac{W_{dst}}{W_{src}}, \quad y' = y \cdot \frac{H_{dst}}{H_{src}} x′=x⋅WsrcWdst,y′=y⋅HsrcHdst
当 WdstWsrc≠HdstHsrc\frac{W_{dst}}{W_{src}} \neq \frac{H_{dst}}{H_{src}}WsrcWdst=HsrcHdst 时,两方向缩放比不同,图像几何形状被改变 ------ 圆变椭圆,正方形变矩形。手机照片常见长宽比为 4:3 或 16:9,直接缩放到 1:1 必然发生这种失真。
3.2 等比缩放 + 黑边填充(任务 3,Letterbox)
为保持原图几何比例不变,水平和垂直方向必须使用同一缩放比:
s=min(WdstWsrc, HdstHsrc) s = \min\left(\frac{W_{dst}}{W_{src}},\ \frac{H_{dst}}{H_{src}}\right) s=min(WsrcWdst, HsrcHdst)
取较小者,保证缩放后图像两个方向都不超过目标画布。缩放后图像尺寸为:
Wnew=⌊Wsrc⋅s⌉,Hnew=⌊Hsrc⋅s⌉ W_{new} = \lfloor W_{src} \cdot s \rceil, \quad H_{new} = \lfloor H_{src} \cdot s \rceil Wnew=⌊Wsrc⋅s⌉,Hnew=⌊Hsrc⋅s⌉
然后在 Wdst×HdstW_{dst} \times H_{dst}Wdst×Hdst 的黑色画布上居中粘贴,左上角偏移:
top=⌊Hdst−Hnew2⌋,left=⌊Wdst−Wnew2⌋ \text{top} = \left\lfloor \frac{H_{dst} - H_{new}}{2} \right\rfloor, \quad \text{left} = \left\lfloor \frac{W_{dst} - W_{new}}{2} \right\rfloor top=⌊2Hdst−Hnew⌋,left=⌊2Wdst−Wnew⌋
这种方法在深度学习目标检测(YOLO、SSD 等)中是标准的输入预处理方式,因为变形会显著影响检测精度。
3.3 插值方法选择
OpenCV resize 的 interpolation 参数对结果有影响:
| 缩放方向 | 推荐方法 | 原因 |
|---|---|---|
| 缩小 (scale < 1) | cv2.INTER_AREA |
基于像素区域加权平均,抗锯齿、保留细节 |
| 放大 (scale > 1) | cv2.INTER_CUBIC 或 INTER_LINEAR |
三次插值更平滑,线性更快 |
本实验中两个函数都根据缩放方向自动选择插值方法。
四、核心代码
完整代码见附件 opencv_homework.py,关键函数如下。
4.1 直接缩放
python
def resize_direct(img: np.ndarray, target_size: int = 1024) -> np.ndarray:
h, w = img.shape[:2]
interp = cv2.INTER_AREA if target_size < max(h, w) else cv2.INTER_CUBIC
return cv2.resize(img, (target_size, target_size), interpolation=interp)
4.2 Letterbox 等比缩放
python
def resize_letterbox(img, target_size=1024, pad_color=(0, 0, 0)):
h, w = img.shape[:2]
# 1) 计算等比缩放比
scale = min(target_size / h, target_size / w)
new_w, new_h = int(round(w * scale)), int(round(h * scale))
# 2) 缩放
interp = cv2.INTER_AREA if scale < 1 else cv2.INTER_CUBIC
resized = cv2.resize(img, (new_w, new_h), interpolation=interp)
# 3) 居中粘贴到目标画布
canvas = np.full((target_size, target_size, 3), pad_color, dtype=np.uint8)
top = (target_size - new_h) // 2
left = (target_size - new_w) // 2
canvas[top:top + new_h, left:left + new_w] = resized
return canvas
五、实验结果
5.1 输入
测试图像为模拟手机照片,尺寸 4032 × 3024 ,长宽比 4:3 ≈ 1.333,含网格线、同心圆、四角彩色方块用于直观判断变形情况。
5.2 输出三联对比

(左:原图缩略;中:直接缩放;右:letterbox 等比缩放)
5.3 定量与定性分析
| 指标 | 直接缩放 | Letterbox 等比缩放 |
|---|---|---|
| 输出尺寸 | 1024 × 1024 ✅ | 1024 × 1024 ✅ |
| 横向缩放比 | 1024/4032 ≈ 0.254 | 1024/4032 ≈ 0.254 |
| 纵向缩放比 | 1024/3024 ≈ 0.339 | 1024/4032 ≈ 0.254 |
| 圆是否仍为圆 | ❌ 变成椭圆(垂直拉伸 ≈ 33%) | ✅ 保持圆形 |
| 正方形是否仍为正方形 | ❌ 变成矩形 | ✅ 保持正方形 |
| 文字是否变形 | ❌ 字符竖向变胖 | ✅ 不变形 |
| 有效图像占比 | 100%(但形变) | 1024×768 / 1024² ≈ 75% |
| 填充区域 | 无 | 上下各 128 像素黑边 |
直接缩放横纵比相差 33.3%,对应中心圆的垂直直径被拉长约 1/3,肉眼极易察觉。Letterbox 方案以损失 25% 画布面积(变为黑色填充)为代价,换得完整保留原图几何信息。
5.4 控制台输出
[输入] sample_photo.jpg 尺寸: 4032 x 3024 长宽比: 1.3333
[任务2] 直接缩放 -> output/02_direct_1024x1024.jpg 尺寸: 1024x1024 (已变形)
[任务3] 等比缩放 -> output/03_letterbox_1024x1024.jpg 尺寸: 1024x1024 (无变形)
[对比图] -> output/04_compare.jpg
六、讨论与扩展
- 填充颜色的选择 :本实验用纯黑
(0,0,0)。若用于神经网络输入,常用(114,114,114)灰色(YOLOv5 默认),原因是灰色更接近自然图像的均值,引入的偏差小。 - 舍入误差 :
int(round(w*scale))可能让new_w比目标少 1 像素,导致左右黑边不完全对称。生产环境可对最右/最下一行单独 pad 一像素。 - 逆变换 :若后续要把检测框坐标映射回原图,需要保留
scale, top, left三个参数,按x_orig = (x_pad - left) / scale反推。这是检测/分割任务后处理的常见步骤。 - 替代方案 :除了黑边填充,还可以用 center crop (中心裁剪)或 reflect padding(镜像填充),各有适用场景;本实验按作业要求使用黑边填充。
七、结论
- 成功在 WSL2 + VSCode 环境部署了 OpenCV 4.10。
- 验证了
cv2.resize直接缩放在长宽比不匹配时会引入几何失真。 - 通过 letterbox 算法(等比缩放 + 中心粘贴 + 黑边填充)实现了无失真的 1024×1024 输出,代码可作为后续 CV 项目的通用预处理工具。
附录:完整运行方式
bash
# 激活环境
conda activate cv_env
# 运行(输入你的手机照片路径)
python opencv_homework.py /path/to/your_photo.jpg -o ./output
# 默认输出目录 ./output/ 下包含:
# 02_direct_1024x1024.jpg - 任务 2 结果
# 03_letterbox_1024x1024.jpg - 任务 3 结果
# 04_compare.jpg - 三联对比图
可选参数:
--size 512:改为缩放到其他边长-o ./out:指定输出目录