完整教程:Opencv(十) : 图像镜像旋转
文章目录
思维导图:

引言
在计算机视觉、图像处理及多媒体开发中,图像镜像旋转(又称图像翻转)是最基础且常用的操作之一。它通过改变图像像素的坐标分布,实现水平、垂直或双向的翻转效果,广泛应用于照片后期处理、视频剪辑、目标检测数据增强、游戏场景渲染等领域。
一、图像镜像旋转的核心原理
1.1 定义与本质
图像镜像旋转是指将图像围绕特定坐标轴(或同时围绕两个坐标轴)进行对称翻转,使得图像的像素点按照对称规则重新排列。其本质是像素坐标的线性变换——通过修改每个像素在图像坐标系中的位置,生成翻转后的新图像。
在数字图像中,我们通常采用“左上角为原点(0,0),x轴水平向右,y轴垂直向下”的坐标系(与OpenCV默认坐标系一致)。图像的宽度为width(x轴范围:0width-1),高度为`height`(y轴范围:0height-1),每个像素的位置用坐标(x, y)表示(x为列索引,y为行索引)。
1.2 三种翻转类型的数学原理
图像镜像旋转主要分为三种类型,每种类型对应不同的坐标变换规则,具体如下:
(1)垂直翻转(flipCode = 0)
垂直翻转又称“上下翻转”,是围绕图像的水平中轴线(x轴方向) 进行对称翻转。
- 变换规则:原始像素
(x, y)翻转后变为(x, height - y - 1)。 - 通俗理解:图像的上半部分与下半部分交换位置,比如顶部的像素会移动到对应的底部位置,底部像素则移动到顶部。
例:假设图像高度height = 5(y轴范围0~4),原始像素(2, 0)(顶部第0行)翻转后变为(2, 4)(底部第4行);原始像素(3, 2)(中间行)翻转后位置不变。
(2)水平翻转(flipCode > 0)
水平翻转又称“左右翻转”,是围绕图像的垂直中轴线(y轴方向) 进行对称翻转。
- 变换规则:原始像素
(x, y)翻转后变为(width - x - 1, y)。 - 通俗理解:图像的左半部分与右半部分交换位置,比如左侧的像素会移动到对应的右侧位置,右侧像素则移动到左侧。
例:假设图像宽度width = 6(x轴范围0~5),原始像素(0, 3)(左侧第0列)翻转后变为(5, 3)(右侧第5列);原始像素(2, 1)翻转后变为(3, 1)。
(3)水平垂直翻转(flipCode < 0)
水平垂直翻转是水平翻转与垂直翻转的结合,相当于先进行水平翻转,再进行垂直翻转(或反之,顺序不影响结果)。
- 变换规则:原始像素
(x, y)翻转后变为(width - x - 1, height - y - 1)。 - 通俗理解:图像既左右翻转,又上下翻转,最终效果相当于围绕图像中心旋转180°。
例:图像width=6、height=5,原始像素(0, 0)翻转后变为(5, 4);原始像素(2, 3)翻转后变为(3, 1)。
1.3 数学公式总结
三种翻转类型的像素变换公式可统一表示为:
其中:
src:原始图像(source image);dst:翻转后的目标图像(destination image);i:目标图像的行索引(对应y轴坐标);j:目标图像的列索引(对应x轴坐标);height:原始图像的高度;width:原始图像的宽度。
二、OpenCV cv2.flip()函数详解
OpenCV提供的cv2.flip()函数是实现图像镜像旋转的核心工具,支持所有三种翻转类型,具有运行高效、使用简洁的特点。
2.1 函数原型
cv2.flip(src, flipCode[, dst]) -> dst
2.2 参数说明
| 参数名 | 类型 | 说明 |
|---|---|---|
src | numpy.ndarray | 输入图像(原始图像),可以是单通道(灰度图)、三通道(RGB/BGR图)或四通道(带透明通道图)。 |
flipCode | int | 翻转类型标志位,取值规则: - flipCode = 0:垂直翻转(上下翻转);- flipCode > 0:水平翻转(左右翻转)(常用1);- flipCode < 0:水平垂直翻转(常用-1)。 |
dst | numpy.ndarray | 可选参数,输出图像(翻转后的图像)。若不指定,函数会自动创建与src尺寸、数据类型相同的数组。 |
2.3 返回值
dst:翻转后的目标图像,数据类型、通道数与输入图像src一致,尺寸与src完全相同(翻转操作不改变图像的宽高)。
2.4 函数特点
- 支持任意尺寸、任意通道数的图像;
- 原地操作(in-place):若指定
dst参数,函数会直接将结果写入dst,避免额外内存分配; - 计算高效:底层由C++实现,即使处理大尺寸图像(如4K图片)也能快速完成;
- 兼容性强:支持OpenCV支持的所有图像数据类型(如
uint8、float32等)。
三、实战案例:三种翻转类型的代码实现
下面通过完整的Python代码,演示三种翻转类型的具体实现,包括图像读取、翻转操作、结果显示与保存。
3.1 环境准备
首先确保已安装OpenCV库,若未安装,可通过以下命令安装:
pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple
3.2 通用代码框架
所有翻转案例的核心流程的一致:
- 读取图像(使用
cv2.imread()); - 调用
cv2.flip()实现翻转; - 显示原始图像与翻转后的图像(使用
cv2.imshow()); - 等待用户按键(使用
cv2.waitKey()); - 释放窗口资源(使用
cv2.destroyAllWindows()); - (可选)保存翻转后的图像(使用
cv2.imwrite())。
3.3 案例1:垂直翻转(flipCode = 0)
代码实现
import cv2
import os
if __name__ == "__main__":
# 1. 定义图像路径(请根据实际情况修改)
img_path = "./lena.png"
save_path = "./lena_vertical_flip.png"
# 2. 读取图像
# cv2.imread()返回numpy.ndarray,默认以BGR格式读取
src_img = cv2.imread(img_path)
# 3. 检查图像是否读取成功
if src_img is None:
print(f"错误:无法读取图像,请检查路径 '{img_path}' 是否正确!")
# 若路径错误,尝试查找当前目录下的图片文件
current_files = [f for f in os.listdir(".") if f.endswith((".png", ".jpg", ".jpeg"))]
if current_files:
print(f"当前目录下可用的图片文件:{current_files}")
exit()
# 4. 垂直翻转(flipCode = 0)
vertical_flip_img = cv2.flip(src_img, flipCode=0)
# 5. 显示图像
# 创建两个窗口,分别显示原始图像和翻转后的图像
cv2.namedWindow("Original Image", cv2.WINDOW_NORMAL) # 可调整窗口大小
cv2.namedWindow("Vertical Flip Image", cv2.WINDOW_NORMAL)
cv2.imshow("Original Image", src_img)
cv2.imshow("Vertical Flip Image", vertical_flip_img)
# 6. 等待用户按键(0表示无限等待,按任意键关闭窗口)
key = cv2.waitKey(0)
if key == ord("s"):
# 按"s"键保存翻转后的图像
cv2.imwrite(save_path, vertical_flip_img)
print(f"垂直翻转后的图像已保存至:{save_path}")
# 7. 释放窗口资源(必须调用,否则会占用内存)
cv2.destroyAllWindows()
效果说明


