blob: 44a38c55c4d5f16dd5812bb2ac77414a1aae2422 [file] [log] [blame]
Jack Jansend35509a2000-09-22 12:46:19 +00001'''
2ImageMac.py by Trocca Riccardo (rtrocca@libero.it)
3This module provides functions to display images and Numeric arrays
4It provides two classes ImageMacWin e NumericMacWin and two simple methods showImage and
5showNumeric.
6
7They work like this:
8showImage(Image,"optional window title",zoomFactor)
9the same for showNumeric
10zoomfactor (defaults to 1) allows to zoom in the image by a factor of 1x 2x 3x and so on
11I did't try with a 0.5x or similar.
12The windows don't provide a scrollbar or a resize box.
13Probably a better solution (and more similar to the original implementation in PIL and NumPy)
14would be to save a temp file is some suitable format and then make an application (through appleevents) to open it.
15Good guesses should be GraphicConverter or PictureViewer.
16
17However the classes ImageMacWin e NumericMacWin use an extended version of PixMapWrapper in order to
18provide an image buffer and then blit it in the window.
19
20Being one of my first experiences with Python I didn't use Exceptions to signal error conditions, sorry.
21
22'''
23import W
Jack Jansen5a6fdcd2001-08-25 12:15:04 +000024from Carbon import Qd
Jack Jansend35509a2000-09-22 12:46:19 +000025from ExtPixMapWrapper import *
26from Numeric import *
27import Image
28import macfs
29
30class ImageMacWin(W.Window):
31
32 def __init__(self,size=(300,300),title="ImageMacWin"):
33 self.pm=ExtPixMapWrapper()
34 self.empty=1
35 self.size=size
36 W.Window.__init__(self,size,title)
37
38 def Show(self,image,resize=0):
39 #print "format: ", image.format," size: ",image.size," mode: ",image.mode
40 #print "string len :",len(image.tostring())
41 self.pm.fromImage(image)
42 self.empty=0
43 if resize:
44 self.size=(image.size[0]*resize,image.size[1]*resize)
45 W.Window.do_resize(self,self.size[0],self.size[1],self.wid)
46 self.do_drawing()
47
48 def do_drawing(self):
49 #print "do_drawing"
50 self.SetPort()
51 Qd.RGBForeColor( (0,0,0) )
52 Qd.RGBBackColor((65535, 65535, 65535))
53 Qd.EraseRect((0,0,self.size[0],self.size[1]))
54 if not self.empty:
55 #print "should blit"
56 self.pm.blit(0,0,self.size[0],self.size[1])
57
58 def do_update(self,macoswindowid,event):
59 #print "update"
60 self.do_drawing()
61
62class NumericMacWin(W.Window):
63
64 def __init__(self,size=(300,300),title="ImageMacWin"):
65 self.pm=ExtPixMapWrapper()
66 self.empty=1
67 self.size=size
68 W.Window.__init__(self,size,title)
69
70 def Show(self,num,resize=0):
71 #print "shape: ", num.shape
72 #print "string len :",len(num.tostring())
73 self.pm.fromNumeric(num)
74 self.empty=0
75 if resize:
76 self.size=(num.shape[1]*resize,num.shape[0]*resize)
77 W.Window.do_resize(self,self.size[0],self.size[1],self.wid)
78 self.do_drawing()
79
80 def do_drawing(self):
81 #print "do_drawing"
82 self.SetPort()
83 Qd.RGBForeColor( (0,0,0) )
84 Qd.RGBBackColor((65535, 65535, 65535))
85 Qd.EraseRect((0,0,self.size[0],self.size[1]))
86 if not self.empty:
87 #print "should blit"
88 self.pm.blit(0,0,self.size[0],self.size[1])
89
90 def do_update(self,macoswindowid,event):
91 #print "update"
92 self.do_drawing()
93
94'''
95Some utilities: convert an Image to a NumPy array and viceversa.
96The Image2Numeric function doesn't make any color space conversion.
97The Numeric2Image function returns an L or RGB or RGBA images depending on the shape of
98the array:
99 (x,y) -> 'L'
100 (x,y,1) -> 'L'
101 (x,y,3) -> 'RGB'
102 (x,y,4) -> 'RGBA'
103'''
104def Image2Numeric(im):
105 tmp=fromstring(im.tostring(),UnsignedInt8)
106
107 if (im.mode=='RGB')|(im.mode=='YCbCr'):
108 bands=3
109
110 if (im.mode=='RGBA')|(im.mode=='CMYK'):
111 bands=4
112
113 if (im.mode=='L'):
114 bands=1
115
116 tmp.shape=(im.size[0],im.size[1],bands)
117 return transpose(tmp,(1,0,2))
118
119def Numeric2Image(num):
120 #sometimes a monoband image's shape can be (x,y,1), other times just (x,y). Here w deal with both
121 if len(num.shape)==3:
122 bands=num.shape[2]
123 if bands==1:
124 mode='L'
125 elif bands==3:
126 mode='RGB'
127 else:
128 mode='RGBA'
129 return Image.fromstring(mode,(num.shape[1],num.shape[0]),transpose(num,(1,0,2)).astype(UnsignedInt8).tostring())
130 else:
131 return Image.fromstring('L',(num.shape[1],num.shape[0]),transpose(num).astype(UnsignedInt8).tostring())
132
133def showImage(im,title="ImageWin",zoomFactor=1):
134 imw=ImageMacWin((300,200),title)
135 imw.open()
136 try:
137 imw.Show(im,zoomFactor )
138 except MemoryError,e:
139 imw.close()
140 print "ImageMac.showImage: Insufficient Memory"
141
142
143def showNumeric(num,title="NumericWin",zoomFactor=1):
144 #im=Numeric2Image(num)
145 numw=NumericMacWin((300,200),title)
146 numw.open()
147 try:
148 numw.Show(num,zoomFactor )
149 except MemoryError:
150 numw.close()
151 print "ImageMac.showNumeric Insufficient Memory"
152
153'''
154GimmeImage pops up a file dialog and asks for an image file.
155it returns a PIL image.
156Optional argument: a string to be displayed by the dialog.
157'''
158
159def GimmeImage(prompt="Image File:"):
160 import macfs
161 fsspec, ok = macfs.PromptGetFile(prompt)
162 if ok:
163 path = fsspec.as_pathname()
164 return Image.open(path)
165 return None
166
167'''
168This is just some experimental stuff:
169 Filter3x3 a convolution filter (too slow use signal tools instead)
170 diffBWImage subtracts 2 images contained in NumPy arrays
171 averageN it computes the average of a list incrementally
172 BWImage converts an RGB or RGBA image (in a NumPy array) to BW
173 SplitBands splits the bands of an Image (inside a NumPy)
174 NumHisto and PlotHisto are some experiments to plot an intesity histogram
175'''
176
177def Filter3x3(mul,fi,num):
178 (a,b,c,d,e,f,g,h,i)=fi
179 print fi
180 num.shape=(num.shape[0],num.shape[1])
181 res=zeros(num.shape)
182 for x in range(1,num.shape[0]-1):
183 for y in range(1,num.shape[1]-1):
184 xb=x-1
185 xa=x+1
186 yb=y-1
187 ya=y+1
188 res[x,y]=int((a*num[xb,yb]+b*num[x,yb]+c*num[xa,yb]+d*num[xb,y]+e*num[x,y]+f*num[xa,y]+g*num[xb,ya]+h*num[x,ya]+i*num[xa,ya])/mul)
189 return res
190
191def diffBWImage(num1,num2):
192 return 127+(num1-num2)/2
193
194def averageN(N,avrg,new):
195 return ((N-1)*avrg+new)/N
196
197def BWImage(num):
198 if num.shape[2]==3:
199 bw=array(((0.3086,0.6094,0.0820)))
200 else:
201 bw=array(((0.3086,0.6094,0.0820,0)))
202 res=innerproduct(num,bw)
203 res.shape=(res.shape[0],res.shape[1])
204 return res
205
206def SplitBands(num):
207 x=num.shape[0]
208 y=num.shape[1]
209 if num.shape[2]==3:
210 return (reshape(num[:,:,0],(x,y)),reshape(num[:,:,1],(x,y)),reshape(num[:,:,2],(x,y)))
211 else:
212 return (reshape(num[:,:,0],(x,y)),reshape(num[:,:,1],(x,y)),reshape(num[:,:,2],(x,y)),reshape(num[:,:,3],(x,y)))
213
214def NumHisto(datas):
215 #print "type(datas) ",type(datas)
216 a=ravel(datas)
217 n=searchsorted(sort(a),arange(0,256))
218 n=concatenate([n,[len(a)]])
219 return n[1:]-n[:-1]
220
221def PlotHisto(datas,ratio=1):
222 from graphite import *
223 from MLab import max
224 h=NumHisto(datas)
225 #print "histo: ",h
226 #print "histo.shape: ",h.shape
227 maxval=max(h)
228 #print "maxval ",maxval
229 h.shape=(256,1)
230 x=arange(0,256)
231 x.shape=(256,1)
232 datah=concatenate([x,h],1)
233 print "data: "
234 print datah
235 g=Graph()
236 g.datasets.append(Dataset(datah))
237 f0=PointPlot()
238 f0.lineStyle = LineStyle(width=2, color=red, kind=SOLID)
239 g.formats = [f0]
240 g.axes[X].range = [0,255]
241 g.axes[X].tickMarks[0].spacing = 10
242 #g.axes[X].tickMarks[0].labels = "%d"
243 g.axes[Y].range = [0,maxval/ratio]
244 g.bottom = 370
245 g.top =10
246 g.left=10
247 g.right=590
248
249 genOutput(g,'QD',size=(600,400))
250
251def test():
252 import MacOS
253 import Image
254 import ImageFilter
255 import Numeric
256 fsspec, ok = macfs.PromptGetFile("Image File:")
257 if ok:
258 path = fsspec.as_pathname()
259 im=Image.open(path)
260 #im2=im.filter(ImageFilter.SMOOTH)
261 showImage(im,"normal")
262 num=Image2Numeric(im)
263 #num=Numeric.transpose(num,(1,0,2))
264
265 showNumeric(num,"Numeric")
266
267 print "num.shape ",num.shape
268 showImage(Numeric2Image(num),"difficile")
269 #showImage(im.filter(ImageFilter.SMOOTH),"smooth")
270 #showImage(im.filter(ImageFilter.FIND_EDGES).filter(ImageFilter.SHARPEN),"detail")
271
272 print "here"
273 else:
274 print "did not open file"
275
276if __name__ == '__main__':
277 test()