deepy.utils.elastic_distortion()   F
last analyzed

Complexity

Conditions 13

Size

Total Lines 56

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 13
dl 0
loc 56
rs 3.3579

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like deepy.utils.elastic_distortion() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
4
"""
5
This code is copied from https://github.com/vsvinayak/mnist-helper.
6
It requires Scipy to perform convolve2d.
7
Default parameters are modified.
8
"""
9
10
import numpy as np
11
import math
12
from scipy.signal import convolve2d
13
14
from deepy.utils import global_rand
15
16
17
def create_2d_gaussian(dim, sigma):
18
    """
19
    This function creates a 2d gaussian kernel with the standard deviation
20
    denoted by sigma
21
22
    :param dim: integer denoting a side (1-d) of gaussian kernel
23
    :param sigma: floating point indicating the standard deviation
24
25
    :returns: a numpy 2d array
26
    """
27
28
    # check if the dimension is odd
29
    if dim % 2 == 0:
30
        raise ValueError("Kernel dimension should be odd")
31
32
    # initialize the kernel
33
    kernel = np.zeros((dim, dim), dtype=np.float16)
34
35
    # calculate the center point
36
    center = dim/2
37
38
    # calculate the variance
39
    variance = sigma ** 2
40
41
    # calculate the normalization coefficeint
42
    coeff = 1. / (2 * variance)
43
44
    # create the kernel
45
    for x in range(0, dim):
46
        for y in range(0, dim):
47
            x_val = abs(x - center)
48
            y_val = abs(y - center)
49
            numerator = x_val**2 + y_val**2
50
            denom = 2*variance
51
52
            kernel[x,y] = coeff * np.exp(-1. * numerator/denom)
53
54
    return kernel/sum(sum(kernel))
55
56
57
def elastic_distortion(image, kernel_dim=21, sigma=6, alpha=30, negated=True):
58
    """
59
    This method performs elastic transformations on an image by convolving
60
    with a gaussian kernel.
61
    :param image: a numpy nd array
62
    :kernel_dim: dimension(1-D) of the gaussian kernel
63
    :param sigma: standard deviation of the kernel
64
    :param alpha: a multiplicative factor for image after convolution
65
    :param negated: a flag indicating whether the image is negated or not
66
    :returns: a nd array transformed image
67
    """
68
    # check if the image is a negated one
69
    if not negated:
70
        image = 255-image
71
72
    # check if kernel dimesnion is odd
73
    if kernel_dim % 2 == 0:
74
        raise ValueError("Kernel dimension should be odd")
75
76
    # create an empty image
77
    result = np.zeros(image.shape)
78
79
    # create random displacement fields
80
    displacement_field_x = np.array([[global_rand.random_integers(-1, 1) for x in xrange(image.shape[0])] \
81
                            for y in xrange(image.shape[1])]) * alpha
82
    displacement_field_y = np.array([[global_rand.random_integers(-1, 1) for x in xrange(image.shape[0])] \
83
                            for y in xrange(image.shape[1])]) * alpha
84
85
    # create the gaussian kernel
86
    kernel = create_2d_gaussian(kernel_dim, sigma)
87
88
    # convolve the fields with the gaussian kernel
89
    displacement_field_x = convolve2d(displacement_field_x, kernel)
90
    displacement_field_y = convolve2d(displacement_field_y, kernel)
91
92
    # make the distortrd image by averaging each pixel value to the neighbouring
93
    # four pixels based on displacement fields
94
95
    for row in xrange(image.shape[1]):
96
        for col in xrange(image.shape[0]):
97
            low_ii = row + int(math.floor(displacement_field_x[row, col]))
98
            high_ii = row + int(math.ceil(displacement_field_x[row, col]))
99
100
            low_jj = col + int(math.floor(displacement_field_y[row, col]))
101
            high_jj = col + int(math.ceil(displacement_field_y[row, col]))
102
103
            if low_ii < 0 or low_jj < 0 or high_ii >= image.shape[1] -1 \
104
               or high_jj >= image.shape[0] - 1:
105
                continue
106
107
            res = image[low_ii, low_jj]/4 + image[low_ii, high_jj]/4 + \
108
                    image[high_ii, low_jj]/4 + image[high_ii, high_jj]/4
109
110
            result[row, col] = res
111
112
    return result