3.4 案例2:水平翻转(flipCode = 1)
代码实现
import cv2
import os
if __name__ == "__main__":
# 1. 定义图像路径
img_path = "./lena.png"
save_path = "./lena_horizontal_flip.png"
# 2. 读取图像(支持灰度图读取,添加0参数)
src_img = cv2.imread(img_path, 0) # 0表示以灰度图格式读取
# 3. 检查图像读取状态
if src_img is None:
print(f"错误:无法读取图像,请检查路径 '{img_path}' 是否正确!")
exit()
# 4. 水平翻转(flipCode = 1,大于0即可,常用1)
horizontal_flip_img = cv2.flip(src_img, flipCode=1)
# 5. 显示图像
cv2.namedWindow("Original Gray Image", cv2.WINDOW_NORMAL)
cv2.namedWindow("Horizontal Flip Image", cv2.WINDOW_NORMAL)
cv2.imshow("Original Gray Image", src_img)
cv2.imshow("Horizontal Flip Image", horizontal_flip_img)
# 6. 保存与退出
key = cv2.waitKey(0)
if key == ord("s"):
cv2.imwrite(save_path, horizontal_flip_img)
print(f"水平翻转后的灰度图像已保存至:{save_path}")
cv2.destroyAllWindows()
效果说明


- 原始图像为灰度图,水平翻转后,图像左右部分对称交换,比如人物的左眼会翻转到右侧,右眼会翻转到左侧;
- 灰度图的翻转操作与彩色图完全一致,
cv2.flip()会自动处理单通道数据。
3.5 案例3:水平垂直翻转(flipCode = -1)
代码实现
import cv2
import os
if __name__ == "__main__":
# 1. 定义图像路径
img_path = "./lena.png"
save_path = "./lena_both_flip.png"
# 2. 读取彩色图像
src_img = cv2.imread(img_path)
if src_img is None:
print(f"错误:无法读取图像,请检查路径 '{img_path}' 是否正确!")
exit()
# 3. 水平垂直翻转(flipCode = -1,小于0即可,常用-1)
both_flip_img = cv2.flip(src_img, flipCode=-1)
# 4. 显示对比(创建拼接图,方便直观对比)
# 拼接原始图像和翻转图像(水平拼接)
compare_img = cv2.hconcat([src_img, both_flip_img])
cv2.namedWindow("Original vs Both Flip", cv2.WINDOW_NORMAL)
cv2.imshow("Original vs Both Flip", compare_img)
# 5. 保存与退出
key = cv2.waitKey(0)
if key == ord("s"):
cv2.imwrite(save_path, both_flip_img)
cv2.imwrite("./lena_compare.png", compare_img)
print(f"水平垂直翻转后的图像已保存至:{save_path}")
print(f"对比图已保存至:./lena_compare.png")
cv2.destroyAllWindows()
效果说明

