Skip to content

Commit 720149d

Browse files
committed
First Version
1 parent 83414bd commit 720149d

File tree

5 files changed

+307
-1
lines changed

5 files changed

+307
-1
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
*.pyc
2+
*~
3+
.ropeproject/
4+
*.jpg

EffectLab/Effect.py

+252
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
#!/usr/bin/env python
2+
# author: Hua Liang [ Stupid ET ]
3+
4+
# website: http://EverET.org
5+
#
6+
7+
import random, string, md5, time
8+
import Image, ImageDraw, ImageFont, ImageChops, ImageFilter
9+
import StringIO
10+
import math, operator
11+
12+
# Filters that input Image and output Image
13+
#
14+
15+
class Effect(object):
16+
'''The base Effect
17+
All Effects have a member function called "filter"
18+
which receives a PIL Image and return a PIL Image
19+
'''
20+
name = 'Base Effect'
21+
empty_color = (128, 128, 128, 255)
22+
def __init__(self):
23+
pass
24+
25+
def __call__(self, img):
26+
'''The effect can act like a filter function'''
27+
return self.filter(img)
28+
29+
def filter(self, img):
30+
return img
31+
32+
33+
class GlobalWarpEffect(Effect):
34+
'''Warping Effect Base class.
35+
provide basic warping framework
36+
'''
37+
name = 'Warp Effect'
38+
39+
def __init__(self, formula, antialias=2):
40+
self.formula = formula
41+
self.antialias = antialias
42+
43+
def filter(self, img):
44+
'''Effect Kernel of radius based Effect.
45+
@param formula is a function like f(x, y) => (x', y'), -1 <= x <= 1 and -1 <= y <= 1
46+
'''
47+
width, height = img.size
48+
nx, ny = width, height
49+
new_img = img.copy()
50+
nband = len(img.getpixel((0, 0)))
51+
for j in range(height):
52+
for i in range(width):
53+
found = 0
54+
psum = (0, ) * nband
55+
new_img.putpixel((i, j), Effect.empty_color)
56+
# antialias
57+
for ai in range(self.antialias):
58+
x = 2 * (i + ai / float(self.antialias)) / width - 1
59+
for aj in range(self.antialias):
60+
y = 2 * (j + aj / float(self.antialias)) / height - 1
61+
62+
# distortion
63+
xnew, ynew = self.formula(x, y)
64+
65+
i2 = int(round(0.5 * nx * (xnew + 1)))
66+
j2 = int(round(0.5 * ny * (ynew + 1)))
67+
68+
if not (0 <= i2 < nx and 0 <= j2 < ny):
69+
continue
70+
71+
pt = img.getpixel((i2, j2))
72+
psum = map(operator.add, psum, pt)
73+
found += 1
74+
75+
if found > 0:
76+
psum = map(operator.div, psum, (self.antialias * self.antialias, ) * len(psum))
77+
new_img.putpixel((i, j), tuple(psum))
78+
79+
return new_img
80+
81+
82+
class RadianFormulaEffect(Effect):
83+
'''Transform the Image according to the input formula
84+
@note The formula is a function like f(r, phi) => (r, phi)
85+
which r is radius and phi is radian angel.
86+
'''
87+
name = 'Radian Formula Effect'
88+
89+
def __init__(self, formula, antialias=2):
90+
self.formula = formula
91+
self.antialias = antialias
92+
93+
def filter(self, img):
94+
def radian_formula(x, y):
95+
'''transform formula
96+
func is a function that like f(r, phi) => (r, phi)
97+
'''
98+
r = math.sqrt(x ** 2 + y ** 2)
99+
phi = math.atan2(y, x)
100+
101+
r, phi = self.formula(r, phi)
102+
103+
xnew = r * math.cos(phi)
104+
ynew = r * math.sin(phi)
105+
106+
return xnew, ynew
107+
108+
warp = GlobalWarpEffect(radian_formula, self.antialias)
109+
return warp(img)
110+
111+
112+
class RadianSqrtEffect(RadianFormulaEffect):
113+
name = 'r = sqrt(r)'
114+
def __init__(self):
115+
super(RadianSqrtEffect, self).__init__(
116+
lambda r, phi: (math.sqrt(r), phi))
117+
118+
119+
class WaveEffect(Effect):
120+
name = 'Wave Effect'
121+
def __init__(self, vertical_delta=0.1, horizon_delta=0, box=None):
122+
self.vertical_delta = vertical_delta
123+
self.horizon_delta = horizon_delta
124+
self.box = box
125+
126+
def filter(self, img):
127+
if self.box == None:
128+
left, top = 0, 0
129+
right, bottom = img.size[0] - 1, img.size[1] - 1
130+
else:
131+
left, top, right, bottom = self.box
132+
133+
width, height = img.size
134+
135+
mid_x = (right + left) / 2.0
136+
mid_y = (top + bottom) / 2.0
137+
138+
new_img = img.copy()
139+
height_delta = (bottom - top + 1) * self.vertical_delta
140+
width_delta = 2 * math.pi / (right - left + 1) * (self.horizon_delta + 1)
141+
for x in range(left, right):
142+
degree = x * width_delta
143+
for y in range(top, bottom):
144+
h = math.sin(degree) * height_delta * ((bottom - top) / 2 - math.sqrt((y - mid_y) ** 2 + (x - mid_x) ** 2)) / mid_y
145+
offset = int(round(h))
146+
if 0 < x < width and 0 < y + offset < height:
147+
new_img.putpixel((x, y), img.getpixel((x, y + offset)))
148+
else:
149+
new_img.putpixel((x, y), Effect.empty_color)
150+
151+
return new_img
152+
153+
154+
class EffectGlue(Effect):
155+
name = 'Effect Glue'
156+
def __init__(self, name=None):
157+
self.name = name if name else EffectGlue.name
158+
self.effect_pipeline = []
159+
160+
def append(self, effect):
161+
self.effect_pipeline.append(effect)
162+
163+
def remove(self, effect):
164+
self.effect_pipeline.remove(effect)
165+
166+
def insert(self, index, effect):
167+
self.effect_pipeline.insert(index, Effect)
168+
169+
def pop(self):
170+
return self.effect_pipeline.pop()
171+
172+
def filter(self, img):
173+
for f in self.effect_pipeline:
174+
img = f.filter(img)
175+
return img
176+
177+
178+
class GridMaker(Effect):
179+
name = 'Grid Maker'
180+
def __init__(self, width_offset, height_offset, color=(0, 0, 0, 255)):
181+
self.width_offset = width_offset
182+
self.height_offset = height_offset
183+
self.color = color
184+
185+
def filter(self, img):
186+
width, height = img.size
187+
188+
# draw grid
189+
draw = ImageDraw.Draw(img)
190+
for x in range(0, width, self.width_offset):
191+
draw.line((x, 0, x, height), self.color)
192+
for y in range(0, height, self.height_offset):
193+
draw.line((0, y, width, y), self.color)
194+
195+
del draw
196+
return img
197+
198+
199+
class TextWriter(Effect):
200+
name = 'Text Writer'
201+
def __init__(self, (x, y), text, color=(0, 0, 0, 255), font=None):
202+
self.x = x
203+
self.y = y
204+
self.text = text
205+
self.color = color
206+
207+
def filter(self, img):
208+
draw = ImageDraw.Draw(img)
209+
draw.text((self.x, self.y), self.text, self.color)
210+
del draw
211+
return img
212+
213+
214+
def GenerateImage(effect):
215+
# draw img
216+
# img = Image.open('z.jpg')
217+
img = Image.new("RGBA", (300, 300), (255, 255, 255, 255))
218+
219+
width, height = img.size
220+
221+
grid = GridMaker(20, 20)
222+
text = TextWriter((10, 100), string.letters)
223+
224+
img = grid.filter(text.filter(img))
225+
226+
old = img.copy()
227+
228+
img = effect(img)
229+
230+
out = Image.new("RGBA", (width * 2, height))
231+
out.paste(old, (0, 0))
232+
out.paste(img, (width, 0))
233+
draw = ImageDraw.Draw(out)
234+
235+
draw.line((width, 0, width, height), (255, 0, 0, 255))
236+
237+
out.save('haha.png')
238+
239+
def sign(v):
240+
return 1 if v >= 0 else -1
241+
242+
if __name__ == '__main__':
243+
wave = WaveEffect(0.2, 0.5, (100, 50, 200, 200))
244+
sqrt = RadianSqrtEffect()
245+
effect = RadianFormulaEffect(lambda r, phi: (r ** 1.2, phi))
246+
effect = RadianFormulaEffect(lambda r, phi: (r ** 1.5 * math.cos(r), phi))
247+
effect = RadianFormulaEffect(lambda r, phi: (r, phi + 0.5))
248+
effect = GlobalWarpEffect(lambda x, y: (x + 0.1, y))
249+
effect = GlobalWarpEffect(lambda x, y: (math.sin(x * math.pi / 2), math.sin(y * math.pi / 2)))
250+
effect = GlobalWarpEffect(lambda x, y: (sign(x) * x ** 2, sign(y) * y ** 2))
251+
effect = RadianFormulaEffect(lambda r, phi: (r ** 2, phi), 4)
252+
GenerateImage(effect)

