From d35509a82d8fc1cb41ac9f10755f359e60a339a4 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Fri, 22 Sep 2000 12:46:19 +0000 Subject: [PATCH] Contributed modules by Riccardo Trocca. Extended pixmap wrapper, NumPy visualiser and QuickTime to images. --- Mac/Contrib/ImageHelpers/ExtPixMapWrapper.py | 46 +++ Mac/Contrib/ImageHelpers/ImageMac.py | 277 +++++++++++++++++++ Mac/Contrib/ImageHelpers/MovieUtils.py | 269 ++++++++++++++++++ Mac/Contrib/ImageHelpers/ReadMe | 22 ++ 4 files changed, 614 insertions(+) create mode 100644 Mac/Contrib/ImageHelpers/ExtPixMapWrapper.py create mode 100644 Mac/Contrib/ImageHelpers/ImageMac.py create mode 100644 Mac/Contrib/ImageHelpers/MovieUtils.py create mode 100644 Mac/Contrib/ImageHelpers/ReadMe diff --git a/Mac/Contrib/ImageHelpers/ExtPixMapWrapper.py b/Mac/Contrib/ImageHelpers/ExtPixMapWrapper.py new file mode 100644 index 00000000000..ac261b5d37b --- /dev/null +++ b/Mac/Contrib/ImageHelpers/ExtPixMapWrapper.py @@ -0,0 +1,46 @@ +''' +A really quick and dirty hack to extend PixMapWrapper +They are mere copies of the toImage and fromImage methods. +Riccardo Trocca (rtrocca@libero.it) +''' +from PixMapWrapper import * +import Numeric + +class ExtPixMapWrapper(PixMapWrapper): + + def toNumeric(self): + + data = self.tostring()[1:] + chr(0) + bounds = self.bounds + tmp=Numeric.fromstring(data,Numeric.UnsignedInt8) + #tmp.shape=(bounds[3]-bounds[1],bounds[2]-bounds[0],4) + tmp.shape=(bounds[2]-bounds[0],bounds[3]-bounds[1],4) + return Numeric.transpose(tmp,(1,0,2)) + + def fromNumeric(self,num): + s=num.shape + x=num.shape[1] + y=num.shape[0] + #bands=1 Greyscale image + #bands=3 RGB image + #bands=4 RGBA image + if len(s)==2: + bands=1 + num=Numeric.resize(num,(y,x,1)) + else: + bands=num.shape[2] + + if bands==1: + num=Numeric.concatenate((num,num,num),2) + bands=3 + if bands==3: + alpha=Numeric.ones((y,x))*255 + alpha.shape=(y,x,1) + num=Numeric.concatenate((num,alpha),2) + + data=chr(0)+Numeric.transpose(num,(1,0,2)).astype(Numeric.UnsignedInt8).tostring() + PixMapWrapper.fromstring(self,data,x,y) + + + + diff --git a/Mac/Contrib/ImageHelpers/ImageMac.py b/Mac/Contrib/ImageHelpers/ImageMac.py new file mode 100644 index 00000000000..3e465325c3f --- /dev/null +++ b/Mac/Contrib/ImageHelpers/ImageMac.py @@ -0,0 +1,277 @@ +''' +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 +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() \ No newline at end of file diff --git a/Mac/Contrib/ImageHelpers/MovieUtils.py b/Mac/Contrib/ImageHelpers/MovieUtils.py new file mode 100644 index 00000000000..7c9130f1c41 --- /dev/null +++ b/Mac/Contrib/ImageHelpers/MovieUtils.py @@ -0,0 +1,269 @@ +import Qt +import QuickTime +import macfs +import Qd +from QuickDraw import srcCopy +from ExtPixMapWrapper import ExtPixMapWrapper +from Qdoffs import * +import ImageMac +import W + + + + +def GetFrames(m): + frameCount=0 + theTime=0 + type=QuickTime.VideoMediaType + #type='MPEG' + flags=QuickTime.nextTimeMediaSample + flags=flags+QuickTime.nextTimeEdgeOK + + while theTime>=0: + (theTime,duration)=m.GetMovieNextInterestingTime(flags,1,type,theTime,0) + #print "theTime ",theTime," duration ",duration + frameCount=frameCount+1 + flags = QuickTime.nextTimeMediaSample + + + return frameCount-1 + +def GetMovieFromOpenFile(): + fss, ok = macfs.StandardGetFile(QuickTime.MovieFileType) + mov = None + if ok: + movieResRef = Qt.OpenMovieFile(fss, 1) + mov, d1, d2 = Qt.NewMovieFromFile(movieResRef, 0, QuickTime.newMovieActive) + + return mov + + +class ExtMovie: + def __init__(self,mov): + + self.frames=0 + self.frameArray=[] + self.movie=mov + self._countFrames() + r=self.movie.GetMovieBox() + self.myRect=(0,0,r[2]-r[0],r[3]-r[1]) + self.movie.SetMovieBox(self.myRect) + self.pm=ExtPixMapWrapper() + self.pm.left=0 + self.pm.top=0 + self.pm.right=r[2]-r[0] + self.pm.bottom=r[3]-r[1] + self.gw=NewGWorld(32,self.myRect,None,None,0) + self.movie.SetMovieGWorld(self.gw.as_GrafPtr(), self.gw.GetGWorldDevice()) + self.GotoFrame(0) + + def _countFrames(self): + #deve contare il numero di frame, creare un array con i tempi per ogni frame + theTime=0 + #type=QuickTime.VIDEO_TYPE + type=QuickTime.VideoMediaType + flags=QuickTime.nextTimeMediaSample+QuickTime.nextTimeEdgeOK + + while theTime>=0: + (theTime,duration)=self.movie.GetMovieNextInterestingTime(flags,1,type,theTime,0) + self.frameArray.append((theTime,duration)) + flags = QuickTime.nextTimeMediaSample + self.frames=self.frames+1 + + + + def GotoFrame(self,n): + if n<=self.frames: + self.curFrame=n + (port,device)=GetGWorld() + SetGWorld(self.gw.as_GrafPtr(),None) + (self.now,self.duration)=self.frameArray[n] + self.movie.SetMovieTimeValue(self.now) + pixmap=self.gw.GetGWorldPixMap() + + if not LockPixels(pixmap): + print "not locked" + else: + + #Qd.EraseRect(self.myRect) + #this draws the frame inside the current gworld + self.movie.MoviesTask(0) + #this puts it in the buffer pixmap + self.pm.grab(0,0,self.myRect[2],self.myRect[3]) + UnlockPixels(pixmap) + #self.im=self.pm.toImage() + SetGWorld(port,device) + + def NextFrame(self): + self.curFrame=self.curFrame+1 + if self.curFrame>self.frames: + self.curFrame=0 + self.GotoFrame(self.curFrame) + + def isLastFrame(): + return self.curFrame==self.frames + + + def GetImage(self): + return self.pm.toImage() + + def GetImageN(self,n): + self.GotoFrame(n) + return self.pm.toImage() + + def GetNumeric(self): + return self.pm.toNumeric() + + def GetNumericN(self,n): + self.GotoFrame(n) + return self.pm.toNumeric() + + def Blit(self,destRect): + Qd.RGBForeColor( (0,0,0) ) + Qd.RGBBackColor((65535, 65535, 65535)) + + #Qd.MoveTo(10,10) + #Qd.LineTo(200,150) + Qd.CopyBits(self.gw.portBits,Qd.GetPort().portBits,self.myRect,destRect,srcCopy,None) + +class MovieWin(W.Window): + + def __init__(self,eMovie,title="MovieWin"): + self.ExtMovie=eMovie + +def test(): + import ImageFilter + from MLab import max + from MLab import min + from Numeric import * + Qt.EnterMovies() + m=GetMovieFromOpenFile() + em=ExtMovie(m) + print "Total frames:",em.frames," Current frame:",em.curFrame + #ImageMac.showImage(em.GetImage(),"frame 0",1) + #em.GotoFrame(500) + #ImageMac.showImage(em.GetImage().filter(ImageFilter.SMOOTH),"frame 500",2) + #ImageMac.showImage(em.GetImageN(1000),"frame 1000",2) + #r=array(((1,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0))) + #g=array(((0,0,0,0),(0,1,0,0),(0,0,0,0),(0,0,0,0))) + #b=array(((0,0,0,0),(0,0,0,0),(0,0,1,0),(0,0,0,0))) + #bw=array(((0.3086,0.6094,0.0820,0))) + #r2=array(((1,0,0,0))) + #ImageMac.showNumeric(em.GetNumericN(0),"frame 0",1) + #print em.GetNumericN(500).shape + #print "original (1,1)",em.GetNumericN(0)[100,100] + #print "product shape ",innerproduct(em.GetNumericN(0),r).shape + #print "product (1,1) ",innerproduct(em.GetNumericN(0),r)[100,100] + + #ImageMac.showNumeric(ImageMac.BWImage(em.GetNumericN(50))) + #ImageMac.showNumeric(innerproduct(em.GetNumericN(500),r),"frame 500r",2) + #ImageMac.showNumeric(innerproduct(em.GetNumericN(500),g),"frame 500g",2) + #ImageMac.showNumeric(innerproduct(em.GetNumericN(500),b),"frame 500b",2) + + #ImageMac.showNumeric(innerproduct(em.GetNumericN(500),r2),"frame 500r2",2) + #ImageMac.showNumeric(innerproduct(em.GetNumericN(10),bw),"frame 0bw",1) + #ImageMac.showNumeric(innerproduct(em.GetNumericN(400),bw),"frame 10bw",1) + #colordif=(em.GetNumericN(100)-em.GetNumericN(10))+(255,255,255,255) + #colordif=colordif/2 + #ImageMac.showNumeric(colordif,"colordif",1) + #ImageMac.showNumeric(ImageMac.BWImage(colordif),"bwcolordif",1) + ilut=arange(0,256) + #ilut[118]=255 + #ilut[119]=255 + #ilut[120]=255 + ilut[121]=255 + ilut[122]=255 + ilut[123]=255 + ilut[124]=255 + ilut[125]=255 + ilut[126]=255 + ilut[127]=255 + ilut[128]=255 + ilut[129]=255 + #ilut[130]=255 + #ilut[131]=255 + #ilut[132]=255 + mlut=ones(256) + mlut[118]=0 + mlut[119]=0 + mlut[120]=0 + mlut[121]=0 + mlut[122]=0 + mlut[123]=0 + mlut[124]=0 + mlut[125]=0 + mlut[126]=0 + mlut[127]=0 + mlut[128]=0 + mlut[129]=0 + mlut[130]=0 + mlut[131]=0 + mlut[132]=0 + + ImageMac.showImage(em.GetImageN(100),"provaImg",2) + ImageMac.showNumeric(em.GetNumericN(100),"provaNum",2) + ImageMac.showImage(em.GetImageN(100).filter(ImageFilter.SMOOTH),"frame 500",2) + #image=ImageMac.BWImage(em.GetNumericN(100)) + #ImageMac.showNumeric(image) + + + + + + + + + #difimage=abs(image-ImageMac.BWImage(em.GetNumericN(10))) + #ImageMac.PlotHisto(difimage,32) + #ImageMac.showNumeric(difimage) + #difimage=127+(image-ImageMac.BWImage(em.GetNumericN(10)))/2 + #ImageMac.PlotHisto(difimage,32) + #ImageMac.showNumeric(difimage) + #fimage=ImageMac.Filter3x3(16.0,(1,1,1,1,8,1,1,1,1),difimage) + #ImageMac.showNumeric(fimage) + #difimage2=choose(fimage.astype(UnsignedInt8),ilut) + #ImageMac.showNumeric(difimage2) + + #(r,g,b,a)=ImageMac.SplitBands(em.GetNumericN(10)) + #ImageMac.showNumeric(r,"r") + #ImageMac.showNumeric(g,"g") + #ImageMac.showNumeric(b,"b") + #ImageMac.showNumeric(a,"a") + #bwdif=abs(((innerproduct(em.GetNumericN(400),bw)-innerproduct(em.GetNumericN(10),bw))+255)/2) + #ImageMac.showNumeric(bwdif,"frame diff/bw",1) + #ImageMac.PlotHisto(bwdif) + #ImageMac.showNumeric(choose(bwdif.astype(UnsignedInt8),ilut),"frame diff/bw",1) + #ImageMac.PlotHisto(choose(bwdif.astype(UnsignedInt8),ilut)) + #bwimage=ImageMac.BWImage(em.GetNumericN(100)) + #ImageMac.showNumeric((ImageMac.BWImage(em.GetNumericN(90))+ImageMac.BWImage(em.GetNumericN(110))+ImageMac.BWImage(em.GetNumericN(130))+ImageMac.BWImage(em.GetNumericN(150))+ImageMac.BWImage(em.GetNumericN(170)))/5) + #bwdif=abs(((bwimage-ImageMac.BWImage(em.GetNumericN(10)))+255)/2) + #ImageMac.showNumeric(bwimage,"original frame",1) + #ImageMac.showNumeric(bwdif,"frame diff/bw",1) + #ImageMac.PlotHisto(bwdif) + #ImageMac.showNumeric(choose(bwdif.astype(UnsignedInt8),ilut),"frame diff/bw",1) + #mmask=choose(bwdif.astype(UnsignedInt8),mlut) + #ImageMac.showNumeric(255-255*mmask,"frame diff/bw",1) + #mmask.shape=bwimage.shape + #ImageMac.showNumeric(mmask*bwimage,"frame diff/bw",1) + + #ImageMac.showNumeric((innerproduct(em.GetNumericN(300),bw)-innerproduct(em.GetNumericN(0),bw)),"frame diff/bw",1) + #ImageMac.showNumeric((innerproduct(em.GetNumericN(400)-em.GetNumericN(10),bw)),"frame diff2/bw",1) + #cdif=em.GetNumericN(400)-em.GetNumericN(10) + #ImageMac.showNumeric(,"frame diff2/bw",1) + + #ImageMac.showNumeric(innerproduct(cdif,r),"frame 500r",1) + #ImageMac.showNumeric(innerproduct(cdif,g),"frame 500g",1) + #ImageMac.showNumeric(innerproduct(cdif,b),"frame 500b",1) +def test2(): + Qt.EnterMovies() + m=GetMovieFromOpenFile() + if m==None: + print "no movie opened" + else: + em=ExtMovie(m) + print "Total frames: ",em.frames," Current frame:",em.curFrame + ImageMac.showImage(em.GetImage(),"frame 0",1) + +if __name__ == '__main__': + test2() + \ No newline at end of file diff --git a/Mac/Contrib/ImageHelpers/ReadMe b/Mac/Contrib/ImageHelpers/ReadMe new file mode 100644 index 00000000000..b6267f75621 --- /dev/null +++ b/Mac/Contrib/ImageHelpers/ReadMe @@ -0,0 +1,22 @@ +ExtPixMapWrapper.py +ImageMac.py +Hello these are the classes to deal with Images and NumPy arrays I told +you about. I left everything unchanged, it is the same copy I use with +comments added. However I think that in ImageMac the only part worth including +in MacPython (if you think it is worth), is the first half, until GimmeImage. +After that it is almost rubbish I used in my CV experiments. + +MovieUtils.py +This is another class I use. IT contais a lot of my experiments (unuseful), but +the first function GetFrames(). it is almost the translation of a QT sample. +GetMovieFromOpenFile() it is the usual shortcut to get a movie. (no error tracking +done). +The class ExtMovie requires a movie in the constructor and then +provides a method to take every single frame and convert it to an +Image or a NUmPy array. +If you think that it can be included in the qt examples I'll write comments and +polish it a bit. (exceptions handling) + + Riccardo Trocca + +P.S. Everything works with 2.0b1