Skip to content

odak.learn.tools

odak.learn.tools

Provides necessary definitions for general tools used across the library.

load_image(fn, normalizeby=0.0, torch_style=False)

Definition to load an image from a given location as a torch tensor.

Parameters:

  • fn
           Filename.
    
  • normalizeby
           Value to to normalize images with. Default value of zero will lead to no normalization.
    
  • torch_style
           If set True, it will load an image mxnx3 as 3xmxn.
    

Returns:

  • image ( ndarray ) –

    Image loaded as a Numpy array.

Source code in odak/learn/tools/file.py
def load_image(fn, normalizeby = 0., torch_style = False):
    """
    Definition to load an image from a given location as a torch tensor.

    Parameters
    ----------
    fn           : str
                   Filename.
    normalizeby  : float or optional
                   Value to to normalize images with. Default value of zero will lead to no normalization.
    torch_style  : bool or optional
                   If set True, it will load an image mxnx3 as 3xmxn.

    Returns
    -------
    image        :  ndarray
                    Image loaded as a Numpy array.

    """
    image = odak.tools.load_image(fn, normalizeby = normalizeby, torch_style = torch_style)
    image = torch.from_numpy(image).float()
    return image

resize(image, multiplier=0.5, mode='nearest')

Definition to resize an image.

Parameters:

  • image
            Image with MxNx3 resolution.
    
  • multiplier
            Multiplier used in resizing operation (e.g., 0.5 is half size in one axis).
    
  • mode
            Mode to be used in scaling, nearest, bilinear, etc.
    

Returns:

  • new_image ( tensor ) –

    Resized image.

Source code in odak/learn/tools/file.py
def resize(image, multiplier = 0.5, mode = 'nearest'):
    """
    Definition to resize an image.

    Parameters
    ----------
    image         : torch.tensor
                    Image with MxNx3 resolution.
    multiplier    : float
                    Multiplier used in resizing operation (e.g., 0.5 is half size in one axis).
    mode          : str
                    Mode to be used in scaling, nearest, bilinear, etc.

    Returns
    -------
    new_image     : torch.tensor
                    Resized image.

    """
    scale = torch.nn.Upsample(scale_factor = multiplier, mode = mode)
    new_image = torch.zeros((int(image.shape[0] * multiplier), int(image.shape[1] * multiplier), 3)).to(image.device)
    for i in range(3):
        cache = image[:,:,i].unsqueeze(0)
        cache = cache.unsqueeze(0)
        new_cache = scale(cache).unsqueeze(0)
        new_image[:,:,i] = new_cache.unsqueeze(0)
    return new_image

save_image(fn, img, cmin=0, cmax=255, color_depth=8)

Definition to save a torch tensor as an image.

Parameters:

  • fn
           Filename.
    
  • img
           A numpy array with NxMx3 or NxMx1 shapes.
    
  • cmin
           Minimum value that will be interpreted as 0 level in the final image.
    
  • cmax
           Maximum value that will be interpreted as 255 level in the final image.
    
  • color_depth
           Color depth of an image. Default is eight.
    

Returns:

  • bool ( bool ) –

    True if successful.

Source code in odak/learn/tools/file.py
def save_image(fn, img, cmin = 0, cmax = 255, color_depth = 8):
    """
    Definition to save a torch tensor as an image.

    Parameters
    ----------
    fn           : str
                   Filename.
    img          : ndarray
                   A numpy array with NxMx3 or NxMx1 shapes.
    cmin         : int
                   Minimum value that will be interpreted as 0 level in the final image.
    cmax         : int
                   Maximum value that will be interpreted as 255 level in the final image.
    color_depth  : int
                   Color depth of an image. Default is eight.


    Returns
    ----------
    bool         :  bool
                    True if successful.

    """
    if len(img.shape) ==  4:
        img = img.squeeze(0)
    if len(img.shape) > 2 and torch.argmin(torch.tensor(img.shape)) == 0:
        new_img = torch.zeros(img.shape[1], img.shape[2], img.shape[0]).to(img.device)
        for i in range(img.shape[0]):
            new_img[:, :, i] = img[i].detach().clone()
        img = new_img.detach().clone()
    img = img.cpu().detach().numpy()
    return odak.tools.save_image(fn, img, cmin = cmin, cmax = cmax, color_depth = color_depth)

save_torch_tensor(fn, tensor)

Definition to save a torch tensor.

Parameters:

  • fn
           Filename.
    
  • tensor
           Torch tensor to be saved.
    
Source code in odak/learn/tools/file.py
def save_torch_tensor(fn, tensor):
    """
    Definition to save a torch tensor.


    Parameters
    ----------
    fn           : str
                   Filename.
    tensor       : torch.tensor
                   Torch tensor to be saved.
    """ 
    torch.save(tensor, expanduser(fn))

torch_load(fn)

Definition to load a torch files (*.pt).

Parameters:

  • fn
           Filename.
    

Returns:

  • data ( any ) –

    See torch.load() for more.

Source code in odak/learn/tools/file.py
def torch_load(fn):
    """
    Definition to load a torch files (*.pt).

    Parameters
    ----------
    fn           : str
                   Filename.

    Returns
    -------
    data         : any
                   See torch.load() for more.
    """  
    data = torch.load(expanduser(fn))
    return data

multi_layer_perceptron

Bases: Module

A flexible class to correlate one dimensional input data to an one dimensional output data.

