import numpy as np import cv2 import plotly.graph_objects as go from math import cos, sin from scipy.spatial.transform import Rotation as R def plot_3D_rotation(rotation_matrix): fig = go.Figure() # Original axis orientation axes_points = np.array([ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0] ], dtype=np.float64) # Plot original axes fig.add_trace(go.Scatter3d( x=[0, axes_points[0, 0]], y=[0, axes_points[1, 0]], z=[0, axes_points[2, 0]], mode='lines+text', line=dict(color='blue', width=6), name='Canonical X-axis', text=['', 'X axis'], textposition='middle center', )) fig.add_trace(go.Scatter3d( x=[0, axes_points[0, 1]], y=[0, axes_points[1, 1]], z=[0, axes_points[2, 1]], mode='lines+text', line=dict(color='blue', width=6), name='Canonical Z-axis', text=['', 'Z axis'], textposition='middle center', )) fig.add_trace(go.Scatter3d( x=[0, axes_points[0, 2]], y=[0, axes_points[1, 2]], z=[0, axes_points[2, 2]], mode='lines+text', line=dict(color='blue', width=6), name='Canonical Y-axis', text=['', 'Y axis'], textposition='middle center', )) # Apply rotation axes_points = rotation_matrix @ axes_points # Plot rotated axes fig.add_trace(go.Scatter3d( x=[0, axes_points[0, 0]], y=[0, axes_points[1, 0]], z=[0, axes_points[2, 0]], mode='lines+text', line=dict(color='red', width=6), name='Rotated X\'-axis', text=['', 'Rotated X axis'], textposition='middle center', )) fig.add_trace(go.Scatter3d( x=[0, axes_points[0, 1]], y=[0, axes_points[1, 1]], z=[0, axes_points[2, 1]], mode='lines+text', line=dict(color='red', width=6), name='Rotated Z\'-axis', text=['', 'Rotated Z axis'], textposition='middle center', )) fig.add_trace(go.Scatter3d( x=[0, axes_points[0, 2]], y=[0, axes_points[1, 2]], z=[0, axes_points[2, 2]], mode='lines+text', line=dict(color='red', width=6), name='Rotated Y\'-axis', text=['', 'Rotated Y axis'], textposition='middle center', )) # Retrieve pitch, yaw, roll from rotation matrix r = R.from_matrix(rotation_matrix) pitch, yaw, roll = r.as_euler('xzy', degrees=True) # Set layout fig.update_layout( scene=dict( xaxis=dict(title='X-axis', range=[-1.2, 1.2]), yaxis=dict(title='Z-axis', range=[-1.2, 1.2]), zaxis=dict(title='Y-axis', range=[-1.2, 1.2]), xaxis_tickvals=np.arange(-1.2, 1.2, 0.6), yaxis_tickvals=np.arange(-1.2, 1.2, 0.5), zaxis_tickvals=np.arange(-1.2, 1.2, 0.5), aspectmode='cube', aspectratio=dict(x=1, y=1, z=1), ), margin=dict(l=0, r=0, t=0, b=30), ) # add annotation fig.add_annotation(dict(font=dict(color='black',size=15), x=-30, y=50, showarrow=False, text=f"Pitch: {int(pitch)} - Yaw: {int(yaw)} - Roll: {int(roll)}", textangle=0, xanchor='left', xref="paper", yref="paper")) return fig def draw_2D_axes(img, roll, pitch, yaw, tdx=None, tdy=None, size=150.): # Input is a cv2 image # pose_params: (pitch, yaw, roll, tdx, tdy) # Where (tdx, tdy) is the translation of the face. # For pose we have [pitch yaw roll tdx tdy tdz scale_factor] p = pitch * np.pi / 180 y = (yaw * np.pi / 180) r = -roll * np.pi / 180 if tdx != None and tdy != None: face_x = tdx - 0.50 * size face_y = tdy - 0.50 * size else: height, width = img.shape[:2] face_x = width / 2 - 0.5 * size face_y = height / 2 - 0.5 * size x1 = size * (cos(y) * cos(r)) + face_x y1 = size * (cos(p) * sin(r) + cos(r) * sin(p) * sin(y)) + face_y x2 = size * (-cos(y) * sin(r)) + face_x y2 = size * (cos(p) * cos(r) - sin(p) * sin(y) * sin(r)) + face_y x3 = size * (sin(y)) + face_x y3 = size * (-cos(y) * sin(p)) + face_y # Draw base in red cv2.line(img, (int(face_x), int(face_y)), (int(x1),int(y1)),(0,0,255),3) cv2.line(img, (int(face_x), int(face_y)), (int(x2),int(y2)),(0,0,255),3) cv2.line(img, (int(x2), int(y2)), (int(x2+x1-face_x),int(y2+y1-face_y)),(0,0,255),3) cv2.line(img, (int(x1), int(y1)), (int(x1+x2-face_x),int(y1+y2-face_y)),(0,0,255),3) # Draw pillars in blue cv2.line(img, (int(face_x), int(face_y)), (int(x3),int(y3)),(255,0,0),2) cv2.line(img, (int(x1), int(y1)), (int(x1+x3-face_x),int(y1+y3-face_y)),(255,0,0),2) cv2.line(img, (int(x2), int(y2)), (int(x2+x3-face_x),int(y2+y3-face_y)),(255,0,0),2) cv2.line(img, (int(x2+x1-face_x),int(y2+y1-face_y)), (int(x3+x1+x2-2*face_x),int(y3+y2+y1-2*face_y)),(255,0,0),2) # Draw top in green cv2.line(img, (int(x3+x1-face_x),int(y3+y1-face_y)), (int(x3+x1+x2-2*face_x),int(y3+y2+y1-2*face_y)),(0,255,0),2) cv2.line(img, (int(x2+x3-face_x),int(y2+y3-face_y)), (int(x3+x1+x2-2*face_x),int(y3+y2+y1-2*face_y)),(0,255,0),2) cv2.line(img, (int(x3), int(y3)), (int(x3+x1-face_x),int(y3+y1-face_y)),(0,255,0),2) cv2.line(img, (int(x3), int(y3)), (int(x3+x2-face_x),int(y3+y2-face_y)),(0,255,0),2) return img