code: def finalise(
      self, full_res=False, vote_miou=True, ply_output="", **kwargs
  ):
      per_class_iou = (
          self._confusion_matrix.get_intersection_union_per_class()[0]
      )
      self._iou_per_class = {
          self._dataset.INV_OBJECT_LABEL[k]: v
          for k, v in enumerate(per_class_iou)
      }
  
      if vote_miou and self._test_area:
          # Complete for points that have a prediction
          self._test_area = self._test_area.to("cpu")
          c = ConfusionMatrix(self._num_classes)
          has_prediction = self._test_area.prediction_count > 0
          gt = self._test_area.y[has_prediction].numpy()
          pred = torch.argmax(
              self._test_area.votes[has_prediction], 1
          ).numpy()
          c.count_predicted_batch(gt, pred)
          self._vote_miou = c.get_average_intersection_union() * 100
  
      if full_res:
          self._compute_full_miou()
  
      if ply_output:
          has_prediction = self._test_area.prediction_count > 0
          self._dataset.to_ply(
              self._test_area.pos[has_prediction].cpu(),
              torch.argmax(self._test_area.votes[has_prediction], 1)
              .cpu()
              .numpy(),
              ply_output,
          )
  
file_path: torch-points3d/torch_points3d/metrics/s3dis_tracker.py
imports: from typing import Dict, Any
  import logging
  import torch
  from torch_geometric.nn.unpool import knn_interpolate
  from torch_points3d.metrics.confusion_matrix import ConfusionMatrix
  from torch_points3d.metrics.segmentation_tracker import SegmentationTracker
  from torch_points3d.metrics.base_tracker import BaseTracker, meter_value
  from torch_points3d.datasets.segmentation import IGNORE_LABEL
  from torch_points3d.core.data_transform import SaveOriginalPosId
  from torch_points3d.models import model_interface
label_desc: Use image node_id 3 for calling the S3DISTracker obj's underlying member method code with example usage: obj.finalise(full_res, vote_miou, ply_output) without return types