- 水平垂直翻转后的图像同时实现了左右和上下翻转,效果相当于将原始图像旋转180°;
- 代码中使用
cv2.hconcat()将原始图像和翻转图像水平拼接,方便直观对比效果(类似的还有cv2.vconcat()垂直拼接)。
3.6 案例4:批量处理文件夹中的所有图像
在实际开发中,经常需要对文件夹中的所有图像进行批量翻转。以下代码实现批量读取指定文件夹的图片,执行水平翻转后,保存到新文件夹中。
import cv2
import os
import glob
if __name__ == "__main__":
# 1. 配置路径
input_dir = "./input_images/" # 输入文件夹(存放原始图像)
output_dir = "./output_images/" # 输出文件夹(存放翻转后的图像)
flip_type = 1 # 翻转类型:1=水平翻转,0=垂直翻转,-1=水平垂直翻转
# 2. 创建输出文件夹(若不存在)
if not os.path.exists(output_dir):
os.makedirs(output_dir)
print(f"创建输出文件夹:{output_dir}")
# 3. 获取文件夹中所有图片文件(支持png、jpg、jpeg格式)
img_paths = glob.glob(os.path.join(input_dir, "*.[pP][nN][gG]")) + \
glob.glob(os.path.join(input_dir, "*.[jJ][pP][gG]")) + \
glob.glob(os.path.join(input_dir, "*.[jJ][pP][eE][gG]"))
if not img_paths:
print(f"错误:在输入文件夹 '{input_dir}' 中未找到图片文件!")
exit()
# 4. 批量翻转并保存
total = len(img_paths)
for i, img_path in enumerate(img_paths):
# 读取图像
src_img = cv2.imread(img_path)
if src_img is None:
print(f"警告:跳过无法读取的文件:{img_path}")
continue
# 执行翻转
flip_img = cv2.flip(src_img, flipCode=flip_type)
# 获取文件名(保持原文件名,添加后缀标识)
filename = os.path.basename(img_path)
name, ext = os.path.splitext(filename)
if flip_type == 0:
save_filename = f"{name}_vertical_flip{ext}"
elif flip_type == 1:
save_filename = f"{name}_horizontal_flip{ext}"
else:
save_filename = f"{name}_both_flip{ext}"
# 保存图像
save_path = os.path.join(output_dir, save_filename)
cv2.imwrite(save_path, flip_img)
# 打印进度
print(f"进度:{i+1}/{total} | 处理完成:{filename} -> 保存为:{save_filename}")
print(f"\n批量处理完成!所有翻转后的图像已保存至:{output_dir}")
代码特点
- 支持多种图片格式(png、jpg、jpeg),不区分大小写;
- 自动创建输出文件夹,避免路径错误;
- 对无法读取的文件进行跳过处理,提高鲁棒性;
- 保存的文件名添加翻转类型后缀,便于区分。
四、进阶应用:结合其他图像处理操作
图像镜像旋转常与缩放、裁剪、滤波等操作结合使用,实现更复杂的图像处理需求。以下是两个典型的进阶案例。
4.1 案例:翻转 + 缩放 + 边缘检测
import cv2
import numpy as np
if __name__ == "__main__":
img_path = "./lena.png"
src_img = cv2.imread(img_path)
if src_img is None:
print("无法读取图像!")
exit()
# 1. 水平翻转
flip_img = cv2.flip(src_img, 1)
# 2. 缩放(缩小到原来的0.8倍)
scale = 0.8
h, w = flip_img.shape[:2]
resized_img = cv2.resize(flip_img, (int(w*scale), int(h*scale)), interpolation=cv2.INTER_LINEAR)
# 3. 灰度化
gray_img = cv2.cvtColor(resized_img, cv2.COLOR_BGR2GRAY)
# 4. 边缘检测(Canny算子)
edge_img = cv2.Canny(gray_img, threshold1=100, threshold2=200)
# 5. 显示结果
cv2.namedWindow("Flip + Resize + Edge Detection", cv2.WINDOW_NORMAL)
cv2.imshow("Flip + Resize + Edge Detection", edge_img)
cv2.waitKey(0)
cv2.imwrite("./lena_edge_flip.png", edge_img)
cv2.destroyAllWindows()
4.2 案例:翻转 + 图像拼接(制作对称全景图)
import cv2
import numpy as np
if __name__ == "__main__":
img_path = "./mountain.jpg"
src_img = cv2.imread(img_path)
if src_img is None:
print("无法读取图像!")
exit()
# 1. 水平翻转
flip_img = cv2.flip(src_img, 1)
# 2. 拼接原始图像和翻转图像,制作对称全景图
panorama_img = cv2.hconcat([src_img, flip_img])
# 3. 优化:添加中间过渡带(避免拼接痕迹)
h, w = src_img.shape[:2]
transition_width = 50 # 过渡带宽度(像素)
# 创建过渡掩码
mask = np.ones((h, w), dtype=np.float32)
mask[:, w-transition_width:] = np.linspace(1, 0, transition_width)
# 应用过渡掩码
left_part = src_img.astype(np.float32)
right_part = flip_img.astype(np.float32)
left_part[:, w-transition_width:] *= mask[:, w-transition_width:][:, :, np.newaxis]
right_part[:, :transition_width] *= (1 - mask[:, :transition_width])[:, :, np.newaxis]
# 拼接优化后的图像
optimized_panorama = left_part + right_part
optimized_panorama = np.clip(optimized_panorama, 0, 255).astype(np.uint8)
# 4. 显示对比
cv2.namedWindow("Original Panorama", cv2.WINDOW_NORMAL)
cv2.namedWindow("Optimized Panorama", cv2.WINDOW_NORMAL)
cv2.imshow("Original Panorama", panorama_img)
cv2.imshow("Optimized Panorama", optimized_panorama)
cv2.waitKey(0)
cv2.imwrite("./panorama_original.png", panorama_img)
cv2.imwrite("./panorama_optimized.png", optimized_panorama)
cv2.destroyAllWindows()
五、常见问题与解决方案
在使用cv2.flip()进行图像镜像旋转时,初学者常遇到图像读取失败、窗口无法关闭、翻转方向错误等问题。以下是详细的问题分析与解决方案。
5.1 问题1:图像读取失败(src_img is None)
原因:
- 图像路径错误(绝对路径/相对路径混淆);
- 图像文件损坏或格式不支持;
- 文件名包含中文或特殊字符;
- 未安装OpenCV或版本不兼容。
解决方案:
检查路径:
- 相对路径:确保图像文件与代码在同一目录,或使用
./folder/img.png格式; - 绝对路径:在Windows系统中使用双反斜杠(
C:\\Users\\xxx\\lena.png),在Linux/Mac系统中使用斜杠(/home/xxx/lena.png); - 推荐使用
os.path.abspath()获取绝对路径,避免路径错误:import os img_path = os.path.abspath("./lena.png") print(f"图像绝对路径:{img_path}") src_img = cv2.imread(img_path)
- 相对路径:确保图像文件与代码在同一目录,或使用
检查文件:
- 确保图像文件后缀正确(如
png、jpg),且未被修改后缀(如将jpg改为png); - 尝试用图片查看器打开文件,确认文件未损坏。
- 确保图像文件后缀正确(如
处理中文路径:
- 若路径包含中文,OpenCV默认不支持,可通过
numpy读取文件后转换为OpenCV格式:import cv2 import numpy as np from PIL import Image import os img_path = "./测试图片.png" # 用PIL读取中文路径图像 pil_img = Image.open(img_path) # 转换为OpenCV格式(BGR) src_img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)
- 若路径包含中文,OpenCV默认不支持,可通过
5.2 问题2:窗口无法关闭或闪退
原因:
- 未调用
cv2.waitKey():OpenCV的窗口需要等待用户按键才能保持显示,否则会立即闪退; - 未调用
cv2.destroyAllWindows():按键后窗口不会自动关闭,需要手动释放资源; cv2.waitKey()的参数设置错误(如设置为0表示无限等待,设置为1000表示等待1秒后自动关闭)。
解决方案:
# 正确的窗口显示流程
cv2.imshow("Window Name", img)
cv2.waitKey(0) # 无限等待用户按键(按任意键关闭)
cv2.destroyAllWindows() # 释放所有窗口资源
5.3 问题3:翻转方向与预期不符
原因:
对flipCode参数的含义理解错误,或混淆了图像坐标系的方向(OpenCV默认左上角为原点)。
解决方案:
- 牢记
flipCode的取值规则:- 想实现“上下翻转”→
flipCode=0; - 想实现“左右翻转”→
flipCode=1; - 想实现“180°翻转”→
flipCode=-1;
- 想实现“上下翻转”→
- 若仍有疑问,可通过小尺寸图像(如200x200的简单图形)测试,直观观察翻转效果。
5.4 问题4:保存的图像颜色失真(如RGB转BGR)
原因:
OpenCV读取图像时默认以BGR格式存储,而Python的PIL库、Matplotlib等工具默认以RGB格式显示/保存,直接混合使用会导致颜色失真。
解决方案:
- 若用
cv2.imwrite()保存图像:直接保存即可,cv2.imwrite()会自动处理BGR格式; - 若用Matplotlib显示图像:需要将BGR转换为RGB:
import cv2 import matplotlib.pyplot as plt src_img = cv2.imread("./lena.png") # BGR转RGB rgb_img = cv2.cvtColor(src_img, cv2.COLOR_BGR2RGB) plt.imshow(rgb_img) plt.show()
六、总结与拓展
6.1 核心知识点回顾
- 图像镜像旋转的本质是像素坐标的线性变换,分为垂直翻转(flipCode=0)、水平翻转(flipCode>0)、水平垂直翻转(flipCode<0)三种类型;
- OpenCV的
cv2.flip()函数是实现翻转的核心工具,支持任意尺寸、任意通道数的图像,高效简洁; - 实际开发中需注意图像路径、窗口显示、颜色格式等问题,避免常见错误;
- 图像翻转常与缩放、裁剪、滤波等操作结合,应用于数据增强、后期处理、游戏开发等多个领域。
6.2 拓展学习建议
- 图像旋转:除了镜像翻转,OpenCV还提供
cv2.rotate()函数实现90°、180°、270°的旋转,以及cv2.warpAffine()实现任意角度的旋转,可进一步学习; - 仿射变换:镜像翻转是仿射变换的特殊情况,学习
cv2.getAffineTransform()函数,掌握更灵活的图像变换(如平移、旋转、缩放、剪切); - 深度学习中的数据增强:结合
albumentations、torchvision.transforms等库,实现翻转、旋转、裁剪、缩放等多种数据增强操作的组合; - 实时视频翻转:使用
cv2.VideoCapture()读取摄像头视频流,实时对每一帧进行翻转,实现视频镜像功能。
浙公网安备 33010602011771号