Source code in odak/learn/tools/fitcurve.py
class multi_layer_perceptron(nn.Module):
    """
    A flexible class to correlate one dimensional input data to an one dimensional output data.
    """
    def __init__(self, n_input=1, n_hidden=64, n_output=1, n_layers=4):
        """
        Parameters
        ----------
        n_input         : int
                          Input size [a].
        n_hidden        : int
                          Hidden layer size [b].
        n_output        : int
                          Output size [c].
        n_layers        : int
                          Number of cascaded linear layers.
        """
        super(multi_layer_perceptron, self).__init__()
        self.layers = nn.ModuleList()
        self.layers.append(torch.nn.Linear(n_input, n_hidden))
        for i in range(n_layers):
            new_layer = nn.Sequential(
                                      torch.nn.Linear(n_hidden, n_hidden),
                                      torch.nn.ReLU(inplace=True)
                                     )
            self.layers.append(new_layer)
        self.layer_final = torch.nn.Linear(n_hidden, n_output)


    def forward(self, x):
        """
        Internal function representing the forward model.
        """
        for layer in self.layers:
            x = layer(x)
        x = self.layer_final(x)
        return x

    def estimate(self, x):
        """
        Internal function representing the forward model w/o grad.
        """
        return self.forward(x).detach()


    def fit(self, x_values, y_values, epochs = 100, learning_rate = 1e-5):
        """
        Function to train the weights of the multi layer perceptron.

        Parameters
        ----------
        x_values        : torch.tensor
                          Input values [mx1].
        y_values        : torch.tensor
                          Output values [nx1].
        epochs          : int
                          Number of epochs.
        learning_rate   : float
                          Learning rate of the optimizer.
        """
        t = tqdm(range(epochs), leave = False, dynamic_ncols = True)
        self.optimizer = torch.optim.Adam(self.parameters(), lr=learning_rate)
        self.loss_function = torch.nn.MSELoss()
        for i in t:
            self.optimizer.zero_grad()
            estimate = self.forward(x_values)
            loss = self.loss_function(estimate, y_values)
            loss.backward(retain_graph = True)
            self.optimizer.step()
            description = 'Loss:{:.4f}'.format(loss.item())
            t.set_description(description)
        print(description)
        return True


    def save_weights(self, filename='./weights.pt'):
        """
        Function to save the current weights of the multi layer perceptron to a file.

        Parameters
        ----------
        filename        : str
                          Filename.
        """
        torch.save(self.state_dict(), filename)


    def load_weights(self, filename='./weights.pt'):
        """
        Function to load weights for this multi layer perceptron from a file.

        Parameters
        ----------
        filename        : str
                          Filename.
        """
        self.load_state_dict(torch.load(filename))

__init__(n_input=1, n_hidden=64, n_output=1, n_layers=4)

Parameters:

  • n_input
              Input size [a].
    
  • n_hidden
              Hidden layer size [b].
    
  • n_output
              Output size [c].
    
  • n_layers
              Number of cascaded linear layers.
    
Source code in odak/learn/tools/fitcurve.py
def __init__(self, n_input=1, n_hidden=64, n_output=1, n_layers=4):
    """
    Parameters
    ----------
    n_input         : int
                      Input size [a].
    n_hidden        : int
                      Hidden layer size [b].
    n_output        : int
                      Output size [c].
    n_layers        : int
                      Number of cascaded linear layers.
    """
    super(multi_layer_perceptron, self).__init__()
    self.layers = nn.ModuleList()
    self.layers.append(torch.nn.Linear(n_input, n_hidden))
    for i in range(n_layers):
        new_layer = nn.Sequential(
                                  torch.nn.Linear(n_hidden, n_hidden),
                                  torch.nn.ReLU(inplace=True)
                                 )
        self.layers.append(new_layer)
    self.layer_final = torch.nn.Linear(n_hidden, n_output)

estimate(x)

Internal function representing the forward model w/o grad.

Source code in odak/learn/tools/fitcurve.py
def estimate(self, x):
    """
    Internal function representing the forward model w/o grad.
    """
    return self.forward(x).detach()

fit(x_values, y_values, epochs=100, learning_rate=1e-05)

Function to train the weights of the multi layer perceptron.

Parameters:

  • x_values
              Input values [mx1].
    
  • y_values
              Output values [nx1].
    
  • epochs
              Number of epochs.
    
  • learning_rate
              Learning rate of the optimizer.
    
Source code in odak/learn/tools/fitcurve.py
def fit(self, x_values, y_values, epochs = 100, learning_rate = 1e-5):
    """
    Function to train the weights of the multi layer perceptron.

    Parameters
    ----------
    x_values        : torch.tensor
                      Input values [mx1].
    y_values        : torch.tensor
                      Output values [nx1].
    epochs          : int
                      Number of epochs.
    learning_rate   : float
                      Learning rate of the optimizer.
    """
    t = tqdm(range(epochs), leave = False, dynamic_ncols = True)
    self.optimizer = torch.optim.Adam(self.parameters(), lr=learning_rate)
    self.loss_function = torch.nn.MSELoss()
    for i in t:
        self.optimizer.zero_grad()
        estimate = self.forward(x_values)
        loss = self.loss_function(estimate, y_values)
        loss.backward(retain_graph = True)
        self.optimizer.step()
        description = 'Loss:{:.4f}'.format(loss.item())
        t.set_description(description)
    print(description)
    return True

forward(x)

Internal function representing the forward model.

Source code in odak/learn/tools/fitcurve.py
def forward(self, x):
    """
    Internal function representing the forward model.
    """
    for layer in self.layers:
        x = layer(x)
    x = self.layer_final(x)
    return x

load_weights(filename='./weights.pt')

Function to load weights for this multi layer perceptron from a file.

Parameters:

  • filename
              Filename.
    
Source code in odak/learn/tools/fitcurve.py
def load_weights(self, filename='./weights.pt'):
    """
    Function to load weights for this multi layer perceptron from a file.

    Parameters
    ----------
    filename        : str
                      Filename.
    """
    self.load_state_dict(torch.load(filename))

save_weights(filename='./weights.pt')

Function to save the current weights of the multi layer perceptron to a file.

Parameters:

  • filename
              Filename.
    
Source code in odak/learn/tools/fitcurve.py
def save_weights(self, filename='./weights.pt'):
    """
    Function to save the current weights of the multi layer perceptron to a file.

    Parameters
    ----------
    filename        : str
                      Filename.
    """
    torch.save(self.state_dict(), filename)

