code: def convolve_(image, kernel):
      """Apply a convolution kernel (or one per channel) in-place to an image.
  
      Use a list of matrices to apply one kernel per channel.
  
      Added in 0.5.0.
  
      **Supported dtypes**:
  
          * ``uint8``: yes; fully tested
          * ``uint16``: yes; tested
          * ``uint32``: no (1)
          * ``uint64``: no (2)
          * ``int8``: yes; tested (3)
          * ``int16``: yes; tested
          * ``int32``: no (2)
          * ``int64``: no (2)
          * ``float16``: yes; tested (4)
          * ``float32``: yes; tested
          * ``float64``: yes; tested
          * ``float128``: no (1)
          * ``bool``: yes; tested (4)
  
          - (1) rejected by ``cv2.filter2D()``.
          - (2) causes error: cv2.error: OpenCV(3.4.2) (...)/filter.cpp:4487:
                error: (-213:The function/feature is not implemented)
                Unsupported combination of source format (=1), and destination
                format (=1) in function 'getLinearFilter'.
          - (3) mapped internally to ``int16``.
          - (4) mapped internally to ``float32``.
  
      Parameters
      ----------
      image : ndarray
          ``(H,W)`` or ``(H,W,C)`` image array.
          May be modified in-place.
  
      kernel : ndarray or list of ndarray
          Either a single 2D kernel matrix (will be applied to all channels)
          or a list of 2D matrices (one per image channel).
  
      Returns
      -------
      image
          Image of the same shape and dtype as the input array.
          Might have been modified in-place.
  
      """
      iadt.gate_dtypes_strs(
          {image.dtype},
          allowed="bool uint8 uint16 int8 int16 float16 float32 float64",
          disallowed="uint32 uint64 int32 int64 float128",
      )
  
      # currently we don't have to worry here about alignemnt with
      # non-image data and therefore can just place this before any
      # sampling
      if image.size == 0:
          return image
  
      input_shape = image.shape
      nb_channels = 1 if len(input_shape) == 2 else input_shape[2]
  
      input_dtype = image.dtype
      if image.dtype in {iadt._BOOL_DTYPE, iadt._FLOAT16_DTYPE}:
          image = image.astype(np.float32, copy=False)
      elif image.dtype == iadt._INT8_DTYPE:
          image = image.astype(np.int16, copy=False)
  
      if ia.is_np_array(kernel):
          assert kernel.ndim == 2, (
              "Expected kernel to be either a list of (H,W) arrays or a "
              "single (H,W) array, got array of shape %s."
              % (kernel.shape,)
          )
          matrices = [kernel]
      else:
          assert isinstance(kernel, list), (
              "Expected kernel to be either a list of (H,W) arrays or a "
              "single (H,W) array, got type %s."
              % (type(kernel).__name__,)
          )
          assert len(kernel) == nb_channels, (
              "Kernel was given as a list. Expected that list to contain as "
              "many arrays as there are image channels. "
              "Got %d, but expected %d for image of shape %s."
              % (len(kernel), nb_channels, image.shape)
          )
          matrices = kernel
  
      if not image.flags["C_CONTIGUOUS"]:
          image = np.ascontiguousarray(image)
  
      # force channelwise application for >512 channels
      if nb_channels > 512 and len(matrices) == 1:
          matrices = [matrices[0]] * nb_channels
  
      if len(matrices) == 1:
          if matrices[0] is not None:
              if image.base is not None and image.base.shape[0] == 1:
                  image = np.copy(image)
              image = cv2.filter2D(image, -1, matrices[0], dst=image)
      else:
          for channel in sm.xrange(nb_channels):
              if matrices[channel] is not None:
                  arr_channel = np.copy(image[..., channel])
                  image[..., channel] = cv2.filter2D(
                      arr_channel,
                      -1,
                      matrices[channel],
                      dst=arr_channel,
                  )
  
      if input_dtype.kind == "b":
          image = image > 0.5
      elif input_dtype in {iadt._INT8_DTYPE, iadt._FLOAT16_DTYPE}:
          image = iadt.restore_dtypes_(image, input_dtype)
  
      if len(input_shape) == 3 and image.ndim == 2:
          image = image[:, :, np.newaxis]
  
      return image
  
imports: from __future__ import print_function, division, absolute_import
  import itertools
  import numpy
  import cv2
  import six.moves
  import imgaug
  from .None import meta
  from ..None import parameters
  from ..None import dtypes
label_desc: Use image node_id 2 for calling a global function with example usage: convolve_(image, kernel) and returns: image, image