class_docstr: Plain convolutional kernel as described in :cite:t:`vdw2017convgp`. Defines
  a GP :math:`f()` that is constructed from a sum of responses of individual patches
  in an image:
  
  .. math::
     f(x) = \sum_p x^{[p]}
  
  where :math:`x^{[p]}` is the :math:`p`'th patch in the image.
  
  The key reference is :cite:t:`vdw2017convgp`.
class_docstr_tok: ["Plain","convolutional","kernel","as","described","in",":","cite",":","t",":","`","vdw2017convgp","`",".","Defines","a","GP",":","math",":","`","f","(",")","`","that","is","constructed","from","a","sum","of","responses","of","individual","patches","in","an","image",":","..","math",":",":","f","(","x",")","=","\\sum_p","x^","{","[","p","]","}","where",":","math",":","`","x^","{","[","p","]","}","`","is","the",":","math",":","`","p","`","'th","patch","in","the","image",".","The","key","reference","is",":","cite",":","t",":","`","vdw2017convgp","`","."]
docstr: Extracts patches from the images X. Patches are extracted separately for each of the colour
  channels.
  
  :param X: Images.
  :return: Patches.
docstr_tok: ["Extracts","patches","from","the","images","X.","Patches","are","extracted","separately","for","each","of","the","colour","channels",".",":","param","X",":","Images",".",":","return",":","Patches","."]
code: def get_patches(self, X: TensorType) -> tf.Tensor:
      """
      Extracts patches from the images X. Patches are extracted separately for each of the colour
      channels.
  
      :param X: Images.
      :return: Patches.
      """
      # Roll the colour channel to the front, so it appears to
      # `tf.extract_image_patches()` as separate images. Then extract patches
      # and reshape to have the first axis the same as the number of images.
      # The separate patches will then be in the second axis.
      batch = tf.shape(X)[:-2]
      N = tf.shape(X)[-2]
      flat_batch = tf.reduce_prod(batch)
      num_data = flat_batch * N
      X = cs(
          tf.transpose(
              tf.reshape(X, [num_data, -1, self.colour_channels]),
              [0, 2, 1],
          ),
          "[num_data, C, W_x_H]",
      )
      X = cs(
          tf.reshape(
              X,
              [-1, self.image_shape[0], self.image_shape[1], 1],
              name="rX",
          ),
          "[num_data_x_C, W, H, 1]",
      )
      patches = cs(
          tf.image.extract_patches(
              X,
              [1, self.patch_shape[0], self.patch_shape[1], 1],
              [1, 1, 1, 1],
              [1, 1, 1, 1],
              "VALID",
          ),
          "[num_data_x_C, n_x_patches, n_y_patches, S]",
      )
      shp = tf.shape(patches)
      reshaped_patches = cs(
          tf.reshape(
              patches,
              tf.concat(
                  [
                      batch,
                      [
                          N,
                          self.colour_channels * shp[1] * shp[2],
                          shp[3],
                      ],
                  ],
                  0,
              ),
          ),
          "[batch..., N, P, S]",
      )
      return to_default_float(reshaped_patches)
  
file_path: GPflow/gpflow/kernels/convolutional.py
imports: from typing import Optional, Sequence, cast
  import numpy
  import tensorflow
  from check_shapes import check_shape
  from check_shapes import check_shapes, inherit_check_shapes
  from ..base import Parameter, TensorType
  from ..config import default_float
  from ..utilities import to_default_float
  from .base import Kernel
label_desc: Use image node_id 2 for calling the Convolutional obj's underlying member method code with example usage: obj.get_patches(X) and returns: to_default_float