histogram_loss(frame, ground_truth, bins=32, limits=[0.0, 1.0])

Function for evaluating a frame against a target using histogram.

Parameters:

  • frame
               Input frame [1 x 3 x m x n]  or [3 x m x n] or [1 x m x n] or [m x n].
    
  • ground_truth
               Ground truth [1 x 3 x m x n] or  [3 x m x n] or [1 x m x n] or  [m x n].
    
  • bins
               Number of bins.
    
  • limits
               Limits.
    

Returns:

  • loss ( float ) –

    Loss from evaluation.

Source code in odak/learn/tools/loss.py
def histogram_loss(frame, ground_truth, bins = 32, limits = [0., 1.]):
    """
    Function for evaluating a frame against a target using histogram.

    Parameters
    ----------
    frame            : torch.tensor
                       Input frame [1 x 3 x m x n]  or [3 x m x n] or [1 x m x n] or [m x n].
    ground_truth     : torch.tensor
                       Ground truth [1 x 3 x m x n] or  [3 x m x n] or [1 x m x n] or  [m x n].
    bins             : int
                       Number of bins.
    limits           : list
                       Limits.

    Returns
    -------
    loss             : float
                       Loss from evaluation.
    """
    if len(frame.shape) == 2:
        frame = frame.unsqueeze(0)
    if len(frame.shape) == 3:
        frame = frame.unsqueeze(0)
    histogram_frame = torch.zeros(frame.shape[1], bins).to(frame.device)
    histogram_ground_truth = torch.zeros(frame.shape[1], bins).to(frame.device)
    l2 = torch.nn.MSELoss()
    for i in range(frame.shape[1]):
        histogram_frame[i] = torch.histc(frame[:, i].flatten(), bins = bins, min = limits[0], max = limits[1])
        histogram_ground_truth[i] = torch.histc(frame[:, i].flatten(), bins = bins, min = limits[0], max = limits[1])
    loss = l2(histogram_frame, histogram_ground_truth)
    return loss

michelson_contrast(image, roi_high, roi_low)

A function to calculate michelson contrast ratio of given region of interests of the image.

Parameters:

  • image
            Image to be tested [1 x 3 x m x n] or [3 x m x n] or [m x n].
    
  • roi_high
            Corner locations of the roi for high intensity area [m_start, m_end, n_start, n_end].
    
  • roi_low
            Corner locations of the roi for low intensity area [m_start, m_end, n_start, n_end].
    

Returns:

  • result ( tensor ) –

    Michelson contrast for the given regions. [1] or [3] depending on input image.

Source code in odak/learn/tools/loss.py
def michelson_contrast(image, roi_high, roi_low):
    """
    A function to calculate michelson contrast ratio of given region of interests of the image.

    Parameters
    ----------
    image         : torch.tensor
                    Image to be tested [1 x 3 x m x n] or [3 x m x n] or [m x n].
    roi_high      : torch.tensor
                    Corner locations of the roi for high intensity area [m_start, m_end, n_start, n_end].
    roi_low       : torch.tensor
                    Corner locations of the roi for low intensity area [m_start, m_end, n_start, n_end].

    Returns
    -------
    result        : torch.tensor
                    Michelson contrast for the given regions. [1] or [3] depending on input image.
    """
    if len(image.shape) == 2:
        image = image.unsqueeze(0)
    if len(image.shape) == 3:
        image = image.unsqueeze(0)
    region_low = image[:, :, roi_low[0]:roi_low[1], roi_low[2]:roi_low[3]]
    region_high = image[:, :, roi_high[0]:roi_high[1], roi_high[2]:roi_high[3]]
    high = torch.mean(region_high, dim = (2, 3))
    low = torch.mean(region_low, dim = (2, 3))
    result = (high - low) / (high + low)
    return result.squeeze(0)

multi_scale_total_variation_loss(frame, levels=3)

Function for evaluating a frame against a target using multi scale total variation approach. Here, multi scale refers to image pyramid of an input frame, where at each level image resolution is half of the previous level.

Parameters:

  • frame
            Input frame [1 x 3 x m x n] or [3 x m x n] or [m x n].
    
  • levels
            Number of levels to go in the image pyriamid.
    

Returns:

  • loss ( float ) –

    Loss from evaluation.

Source code in odak/learn/tools/loss.py
def multi_scale_total_variation_loss(frame, levels = 3):
    """
    Function for evaluating a frame against a target using multi scale total variation approach. Here, multi scale refers to image pyramid of an input frame, where at each level image resolution is half of the previous level.

    Parameters
    ----------
    frame         : torch.tensor
                    Input frame [1 x 3 x m x n] or [3 x m x n] or [m x n].
    levels        : int
                    Number of levels to go in the image pyriamid.

    Returns
    -------
    loss          : float
                    Loss from evaluation.
    """
    if len(frame.shape) == 2:
        frame = frame.unsqueeze(0)
    if len(frame.shape) == 3:
        frame = frame.unsqueeze(0)
    scale = torch.nn.Upsample(scale_factor = 0.5, mode = 'nearest')
    level = frame
    loss = 0
    for i in range(levels):
        if i != 0:
           level = scale(level)
        loss += total_variation_loss(level) 
    return loss

psnr(image, ground_truth, peak_value=1.0)

A function to calculate peak-signal-to-noise ratio of an image with respect to a ground truth image.

Parameters:

  • image
            Image to be tested.
    
  • ground_truth
            Ground truth image.
    
  • peak_value
            Peak value that given tensors could have.
    

Returns:

  • result ( tensor ) –

    Peak-signal-to-noise ratio.

