class_docstr: ### Description
  This network estimates affine transformations from
      a pair of moving and fixed image:
  
          Hu et al., Label-driven weakly-supervised learning for
          multimodal deformable image registration, arXiv:1711.01666
          https://arxiv.org/abs/1711.01666
  
          Hu et al., Weakly-Supervised Convolutional Neural Networks for
          Multimodal Image Registration, Medical Image Analysis (2018)
          https://doi.org/10.1016/j.media.2018.07.002
  
      see also:
          https://github.com/YipengHu/label-reg
  
  ### Building blocks
  [DOWN CONV]         - Convolutional layer + Residual Unit + Max pooling
  [CONV]              - Convolutional layer
  [FC]                - Fully connected layer, outputs the affine matrix
  [WARPER]            - Grid resampling with the obtained affine matrix
  
  ### Diagram
  
  INPUT PAIR --> [DOWN CONV]x4 --> [CONV] --> [FC] --> [WARPER] --> DISPLACEMENT FIELD
  
  ### Constraints
  - input spatial rank should be either 2 or 3 (2D or 3D images only)
class_docstr_tok: ["#","#","#","Description","This","network","estimates","affine","transformations","from","a","pair","of","moving","and","fixed","image",":","Hu","et","al.",",","Label-driven","weakly-supervised","learning","for","multimodal","deformable","image","registration",",","arXiv:1711.01666","https",":","\/\/arxiv.org\/abs\/1711.01666","Hu","et","al.",",","Weakly-Supervised","Convolutional","Neural","Networks","for","Multimodal","Image","Registration",",","Medical","Image","Analysis","(","2018",")","https",":","\/\/doi.org\/10.1016\/j.media.2018.07.002","see","also",":","https",":","\/\/github.com\/YipengHu\/label-reg","#","#","#","Building","blocks","[","DOWN","CONV","]","-","Convolutional","layer","+","Residual","Unit","+","Max","pooling","[","CONV","]","-","Convolutional","layer","[","FC","]","-","Fully","connected","layer",",","outputs","the","affine","matrix","[","WARPER","]","-","Grid","resampling","with","the","obtained","affine","matrix","#","#","#","Diagram","INPUT","PAIR","--",">","[","DOWN","CONV","]","x4","--",">","[","CONV","]","--",">","[","FC","]","--",">","[","WARPER","]","--",">","DISPLACEMENT","FIELD","#","#","#","Constraints","-","input","spatial","rank","should","be","either","2","or","3","(","2D","or","3D","images","only",")"]
docstr: :param fixed_image: tensor, fixed image for registration (defines reference space)
  :param moving_image: tensor, moving image to be registered to fixed
  :param is_training: boolean, True if network is in training mode
  :return: displacement fields transformed by estimating affine
docstr_tok: [":","param","fixed_image",":","tensor",",","fixed","image","for","registration","(","defines","reference","space",")",":","param","moving_image",":","tensor",",","moving","image","to","be","registered","to","fixed",":","param","is_training",":","boolean",",","True","if","network","is","in","training","mode",":","return",":","displacement","fields","transformed","by","estimating","affine"]
code: def layer_op(
      self, fixed_image, moving_image, is_training=True, **unused_kwargs
  ):
      """
  
      :param fixed_image: tensor, fixed image for registration (defines reference space)
      :param moving_image: tensor, moving image to be registered to fixed
      :param is_training: boolean, True if network is in training mode
      :return: displacement fields transformed by estimating affine
      """
  
      spatial_rank = infer_spatial_rank(moving_image)
      spatial_shape = fixed_image.get_shape().as_list()[1:-1]
  
      # resize the moving image to match the fixed
      moving_image = Resize(spatial_shape)(moving_image)
      img = tf.concat([moving_image, fixed_image], axis=-1)
      res_1 = DownRes(self.fea[0], kernel_size=7, **self.res_param)(
          img, is_training
      )[0]
      res_2 = DownRes(self.fea[1], **self.res_param)(
          res_1, is_training
      )[0]
      res_3 = DownRes(self.fea[2], **self.res_param)(
          res_2, is_training
      )[0]
      res_4 = DownRes(self.fea[3], **self.res_param)(
          res_3, is_training
      )[0]
  
      conv_5 = Conv(
          n_output_chns=self.fea[4],
          kernel_size=self.k_conv,
          with_bias=False,
          feature_normalization="batch",
          **self.res_param,
      )(res_4, is_training)
  
      if spatial_rank == 2:
          affine_size = 6
      elif spatial_rank == 3:
          affine_size = 12
      else:
          tf.logging.fatal("Not supported spatial rank")
          raise NotImplementedError
  
      if self.affine_w_initializer is None:
          self.affine_w_initializer = init_affine_w()
      if self.affine_b_initializer is None:
          self.affine_b_initializer = init_affine_b(spatial_rank)
      affine = FC(
          n_output_chns=affine_size,
          feature_normalization=None,
          w_initializer=self.affine_w_initializer,
          b_initializer=self.affine_b_initializer,
          **self.affine_param,
      )(conv_5)
      grid_global = Grid(
          source_shape=spatial_shape, output_shape=spatial_shape
      )(affine)
      return grid_global
  
file_path: NiftyNet/niftynet/network/interventional_affine_net.py
imports: from __future__ import absolute_import, print_function
  import numpy
  import tensorflow
  from tensorflow.contrib.layers.python.layers import regularizers
  from niftynet.engine.application_initializer import GlorotUniform
  from niftynet.layer.convolution import ConvolutionalLayer
  from niftynet.layer.downsample_res_block import DownBlock
  from niftynet.layer.fully_connected import FullyConnectedLayer
  from niftynet.layer.grid_warper import AffineGridWarperLayer
  from niftynet.layer.layer_util import infer_spatial_rank
  from niftynet.layer.linear_resize import LinearResizeLayer
  from niftynet.network.base_net import BaseNet
label_desc: Use image node_id 2 for calling the INetAffine obj's underlying member method code with example usage: obj.layer_op(fixed_image, moving_image, is_training) and returns: grid_global