################################################################################ # # df3.py # # Copyright (C) 2005 Mike Kost # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # ################################################################################ # # Creation functions # __init__(x=1, y=1, z=1) : default constructor # clone(indf3) : make this df3 look like indf3 # # Info functions # sizeX(): returns X dimension # sizeY(): returns Y dimension # sizeZ(): returns Z dimension # # Scalar functions # mult(): # add(): # max(): returns highest voxel value in df3 # min(): returns lowest voxel value in df3 # # Vector functions # # Import/Export functions # exportDF3(): # importDF3(): # ################################################################################ import struct import os import stat import array import sys # -+-+-+- Start df3 Class -+-+-+- class df3: __version__ = '0.2' __arraytype__ = 'f' __struct4byte__ = '>I' __struct2byte__ = '>H' __struct2byte3__ = '>HHH' __struct1byte__ = '>B' __array4byte__ = 'I' __array2byte__ = 'H' __array1byte__ = 'B' def __init__(self, x=1, y=1, z=1): self.maxX = x self.maxY = y self.maxZ = z self.voxel = self.__create__(x, y, z) def clone(self, indf3): self.voxel = array.array(self.__arraytype__) for i in range(indf3.sizeX()*indf3.sizeY()*indf3.sizeZ()): self.voxel[i] = indf3.voxel[i] return self #### Info Functions def sizeX(self): return self.maxX def sizeY(self): return self.maxY def sizeZ(self): return self.maxZ def size(self): tmp = [] tmp.append(self.sizeX()) tmp.append(self.sizeY()) tmp.append(self.sizeZ()) return tmp #### Voxel Access Functions def get(self, x, y, z): return self.voxel[self.__voxa__(x,y,z)] def getB(self, x, y, z): if (x > self.sizeX() or x < 0): return 0 if (y > self.sizeX() or y < 0): return 0 if (z > self.sizeX() or z < 0): return 0 return self.voxel[self.__voxa__(x,y,z)] def set(self, x, y, z, val): self.voxel[self.__voxa__(x,y,z)] = val def setB(self, x, y, z, val): if (x > self.sizeX() or x < 0): return if (y > self.sizeX() or y < 0): return if (z > self.sizeX() or z < 0): return self.voxel[self.__voxa__(x,y,z)] = val #### Scalar Functions def mult(self, val): for i in range(self.sizeX()*self.sizeY()*self.sizeZ()): self.voxel[i] = self.voxel[i] * val return self def add(self, val): for i in range(self.sizeX()*self.sizeY()*self.sizeZ()): self.voxel[i] = self.voxel[i] + val return self def max(self): tmp = self.voxel[0] for i in range(self.sizeX()*self.sizeY()*self.sizeZ()): if (self.voxel[i] > tmp): tmp = self.voxel[i] return tmp def min(self): tmp = self.voxel[0] for i in range(self.sizeX()*self.sizeY()*self.sizeZ()): if (self.voxel[i] < tmp): tmp = self.voxel[i] return tmp #### Vector Functions def compare(self, indf3): if (self.__samesize__(indf3) == 0): return 0 if (self.voxel == indf3.voxel): return 1 return 0 def multV(self, indf3): if (self.__samesize__(indf3) == 0): print("Cannot multiply voxels - not same size") return for i in range(self.sizeX()*self.sizeY()*self.sizeZ()): self.voxel[i] = self.voxel[i]*indf3.voxel[i] return self def addV(self, indf3): if (self.__samesize__(indf3) == 0): print("Cannot add voxels - not same size") return for i in range(self.sizeX()*self.sizeY()*self.sizeZ()): self.voxel[i] = self.voxel[i]+indf3.voxel[i] return self def convolveV(self, filt): fx = filt.sizeX() fy = filt.sizeY() fz = filt.sizeZ() if (fx % 2 != 1): print("Incompatible filter - must be odd number of X") return self if (fy % 2 != 1): print("Incompatible filter - must be odd number of Y") return self if (fz % 2 != 1): print("Incompatible filter - must be odd number of Z") return self fdx = (fx-1)/2 fdy = (fy-1)/2 fdz = (fz-1)/2 flen = fx*fy*fz newV = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ()); for x in range(self.sizeX()): for y in range(self.sizeY()): for z in range(self.sizeZ()): rip = self.__rip__(x-fdx, x+fdx, y-fdy, y+fdy, z-fdz, z+fdz) tmp = 0.0 for i in range(flen): tmp += rip[i]*filt.voxel[i] newV[self.__voxa__(x,y,z)] = tmp self.voxel = newV return self #### Import/Export Functions def exportDF3(self, file, depth=8, rescale=1): x = self.sizeX() y = self.sizeY() z = self.sizeZ() try: f = open(file, 'wb'); except: print("Could not open " + file + " for write"); return f.write(struct.pack(self.__struct2byte3__, x, y, z)); tmp = self.__toInteger__(pow(2,depth)-1, rescale) if (depth > 16): # 32-bit for i in range( x*y*z ): f.write(struct.pack(self.__struct4byte__, tmp[i])) elif (depth > 8): # 16-bit for i in range( x*y*z ): f.write(struct.pack(self.__struct2byte__, tmp[i])) else: for i in range( x*y*z ): f.write(struct.pack(self.__struct1byte__, tmp[i])) def importDF3(self, file, scale=1): try: f = open(file, 'rb'); size = os.stat(file)[stat.ST_SIZE] except: print("Could not open " + file + " for read"); return [] (x, y, z) = struct.unpack(self.__struct2byte3__, f.read(6) ) self.voxel = self.__create__(x, y, z) self.maxX = x self.maxY = y self.maxZ = z size = size-6 if (size == x*y*z): format = 8 elif (size == 2*x*y*z): format = 16 elif (size == 4*x*y*z): format = 32 if (format == 32): for i in range(x*y*z): self.voxel[i] = float(struct.unpack(self.__struct4byte__, f.read(4) )[0]) elif (format == 16): for i in range(x*y*z): self.voxel[i] = float(struct.unpack(self.__struct2byte__, f.read(2) )[0]) elif (format == 8): for i in range(x*y*z): self.voxel[i] = float(struct.unpack(self.__struct1byte__, f.read(1) )[0]) return self #### Local classes not intended for user use def __rip__(self, minX, maxX, minY, maxY, minZ, maxZ): sizeX = maxX-minX+1 sizeY = maxY-minY+1 sizeZ = maxZ-minZ+1 tmpV = self.__create__(sizeX, sizeY, sizeZ) for x in range(sizeX): for y in range(sizeY): for z in range(sizeZ): # Check X if ((minX + x) < 0): tmpV[(z*sizeZ+y)*sizeY+x] = 0.0 elif ((minX + x) > self.sizeX()-1): tmpV[(z*sizeZ+y)*sizeY+x] = 0.0 # Check Y elif ((minY + y) < 0): tmpV[(z*sizeZ+y)*sizeY+x] = 0.0 elif ((minY + y) > self.sizeY()-1): tmpV[(z*sizeZ+y)*sizeY+x] = 0.0 # Check Z elif ((minZ + z) < 0): tmpV[(z*sizeZ+y)*sizeY+x] = 0.0 elif ((minZ + z) > self.sizeZ()-1): tmpV[(z*sizeZ+y)*sizeY+x] = 0.0 else: tmpV[(z*sizeZ+y)*sizeY+x] = self.get(minX+x,minY+y,minZ+z) return tmpV def __samesize__(self, indf3): if (self.sizeX() != indf3.sizeX()): return 0 if (self.sizeY() != indf3.sizeY()): return 0 if (self.sizeZ() != indf3.sizeZ()): return 0 return 1 def __voxa__(self, x, y, z): return ((z*self.sizeY()+y)*self.sizeX()+x) def __create__(self, x, y, z, atype='0', init=1): if (atype == '0'): tmp = self.__arraytype__ else: tmp = atype if (init == 1): if tmp in ('f','d'): voxel = array.array(tmp, [0.0 for i in range(x*y*z)]) else: voxel = array.array(tmp, [0 for i in range(x*y*z)]) else: voxel = array.array(tmp) return voxel def __toInteger__(self, scale, rescale=1): if (scale < pow(2,8)): # 8-bit tmp = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ(), self.__array1byte__) elif (scale < pow(2,16)): # 16-bit tmp = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ(), self.__array2byte__) else: # 32-bit tmp = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ(), self.__array4byte__) maxVal = self.max() print(scale) for i in range(self.sizeX()*self.sizeY()*self.sizeZ()): if (rescale == 1): tmp[i] = max(0,int(round(scale*self.voxel[i]/maxVal))) else: tmp[i] = max(0,min(scale,int(round(self.voxel[i])))) return tmp # -=-=-=- End df3 Class -=-=-=- ##########DEFAULT EXAMPLES # if __name__ == '__main__': # localX = 80 # localY = 90 # localZ = 100 ## Generate an output # temp = df3(localX, localY, localZ) # for i in range(localX): # for j in range(localY): # for k in range(localZ): # if (i >= (localX/2)): # temp.set(i, j, k, 1.0) # temp.exportDF3('temp.df3', 16) ############################################################################### ## Import # temp2 = df3().importDF3('temp.df3') # temp2.mult(1/temp2.max()) ## Compare # print(temp2.size()) # if (temp.compare(temp2) == 0): print("DF3's Do Not Match") ############################################################################### # ChangeLog # --------- # 08/09/05: 0.20 released # + Change internal representation to floating point # + Rewrite import/export for speed # + Convert from 3-d list structure to Array class for data storage # + Add element access, scalar, and vector functions # 07/13/05: 0.10 released ###############################################################################