code: def split_crops(
      crops: List[np.ndarray],
      max_ratio: float,
      target_ratio: int,
      dilation: float,
      channels_last: bool = True,
  ) -> Tuple[List[np.ndarray], List[Union[int, Tuple[int, int]]], bool]:
      """Chunk crops horizontally to match a given aspect ratio
  
      Args:
      ----
          crops: list of numpy array of shape (H, W, 3) if channels_last or (3, H, W) otherwise
          max_ratio: the maximum aspect ratio that won't trigger the chunk
          target_ratio: when crops are chunked, they will be chunked to match this aspect ratio
          dilation: the width dilation of final chunks (to provide some overlaps)
          channels_last: whether the numpy array has dimensions in channels last order
  
      Returns:
      -------
          a tuple with the new crops, their mapping, and a boolean specifying whether any remap is required
      """
      _remap_required = False
      crop_map: List[Union[int, Tuple[int, int]]] = []
      new_crops: List[np.ndarray] = []
      for crop in crops:
          h, w = crop.shape[:2] if channels_last else crop.shape[-2:]
          aspect_ratio = w / h
          if aspect_ratio > max_ratio:
              # Determine the number of crops, reference aspect ratio = 4 = 128 / 32
              num_subcrops = int(aspect_ratio // target_ratio)
              # Find the new widths, additional dilation factor to overlap crops
              width = dilation * w / num_subcrops
              centers = [
                  (w / num_subcrops) * (1 / 2 + idx)
                  for idx in range(num_subcrops)
              ]
              # Get the crops
              if channels_last:
                  _crops = [
                      crop[
                          :,
                          max(0, int(round(center - width / 2))) : min(
                              w - 1, int(round(center + width / 2))
                          ),
                          :,
                      ]
                      for center in centers
                  ]
              else:
                  _crops = [
                      crop[
                          :,
                          :,
                          max(0, int(round(center - width / 2))) : min(
                              w - 1, int(round(center + width / 2))
                          ),
                      ]
                      for center in centers
                  ]
              # Avoid sending zero-sized crops
              _crops = [
                  crop
                  for crop in _crops
                  if all(s > 0 for s in crop.shape)
              ]
              # Record the slice of crops
              crop_map.append(
                  (len(new_crops), len(new_crops) + len(_crops))
              )
              new_crops.extend(_crops)
              # At least one crop will require merging
              _remap_required = True
          else:
              crop_map.append(len(new_crops))
              new_crops.append(crop)
  
      return new_crops, crop_map, _remap_required
  
imports: from typing import List, Tuple, Union
  import numpy
  from ..utils import merge_multi_strings
label_desc: Use image node_id 1 for calling a global function with example usage: split_crops(crops, max_ratio, target_ratio, dilation, channels_last) and returns: new_crops,  crop_map,  _remap_required