使用Python-OpenCV按Roll、Pitch、Yaw旋转图像出错求助
Fixing Incorrect Pitch Rotation for Images
Let's break down why your current code isn't working and walk through the correct approach to rotate an image by a Pitch angle.
What's Wrong With Your Current Code?
The core issue is that you're using a 3D rotation matrix directly with cv2.warpPerspective, which is designed for 2D perspective transformations. Here's the breakdown:
cv2.warpPerspectiveexpects a 2D-to-2D transformation matrix, but yourRis a 3D space rotation matrix. There's no consideration for how 3D points project back to a 2D image plane.- You didn't account for camera intrinsic parameters (like focal length and image center), which are critical for realistic 3D-to-2D projection.
- The coordinate systems for 3D Euler rotations and OpenCV's image space don't align, leading to unexpected rotation directions or skewing.
Correct Solution: Simulate 3D Camera Rotation & Projection
To properly apply Pitch (or Yaw/Roll) rotations, we need to model the image as a camera frame, rotate that frame in 3D space, then project the result back to a 2D image. Here's the working code:
import numpy as np import math import cv2 def get_perspective_rotation_matrix(pitch, yaw, roll, img_width, img_height): # Step 1: Define camera intrinsic parameters (pinhole camera model) # Focal length set to image width (adjust based on desired perspective strength) focal_length = img_width center_x, center_y = img_width / 2, img_height / 2 camera_matrix = np.array([ [focal_length, 0, center_x], [0, focal_length, center_y], [0, 0, 1] ], dtype=np.float32) # Step 2: Convert Euler angles to 3D rotation matrix (match OpenCV's coordinate system) # OpenCV image space: X=right, Y=down, Z=forward (towards the viewer) pitch_rad = math.radians(pitch) yaw_rad = math.radians(yaw) roll_rad = math.radians(roll) # Rotation matrices for each axis (Roll → Pitch → Yaw order) R_roll = np.array([[1, 0, 0], [0, math.cos(roll_rad), -math.sin(roll_rad)], [0, math.sin(roll_rad), math.cos(roll_rad)]]) R_pitch = np.array([[math.cos(pitch_rad), 0, math.sin(pitch_rad)], [0, 1, 0], [-math.sin(pitch_rad), 0, math.cos(pitch_rad)]]) R_yaw = np.array([[math.cos(yaw_rad), -math.sin(yaw_rad), 0], [math.sin(yaw_rad), math.cos(yaw_rad), 0], [0, 0, 1]]) # Combine rotation matrices R_total = np.dot(R_yaw, np.dot(R_pitch, R_roll)) # Step 3: Compute the 2D perspective transformation matrix # This maps the rotated 3D frame back to the original image plane inv_camera_matrix = np.linalg.inv(camera_matrix) transform_matrix = np.dot(camera_matrix, np.dot(R_total, inv_camera_matrix)) return transform_matrix # Load your image image = cv2.imread('yaw.png') img_height, img_width = image.shape[:2] # Generate transformation matrix for 30-degree Pitch rotation rotation_matrix = get_perspective_rotation_matrix(pitch=30, yaw=0, roll=0, img_width=img_width, img_height=img_height) # Apply transformation with expanded output size to avoid cropping output_width = int(img_width * 1.5) output_height = int(img_height * 1.5) rotated_image = cv2.warpPerspective(image, rotation_matrix, (output_width, output_height)) # Display result cv2.imshow('Pitch-Rotated Image', rotated_image) cv2.waitKey(0) cv2.destroyAllWindows()
Key Fixes Explained
- Camera Intrinsics: We added a camera matrix to simulate how 3D points project to 2D. This ensures the rotation looks natural, not distorted.
- Coordinate Alignment: Adjusted the rotation matrices to match OpenCV's image coordinate system, so Pitch rotation behaves as expected (tilting up/down).
- Perspective Transformation: Derived the correct 2D transform matrix by combining the 3D rotation with camera projection logic.
- Output Size: Expanded the output dimensions to prevent cropping parts of the rotated image.
Extra Tips
- If you just need a flat 2D rotation (like Roll), use
cv2.getRotationMatrix2Dinstead—it's simpler and faster. - Euler angles can suffer from gimbal lock. For more stable rotations, consider converting quaternions to rotation matrices instead.
内容的提问来源于stack exchange,提问作者alec.tu




