comments for filters
[imago.git] / imago_pack / filters.py
1 """Image filters module.
2
3 All filters return a filtered copy of the image, the original image is
4 preserved.
5 """
6
7 from PIL import Image, ImageFilter
8
9 import pcf
10
11 def color_enhance(image):
12     """Stretch all color channels to their full range."""
13     image_l = image.load()
14     min_r, min_g, min_b = 999, 999, 999
15     max_r, max_g, max_b = -1, -1, -1
16
17     for x in xrange(image.size[0]):
18         for y in xrange(image.size[1]):
19             min_r = min(min_r, image_l[x, y][0])
20             max_r = max(max_r, image_l[x, y][0])
21             min_g = min(min_g, image_l[x, y][1])
22             max_g = max(max_g, image_l[x, y][1])
23             min_b = min(min_b, image_l[x, y][2])
24             max_b = max(max_b, image_l[x, y][2])
25
26     new_image = Image.new('RGB', image.size)
27     new_image_l = new_image.load()
28     for x in xrange(image.size[0]):
29         for y in xrange(image.size[1]):
30             r, g, b = image_l[x, y]
31             r = (r - min_r) * 255 / (max_r - min_r)
32             g = (g - min_g) * 255 / (max_g - min_g)
33             b = (b - min_b) * 255 / (max_b - min_b)
34             new_image_l[x, y] = (r, g, b)
35            # print min_r, max_r, r, g, b
36
37     return new_image
38
39 def edge_detection(image):
40     """Edge detection (on BW images)."""
41     new_image = image.filter(ImageFilter.GaussianBlur())
42     # GaussianBlur is undocumented class, it might not work in future versions
43     # of PIL
44     new_image = Image.fromstring('L', image.size,
45                              pcf.edge(image.size, image.tostring()))
46     return new_image
47
48 def peaks(image):
49     """Peak filter (on BW images)."""
50     image_l = image.load()
51     new_image = Image.new('L', image.size)
52     new_image_l = new_image.load()
53     
54     for x in range(2, image.size[0] - 2):
55         for y in range(2, image.size[1] - 2):
56             pix = (sum([sum([
57                 - image_l[a, b] 
58                     for b in range(y - 2, y + 3)]) 
59                     for a in range(x - 2, x + 3)])
60                 + (17 * image_l[x, y]))
61             if pix > 255:
62                 pix = 255
63             if pix < 0:
64                 pix = 0 
65             new_image_l[x, y] = pix
66     return new_image
67
68 def high_pass(image, height):
69     """High pass filter (on BW images)."""
70     image_l = image.load()
71     new_image = Image.new('L', image.size)
72     new_image_l = new_image.load()
73     
74     for x in xrange(image.size[0]):
75         for y in xrange(image.size[1]):
76             if image_l[x, y] < height:
77                 new_image_l[x, y] = 0
78             else:
79                 new_image_l[x, y] = image_l[x, y]
80
81     return new_image
82
83 # TODO factor these into one method
84 # TODO comment it
85 def components(image):
86     image_l = image.load()
87     new_image = Image.new('L', image.size)
88     new_image_l = new_image.load()
89
90     components = [None]
91     comp_counter = 1
92
93     for y in xrange(1, image.size[1] - 1):
94         for x in xrange(1, image.size[0] - 1):
95             if image_l[x, y]:
96                 s = {0}
97                 s.add(new_image_l[x - 1, y - 1])
98                 s.add(new_image_l[x, y - 1])
99                 s.add(new_image_l[x + 1, y - 1])
100                 s.add(new_image_l[x - 1, y])
101                 if len(s) == 1:
102                     components.append(set())
103                     new_image_l[x, y] = comp_counter
104                     components[comp_counter].add((x, y))
105                     comp_counter += 1
106                 elif len(s) == 2:
107                     s.remove(0)
108                     c = s.pop()
109                     new_image_l[x, y] = c
110                     components[c].add((x,y))
111                 else:
112                     s.remove(0)
113                     c1, c2 = s.pop(), s.pop()
114                     components[c2].add((x, y))
115                     for (x1, y1) in components[c2]:
116                         new_image_l[x1, y1] = c1
117                     components[c1] = components[c1] | components[c2]
118                     components[c2] = None
119
120     new_image = Image.new('L', image.size)
121     new_image_l = new_image.load()
122
123     for component in components:
124         if component:
125             x_c = 0
126             y_c = 0
127             c = 0
128             for (x, y) in component:
129                 x_c += x
130                 y_c += y
131                 c += 1
132             new_image_l[int(round(float(x_c)/c)), int(round(float(y_c)/c))] = 255
133
134     return new_image
135
136 def components2(image):
137     image_l = image.load()
138     new_image = Image.new('L', image.size)
139     new_image_l = new_image.load()
140
141     components = [None]
142     comp_counter = 1
143
144     for y in xrange(2, image.size[1] - 2):
145         for x in xrange(2, image.size[0] - 2):
146             if image_l[x, y]:
147
148                 s = {0}
149                 for (a, b) in [(a,b) for a in range(x - 2, x + 3) 
150                           for b in range(y - 2, y + 1)]:
151                     if not (b == y and a >= x):
152                         s.add(new_image_l[a, b])
153
154                 if len(s) == 1:
155                     components.append(set())
156                     new_image_l[x, y] = comp_counter
157                     components[comp_counter].add((x, y))
158                     comp_counter += 1
159                 elif len(s) == 2:
160                     s.remove(0)
161                     c = s.pop()
162                     new_image_l[x, y] = c
163                     components[c].add((x,y))
164                 else:
165                     s.remove(0)
166                     c1 = s.pop()
167                     components[c1].add((x, y))
168                     new_image_l[x, y] = c1
169                     for c2 in s:
170                         for (x1, y1) in components[c2]:
171                             new_image_l[x1, y1] = c1
172                         components[c1] = components[c1] | components[c2]
173                         components[c2] = None
174
175     new_image = Image.new('L', image.size)
176     new_image_l = new_image.load()
177
178     for component in components:
179         if component:
180             x_c = 0
181             y_c = 0
182             c = 0
183             for (x, y) in component:
184                 x_c += x
185                 y_c += y
186                 c += 1
187             new_image_l[int(round(float(x_c)/c)), int(round(float(y_c)/c))] = 255
188
189     return new_image