## Here’s the backstory of this article:

I was working on a Computer Vision Project as a part of an internship and I needed a script which can generate custom B/W gradient images. By custom gradient, I mean images like this:

Along with the above structures, I also wanted to vary the spread of the gradient and combine different such structures to get the following samples:

I tried to search online but couldn’t find the solution which I really wanted. To help others like me, I decided to write this article. I use NumPy arrays with loops to generate such gradient images.

## Code:

Gradients are essentially uneven arrays of numbers. So first, we have to write a function for uneven array creation. Refer this for explanation:

# cross = True if cross crease is wanted | |

def create_uneven_array(low, up, steps, spacing=1, cross=False): | |

span = up – low | |

dx = 1.0 / steps | |

if cross: | |

arr = np.array([low + (i*dx)**spacing*span for i in range(steps//2)]) | |

return np.append(arr, arr[::–1]) | |

else : | |

arr = np.array([low + (i*dx)**spacing*span for i in range(steps)]) | |

return arr |

We can use this function for creating different types of gradients as follows:

def parabolic_crease(spacing, c, scale=100, corner=1, resolution = 1000): | |

“”” | |

Parameters: | |

spacing = controls how close the intermediate values will be to lower value | |

c = higher the c more spread out the gradient will be | |

scale = lesser the scale more concentrated is gradient towards the corner | |

“”” | |

img = np.zeros((resolution, resolution)) | |

# Varying the scale parameter of create_uneven_array will give the parabolic gradient transition | |

for i in range(resolution): | |

img[i] = create_uneven_array(255, 0, resolution, spacing + c*i/scale) | |

if corner == 1: | |

return img | |

elif corner == 2: | |

return img[::–1] | |

elif corner == 3: | |

return img.T | |

else: | |

return img.T[::–1] | |

# If cross=1, then cross crease else linear crease is returned | |

def cross_crease(spacing, cross=1, resolution = 1000): | |

a = create_uneven_array(255, 0, resolution, spacing, cross=True) | |

img = np.tile(a, (resolution, 1)) | |

return normalize_img(img*img.T) if cross else img |

Finally, we can write a function which returns a gradient of one of the above types with random parameters:

# Final function to return some random crease from 8 different types | |

def custom_crease(): | |

spacing = random.uniform(1, 1.5) | |

scale = random.randint(100, 300) | |

corner = random.randint(1, 4) | |

# constant determines the type of crease and also is used to scale spacing in parabolic_crease | |

constant = random.randint(1, 10) | |

# Returning those creases which are based on parabolic | |

parabolic = parabolic_crease(spacing, constant, scale, corner) | |

if constant == 1: | |

return parabolic | |

elif constant == 2: | |

return normalize_img(parabolic*parabolic.T*parabolic[::–1]*parabolic.T[::–1]) | |

# Returning those creases which are based on parabolic and cross | |

cross = cross_crease(spacing) | |

if constant == 3: | |

return cross | |

elif constant == 4: | |

return normalize_img(parabolic * cross) | |

elif constant == 5: | |

return normalize_img(cross * parabolic * parabolic.T) | |

# Returning those creases which are based on parabolic and linear | |

linear = cross_crease(spacing, 0) | |

if constant == 6: | |

return linear | |

elif constant == 7: | |

return linear.T | |

else: | |

return normalize_img(linear * parabolic) |

Finally, when we run the custom_gradient() function, it will return one of the gradient image type. Complete code is available in this notebook.

Thanks for reading 🙂

Have a nice day!