docs: def detect(self, color_im, depth_im, cfg, camera_intr,
                 T_camera_world,
                 vis_foreground=False, vis_segmentation=False, segmask=None):
          """Detects all relevant objects in an rgbd image pair using foreground masking.
  
          Parameters
          ----------
          color_im : :obj:`ColorImage`
              color image for detection
          depth_im : :obj:`DepthImage`
              depth image for detection (corresponds to color image)
          cfg : :obj:`YamlConfig`
              parameters of detection function
          camera_intr : :obj:`CameraIntrinsics`
              intrinsics of the camera
          T_camera_world : :obj:`autolab_core.RigidTransform`
              registration of the camera to world frame
          segmask : :obj:`BinaryImage`
              optional segmask of invalid pixels
  
          Returns
          -------
          :obj:`list` of :obj:`RgbdDetection`
              all detections in the image
          """
          # read params
          min_pt_box = np.array(cfg['min_pt'])
          max_pt_box = np.array(cfg['max_pt'])
          min_contour_area = cfg['min_contour_area']
          max_contour_area = cfg['max_contour_area']
          min_box_area = cfg['min_box_area']
          max_box_area = cfg['max_box_area']
          box_padding_px = cfg['box_padding_px']
          crop_height = cfg['image_height']
          crop_width = cfg['image_width']
          depth_grad_thresh = cfg['depth_grad_thresh']
          point_cloud_mask_only = cfg['point_cloud_mask_only']
  
          w = cfg['filter_dim']
  
          half_crop_height = float(crop_height) / 2
          half_crop_width = float(crop_width) / 2
          half_crop_dims = np.array([half_crop_height, half_crop_width])
  
          fill_depth = np.max(depth_im.data[depth_im.data > 0])
  
          kinect2_denoising = False
          if 'kinect2_denoising' in cfg.keys() and cfg['kinect2_denoising']:
              kinect2_denoising = True
              depth_offset = cfg['kinect2_noise_offset']
              max_depth = cfg['kinect2_noise_max_depth']
  
          box = Box(min_pt_box, max_pt_box, 'world')
  
          # project into 3D
          point_cloud_cam = camera_intr.deproject(depth_im)
          point_cloud_world = T_camera_world * point_cloud_cam
          seg_point_cloud_world, _ = point_cloud_world.box_mask(box)
          seg_point_cloud_cam = T_camera_world.inverse() * seg_point_cloud_world
          depth_im_seg = camera_intr.project_to_image(seg_point_cloud_cam)
  
          # mask image using background detection
          bgmodel = color_im.background_model()
          binary_im = depth_im_seg.to_binary()
          if segmask is not None:
              binary_im = binary_im.mask_binary(segmask.inverse())
  
          # filter the image
          y, x = np.ogrid[-w/2+1:w/2+1, -w/2+1:w/2+1]
          mask = x*x + y*y <= w/2*w/2
          filter_struct = np.zeros([w,w]).astype(np.uint8)
          filter_struct[mask] = 1
          binary_im_filtered_data = snm.binary_dilation(binary_im.data, structure=filter_struct)
          binary_im_filtered = BinaryImage(binary_im_filtered_data.astype(np.uint8),
                                           frame=binary_im.frame,
                                           threshold=0)
  
          # find all contours
          contours = binary_im_filtered.find_contours(min_area=min_contour_area, max_area=max_contour_area)
  
          if vis_foreground:
              plt.figure()
              plt.subplot(1,3,1)
              plt.imshow(color_im.data)
              plt.imshow(segmask.data, cmap=plt.cm.gray)
              plt.axis('off')
              plt.subplot(1,3,2)
              plt.imshow(binary_im.data, cmap=plt.cm.gray)
              plt.axis('off')
              plt.subplot(1,3,3)
              plt.imshow(binary_im_filtered.data, cmap=plt.cm.gray)
              plt.axis('off')
              plt.show()
  
          # switch to just return the mean of nonzero_px
          if point_cloud_mask_only == 1:
              center_px = np.mean(binary_im_filtered.nonzero_pixels(), axis=0)
              ci = center_px[0]
              cj = center_px[1]
              binary_thumbnail = binary_im_filtered.crop(crop_height, crop_width, ci, cj)
              color_thumbnail = color_im.crop(crop_height, crop_width, ci, cj)
              depth_thumbnail = depth_im.crop(crop_height, crop_width, ci, cj)
              thumbnail_intr = camera_intr
              if camera_intr is not None:
                  thumbnail_intr = camera_intr.crop(crop_height, crop_width, ci, cj)
                  
                  
              query_box = Box(center_px - half_crop_dims, center_px + half_crop_dims)
              return [RgbdDetection(color_thumbnail,
                                    depth_thumbnail,
                                    query_box,
                                    binary_thumbnail=binary_thumbnail,
                                    contour=None,
                                    camera_intr=thumbnail_intr)]
  
          # convert contours to detections
          detections = []
          for i, contour in enumerate(contours):
              orig_box = contour.bounding_box
              logging.debug('Orig box %d area: %.3f' %(i, orig_box.area))
              if orig_box.area > min_box_area and orig_box.area < max_box_area:
                  # convert orig bounding box to query bounding box
                  min_pt = orig_box.center - half_crop_dims
                  max_pt = orig_box.center + half_crop_dims
                  query_box = Box(min_pt, max_pt, frame=orig_box.frame)
  
                  # segment color to get refined detection
                  contour_mask = binary_im_filtered.contour_mask(contour)
                  binary_thumbnail = contour_mask.crop(query_box.height, query_box.width, query_box.ci, query_box.cj)
  
              else:
                  # otherwise take original bounding box
                  query_box = Box(contour.bounding_box.min_pt - box_padding_px,
                                  contour.bounding_box.max_pt + box_padding_px,
                                  frame = contour.bounding_box.frame)
  
                  binary_thumbnail = binary_im_filtered.crop(query_box.height, query_box.width, query_box.ci, query_box.cj)
  
              # crop to get thumbnails
              color_thumbnail = color_im.crop(query_box.height, query_box.width, query_box.ci, query_box.cj)
              depth_thumbnail = depth_im.crop(query_box.height, query_box.width, query_box.ci, query_box.cj)
              thumbnail_intr = camera_intr
              if camera_intr is not None:
                  thumbnail_intr = camera_intr.crop(query_box.height, query_box.width, query_box.ci, query_box.cj)
  
              # fix depth thumbnail
              depth_thumbnail = depth_thumbnail.replace_zeros(fill_depth)
              if kinect2_denoising:
                  depth_data = depth_thumbnail.data
                  min_depth = np.min(depth_data)
                  binary_mask_data = binary_thumbnail.data
                  depth_mask_data = depth_thumbnail.mask_binary(binary_thumbnail).data
                  depth_mask_data += depth_offset
                  depth_data[binary_mask_data > 0] = depth_mask_data[binary_mask_data > 0]
                  depth_thumbnail = DepthImage(depth_data, depth_thumbnail.frame)
  
              # append to detections
              detections.append(RgbdDetection(color_thumbnail,
                                              depth_thumbnail,
                                              query_box,
                                              binary_thumbnail=binary_thumbnail,
                                              contour=contour,
                                              camera_intr=thumbnail_intr))
  
          return detections