1+ '''
2+ ImageMac.py by Trocca Riccardo ([email protected] ) 3+ This module provides functions to display images and Numeric arrays
4+ It provides two classes ImageMacWin e NumericMacWin and two simple methods showImage and
5+ showNumeric.
6+
7+ They work like this:
8+ showImage(Image,"optional window title",zoomFactor)
9+ the same for showNumeric
10+ zoomfactor (defaults to 1) allows to zoom in the image by a factor of 1x 2x 3x and so on
11+ I did't try with a 0.5x or similar.
12+ The windows don't provide a scrollbar or a resize box.
13+ Probably a better solution (and more similar to the original implementation in PIL and NumPy)
14+ would be to save a temp file is some suitable format and then make an application (through appleevents) to open it.
15+ Good guesses should be GraphicConverter or PictureViewer.
16+
17+ However the classes ImageMacWin e NumericMacWin use an extended version of PixMapWrapper in order to
18+ provide an image buffer and then blit it in the window.
19+
20+ Being one of my first experiences with Python I didn't use Exceptions to signal error conditions, sorry.
21+
22+ '''
23+ import W
24+ import Qd
25+ from ExtPixMapWrapper import *
26+ from Numeric import *
27+ import Image
28+ import macfs
29+
30+ class 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+
62+ class 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+ '''
95+ Some utilities: convert an Image to a NumPy array and viceversa.
96+ The Image2Numeric function doesn't make any color space conversion.
97+ The Numeric2Image function returns an L or RGB or RGBA images depending on the shape of
98+ the array:
99+ (x,y) -> 'L'
100+ (x,y,1) -> 'L'
101+ (x,y,3) -> 'RGB'
102+ (x,y,4) -> 'RGBA'
103+ '''
104+ def 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+
119+ def 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+
133+ def 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+
143+ def 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+ '''
154+ GimmeImage pops up a file dialog and asks for an image file.
155+ it returns a PIL image.
156+ Optional argument: a string to be displayed by the dialog.
157+ '''
158+
159+ def 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+ '''
168+ This 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+
177+ def 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+
191+ def diffBWImage (num1 ,num2 ):
192+ return 127 + (num1 - num2 )/ 2
193+
194+ def averageN (N ,avrg ,new ):
195+ return ((N - 1 )* avrg + new )/ N
196+
197+ def 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+
206+ def 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+
214+ def 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+
221+ def 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+
251+ def 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+
276+ if __name__ == '__main__' :
277+ test ()
0 commit comments