code: def smooth_array(
      arr, affine, fwhm=None, ensure_finite=True, copy=True
  ):
      """Smooth images by applying a Gaussian filter.
  
      Apply a Gaussian filter along the three first dimensions of `arr`.
  
      Parameters
      ----------
      arr : :class:`numpy.ndarray`
          4D array, with image number as last dimension. 3D arrays are also
          accepted.
  
      affine : :class:`numpy.ndarray`
          (4, 4) matrix, giving affine transformation for image. (3, 3) matrices
          are also accepted (only these coefficients are used).
          If `fwhm='fast'`, the affine is not used and can be None.
      %(fwhm)s
      ensure_finite : :obj:`bool`, default=True
          If True, replace every non-finite values (like NaNs) by zero before
          filtering.
  
      copy : :obj:`bool`, default=True
          If True, input array is not modified. True by default: the filtering
          is not performed in-place.
  
      Returns
      -------
      :class:`numpy.ndarray`
          Filtered `arr`.
  
      Notes
      -----
      This function is most efficient with arr in C order.
  
      """
      # Here, we have to investigate use cases of fwhm. Particularly, if fwhm=0.
      # See issue #1537
      if isinstance(fwhm, (int, float)) and (fwhm == 0.0):
          warnings.warn(
              f"The parameter 'fwhm' for smoothing is specified as {fwhm}. "
              "Setting it to None (no smoothing will be performed)"
          )
          fwhm = None
      if arr.dtype.kind == "i":
          if arr.dtype == np.int64:
              arr = arr.astype(np.float64)
          else:
              arr = arr.astype(
                  np.float32
              )  # We don't need crazy precision.
      if copy:
          arr = arr.copy()
      if ensure_finite:
          # SPM tends to put NaNs in the data outside the brain
          arr[np.logical_not(np.isfinite(arr))] = 0
      if isinstance(fwhm, str) and (fwhm == "fast"):
          arr = _fast_smooth_array(arr)
      elif fwhm is not None:
          fwhm = np.asarray([fwhm]).ravel()
          fwhm = np.asarray(
              [0.0 if elem is None else elem for elem in fwhm]
          )
          affine = affine[:3, :3]  # Keep only the scale part.
          fwhm_over_sigma_ratio = np.sqrt(
              8 * np.log(2)
          )  # FWHM to sigma.
          vox_size = np.sqrt(np.sum(affine**2, axis=0))
          sigma = fwhm / (fwhm_over_sigma_ratio * vox_size)
          for n, s in enumerate(sigma):
              if s > 0.0:
                  gaussian_filter1d(arr, s, output=arr, axis=n)
      return arr
  
imports: import collections.abc
  import copy
  import itertools
  import warnings
  import nibabel
  import numpy
  from joblib import Memory, Parallel, delayed
  from scipy.ndimage import gaussian_filter1d, generate_binary_structure, label
  from scipy.stats import scoreatpercentile
  from ..None import signal
  from .._utils import _repr_niimgs, as_ndarray, check_niimg, check_niimg_3d, check_niimg_4d, fill_doc
  from .._utils.exceptions import DimensionError
  from .._utils.helpers import rename_parameters, stringify_path
  from .._utils.niimg import _get_data, safe_get_data
  from .._utils.niimg_conversions import _index_img, check_same_fov, iter_check_niimg
  from .._utils.param_validation import check_threshold
  from .._utils.path_finding import resolve_globbing
label_desc: Use image node_id 4 for calling a global function with example usage: smooth_array(arr, affine, fwhm, ensure_finite, copy) and returns: arr