code: def get_viewed_points(self, image_id):
      image = self.images[image_id]
  
      # get unfiltered points
      point3D_idxs = set(self.point3D_id_to_point3D_idx.values())
      point3D_idxs.discard(SceneManager.INVALID_POINT3D)
      point3D_idxs = list(point3D_idxs)
      points3D = self.points3D[point3D_idxs, :]
  
      # orient points relative to camera
      R = image.q.ToR()
      points3D = points3D.dot(R.T) + image.tvec[np.newaxis, :]
      points3D = points3D[
          points3D[:, 2] > 0, :
      ]  # keep points with positive z
  
      # put points into image coordinates
      camera = self.cameras[image.camera_id]
      points2D = points3D.dot(camera.get_camera_matrix().T)
      points2D = points2D[:, :2] / points2D[:, 2][:, np.newaxis]
  
      # keep points that are within the image
      mask = (
          (points2D[:, 0] >= 0)
          & (points2D[:, 1] >= 0)
          & (points2D[:, 0] < camera.width - 1)
          & (points2D[:, 1] < camera.height - 1)
      )
  
      return points2D[mask, :], points3D[mask, :]
  
imports: from collections import OrderedDict, defaultdict
  from io import StringIO
  from itertools import combinations
  import os
  import struct
  from .camera import Camera
  from .image import Image
  import numpy
  from .rotation import Quaternion
label_desc: Use image node_id 29 for calling the SceneManager obj's underlying member method code with example usage: obj.get_viewed_points(image_id) and returns: points2D,  points3D