I've posted many times on this blog, my experiments in image generation through Python. I've been working on what I call my "Noisefield" project, where I generated a bitmap with random black and white pixels. I have now done something similar, except this time I generated a black to white gradient, using the PIL library in Python.
import time | |
import random | |
from PIL import Image | |
LINE = [] | |
for i in range(256): | |
LINE.append(i) | |
MATRIX = LINE*256 | |
nixel = iter(MATRIX) | |
def noisefield(): | |
im = Image.new("L", (256, 256)) | |
for x in range(256): | |
for y in range(256): | |
im.putpixel((x, y), next(nixel)) | |
im.save('<FILEPATH>'+time.strftime('%Y%m%d%H%M%S')+".png") | |
im.show() | |
noisefield() |
The idea is pretty simple. You create a vector or array of values from 0 to 255, then you repeat that 256 times, to make a square matrix, or bitmap (because Python puts in the pixels from top-left downwards and towards the right, line by line). So that way you get a gradient. I took the "LINE" variable that I created with a for loop and range() function and then multiplied it by 256 in a variable called MATRIX. I then used an iterator function on the Matrix which I called in the image-generation function by calling next(MATRIX). The result is a smooth matrix.
ADDENDUM: I have found a simpler way of generating a black to white gradient, using the np.linspace function in Numpy.
import numpy as np | |
from PIL import Image | |
# gradient between 0 and 1 for 256*256 | |
array = np.linspace(0,1,256*256) | |
# reshape to 2d | |
mat = np.reshape(array,(256,256)) | |
# Creates and saves PIL image | |
img = Image.fromarray(np.uint8(mat * 255) , 'L') | |
img.save('/FILEPATH/Gradient.jpg') | |
# OR img.show() | |
''' | |
# If you want to create a 512 pixel by 512 pixel image instead: | |
>>> array = np.linspace(0,1,256*256) | |
>>> array = np.repeat(array, 4) | |
>>> len(array) | |
262144 | |
>>> mat = np.reshape(array,(512,512)) | |
>>> img = Image.fromarray(np.uint8(mat*255), 'L') | |
>>> img.save('/FILEPATH/Gradient.jpg') | |
# OR img.show() | |
''' |
FOR YOUR INFORMATION: I have written a few blog posts in the past about generating bitmaps with random black and white pixel values, or grey values between 0 and 255. I found a much quicker way to do this using the OpenCV library (cv2). (In passing, this np.random.randint() function gives the same results as the uniform_noise function below, in the second Gist below:
import cv2 | |
import numpy as np | |
noise = np.random.randint(0,256, size= (512, 512), dtype=np.uint8) | |
cv2.imwrite("Noise.jpg", noise) | |
''' | |
# OR JUST USE THE FOLLOWING: | |
import matplotlib.pyplot as plt | |
plt.imsave("Noise.jpg", noise, cmap='Greys') | |
''' |
Here's another way to generate noise, Gaussian noise in this case, via OpenCV (cv2). The Gaussian distribution is "smoother" in appearance, as it has mean 128 and standard deviation 20:
from PIL import Image | |
import cv2 | |
import numpy as np | |
image = Image.new(mode = "L", size = (512,512)) | |
image = np.array(image) | |
gaussian_noise = np.zeros((image.shape[0], image.shape[1]),dtype=np.uint8) | |
cv2.randn(gaussian_noise, 128, 20) | |
cv2.imwrite("GaussianRandomNoise.jpg",gaussian_noise) | |
''' | |
# OR FOR DIFFERENT DISTRIBUTION OF NOISE, WITH MEAN 0 AND STANDARD DEVIATION 256, USE: | |
>>> cv2.randn(gaussian_noise, 0, 256) | |
uniform_noise = np.zeros((image.shape[0], image.shape[1]),dtype=np.uint8) | |
# OR: | |
>>> cv2.randu(uniform_noise,0,255) | |
>>> cv2.imwrite("Uniform random noise.jpg",uniform_noise) | |
# OR: | |
>>> ret,impulse_noise = cv2.threshold(uniform_noise,250,255,cv2.THRESH_BINARY) | |
>>> cv2.imwrite("Impulse noise.jpg",impulse_noise) | |
''' |
With mean 0 and standard deviation 256, we get a "coarser" noise distribution:
As stated, the uniform_noise "randu" function gives the same result as the previous np.random.randint() function, a uniform noise distribution:
If I add the following, "ret,thresh1 = cv2.threshold(uniform_noise,64,255,cv2.THRESH_BINARY)" and then write "cv2.imwrite("Noise.jpg",thresh1)", I get a noisy distribution with many more whites, because of the threshold value being at 64. For every pixel, the same threshold value is applied. If the pixel value is smaller than the threshold, it is set to 0, otherwise it is set to a maximum value, in this case 255, which is pure white. This way it is possible to adjust the parseness if you will of the noisy distribution using the threshold function:
The opposite would be true if we set the treshold higher, to say 250. Then it's mostly black, or at a pixel value of 0:
No comments:
Post a Comment