Source code in odak/learn/tools/loss.py
def psnr(image, ground_truth, peak_value = 1.0):
    """
    A function to calculate peak-signal-to-noise ratio of an image with respect to a ground truth image.

    Parameters
    ----------
    image         : torch.tensor
                    Image to be tested.
    ground_truth  : torch.tensor
                    Ground truth image.
    peak_value    : float
                    Peak value that given tensors could have.

    Returns
    -------
    result        : torch.tensor
                    Peak-signal-to-noise ratio.
    """
    mse = torch.mean((ground_truth - image)**2)
    result = 20 * torch.log10(peak_value / torch.sqrt(mse))
    return result

radial_basis_function(value, epsilon=0.5)

Function to pass a value into radial basis function with Gaussian description.

Parameters:

  • value
               Value(s) to pass to the radial basis function.
    
  • epsilon
               Epsilon used in the Gaussian radial basis function (e.g., y=e^(-(epsilon x value)^2).
    

Returns:

  • output ( tensor ) –

    Output values.

Source code in odak/learn/tools/loss.py
def radial_basis_function(value, epsilon = 0.5):
    """
    Function to pass a value into radial basis function with Gaussian description.

    Parameters
    ----------
    value            : torch.tensor
                       Value(s) to pass to the radial basis function. 
    epsilon          : float
                       Epsilon used in the Gaussian radial basis function (e.g., y=e^(-(epsilon x value)^2).

    Returns
    -------
    output           : torch.tensor
                       Output values.
    """
    output = torch.exp((-(epsilon * value)**2))
    return output

total_variation_loss(frame)

Function for evaluating a frame against a target using total variation approach.

Parameters:

  • frame
            Input frame [1 x 3 x m x n] or [3 x m x n] or [m x n].
    

Returns:

  • loss ( float ) –

    Loss from evaluation.

Source code in odak/learn/tools/loss.py
def total_variation_loss(frame):
    """
    Function for evaluating a frame against a target using total variation approach.

    Parameters
    ----------
    frame         : torch.tensor
                    Input frame [1 x 3 x m x n] or [3 x m x n] or [m x n].

    Returns
    -------
    loss          : float
                    Loss from evaluation.
    """
    if len(frame.shape) == 2:
        frame = frame.unsqueeze(0)
    if len(frame.shape) == 3:
        frame = frame.unsqueeze(0)
    diff_x = frame[:, :, :, 1:] - frame[:, :, :, :-1]
    diff_y = frame[:, :, 1:, :] - frame[:, :, :-1, :]
    pixel_count = frame.shape[0] * frame.shape[1] * frame.shape[2] * frame.shape[3]
    loss = ((diff_x ** 2).sum() + (diff_y ** 2).sum()) / pixel_count
    return loss

weber_contrast(image, roi_high, roi_low)

A function to calculate weber contrast ratio of given region of interests of the image.

Parameters:

  • image
            Image to be tested [1 x 3 x m x n] or [3 x m x n] or [m x n].
    
  • roi_high
            Corner locations of the roi for high intensity area [m_start, m_end, n_start, n_end].
    
  • roi_low
            Corner locations of the roi for low intensity area [m_start, m_end, n_start, n_end].
    

Returns:

  • result ( tensor ) –

    Weber contrast for given regions. [1] or [3] depending on input image.

Source code in odak/learn/tools/loss.py
def weber_contrast(image, roi_high, roi_low):
    """
    A function to calculate weber contrast ratio of given region of interests of the image.

    Parameters
    ----------
    image         : torch.tensor
                    Image to be tested [1 x 3 x m x n] or [3 x m x n] or [m x n].
    roi_high      : torch.tensor
                    Corner locations of the roi for high intensity area [m_start, m_end, n_start, n_end].
    roi_low       : torch.tensor
                    Corner locations of the roi for low intensity area [m_start, m_end, n_start, n_end].

    Returns
    -------
    result        : torch.tensor
                    Weber contrast for given regions. [1] or [3] depending on input image.
    """
    if len(image.shape) == 2:
        image = image.unsqueeze(0)
    if len(image.shape) == 3:
        image = image.unsqueeze(0)
    region_low = image[:, :, roi_low[0]:roi_low[1], roi_low[2]:roi_low[3]]
    region_high = image[:, :, roi_high[0]:roi_high[1], roi_high[2]:roi_high[3]]
    high = torch.mean(region_high, dim = (2, 3))
    low = torch.mean(region_low, dim = (2, 3))
    result = (high - low) / low
    return result.squeeze(0)

blur_gaussian(field, kernel_length=[21, 21], nsigma=[3, 3], padding='same')

A definition to blur a field using a Gaussian kernel.

Parameters:

  • field
            MxN field.
    
  • kernel_length (list, default: [21, 21] ) –
            Length of the Gaussian kernel along X and Y axes.
    
  • nsigma
            Sigma of the Gaussian kernel along X and Y axes.
    
  • padding
            Padding value, see torch.nn.functional.conv2d() for more.
    

Returns:

  • blurred_field ( tensor ) –

    Blurred field.

Source code in odak/learn/tools/matrix.py
def blur_gaussian(field, kernel_length = [21, 21], nsigma = [3, 3], padding = 'same'):
    """
    A definition to blur a field using a Gaussian kernel.

    Parameters
    ----------
    field         : torch.tensor
                    MxN field.
    kernel_length : list
                    Length of the Gaussian kernel along X and Y axes.
    nsigma        : list
                    Sigma of the Gaussian kernel along X and Y axes.
    padding       : int or string
                    Padding value, see torch.nn.functional.conv2d() for more.

    Returns
    ----------
    blurred_field : torch.tensor
                    Blurred field.
    """
    kernel = generate_2d_gaussian(kernel_length, nsigma).to(field.device)
    kernel = kernel.unsqueeze(0).unsqueeze(0)
    if len(field.shape) == 2:
        field = field.view(1, 1, field.shape[-2], field.shape[-1])
    blurred_field = torch.nn.functional.conv2d(field, kernel, padding='same')
    if field.shape[1] == 1:
        blurred_field = blurred_field.view(
                                           blurred_field.shape[-2],
                                           blurred_field.shape[-1]
                                          )
    return blurred_field

convolve2d(field, kernel)

Definition to convolve a field with a kernel by multiplying in frequency space.

Parameters:

  • field
          Input field with MxN shape.
    
  • kernel
          Input kernel with MxN shape.
    

Returns:

  • new_field ( tensor ) –

    Convolved field.

Source code in odak/learn/tools/matrix.py
def convolve2d(field, kernel):
    """
    Definition to convolve a field with a kernel by multiplying in frequency space.

    Parameters
    ----------
    field       : torch.tensor
                  Input field with MxN shape.
    kernel      : torch.tensor
                  Input kernel with MxN shape.

    Returns
    ----------
    new_field   : torch.tensor
                  Convolved field.
    """
    fr = torch.fft.fft2(field)
    fr2 = torch.fft.fft2(torch.flip(torch.flip(kernel, [1, 0]), [0, 1]))
    m, n = fr.shape
    new_field = torch.real(torch.fft.ifft2(fr*fr2))
    new_field = torch.roll(new_field, shifts=(int(n/2+1), 0), dims=(1, 0))
    new_field = torch.roll(new_field, shifts=(int(m/2+1), 0), dims=(0, 1))
    return new_field

crop_center(field, size=None)

Definition to crop the center of a field with 2Mx2N size. The outcome is a MxN array.

Parameters:

  • field
          Input field 2M x 2N or K x L x 2M x 2N array.
    
  • size
          Dimensions to crop with respect to center of the image (e.g., M x N or 1 x 1 x M x N).
    

Returns:

  • cropped ( ndarray ) –

    Cropped version of the input field.

Source code in odak/learn/tools/matrix.py
def crop_center(field, size = None):
    """
    Definition to crop the center of a field with 2Mx2N size. The outcome is a MxN array.

    Parameters
    ----------
    field       : ndarray
                  Input field 2M x 2N or K x L x 2M x 2N array.
    size        : list
                  Dimensions to crop with respect to center of the image (e.g., M x N or 1 x 1 x M x N).

    Returns
    ----------
    cropped     : ndarray
                  Cropped version of the input field.
    """
    orig_resolution = field.shape
    if len(field.shape) < 3:
        field = field.unsqueeze(0)
    if len(field.shape) < 4:
        field = field.unsqueeze(0)
    if type(size) == type(None):
        qx = int(field.shape[-2] // 4)
        qy = int(field.shape[-1] // 4)
        cropped_padded = field[:, :, qx: qx + field.shape[-2] // 2, qy:qy + field.shape[-1] // 2]
    else:
        cx = int(field.shape[-2] // 2)
        cy = int(field.shape[-1] // 2)
        hx = int(size[-2] // 2)
        hy = int(size[-1] // 2)
        cropped_padded = field[:, :, cx-hx:cx+hx, cy-hy:cy+hy]
    cropped = cropped_padded
    if len(orig_resolution) == 2:
        cropped = cropped_padded.squeeze(0).squeeze(0)
    if len(orig_resolution) == 3:
        cropped = cropped_padded.squeeze(0)
    return cropped

generate_2d_gaussian(kernel_length=[21, 21], nsigma=[3, 3], mu=[0, 0], normalize=False)

Generate 2D Gaussian kernel. Inspired from https://stackoverflow.com/questions/29731726/how-to-calculate-a-gaussian-kernel-matrix-efficiently-in-numpy

Parameters:

  • kernel_length (list, default: [21, 21] ) –
            Length of the Gaussian kernel along X and Y axes.
    
  • nsigma
            Sigma of the Gaussian kernel along X and Y axes.
    
  • mu
            Mu of the Gaussian kernel along X and Y axes.
    
  • normalize
            If set True, normalize the output.
    

Returns:

  • kernel_2d ( tensor ) –

    Generated Gaussian kernel.

Source code in odak/learn/tools/matrix.py
def generate_2d_gaussian(kernel_length = [21, 21], nsigma = [3, 3], mu = [0, 0], normalize = False):
    """
    Generate 2D Gaussian kernel. Inspired from https://stackoverflow.com/questions/29731726/how-to-calculate-a-gaussian-kernel-matrix-efficiently-in-numpy

    Parameters
    ----------
    kernel_length : list
                    Length of the Gaussian kernel along X and Y axes.
    nsigma        : list
                    Sigma of the Gaussian kernel along X and Y axes.
    mu            : list
                    Mu of the Gaussian kernel along X and Y axes.
    normalize     : bool
                    If set True, normalize the output.

    Returns
    ----------
    kernel_2d     : torch.tensor
                    Generated Gaussian kernel.
    """
    x = torch.linspace(-kernel_length[0]/2., kernel_length[0]/2., kernel_length[0])
    y = torch.linspace(-kernel_length[1]/2., kernel_length[1]/2., kernel_length[1])
    X, Y = torch.meshgrid(x, y, indexing='ij')
    if nsigma[0] == 0:
        nsigma[0] = 1e-5
    if nsigma[1] == 0:
        nsigma[1] = 1e-5
    kernel_2d = 1. / (2. * np.pi * nsigma[0] * nsigma[1]) * torch.exp(-((X - mu[0])**2. / (2. * nsigma[0]**2.) + (Y - mu[1])**2. / (2. * nsigma[1]**2.)))
    if normalize:
        kernel_2d = kernel_2d / kernel_2d.max()
    return kernel_2d

quantize(image_field, bits=4)

Definition to quantize a image field (0-255, 8 bit) to a certain bits level.

Parameters:

  • image_field (tensor) –
          Input image field.
    
  • bits
          A value in between 0 to 8. Can not be zero.
    

Returns:

  • new_field ( tensor ) –

    Quantized image field.

Source code in odak/learn/tools/matrix.py
def quantize(image_field, bits=4):
    """ 
    Definition to quantize a image field (0-255, 8 bit) to a certain bits level.

    Parameters
    ----------
    image_field : torch.tensor
                  Input image field.
    bits        : int
                  A value in between 0 to 8. Can not be zero.

    Returns
    ----------
    new_field   : torch.tensor
                  Quantized image field.
    """
    divider = 2**(8-bits)
    new_field = image_field/divider
    new_field = new_field.int()
    return new_field

zero_pad(field, size=None, method='center')

Definition to zero pad a MxN array to 2Mx2N array.

Parameters:

  • field
                Input field MxN or KxJxMxN array.
    
  • size
                Size to be zeropadded (e.g., [m, n], last two dimensions only).
    
  • method
                Zeropad either by placing the content to center or to the left.
    

Returns:

  • field_zero_padded ( ndarray ) –

    Zeropadded version of the input field.

Source code in odak/learn/tools/matrix.py
def zero_pad(field, size = None, method = 'center'):
    """
    Definition to zero pad a MxN array to 2Mx2N array.

    Parameters
    ----------
    field             : ndarray
                        Input field MxN or KxJxMxN array.
    size              : list
                        Size to be zeropadded (e.g., [m, n], last two dimensions only).
    method            : str
                        Zeropad either by placing the content to center or to the left.

    Returns
    ----------
    field_zero_padded : ndarray
                        Zeropadded version of the input field.
    """
    orig_resolution = field.shape
    if len(field.shape) < 3:
        field = field.unsqueeze(0)
    if len(field.shape) < 4:
        field = field.unsqueeze(0)
    if type(size) == type(None):
        resolution = [field.shape[0], field.shape[1], 2 * field.shape[-2], 2 * field.shape[-1]]
    else:
        resolution = [field.shape[0], field.shape[1], size[0], size[1]]
    field_zero_padded = torch.zeros(resolution, device = field.device, dtype = field.dtype)
    if method == 'center':
       start = [
                resolution[-2] // 2 - field.shape[-2] // 2,
                resolution[-1] // 2 - field.shape[-1] // 2
               ]
       field_zero_padded[
                         :, :,
                         start[0] : start[0] + field.shape[-2],
                         start[1] : start[1] + field.shape[-1]
                         ] = field
    elif method == 'left':
       field_zero_padded[
                         :, :,
                         0: field.shape[-2],
                         0: field.shape[-1]
                        ] = field
    if len(orig_resolution) == 2:
        field_zero_padded = field_zero_padded.squeeze(0).squeeze(0)
    if len(orig_resolution) == 3:
        field_zero_padded = field_zero_padded.squeeze(0)
    return field_zero_padded

grid_sample(no=[10, 10], size=[100.0, 100.0], center=[0.0, 0.0, 0.0], angles=[0.0, 0.0, 0.0])

Definition to generate samples over a surface.

Parameters:

  • no
          Number of samples.
    
  • size
          Physical size of the surface.
    
  • center
          Center location of the surface.
    
  • angles
          Tilt of the surface.
    

Returns:

  • samples ( tensor ) –

    Samples generated.

  • rotx ( tensor ) –

    Rotation matrix at X axis.

  • roty ( tensor ) –

    Rotation matrix at Y axis.

  • rotz ( tensor ) –

    Rotation matrix at Z axis.

Source code in odak/learn/tools/sample.py
def grid_sample(
                no = [10, 10],
                size = [100., 100.], 
                center = [0., 0., 0.], 
                angles = [0., 0., 0.]):
    """
    Definition to generate samples over a surface.

    Parameters
    ----------
    no          : list
                  Number of samples.
    size        : list
                  Physical size of the surface.
    center      : list
                  Center location of the surface.
    angles      : list
                  Tilt of the surface.

    Returns
    -------
    samples     : torch.tensor
                  Samples generated.
    rotx        : torch.tensor
                  Rotation matrix at X axis.
    roty        : torch.tensor
                  Rotation matrix at Y axis.
    rotz        : torch.tensor
                  Rotation matrix at Z axis.
    """
    center = torch.tensor(center)
    angles = torch.tensor(angles)
    size = torch.tensor(size)
    samples = torch.zeros((no[0], no[1], 3))
    step = [size[0] / (no[0] - 1), size[1] / (no[1] - 1)]
    x = torch.linspace(-size[0] / 2., size[0] / 2., no[0])
    y = torch.linspace(-size[1] / 2., size[1] / 2., no[1])
    X, Y = torch.meshgrid(x, y, indexing='ij')
    samples[:, :, 0] = X.detach().clone()
    samples[:, :, 1] = Y.detach().clone()
    samples = samples.reshape((samples.shape[0] * samples.shape[1], samples.shape[2]))
    samples, rotx, roty, rotz = rotate_points(samples, angles = angles, offset = center)
    return samples, rotx, roty, rotz

get_rotation_matrix(tilt_angles=[0.0, 0.0, 0.0], tilt_order='XYZ')

Function to generate rotation matrix for given tilt angles and tilt order.

Parameters:

  • tilt_angles
                 Tilt angles in degrees along XYZ axes.
    
  • tilt_order
                 Rotation order (e.g., XYZ, XZY, ZXY, YXZ, ZYX).
    

Returns:

  • rotmat ( tensor ) –

    Rotation matrix.

Source code in odak/learn/tools/transformation.py
def get_rotation_matrix(tilt_angles = [0., 0., 0.], tilt_order = 'XYZ'):
    """
    Function to generate rotation matrix for given tilt angles and tilt order.


    Parameters
    ----------
    tilt_angles        : list
                         Tilt angles in degrees along XYZ axes.
    tilt_order         : str
                         Rotation order (e.g., XYZ, XZY, ZXY, YXZ, ZYX).

    Returns
    -------
    rotmat             : torch.tensor
                         Rotation matrix.
    """
    rotx = rotmatx(tilt_angles[0])
    roty = rotmaty(tilt_angles[1])
    rotz = rotmatz(tilt_angles[2])
    if tilt_order =='XYZ':
        rotmat = torch.mm(rotz,torch.mm(roty, rotx))
    elif tilt_order == 'XZY':
        rotmat = torch.mm(roty,torch.mm(rotz, rotx))
    elif tilt_order == 'ZXY':
        rotmat = torch.mm(roty,torch.mm(rotx, rotz))
    elif tilt_order == 'YXZ':
        rotmat = torch.mm(rotz,torch.mm(rotx, roty))
    elif tilt_order == 'ZYX':
         rotmat = torch.mm(rotx,torch.mm(roty, rotz))
    return rotmat

rotate_points(point, angles=torch.tensor([[0, 0, 0]]), mode='XYZ', origin=torch.tensor([[0, 0, 0]]), offset=torch.tensor([[0, 0, 0]]))

Definition to rotate a given point. Note that rotation is always with respect to 0,0,0.

Parameters:

  • point
           A point with size of [3] or [1, 3] or [m, 3].
    
  • angles
           Rotation angles in degrees.
    
  • mode
           Rotation mode determines ordering of the rotations at each axis.
           There are XYZ,YXZ,ZXY and ZYX modes.
    
  • origin
           Reference point for a rotation.
           Expected size is [3] or [1, 3].
    
  • offset
           Shift with the given offset.
           Expected size is [3] or [1, 3] or [m, 3].
    

Returns:

  • result ( tensor ) –

    Result of the rotation [1 x 3] or [m x 3].

  • rotx ( tensor ) –

    Rotation matrix along X axis [3 x 3].

  • roty ( tensor ) –

    Rotation matrix along Y axis [3 x 3].

  • rotz ( tensor ) –

    Rotation matrix along Z axis [3 x 3].

Source code in odak/learn/tools/transformation.py
def rotate_points(
                 point,
                 angles = torch.tensor([[0, 0, 0]]), 
                 mode='XYZ', 
                 origin = torch.tensor([[0, 0, 0]]), 
                 offset = torch.tensor([[0, 0, 0]])
                ):
    """
    Definition to rotate a given point. Note that rotation is always with respect to 0,0,0.

    Parameters
    ----------
    point        : torch.tensor
                   A point with size of [3] or [1, 3] or [m, 3].
    angles       : torch.tensor
                   Rotation angles in degrees. 
    mode         : str
                   Rotation mode determines ordering of the rotations at each axis.
                   There are XYZ,YXZ,ZXY and ZYX modes.
    origin       : torch.tensor
                   Reference point for a rotation.
                   Expected size is [3] or [1, 3].
    offset       : torch.tensor
                   Shift with the given offset.
                   Expected size is [3] or [1, 3] or [m, 3].

    Returns
    ----------
    result       : torch.tensor
                   Result of the rotation [1 x 3] or [m x 3].
    rotx         : torch.tensor
                   Rotation matrix along X axis [3 x 3].
    roty         : torch.tensor
                   Rotation matrix along Y axis [3 x 3].
    rotz         : torch.tensor
                   Rotation matrix along Z axis [3 x 3].
    """
    origin = origin.to(point.device)
    offset = offset.to(point.device)
    if len(point.shape) == 1:
        point = point.unsqueeze(0)
    if len(angles.shape) == 1:
        angles = angles.unsqueeze(0)
    rotx = rotmatx(angles[:, 0])
    roty = rotmaty(angles[:, 1])
    rotz = rotmatz(angles[:, 2])
    new_point = (point - origin).T
    if mode == 'XYZ':
        result = torch.mm(rotz, torch.mm(roty, torch.mm(rotx, new_point))).T
    elif mode == 'XZY':
        result = torch.mm(roty, torch.mm(rotz, torch.mm(rotx, new_point))).T
    elif mode == 'YXZ':
        result = torch.mm(rotz, torch.mm(rotx, torch.mm(roty, new_point))).T
    elif mode == 'ZXY':
        result = torch.mm(roty, torch.mm(rotx, torch.mm(rotz, new_point))).T
    elif mode == 'ZYX':
        result = torch.mm(rotx, torch.mm(roty, torch.mm(rotz, new_point))).T
    result += origin
    result += offset
    return result, rotx, roty, rotz

rotmatx(angle)

Definition to generate a rotation matrix along X axis.

Parameters:

  • angle
           Rotation angles in degrees.
    

Returns:

  • rotx ( tensor ) –

    Rotation matrix along X axis.

Source code in odak/learn/tools/transformation.py
def rotmatx(angle):
    """
    Definition to generate a rotation matrix along X axis.

    Parameters
    ----------
    angle        : torch.tensor
                   Rotation angles in degrees.

    Returns
    ----------
    rotx         : torch.tensor
                   Rotation matrix along X axis.
    """
    angle = torch.deg2rad(angle)
    one = torch.ones(1, device = angle.device)
    zero = torch.zeros(1, device = angle.device)
    rotx = torch.stack([
                        torch.stack([ one,              zero,              zero]),
                        torch.stack([zero,  torch.cos(angle), -torch.sin(angle)]),
                        torch.stack([zero,  torch.sin(angle),  torch.cos(angle)])
                       ]).reshape(3, 3)
    return rotx

rotmaty(angle)

Definition to generate a rotation matrix along Y axis.

Parameters:

  • angle
           Rotation angles in degrees.
    

Returns:

  • roty ( tensor ) –

    Rotation matrix along Y axis.

Source code in odak/learn/tools/transformation.py
def rotmaty(angle):
    """
    Definition to generate a rotation matrix along Y axis.

    Parameters
    ----------
    angle        : torch.tensor
                   Rotation angles in degrees.

    Returns
    ----------
    roty         : torch.tensor
                   Rotation matrix along Y axis.
    """
    angle = torch.deg2rad(angle)
    one = torch.ones(1, device = angle.device)
    zero = torch.zeros(1, device = angle.device)
    roty = torch.stack([
                        torch.stack([ torch.cos(angle), zero, torch.sin(angle)]),
                        torch.stack([             zero,  one,             zero]),
                        torch.stack([-torch.sin(angle), zero, torch.cos(angle)])
                       ]).reshape(3, 3)
    return roty

rotmatz(angle)

Definition to generate a rotation matrix along Z axis.

Parameters:

  • angle
           Rotation angles in degrees.
    

Returns:

  • rotz ( tensor ) –

    Rotation matrix along Z axis.

Source code in odak/learn/tools/transformation.py
def rotmatz(angle):
    """
    Definition to generate a rotation matrix along Z axis.

    Parameters
    ----------
    angle        : torch.tensor
                   Rotation angles in degrees.

    Returns
    ----------
    rotz         : torch.tensor
                   Rotation matrix along Z axis.
    """
    angle = torch.deg2rad(angle)
    one = torch.ones(1, device = angle.device)
    zero = torch.zeros(1, device = angle.device)
    rotz = torch.stack([
                        torch.stack([torch.cos(angle), -torch.sin(angle), zero]),
                        torch.stack([torch.sin(angle),  torch.cos(angle), zero]),
                        torch.stack([            zero,              zero,  one])
                       ]).reshape(3,3)
    return rotz

tilt_towards(location, lookat)

Definition to tilt surface normal of a plane towards a point.

Parameters:

  • location
           Center of the plane to be tilted.
    
  • lookat
           Tilt towards this point.
    

Returns:

  • angles ( list ) –

    Rotation angles in degrees.

Source code in odak/learn/tools/transformation.py
def tilt_towards(location, lookat):
    """
    Definition to tilt surface normal of a plane towards a point.

    Parameters
    ----------
    location     : list
                   Center of the plane to be tilted.
    lookat       : list
                   Tilt towards this point.

    Returns
    ----------
    angles       : list
                   Rotation angles in degrees.
    """
    dx = location[0] - lookat[0]
    dy = location[1] - lookat[1]
    dz = location[2] - lookat[2]
    dist = torch.sqrt(torch.tensor(dx ** 2 + dy ** 2 + dz ** 2))
    phi = torch.atan2(torch.tensor(dy), torch.tensor(dx))
    theta = torch.arccos(dz / dist)
    angles = [0, float(torch.rad2deg(theta)), float(torch.rad2deg(phi))]
    return angles

cross_product(vector1, vector2)

Definition to cross product two vectors and return the resultant vector. Used method described under: http://en.wikipedia.org/wiki/Cross_product

Parameters:

  • vector1
           A vector/ray.
    
  • vector2
           A vector/ray.
    

Returns:

  • ray ( tensor ) –

    Array that contains starting points and cosines of a created ray.

Source code in odak/learn/tools/vector.py
def cross_product(vector1, vector2):
    """
    Definition to cross product two vectors and return the resultant vector. Used method described under: http://en.wikipedia.org/wiki/Cross_product

    Parameters
    ----------
    vector1      : torch.tensor
                   A vector/ray.
    vector2      : torch.tensor
                   A vector/ray.

    Returns
    ----------
    ray          : torch.tensor
                   Array that contains starting points and cosines of a created ray.
    """
    angle = torch.cross(vector1[1].T, vector2[1].T)
    angle = torch.tensor(angle)
    ray = torch.tensor([vector1[0], angle], dtype=torch.float32)
    return ray

distance_between_two_points(point1, point2)

Definition to calculate distance between two given points.

Parameters:

  • point1
          First point in X,Y,Z.
    
  • point2
          Second point in X,Y,Z.
    

Returns:

  • distance ( Tensor ) –

    Distance in between given two points.

Source code in odak/learn/tools/vector.py
def distance_between_two_points(point1, point2):
    """
    Definition to calculate distance between two given points.

    Parameters
    ----------
    point1      : torch.Tensor
                  First point in X,Y,Z.
    point2      : torch.Tensor
                  Second point in X,Y,Z.

    Returns
    ----------
    distance    : torch.Tensor
                  Distance in between given two points.
    """
    point1 = torch.tensor(point1) if not isinstance(point1, torch.Tensor) else point1
    point2 = torch.tensor(point2) if not isinstance(point2, torch.Tensor) else point2

    if len(point1.shape) == 1 and len(point2.shape) == 1:
        distance = torch.sqrt(torch.sum((point1 - point2) ** 2))
    elif len(point1.shape) == 2 or len(point2.shape) == 2:
        distance = torch.sqrt(torch.sum((point1 - point2) ** 2, dim=-1))

    return distance

same_side(p1, p2, a, b)

Definition to figure which side a point is on with respect to a line and a point. See http://www.blackpawn.com/texts/pointinpoly/ for more. If p1 and p2 are on the sameside, this definition returns True.

Parameters:

  • p1
          Point(s) to check.
    
  • p2
          This is the point check against.
    
  • a
          First point that forms the line.
    
  • b
          Second point that forms the line.
    
Source code in odak/learn/tools/vector.py
def same_side(p1, p2, a, b):
    """
    Definition to figure which side a point is on with respect to a line and a point. See http://www.blackpawn.com/texts/pointinpoly/ for more. If p1 and p2 are on the sameside, this definition returns True.

    Parameters
    ----------
    p1          : list
                  Point(s) to check.
    p2          : list
                  This is the point check against.
    a           : list
                  First point that forms the line.
    b           : list
                  Second point that forms the line.
    """
    ba = torch.subtract(b, a)
    p1a = torch.subtract(p1, a)
    p2a = torch.subtract(p2, a)
    cp1 = torch.cross(ba, p1a)
    cp2 = torch.cross(ba, p2a)
    test = torch.dot(cp1, cp2)
    if len(p1.shape) > 1:
        return test >= 0
    if test >= 0:
        return True
    return False