''' ImageMac.py by Trocca Riccardo (rtrocca@libero.it) This module provides functions to display images and Numeric arrays It provides two classes ImageMacWin e NumericMacWin and two simple methods showImage and showNumeric. They work like this: showImage(Image,"optional window title",zoomFactor) the same for showNumeric zoomfactor (defaults to 1) allows to zoom in the image by a factor of 1x 2x 3x and so on I did't try with a 0.5x or similar. The windows don't provide a scrollbar or a resize box. Probably a better solution (and more similar to the original implementation in PIL and NumPy) would be to save a temp file is some suitable format and then make an application (through appleevents) to open it. Good guesses should be GraphicConverter or PictureViewer. However the classes ImageMacWin e NumericMacWin use an extended version of PixMapWrapper in order to provide an image buffer and then blit it in the window. Being one of my first experiences with Python I didn't use Exceptions to signal error conditions, sorry. ''' import W from Carbon import Qd from ExtPixMapWrapper import * from Numeric import * import Image import macfs class ImageMacWin(W.Window): def __init__(self,size=(300,300),title="ImageMacWin"): self.pm=ExtPixMapWrapper() self.empty=1 self.size=size W.Window.__init__(self,size,title) def Show(self,image,resize=0): #print "format: ", image.format," size: ",image.size," mode: ",image.mode #print "string len :",len(image.tostring()) self.pm.fromImage(image) self.empty=0 if resize: self.size=(image.size[0]*resize,image.size[1]*resize) W.Window.do_resize(self,self.size[0],self.size[1],self.wid) self.do_drawing() def do_drawing(self): #print "do_drawing" self.SetPort() Qd.RGBForeColor( (0,0,0) ) Qd.RGBBackColor((65535, 65535, 65535)) Qd.EraseRect((0,0,self.size[0],self.size[1])) if not self.empty: #print "should blit" self.pm.blit(0,0,self.size[0],self.size[1]) def do_update(self,macoswindowid,event): #print "update" self.do_drawing() class NumericMacWin(W.Window): def __init__(self,size=(300,300),title="ImageMacWin"): self.pm=ExtPixMapWrapper() self.empty=1 self.size=size W.Window.__init__(self,size,title) def Show(self,num,resize=0): #print "shape: ", num.shape #print "string len :",len(num.tostring()) self.pm.fromNumeric(num) self.empty=0 if resize: self.size=(num.shape[1]*resize,num.shape[0]*resize) W.Window.do_resize(self,self.size[0],self.size[1],self.wid) self.do_drawing() def do_drawing(self): #print "do_drawing" self.SetPort() Qd.RGBForeColor( (0,0,0) ) Qd.RGBBackColor((65535, 65535, 65535)) Qd.EraseRect((0,0,self.size[0],self.size[1])) if not self.empty: #print "should blit" self.pm.blit(0,0,self.size[0],self.size[1]) def do_update(self,macoswindowid,event): #print "update" self.do_drawing() ''' Some utilities: convert an Image to a NumPy array and viceversa. The Image2Numeric function doesn't make any color space conversion. The Numeric2Image function returns an L or RGB or RGBA images depending on the shape of the array: (x,y) -> 'L' (x,y,1) -> 'L' (x,y,3) -> 'RGB' (x,y,4) -> 'RGBA' ''' def Image2Numeric(im): tmp=fromstring(im.tostring(),UnsignedInt8) if (im.mode=='RGB')|(im.mode=='YCbCr'): bands=3 if (im.mode=='RGBA')|(im.mode=='CMYK'): bands=4 if (im.mode=='L'): bands=1 tmp.shape=(im.size[0],im.size[1],bands) return transpose(tmp,(1,0,2)) def Numeric2Image(num): #sometimes a monoband image's shape can be (x,y,1), other times just (x,y). Here w deal with both if len(num.shape)==3: bands=num.shape[2] if bands==1: mode='L' elif bands==3: mode='RGB' else: mode='RGBA' return Image.fromstring(mode,(num.shape[1],num.shape[0]),transpose(num,(1,0,2)).astype(UnsignedInt8).tostring()) else: return Image.fromstring('L',(num.shape[1],num.shape[0]),transpose(num).astype(UnsignedInt8).tostring()) def showImage(im,title="ImageWin",zoomFactor=1): imw=ImageMacWin((300,200),title) imw.open() try: imw.Show(im,zoomFactor ) except MemoryError,e: imw.close() print "ImageMac.showImage: Insufficient Memory" def showNumeric(num,title="NumericWin",zoomFactor=1): #im=Numeric2Image(num) numw=NumericMacWin((300,200),title) numw.open() try: numw.Show(num,zoomFactor ) except MemoryError: numw.close() print "ImageMac.showNumeric Insufficient Memory" ''' GimmeImage pops up a file dialog and asks for an image file. it returns a PIL image. Optional argument: a string to be displayed by the dialog. ''' def GimmeImage(prompt="Image File:"): import macfs fsspec, ok = macfs.PromptGetFile(prompt) if ok: path = fsspec.as_pathname() return Image.open(path) return None ''' This is just some experimental stuff: Filter3x3 a convolution filter (too slow use signal tools instead) diffBWImage subtracts 2 images contained in NumPy arrays averageN it computes the average of a list incrementally BWImage converts an RGB or RGBA image (in a NumPy array) to BW SplitBands splits the bands of an Image (inside a NumPy) NumHisto and PlotHisto are some experiments to plot an intesity histogram ''' def Filter3x3(mul,fi,num): (a,b,c,d,e,f,g,h,i)=fi print fi num.shape=(num.shape[0],num.shape[1]) res=zeros(num.shape) for x in range(1,num.shape[0]-1): for y in range(1,num.shape[1]-1): xb=x-1 xa=x+1 yb=y-1 ya=y+1 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) return res def diffBWImage(num1,num2): return 127+(num1-num2)/2 def averageN(N,avrg,new): return ((N-1)*avrg+new)/N def BWImage(num): if num.shape[2]==3: bw=array(((0.3086,0.6094,0.0820))) else: bw=array(((0.3086,0.6094,0.0820,0))) res=innerproduct(num,bw) res.shape=(res.shape[0],res.shape[1]) return res def SplitBands(num): x=num.shape[0] y=num.shape[1] if num.shape[2]==3: return (reshape(num[:,:,0],(x,y)),reshape(num[:,:,1],(x,y)),reshape(num[:,:,2],(x,y))) else: return (reshape(num[:,:,0],(x,y)),reshape(num[:,:,1],(x,y)),reshape(num[:,:,2],(x,y)),reshape(num[:,:,3],(x,y))) def NumHisto(datas): #print "type(datas) ",type(datas) a=ravel(datas) n=searchsorted(sort(a),arange(0,256)) n=concatenate([n,[len(a)]]) return n[1:]-n[:-1] def PlotHisto(datas,ratio=1): from graphite import * from MLab import max h=NumHisto(datas) #print "histo: ",h #print "histo.shape: ",h.shape maxval=max(h) #print "maxval ",maxval h.shape=(256,1) x=arange(0,256) x.shape=(256,1) datah=concatenate([x,h],1) print "data: " print datah g=Graph() g.datasets.append(Dataset(datah)) f0=PointPlot() f0.lineStyle = LineStyle(width=2, color=red, kind=SOLID) g.formats = [f0] g.axes[X].range = [0,255] g.axes[X].tickMarks[0].spacing = 10 #g.axes[X].tickMarks[0].labels = "%d" g.axes[Y].range = [0,maxval/ratio] g.bottom = 370 g.top =10 g.left=10 g.right=590 genOutput(g,'QD',size=(600,400)) def test(): import MacOS import Image import ImageFilter import Numeric fsspec, ok = macfs.PromptGetFile("Image File:") if ok: path = fsspec.as_pathname() im=Image.open(path) #im2=im.filter(ImageFilter.SMOOTH) showImage(im,"normal") num=Image2Numeric(im) #num=Numeric.transpose(num,(1,0,2)) showNumeric(num,"Numeric") print "num.shape ",num.shape showImage(Numeric2Image(num),"difficile") #showImage(im.filter(ImageFilter.SMOOTH),"smooth") #showImage(im.filter(ImageFilter.FIND_EDGES).filter(ImageFilter.SHARPEN),"detail") print "here" else: print "did not open file" if __name__ == '__main__': test()