better makefile
[imago.git] / src / 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 import numpy as np
9
10 import pcf
11
12 def color_enhance(image):
13     """Stretch all color channels to their full range."""
14     image_l = image.load()
15     min_r, min_g, min_b = 999, 999, 999
16     max_r, max_g, max_b = -1, -1, -1
17
18     for x in xrange(image.size[0]):
19         for y in xrange(image.size[1]):
20             min_r = min(min_r, image_l[x, y][0])
21             max_r = max(max_r, image_l[x, y][0])
22             min_g = min(min_g, image_l[x, y][1])
23             max_g = max(max_g, image_l[x, y][1])
24             min_b = min(min_b, image_l[x, y][2])
25             max_b = max(max_b, image_l[x, y][2])
26
27     new_image = Image.new('RGB', image.size)
28     new_image_l = new_image.load()
29     for x in xrange(image.size[0]):
30         for y in xrange(image.size[1]):
31             r, g, b = image_l[x, y]
32             r = (r - min_r) * 255 / (max_r - min_r)
33             g = (g - min_g) * 255 / (max_g - min_g)
34             b = (b - min_b) * 255 / (max_b - min_b)
35             new_image_l[x, y] = (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     for x in range(2, image.size[0] - 2):
54         for y in range(2, image.size[1] - 2):
55             pix = (sum([sum([
56                 - image_l[a, b] 
57                     for b in range(y - 2, y + 3)]) 
58                     for a in range(x - 2, x + 3)])
59                 + (17 * image_l[x, y]))
60             if pix > 255:
61                 pix = 255
62             if pix < 0:
63                 pix = 0 
64             new_image_l[x, y] = pix
65     return new_image
66
67 def high_pass(image, height):
68     """High pass filter (on BW images)."""
69     image_l = image.load()
70     new_image = Image.new('L', image.size)
71     new_image_l = new_image.load()
72     
73     for x in xrange(image.size[0]):
74         for y in xrange(image.size[1]):
75             if image_l[x, y] < height:
76                 new_image_l[x, y] = 0
77             else:
78                 new_image_l[x, y] = image_l[x, y]
79
80     return new_image
81
82 def components(image, diameter):
83     # TODO comment 
84     # TODO refactor
85     image_l = image.load()
86     new_image_l = np.zeros(image.size, dtype=np.int)
87
88     components = [None]
89     comp_counter = 1
90
91     if diameter == 1:
92         for y in xrange(1, image.size[1] - 1):
93             for x in xrange(1, image.size[0] - 1):
94                 if image_l[x, y]:
95                     s = {0}
96                     s.add(new_image_l[x - 1, y - 1])
97                     s.add(new_image_l[x, y - 1])
98                     s.add(new_image_l[x + 1, y - 1])
99                     s.add(new_image_l[x - 1, y])
100                     if len(s) == 1:
101                         components.append(set())
102                         new_image_l[x, y] = comp_counter
103                         components[comp_counter].add((x, y))
104                         comp_counter += 1
105                     elif len(s) == 2:
106                         s.remove(0)
107                         c = s.pop()
108                         new_image_l[x, y] = c
109                         components[c].add((x, y))
110                     else:
111                         s.remove(0)
112                         c1, c2 = s.pop(), s.pop()
113                         components[c2].add((x, y))
114                         for (x1, y1) in components[c2]:
115                             new_image_l[x1, y1] = c1
116                         components[c1] = components[c1] | components[c2]
117                         components[c2] = None
118     elif diameter == 2:
119         for y in xrange(2, image.size[1] - 2):
120             for x in xrange(2, image.size[0] - 2):
121                 if image_l[x, y]:
122
123                     s = {0}
124                     for (a, b) in [(a,b) for a in range(x - 2, x + 3) 
125                               for b in range(y - 2, y + 1)]:
126                         if not (b == y and a >= x):
127                             s.add(new_image_l[a, b])
128
129                     if len(s) == 1:
130                         components.append(set())
131                         new_image_l[x, y] = comp_counter
132                         components[comp_counter].add((x, y))
133                         comp_counter += 1
134                     elif len(s) == 2:
135                         s.remove(0)
136                         c = s.pop()
137                         new_image_l[x, y] = c
138                         try:
139                             components[c].add((x, y))
140                         except AttributeError:
141                             print s, c
142                             raise AttributeError
143                     else:
144                         s.remove(0)
145                         c1 = s.pop()
146                         components[c1].add((x, y))
147                         new_image_l[x, y] = c1
148                         for c2 in s:
149                             for (x1, y1) in components[c2]:
150                                 new_image_l[x1, y1] = c1
151                             components[c1] = components[c1] | components[c2]
152                             components[c2] = None
153     else:
154         pass #TODO error
155
156
157     new_image = Image.new('L', image.size)
158     new_image_l = new_image.load()
159
160     for component in components:
161         if component:
162             x_c = 0
163             y_c = 0
164             c = 0
165             for (x, y) in component:
166                 x_c += x
167                 y_c += y
168                 c += 1
169             new_image_l[int(round(float(x_c)/c)), int(round(float(y_c)/c))] = 255
170
171     return new_image
172