Skip to content

Commit ecaabce

Browse files
committed
fix depth camera intrisic and extrinsic params
1 parent 48969f8 commit ecaabce

2 files changed

Lines changed: 85 additions & 12 deletions

File tree

src/physics_simulator/sensor/depth_camera.py

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,41 @@ def get_depth(self):
6565
np.ndarray: Depth map as a numpy array, with values representing
6666
distance from the camera in meters
6767
"""
68+
# Get depth map from MuJoCo
6869
_, depth = self.render(depth=True, segmentation=False)
70+
71+
# Convert MuJoCo depth to real depth
6972
from physics_simulator.utils.camera_utils import get_real_depth_map
70-
7173
depth = get_real_depth_map(self.simulator, depth)
72-
74+
75+
# Flip vertically to match standard image coordinates
7376
depth = np.flipud(depth)
7477

7578
return depth
7679

80+
def _calculate_intrinsics_from_fovy(self):
81+
"""Calculate camera intrinsics from MuJoCo fovy parameter.
82+
83+
MuJoCo cameras only have fovy (field of view in y direction).
84+
We calculate fx, fy, cx, cy from fovy and image dimensions.
85+
"""
86+
# Get camera ID and fovy from MuJoCo
87+
cam_id = self.simulator.model.camera_name2id(self.name)
88+
fovy_rad = self.simulator.model.cam_fovy[cam_id] * np.pi / 180.0 # Convert to radians
89+
90+
# Calculate focal length from fovy
91+
# f = height / (2 * tan(fovy/2))
92+
focal_length = self.height / (2 * np.tan(fovy_rad / 2))
93+
94+
# For square pixels, fx = fy = focal_length
95+
fx = fy = focal_length
96+
97+
# Principal point at image center
98+
cx = self.width / 2
99+
cy = self.height / 2
100+
101+
return fx, fy, cx, cy
102+
77103
def get_point_cloud(self) -> np.ndarray:
78104
"""Generate a 3D point cloud from the depth data in world coordinates.
79105
@@ -91,13 +117,16 @@ def get_point_cloud(self) -> np.ndarray:
91117
# Get depth map
92118
depth_map = self.get_depth()
93119

94-
# Generate point cloud in camera frame using intrinsic parameters
120+
# Calculate intrinsics from MuJoCo fovy
121+
fx, fy, cx, cy = self._calculate_intrinsics_from_fovy()
122+
123+
# Generate point cloud in camera frame using calculated intrinsic parameters
95124
point_cloud_camera = get_point_cloud_from_depth(
96125
depth_image=depth_map,
97-
fx=self.fx,
98-
fy=self.fy,
99-
cx=self.cx,
100-
cy=self.cy
126+
fx=fx,
127+
fy=fy,
128+
cx=cx,
129+
cy=cy
101130
)
102131

103132
# Filter the point cloud to remove invalid points
@@ -154,15 +183,21 @@ def get_point_cloud_wrt_robot(self, robot, downsample_factor=2, max_distance=2.0
154183
from physics_simulator.utils.camera_utils import get_real_depth_map
155184
depth_map = get_real_depth_map(self.simulator, depth_map)
156185

186+
# Flip vertically to match standard image coordinates (same as get_depth method)
187+
depth_map = np.flipud(depth_map)
188+
189+
# Calculate intrinsics from MuJoCo fovy first
190+
fx, fy, cx, cy = self._calculate_intrinsics_from_fovy()
191+
157192
# Downsample for performance if requested
158193
if downsample_factor > 1:
159194
depth_map = depth_map[::downsample_factor, ::downsample_factor]
160-
fx_scaled = self.fx / downsample_factor
161-
fy_scaled = self.fy / downsample_factor
162-
cx_scaled = self.cx / downsample_factor
163-
cy_scaled = self.cy / downsample_factor
195+
fx_scaled = fx / downsample_factor
196+
fy_scaled = fy / downsample_factor
197+
cx_scaled = cx / downsample_factor
198+
cy_scaled = cy / downsample_factor
164199
else:
165-
fx_scaled, fy_scaled, cx_scaled, cy_scaled = self.fx, self.fy, self.cx, self.cy
200+
fx_scaled, fy_scaled, cx_scaled, cy_scaled = fx, fy, cx, cy
166201

167202
# Generate point cloud in camera frame (optimized)
168203
height, width = depth_map.shape

src/physics_simulator/sensor/rgb_camera.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,10 +159,14 @@ def __init__(self, simulator: GalbotEduSim, camera_config: RgbCameraConfig):
159159
self.width = sensor_config.width
160160
self.height = sensor_config.height
161161
self.frequency = sensor_config.frequency
162+
163+
# For MuJoCo cameras, we'll calculate intrinsics from fovy later
164+
# Store config values but they may be overridden
162165
self.fx = sensor_config.fx
163166
self.fy = sensor_config.fy
164167
self.cx = sensor_config.cx
165168
self.cy = sensor_config.cy
169+
166170
self.pixel_size = sensor_config.pixel_size
167171
self.f_stop = sensor_config.f_stop
168172
self.focus_distance = sensor_config.focus_distance
@@ -251,6 +255,40 @@ def __init__(self, simulator: GalbotEduSim, camera_config: RgbCameraConfig):
251255
"frequency": self.frequency,
252256
}
253257

258+
def _calculate_intrinsics_from_fovy(self):
259+
"""Calculate camera intrinsics from MuJoCo fovy parameter.
260+
261+
MuJoCo cameras only have fovy (field of view in y direction).
262+
We calculate fx, fy, cx, cy from fovy and image dimensions.
263+
264+
Returns:
265+
tuple: (fx, fy, cx, cy) camera intrinsics
266+
"""
267+
# Get camera ID and fovy from MuJoCo
268+
cam_id = self.simulator.model.camera_name2id(self.name)
269+
fovy_rad = self.simulator.model.cam_fovy[cam_id] * np.pi / 180.0 # Convert to radians
270+
271+
# Calculate focal length from fovy
272+
# f = height / (2 * tan(fovy/2))
273+
focal_length = self.height / (2 * np.tan(fovy_rad / 2))
274+
275+
# For square pixels, fx = fy = focal_length
276+
fx = fy = focal_length
277+
278+
# Principal point at image center
279+
cx = self.width / 2
280+
cy = self.height / 2
281+
282+
return fx, fy, cx, cy
283+
284+
def get_mujoco_intrinsics(self):
285+
"""Get camera intrinsics calculated from MuJoCo fovy.
286+
287+
Returns:
288+
tuple: (fx, fy, cx, cy) camera intrinsics from MuJoCo
289+
"""
290+
return self._calculate_intrinsics_from_fovy()
291+
254292
def rotation_matrix_to_quaternion(self, R):
255293
"""Convert a 3x3 rotation matrix to a quaternion using scipy.
256294

0 commit comments

Comments
 (0)