Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Image distortion

I'm trying to apply a ripple effect to an image in python. I found Pillow's im.transform(im.size, Image.MESH,.... is it possible? Maybe I have to load the image with numpy and apply the algorithm. I also found this: http://www.pygame.org/project-Water+Ripples-1239-.html

ripple

another way manually but I don't know any algorithm. this is my start. it doesn't do anything...

    #!/usr/bin/env python3

    from PIL import Image
    import sys
    import numpy
    import math

    im = Image.open(sys.argv[1])
    im.show()

    matrix = numpy.asarray(im)
    width = im.size[0]
    height = im.size[1]
    amplitude = ? # parameters
    frequency = ?
    matrix_dest = numpy.zeros((im.size[0],im.size[1],3))

    for x in range(0, width):
        for y in range(0, height):
            pass # ç_ç

    im2 = Image.fromarray(numpy.uint8(matrix_dest))
    im2.show()

EDIT:

I'd really like to keep this structure (using pillow. I already use extensivly in my project and if I can I wouldn't add any other dependency) and not including scipi or matplotlib.. With the following code I have the distortion I wanted, but colors are screwed up. Maybe I have to apply the distortion to R,G,B planes and then compose the result in one image. Or palettize the image and then apply the original palette.

(Btw the image would be used as a texture to display moving water in a 3D environment.)

im = Image.open(sys.argv[1])
im.show()

m = numpy.asarray(im)
m2 = numpy.zeros((im.size[0],im.size[1],3))
width = im.size[0]
height = im.size[1]

A = m.shape[0] / 3.0
w = 1.0 / m.shape[1]

shift = lambda x: A * numpy.sin(2.0*numpy.pi*x * w)

for i in range(m.shape[0]):
    print(int(shift(i)))
    m2[:,i] = numpy.roll(m[:,i], int(shift(i)))

im2 = Image.fromarray(numpy.uint8(m2))
im2.show()
like image 392
roarc Avatar asked Feb 21 '14 17:02

roarc


2 Answers

You could use np.roll to rotate each row or column according to some sine function.

from scipy.misc import lena
import numpy as np
import matplotlib.pyplot as plt

img = lena()

A = img.shape[0] / 3.0
w = 2.0 / img.shape[1]

shift = lambda x: A * np.sin(2.0*np.pi*x * w)

for i in range(img.shape[0]):
    img[:,i] = np.roll(img[:,i], int(shift(i)))

plt.imshow(img, cmap=plt.cm.gray)
plt.show()

enter image description here

like image 53
M4rtini Avatar answered Sep 19 '22 13:09

M4rtini


Why don't you try something like:

# import scipy
# import numpy as np
for x in range(cols):
    column = im[:,x]
    y = np.floor(sin(x)*10)+10
    kernel = np.zeros((20,1))
    kernel[y] = 1
    scipy.ndimage.filters.convolve(col,kernel,'nearest')

I threw this together just right now, so you'll need to tweak it a bit. The frequency of the sin is definitely too high, check here. But I think overall this should work.

like image 24
wbest Avatar answered Sep 20 '22 13:09

wbest