You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用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.warpPerspective expects a 2D-to-2D transformation matrix, but your R is 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

  1. Camera Intrinsics: We added a camera matrix to simulate how 3D points project to 2D. This ensures the rotation looks natural, not distorted.
  2. Coordinate Alignment: Adjusted the rotation matrices to match OpenCV's image coordinate system, so Pitch rotation behaves as expected (tilting up/down).
  3. Perspective Transformation: Derived the correct 2D transform matrix by combining the 3D rotation with camera projection logic.
  4. 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.getRotationMatrix2D instead—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

火山引擎 最新活动