EffectLab/__init__.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/usr/bin/env python
2+
# author: Hua Liang [ Stupid ET ]
3+
4+
# website: http://EverET.org
5+
#
6+
7+
import Effect

README.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
EffectLab
22
=========
33

4-
EffectLab is an image processing laboratory written by Python for agilely testing algorithm.
4+
EffectLab is an image processing laboratory written by Python for agilely testing algorithm.
5+
6+
Author: Hua Liang [Stupid ET]
7+
Website: http://EverET.org
8+

TestEffectLab.py

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/usr/bin/env python
2+
# author: Hua Liang [ Stupid ET ]
3+
4+
# website: http://EverET.org
5+
#
6+
7+
from EffectLab.Effect import *
8+
9+
def make_origin_and_new(img, effect):
10+
'''Merge origin and new Image processed by function effect in one Image
11+
'''
12+
width, height = img.size
13+
grid = GridMaker(20, 20)
14+
old = grid(img)
15+
img = effect(old)
16+
17+
# merge origin and new image
18+
out = Image.new("RGBA", (width * 2, height))
19+
out.paste(old, (0, 0))
20+
out.paste(img, (width, 0))
21+
draw = ImageDraw.Draw(out)
22+
23+
draw.line((width, 0, width, height), (255, 0, 0, 255))
24+
25+
return out
26+
27+
if __name__ == '__main__':
28+
effects = [WaveEffect(0.2, 0.5, (100, 50, 200, 200)),
29+
RadianSqrtEffect(),
30+
RadianFormulaEffect(lambda r, phi: (r ** 1.5 * math.cos(r), phi)),
31+
GlobalWarpEffect(lambda x, y: (math.sin(x * math.pi / 2), math.sin(y * math.pi / 2))),
32+
GlobalWarpEffect(lambda x, y: (sign(x) * x ** 2, sign(y) * y ** 2)),
33+
RadianFormulaEffect(lambda r, phi: (r ** 2, phi), 4),]
34+
#img = Image.open('z.jpg')
35+
img = Image.new("RGBA", (300, 300), (255, 255, 255, 255))
36+
for index, effect in enumerate(effects):
37+
make_origin_and_new(img, effect).save('%d.jpg' % index, quality=90)
38+
print '.',
39+
print 'done'

0 commit comments

Comments
 (0)