如何使用OpenCV旋转和平移图像且不丢失屏幕外数据
问题描述
我尝试用OpenCV执行连续图像变换,希望在保持图像原始尺寸的前提下,同时完成旋转和平移操作。目前使用warpAffine函数结合旋转矩阵与平移矩阵实现,但每次变换后图像边角数据会丢失,无法带入下一次变换中。
效果对比
- 原始图像:

- 旋转后图像:

- 错误结果(旋转+平移后边角被裁剪):

- 期望结果(旋转+平移后保留全部边角,尺寸不变):

我想要得到平移后的位置效果,但不裁剪边角。明白是第一次仿射变换丢失了数据,但不清楚如何在保持原始尺寸(以中心为基准)的同时保留这些数据。我是计算机视觉新手,线性代数基础薄弱,现有代码均来自在线教程,恳请易懂的解决方案。
现有代码
import numpy as np import cv2 def rotate_image(image, angle): w, h = (image.shape[1], image.shape[0]) cx, cy = (w//2,h//2) M = cv2.getRotationMatrix2D((cx,cy), -1*angle, 1.0) rotated = cv2.warpAffine(image, M, (w,h)) return rotated def translate_image(image, d_x, d_y): M = np.float32([ [1,0,d_x], [0,1,d_y] ]) return cv2.warpAffine(image, M, (image.shape[1], image.shape[0])) path = "dog.jpg" image = cv2.imread(path) angle = 30.0 d_x = 200 d_y = 300 rotated = rotate_image(image, angle) translated = translate_image(rotated, d_x, d_y)
解决方案
核心思路是不分开执行旋转和平移,而是将两个变换矩阵合并为一个,直接对原始图像做一次仿射变换,避免中间步骤丢失图像数据。同时调整变换矩阵的偏移量,让旋转后的图像中心对齐原始图像中心,再叠加平移量,最终在原始尺寸内保留全部内容。
完整实现代码
import numpy as np import cv2 def rotate_and_translate(image, angle, d_x, d_y): h, w = image.shape[:2] cx, cy = w // 2, h // 2 # 1. 生成基础旋转矩阵(仅旋转,无偏移) rotation_matrix = cv2.getRotationMatrix2D((cx, cy), -angle, 1.0) # 2. 计算旋转后图像的边界,确定补偿偏移量 # 原始图像四个角的坐标 corners = np.array([ [0, 0], [w, 0], [w, h], [0, h] ], dtype=np.float32) # 得到旋转后的角坐标 rotated_corners = cv2.transform(np.array([corners]), rotation_matrix)[0] # 计算旋转后图像的最小/最大边界值 min_x, max_x = np.min(rotated_corners[:, 0]), np.max(rotated_corners[:, 0]) min_y, max_y = np.min(rotated_corners[:, 1]), np.max(rotated_corners[:, 1]) # 计算让旋转后图像中心对齐原始中心的偏移量 offset_x = cx - (min_x + max_x) / 2 offset_y = cy - (min_y + max_y) / 2 # 3. 合并旋转补偿偏移与用户指定的平移量,修改旋转矩阵 rotation_matrix[0, 2] += offset_x + d_x rotation_matrix[1, 2] += offset_y + d_y # 4. 执行仿射变换,空白区域填充白色 transformed = cv2.warpAffine(image, rotation_matrix, (w, h), borderMode=cv2.BORDER_CONSTANT, borderValue=(255,255,255)) return transformed # 测试使用 path = "dog.jpg" image = cv2.imread(path) angle = 30.0 d_x = 200 d_y = 300 result = rotate_and_translate(image, angle, d_x, d_y) # 保存或显示结果 cv2.imwrite("result.jpg", result) cv2.imshow("Result", result) cv2.waitKey(0) cv2.destroyAllWindows()
关键逻辑解释
- 合并变换矩阵:直接将旋转、旋转补偿偏移、用户平移量整合到一个矩阵中,仅执行一次
warpAffine,避免中间步骤的裁剪。 - 旋转补偿偏移:通过计算旋转后图像的边界,算出让旋转内容在原始尺寸内居中的偏移量,确保旋转后的内容不会被裁剪。
- 边界填充:用
borderMode参数指定空白区域的填充颜色(示例为白色),保证原始图像的所有内容都能保留在输出中。
原始代码裁剪原因说明
你之前的代码先执行旋转时,warpAffine使用原始尺寸,旋转后超出尺寸的边角直接被裁剪;再平移时,丢失的边角数据已经无法恢复。而合并矩阵后直接操作原始图像,所有像素都参与变换,就能完整保留图像内容。
内容的提问来源于stack exchange,提问作者harke
相关产品推荐
相关产品推荐

