Changeset 2461


Ignore:
Timestamp:
04/05/07 18:09:38 (12 years ago)
Author:
mggr
Message:

(mggr checking in for mhen and hoping not to mess up): ongoing development

Location:
TI02-CSML/branches/csml-pml
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • TI02-CSML/branches/csml-pml/csmllibs/NumericTransform.py

    r2460 r2461  
    77# TODO: Currently quite intolerent of incorrect syntax. 
    88# TODO: Implementation of shunting yard too opaque. Possibly rewrite. 
     9# 
     10# Change History 
     11# 2007-05-04 mhen Modified to handle Numeric arrays 
    912 
    1013from math import * 
     
    6366      elif(t == '(' or (t in _symbols and 'prec' not in _symbols[t])):            
    6467         s.append(t) # Function, constant or left parenthesis token. 
    65       elif(t == ')' or t == ','):  
     68      elif(t == ')' or t == ','): # right paren or func separator token.  
    6669         while(len(s)>0 and s[len(s)-1] != '('): 
    6770            q.append(s.pop()) 
     
    8790def isNumericString(candidate): 
    8891   try: float(candidate) 
    89    except: return False 
     92   except ValueError: return False 
    9093   return True 
    9194 
     
    9598      self.tokens = expression.split() 
    9699 
    97    # Solve the tokenised postfix expression stored in self.tokens list and 
     100   # Solve the tokenised postfix expression stored in self.tokens and 
    98101   # return the solution (or None if no solution could be found) 
    99102   def solve(self, **variables): 
     
    124127    
    125128 
    126 # Test: 
     129# Regression Test: 
    127130if __name__ == "__main__": 
    128131   expression_str = " (10* (sqrt(16) + 3) - 20)*x/10^2+-0.42  " 
  • TI02-CSML/branches/csml-pml/csmllibs/csmldataiface.py

    r2460 r2461  
    535535 
    536536 
     537   # Read the data from the raw file into a multidimensional Numeric array 
    537538   def readFile(self, **kwargs): 
    538       # index into an array that determines the type based on various 
    539       # combinations of settings in the CSML.  This is very clever, but 
    540       # rather obscure.. blame mhen :p 
    541       format_index = 0 
    542  
    543       if kwargs['type'] == 'float': 
    544          format_index |= 12 # Float: Set bit 2 (float) and bit 3 (signed) 
    545       elif kwargs['signedness'] != 'unsigned': 
    546          format_index |= 8  # Signed Int: set bit 3 (signed) 
    547           
    548       # Set bits 0 and 1 depending on whether the data are 8, 16, 32 or 64  
    549       # bits wide. 
    550       if kwargs['depth'] in [8,16,32,64]: 
    551          format_index |= [8,16,32,64].index(kwargs['depth']) 
    552           
    553       # Set the endianness of the format string. (Set to Host-Endian if not 
    554       # defined 
    555       if kwargs['endianness'] == 'big': 
    556          format_str = '>' 
    557       elif kwargs['endianness'] == 'little': 
    558          format_str = '<' 
    559       else: 
    560          format_str = '=' 
    561           
    562       # Set the size of the data to read (product of dimensions) 
    563       format_str += str(reduce(lambda a,b:a*b, kwargs['dimensions'])) 
    564        
    565       # Lookup the type character 
    566       format_str += "BHIQ----bhiq--fd"[format_index] 
    567  
     539      # Valid values for numericType and their associated struct format 
     540      # character: 
     541      numericLookup = { 
     542         'uint8':'B', 'uint16':'H', 'uint32':'I', 'uint64':'Q', 
     543          'int8':'b',  'int16':'h',  'int32':'i',  'int64':'q', 
     544         'float':'f', 'double':'d' 
     545      } 
     546 
     547      # Valid values for endianness and their associated struct format 
     548      # character: 
     549      endiannessLookup = { 
     550         'big':'>',  'little':'<',  'host':'=' 
     551      } 
     552 
     553      # Build the desired format string: 
     554      try: 
     555         format_str  = endiannessLookup[kwargs['endianness']] 
     556         format_str += str(reduce(lambda a,b:a*b, kwargs['dimensions'])) 
     557         format_str += numericLookup[kwargs['numericType']] 
     558      except KeyError, TypeError: 
     559         raise TypeError("Missing or invalid parameters. Required: endianness=str, dimensions=list and numericType=str") 
     560 
     561      # Read and unpack data into a Numeric array. 
    568562      self.data = Numeric.array(struct.unpack(format_str, self.file.read())) 
    569563      self.data.shape = tuple(map(int, kwargs['dimensions'])) 
    570564       
     565      # If numericTransform or fillValue were provided, store them as  
     566      # attributes. 
    571567      if 'numericTransform' in kwargs: 
    572          # if a numericTransform was supplied, then compile it: 
    573568         self.numericTransform = NumericTransform.infixExpression(kwargs['numericTransform']) 
    574  
    575569      if 'fillValue' in kwargs: 
    576570         self.fillValue = kwargs['fillValue'] 
    577571 
    578572 
    579  
    580    # Allows data to be indexed as if it were a multidimensional array: 
    581    def index(self, *indices): 
    582       index1d = 0 
    583       factor  = 1 
    584       for n in range(len(indices)): 
    585          index1d += factor * indices[n] 
    586          factor  *= self.dimensions[n] 
    587       return self.data[index1d] 
    588  
    589  
    590573   # Return the fill value, if set, and transform if necessary: 
    591574   def getFillValue(self): 
    592       if(self.fillValue): 
    593          if(self.numericTransform): 
    594             return self.numericTransform.solve( n = float(self.fillValue) ) 
    595          else: 
     575      # Both fillValue and numericTransform attributes may or may 
     576      # not exist... 
     577      try: 
     578         return self.numericTransform.solve( n = float(self.fillValue) ) 
     579      except AttributeError: 
     580         try: 
    596581            return self.fillValue 
    597       else: 
    598          return None 
    599  
    600  
     582         except AttributeError: 
     583            return None 
     584 
     585 
     586   # This is a just a special case of getSubsetOfDataForVar. To avoid 
     587   # duplication of code, just subset the entire array. (getSubset.. is 
     588   # optimised for this case) 
    601589   def getDataForVar(self): 
    602       if self.numericTransform: 
    603          # Solve the numeric transform and return the resulting array of floats 
    604          return self.numericTransform.solve( n = self.data ) 
    605       else: 
    606          return self.data 
    607  
    608  
     590      return self.getSubsetOfDataForVar(lower = (0,)*len(self.data.shape), 
     591                                        upper = self.data.shape) 
     592 
     593 
     594   # Subset the n-dimensional file based on array indices. Accepts parameters 
     595   # in the form of e.g. 
     596   # 
     597   # getSubsetOfDataForVar( lower=(0,0), upper=(1,2) ) 
     598   # 
     599   # Note: The rank of the required subset, must exactly match the 
     600   # rank of the original data: len(lower) == len(upper) == rank of file 
     601   # 
    609602   def getSubsetOfDataForVar(self, **kwargs): 
    610603      # Assume subset parameters are passed as: lower=(0,0) upper=(512,512) 
    611604      if 'lower' not in kwargs or 'upper' not in kwargs: 
     605         # Have not specified any subset parameters that we recognise, so raise 
     606         # an exception: 
    612607         raise NotImplementedError("Only supports subsetting with lower+upper array indices") 
    613       elif len(kwargs['lower']) != len(self.data.shape) or len(kwargs['upper']) != len(self.data.shape): 
    614          raise NotImplementedError("Only supports subsets of same dimensionality as full dataset") 
     608      elif not len(kwargs['lower']) == len(kwargs['upper']) == len(self.data.shape): 
     609         # Rank of subset is not the same as rank of full data array. so raise 
     610         # an exception: 
     611         raise NotImplementedError("Only supports subsets of same rank as full dataset") 
     612      elif Numeric.sometrue(Numeric.greater(kwargs['upper'], self.data.shape)): 
     613         # Requested upper bound of subset is beyond the size of the the full 
     614         # data array, so raise an exception 
     615         raise IndexException("Subset out of range") 
     616      elif Numeric.sometrue(Numeric.less( kwargs['upper'], Numeric.zeros(len(self.data.shape)))): 
     617         # Requested lower bound of subset is beyond the size of the the full 
     618         # data array, so raise an exception 
     619         raise IndexException("Subset out of range") 
     620      elif Numeric.sometrue(Numeric.less_equal(kwargs['upper', kwargs['lower'])): 
     621         # lower bound <= upper_bound for at least one dimension, so raise an 
     622         # exception 
     623         raise IndexException("Upper bound less than lower bound") 
     624      elif tuple(kwargs['lower']) == (0,)*len(self.data.shape) and tuple(kwargs['upper']) == self.data.shape: 
     625         # Special case of requested subset == entire data file. 
     626         subset = self.data 
    615627      else: 
    616          if not self.data: 
    617             self.readFile() 
    618          subset = [] 
    619  
    620          # Recursive function for the purpose of iterating over an array of 
    621          # arbitrary dimensionality. (Iterate over the desired subset, and 
    622          # append each data item encountered to the subset array) 
    623          ptr = [None] * len(self.data.shape) 
    624          def iterate(n = 0): 
    625             for ptr[n] in range(kwargs['lower'][n], kwargs['upper'][n] + 1): 
    626                if n < len(self.data.shape) - 1: 
    627                   iterate(n + 1) 
    628                else: 
    629                   subset.insert(0, self.index(*ptr)) 
    630          iterate() 
    631  
    632       if self.numericTransform: 
    633          # Solve the numeric transform and return the resulting array of floats 
    634          return  self.numericTransform.solve( n = subset ) 
    635       else: 
    636          return subset 
    637  
    638  
    639 # Interface from reading data from image files. Requires PIL Image module 
     628         # We are okay to subset. 
     629 
     630         # I cant see any nice (and speedy) way of subsetting a Numeric 
     631         # array of arbitrary rank without the use of eval. By doing it 
     632         # this way, we can make use of the (possible) acceleration provided 
     633         # by Numeric/NumPy. 
     634         slices = [] 
     635         for i in range(len(self.data.shape)): 
     636            lower = int(kwargs['lower'][i]) 
     637            upper = int(kwargs['upper'][i]) 
     638            slices.append(str(lower)+':'+str(upper)) 
     639         subset = eval("self.data["+','.join(slices)+"]") 
     640 
     641      # Attempt to perform the numericTransform on the data array, if we get 
     642      # AttributeError, it most likely means that numericTransform was not 
     643      # specified, so return the data as-is 
     644      try: 
     645         return self.numericTransform.solve( n = subset ) 
     646      except AttributeError: 
     647         return subset.copy() 
     648 
     649 
     650# Interface for reading data from image files. Requires PIL Image module. 
    640651class ImageFileInterface(RawFileInterface): 
    641652   def __init__(self): 
     
    647658 
    648659   def closeFile(self): 
    649       self.file = None 
     660      self.file = None #...Image does not seem to have a close() method. 
    650661 
    651662   def readFile(self, **kwargs): 
    652663      # Convert the image to a Numeric array 
    653       self.data = Numeric.array(im.getdata()) 
    654       self.data.shape = tuple(map(int, im.size)) 
     664      self.data = Numeric.array(self.file.getdata()) 
     665 
     666      # The order of dimensions in Numeric arrays do not correspond with 
     667      # the order of dimensions in traditional image files, so we need to 
     668      # reverse the dimensions before shaping the array. 
     669      dimensions = map(int,self.file.size) 
     670      dimensions.reverse() 
     671      self.data.shape = tuple(dimensions) # self.data.shape = (Y,X) 
    655672 
    656673      if 'numericTransform' in kwargs: 
  • TI02-CSML/branches/csml-pml/parser.py

    r2460 r2461  
    10651065       meta = {} 
    10661066       meta['dimensions'] = map(int, self.arraySize.CONTENT.split()) 
    1067        if self.numericTransform: 
     1067 
     1068       try:  
    10681069          meta['numericTransform'] = self.numericTransform.CONTENT.strip() 
    1069        if self.endianness: 
     1070       except AttributeError: pass 
     1071       try: 
    10701072          meta['endianness'] = self.endianness.CONTENT.strip() 
    1071        if self.fillValue: 
     1073       except AttributeError: pass 
     1074       try: 
    10721075          meta['fillValue'] = self.fillValue.CONTENT.strip() 
    1073        if self.numericType: 
    1074           type = self.numericType.CONTENT.strip() 
    1075           if type == 'float': 
    1076              meta['signedness'] = 'signed' 
    1077              meta['type']       = 'float' 
    1078              meta['depth']      = 32 
    1079           elif type == 'double': 
    1080              meta['signedness'] = 'signed' 
    1081              meta['type']       = 'float' 
    1082              meta['depth']      = 64 
    1083           elif type[0:4] == 'uint': 
    1084              meta['signedness'] = 'unsigned' 
    1085              meta['type']       = 'int' 
    1086              meta['depth']      = int(type[4:]) 
    1087           elif type[0:3] == 'int': 
    1088              meta['signedness'] = 'signed' 
    1089              meta['type']       = 'int' 
    1090              meta['depth']      = int(type[3:]) 
    1091  
    1092        if self.dataInterface: 
     1076       except AttributeError: pass 
     1077       try: 
     1078          meta['numericType'] = self.numericType.CONTENT.strip() 
     1079       except AttributeError: pass 
     1080        
     1081       try: 
    10931082          DI = self.dataInterface() 
    1094        else: 
     1083       except AttributeError: 
    10951084          DI = csml.csmllibs.csmldataiface.DataInterface() 
    10961085          DI = DI.getUnknownInterfaceType(file) 
     
    11091098 
    11101099 
    1111 class ImageFileExtract(FileExtract, csElement): 
     1100class ImageFileExtract(RawFileExtract, csElement): 
    11121101   def __init__(self,**kwargs): 
    11131102      FileExtract.__init__(self, **kwargs) 
     
    11181107      csElement.__init__(self,**kwargs) 
    11191108      self.dataInterface = csml.csmllibs.csmldataiface.ImageFileInterface 
    1120       self.getData = RawFileExtract.getData 
     1109    
    11211110 
    11221111class SimpleCondition(csElement):  
Note: See TracChangeset for help on using the changeset viewer.