How to generate periodic noise of type Moiré in a grayscale image using Python?
How to generate periodic noise of type Moiré in a grayscale image using Python?
This was the solution I came up with (it may not be the most elegant, or the most efficient, but served its purpose):
from scipy import misc
import numpy as np
orig = misc.imread('bear_original.jpg')
sh = orig.shape[0], orig.shape[1]
noise = np.zeros(sh, dtype='float64')
X, Y = np.meshgrid(range(0, sh[0]), range(0, sh[1]))
A = 40
u0 = 45
v0 = 50
noise += A*np.sin(X*u0 + Y*v0)
A = -18
u0 = -45
v0 = 50
noise += A*np.sin(X*u0 + Y*v0)
noiseada = orig+noise
misc.imsave('bearnoise.jpg', noiseada)
Based on the concept of Moiré from Wikipedia and a little of Analytical Geometry , I created a small routine to apply the effect to an image overlapping with itself.
Follow the routine:
from PIL import Image
import math
def moire(source, target, angle, distance, offsetx = 2, offsety = 2):
#imagem de entrada
img = Image.open(source)
pm = img.load()
# imagem de saída (usando a mesma para gerar sobreposição)
imgout = Image.open(source)
pmout = imgout.load()
# valores para as transformações
cosseno = math.cos(angle)
seno = math.sin(angle)
# distância em cada eixo
dx = distance * cosseno
dy = distance * seno
for x in range(0, img.size[0], offsetx):
for y in range(0, img.size[1], offsety):
# calcula coordenada transformada (rotação + deslocamento)
x2, y2 = dx + math.floor(x * cosseno - y * seno), dy + math.floor(x * seno + y * cosseno)
# ajusta valores fora da imagem (como se a mesma repetisse infinitamente)
if x2 < 0:
x2 = img.size[0] + x2
elif x2 >= img.size[0]:
x2 = x2 - img.size[0]
if y2 < 0:
y2 = img.size[1] + y2
elif y2 >= img.size[1]:
y2 = y2 - img.size[1]
# desenha ponto transformado
pmout[x, y] = pm[x2, y2]
# salva a imagem
imgout.save(target)
Note that in the first line I do the import
of the Pillow image library.
Next is the function that receives the following parameters:
source
: input image target
: location where to save result angle
: moiré angle, that is, how much the image will be rotated distance
: distance of the moiré, that is, how much the image will be shifted from its origin in relation to the angle informed offsetx
: how often the moiré points will be applied in the x
coordinate, that is, the 1
value indicates that all pixels will be processed, the 2
value indicates that one pixel is simulated and another is not and so on. offsety
: idem to previous in coordinate y
Date the image:
# gira a imagem em 45º e aplica o efeito em todos os pontos
moire(r'linhas.png', r'linhas-output-1.png', math.pi / 4, 0, 1, 1)
# gira 30º, ponto sim, ponto não, e desloca 50 pixels nesse ângulo
moire(r'linhas.png', r'linhas-output-2.png', math.pi / 3, 50, 2, 2)
# gira 18º e desenha apenas a cada 5 pontos
moire(r'linhas.png', r'linhas-output-3.png', math.pi / 5, 0, 5, 5)