code: def iter_split(
      self, image: np.ndarray, border_type=cv2.BORDER_CONSTANT, value=0
  ) -> Iterable[Tuple[np.ndarray, Tuple[int, int, int, int]]]:
      if (image.shape[0] != self.image_height) or (
          image.shape[1] != self.image_width
      ):
          raise ValueError()
  
      orig_shape_len = len(image.shape)
  
      for coords, crop_coords in zip(self.crops, self.bbox_crops):
          x, y, tile_width, tile_height = crop_coords
          x1 = max(x, 0)
          y1 = max(y, 0)
          x2 = min(image.shape[1], x + tile_width)
          y2 = min(image.shape[0], y + tile_height)
  
          tile = image[y1:y2, x1:x2]  # .copy()
          if (
              x < 0
              or y < 0
              or (x + tile_width) > image.shape[1]
              or (y + tile_height) > image.shape[0]
          ):
              tile = cv2.copyMakeBorder(
                  tile,
                  top=max(0, -y),
                  bottom=max(0, y + tile_height - image.shape[0]),
                  left=max(0, -x),
                  right=max(0, x + tile_width - image.shape[1]),
                  borderType=border_type,
                  value=value,
              )
  
              # This check recovers possible lack of last dummy dimension for single-channel images
              if len(tile.shape) != orig_shape_len:
                  tile = np.expand_dims(tile, axis=-1)
  
          yield tile, coords
  
imports: import dataclasses
  import math
  from typing import List, Iterable, Tuple, Union, Sequence
  import cv2
  import numpy
  import torch
label_desc: Use image node_id 2 for calling the ImageSlicer obj's underlying member method code with example usage: obj.iter_split(image, border_type, value) without return types