Ruicheng commited on
Commit
1cf86f0
1 Parent(s): 3d478e1

update utils3d

Browse files
utils3d/numpy/__init__.py CHANGED
@@ -58,6 +58,9 @@ __modules_all__ = {
58
  'perspective_from_fov_xy',
59
  'intrinsics_from_focal_center',
60
  'intrinsics_from_fov',
 
 
 
61
  'view_look_at',
62
  'extrinsics_look_at',
63
  'perspective_to_intrinsics',
 
58
  'perspective_from_fov_xy',
59
  'intrinsics_from_focal_center',
60
  'intrinsics_from_fov',
61
+ 'fov_to_focal',
62
+ 'focal_to_fov',
63
+ 'intrinsics_to_fov',
64
  'view_look_at',
65
  'extrinsics_look_at',
66
  'perspective_to_intrinsics',
utils3d/numpy/transforms.py CHANGED
@@ -10,6 +10,9 @@ __all__ = [
10
  'perspective_from_fov_xy',
11
  'intrinsics_from_focal_center',
12
  'intrinsics_from_fov',
 
 
 
13
  'view_look_at',
14
  'extrinsics_look_at',
15
  'perspective_to_intrinsics',
@@ -78,12 +81,12 @@ def perspective(
78
 
79
 
80
  def perspective_from_fov(
81
- fov: Union[float, np.ndarray],
82
- width: Union[int, np.ndarray],
83
- height: Union[int, np.ndarray],
84
- near: Union[float, np.ndarray],
85
- far: Union[float, np.ndarray]
86
- ) -> np.ndarray:
87
  """
88
  Get OpenGL perspective matrix from field of view in largest dimension
89
 
@@ -193,6 +196,20 @@ def intrinsics_from_fov(
193
  return ret
194
 
195
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
  @batched(1,1,1)
197
  def view_look_at(
198
  eye: np.ndarray,
 
10
  'perspective_from_fov_xy',
11
  'intrinsics_from_focal_center',
12
  'intrinsics_from_fov',
13
+ 'fov_to_focal',
14
+ 'focal_to_fov',
15
+ 'intrinsics_to_fov',
16
  'view_look_at',
17
  'extrinsics_look_at',
18
  'perspective_to_intrinsics',
 
81
 
82
 
83
  def perspective_from_fov(
84
+ fov: Union[float, np.ndarray],
85
+ width: Union[int, np.ndarray],
86
+ height: Union[int, np.ndarray],
87
+ near: Union[float, np.ndarray],
88
+ far: Union[float, np.ndarray]
89
+ ) -> np.ndarray:
90
  """
91
  Get OpenGL perspective matrix from field of view in largest dimension
92
 
 
196
  return ret
197
 
198
 
199
+ def focal_to_fov(focal: np.ndarray):
200
+ return 2 * np.arctan(0.5 / focal)
201
+
202
+
203
+ def fov_to_focal(fov: np.ndarray):
204
+ return 0.5 / np.tan(fov / 2)
205
+
206
+
207
+ def intrinsics_to_fov(intrinsics: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
208
+ fov_x = focal_to_fov(intrinsics[..., 0, 0])
209
+ fov_y = focal_to_fov(intrinsics[..., 1, 1])
210
+ return fov_x, fov_y
211
+
212
+
213
  @batched(1,1,1)
214
  def view_look_at(
215
  eye: np.ndarray,
utils3d/numpy/utils.py CHANGED
@@ -362,41 +362,46 @@ def image_pixel(
362
 
363
 
364
  def image_mesh(
365
- height: int,
366
- width: int,
367
  mask: np.ndarray = None,
368
- tri: bool = False
369
- ) -> Tuple[np.ndarray, np.ndarray]:
 
370
  """
371
- Get x quad mesh regarding image pixel uv coordinates as vertices and image grid as faces.
372
 
373
  Args:
374
- width (int): image width
375
- height (int): image height
376
  mask (np.ndarray, optional): binary mask of shape (height, width), dtype=bool. Defaults to None.
377
 
378
  Returns:
379
- uv (np.ndarray): uv corresponding to pixels as described in image_uv()
380
- faces (np.ndarray): quad faces connecting neighboring pixels
381
  indices (np.ndarray, optional): indices of vertices in the original mesh
382
  """
383
- if mask is not None:
384
- assert mask.shape[0] == height and mask.shape[1] == width
385
- assert mask.dtype == np.bool_
386
- uv = image_uv(height, width).reshape((-1, 2))
387
  row_faces = np.stack([np.arange(0, width - 1, dtype=np.int32), np.arange(width, 2 * width - 1, dtype=np.int32), np.arange(1 + width, 2 * width, dtype=np.int32), np.arange(1, width, dtype=np.int32)], axis=1)
388
  faces = (np.arange(0, (height - 1) * width, width, dtype=np.int32)[:, None, None] + row_faces[None, :, :]).reshape((-1, 4))
389
- if mask is not None:
 
 
 
 
 
 
 
390
  quad_mask = (mask[:-1, :-1] & mask[1:, :-1] & mask[1:, 1:] & mask[:-1, 1:]).ravel()
391
  faces = faces[quad_mask]
392
- faces, uv, indices = mesh.remove_unreferenced_vertices(faces, uv, return_indices=True)
393
  if tri:
394
  faces = mesh.triangulate(faces)
395
- return uv, faces, indices
396
- if tri:
397
- faces = mesh.triangulate(faces)
398
- return uv, faces
399
-
400
 
401
  def image_mesh_from_depth(
402
  depth: np.ndarray,
 
362
 
363
 
364
  def image_mesh(
365
+ *image_attrs: np.ndarray,
 
366
  mask: np.ndarray = None,
367
+ tri: bool = False,
368
+ return_indices: bool = False
369
+ ) -> Tuple[np.ndarray, ...]:
370
  """
371
+ Get a mesh regarding image pixel uv coordinates as vertices and image grid as faces.
372
 
373
  Args:
374
+ *image_attrs (np.ndarray): image attributes in shape (height, width, [channels])
 
375
  mask (np.ndarray, optional): binary mask of shape (height, width), dtype=bool. Defaults to None.
376
 
377
  Returns:
378
+ faces (np.ndarray): faces connecting neighboring pixels. shape (T, 4) if tri is False, else (T, 3)
379
+ *vertex_attrs (np.ndarray): vertex attributes in corresponding order with input image_attrs
380
  indices (np.ndarray, optional): indices of vertices in the original mesh
381
  """
382
+ assert (len(image_attrs) > 0) or (mask is not None), "At least one of image_attrs or mask should be provided"
383
+ height, width = next(image_attrs).shape[:2] if mask is None else mask.shape
384
+ assert all(img.shape[:2] == (height, width) for img in image_attrs), "All image_attrs should have the same shape"
385
+
386
  row_faces = np.stack([np.arange(0, width - 1, dtype=np.int32), np.arange(width, 2 * width - 1, dtype=np.int32), np.arange(1 + width, 2 * width, dtype=np.int32), np.arange(1, width, dtype=np.int32)], axis=1)
387
  faces = (np.arange(0, (height - 1) * width, width, dtype=np.int32)[:, None, None] + row_faces[None, :, :]).reshape((-1, 4))
388
+ if mask is None:
389
+ if tri:
390
+ faces = mesh.triangulate(faces)
391
+ ret = [faces, *(img.reshape(-1, *img.shape[2:]) for img in image_attrs)]
392
+ if return_indices:
393
+ ret.append(np.arange(height * width, dtype=np.int32))
394
+ return tuple(ret)
395
+ else:
396
  quad_mask = (mask[:-1, :-1] & mask[1:, :-1] & mask[1:, 1:] & mask[:-1, 1:]).ravel()
397
  faces = faces[quad_mask]
 
398
  if tri:
399
  faces = mesh.triangulate(faces)
400
+ return mesh.remove_unreferenced_vertices(
401
+ faces,
402
+ *(x.reshape(-1, *x.shape[2:]) for x in image_attrs),
403
+ return_indices=return_indices
404
+ )
405
 
406
  def image_mesh_from_depth(
407
  depth: np.ndarray,