code: def test_pinhole_camera_project_and_unproject(self, device, dtype):
      batch_size = 5
      n = 2  # Point per batch
      height, width = 4, 6
      fx, fy, cx, cy = 1, 2, width / 2, height / 2
      alpha, beta, gamma = 0.0, 0.0, 0.4
      tx, ty, tz = 0, 0, 3
  
      intrinsics = self._create_intrinsics(
          batch_size, fx, fy, cx, cy, device=device, dtype=dtype
      )
      extrinsics = self._create_extrinsics_with_rotation(
          batch_size,
          alpha,
          beta,
          gamma,
          tx,
          ty,
          tz,
          device=device,
          dtype=dtype,
      )
  
      height = (
          torch.ones(batch_size, device=device, dtype=dtype) * height
      )
      width = torch.ones(batch_size, device=device, dtype=dtype) * width
  
      pinhole = kornia.geometry.camera.PinholeCamera(
          intrinsics, extrinsics, height, width
      )
  
      point_3d = torch.rand(
          (batch_size, n, 3), device=device, dtype=dtype
      )
  
      depth = point_3d[..., -1:] + tz
  
      point_2d = pinhole.project(point_3d)
      point_3d_hat = pinhole.unproject(point_2d, depth)
      assert_close(point_3d, point_3d_hat, atol=1e-4, rtol=1e-4)
  
imports: import math
  import pytest
  import torch
  from torch.autograd import gradcheck
  import kornia
  from kornia.testing import assert_close, tensor_to_gradcheck_var
label_desc: Use image node_id 10 for calling the TestPinholeCamera obj's underlying member method code with example usage: obj.test_pinhole_camera_project_and_unproject(device, dtype) without return types