Package pyvision :: Package types :: Module RangeImage
[hide private]
[frames] | no frames]

Source Code for Module pyvision.types.RangeImage

  1  # PyVision License 
  2  # 
  3  # Copyright (c) 2009 David S. Bolme 
  4  # All rights reserved. 
  5  # 
  6  # Redistribution and use in source and binary forms, with or without 
  7  # modification, are permitted provided that the following conditions 
  8  # are met: 
  9  #  
 10  # 1. Redistributions of source code must retain the above copyright 
 11  # notice, this list of conditions and the following disclaimer. 
 12  #  
 13  # 2. Redistributions in binary form must reproduce the above copyright 
 14  # notice, this list of conditions and the following disclaimer in the 
 15  # documentation and/or other materials provided with the distribution. 
 16  #  
 17  # 3. Neither name of copyright holders nor the names of its contributors 
 18  # may be used to endorse or promote products derived from this software 
 19  # without specific prior written permission. 
 20  #  
 21  #  
 22  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 23  # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 24  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
 25  # A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR 
 26  # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 27  # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 28  # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
 29  # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 30  # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
 31  # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 32  # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 33   
 34   
 35  import gzip 
 36  import numpy as np 
 37  import time 
 38  import pyvision as pv 
 39  import scipy.interpolate as it 
 40  import scipy.ndimage as nd 
 41   
42 -class RangeImage:
43 ''' 44 This class is used to handle range images. Originally written to handle 45 output from the Minolta Vivid sensors distributed with the Face Recognition 46 Grand Challenge 2004 47 48 This implementation currently can parse range images in ".abs" or ".abs.gz" format. 49 50 Very little type checking is done during parsing so unexpected exception or 51 unusual behavior may occur if the file is not formated properly. 52 53 This is a sample for the .abs file format: 54 480 rows 55 640 columns 56 pixels (flag X Y Z): 57 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ... 58 -999999.000000 -999999.000000 -999999.000000 -9999 ... 59 -999999.000000 -999999.000000 -999999.000000 -9999 ... 60 -999999.000000 -999999.000000 -999999.000000 -9999 ... 61 62 Author: David S. Bolme 2009 63 ''' 64
65 - def __init__(self,filename):
66 ''' 67 Reads a file containing range data. 68 ''' 69 70 if filename[-7:] == '.abs.gz': 71 # Assume the date is a zlib compressed abs file 72 f = gzip.open(filename) 73 74 if filename[-4:] == '.abs': 75 # Assume uncompressed 76 f = open(filename) 77 78 #print buffer[:100] 79 80 #lines = buffer.split(EOL) 81 rows = int(f.next().split()[0]) 82 cols = int(f.next().split()[0]) 83 #format = f.next() 84 85 self.width = cols 86 self.height = rows 87 88 self.flags = np.array([int(v) for v in f.next().split()]).reshape(rows,cols).transpose() 89 self.x = np.array([float(v) for v in f.next().split()]).reshape(rows,cols).transpose() 90 self.y = np.array([float(v) for v in f.next().split()]).reshape(rows,cols).transpose() 91 self.z = np.array([float(v) for v in f.next().split()]).reshape(rows,cols).transpose()
92 93
94 - def getRange(self):
95 ''' 96 @returns: xmin,xmax,ymin,ymax,zmin,zmax 97 ''' 98 99 flags = np.array(self.flags.flatten(),dtype=np.bool) 100 101 X = self.x.flatten()[flags] 102 Y = self.y.flatten()[flags] 103 Z = self.z.flatten()[flags] 104 return min(X),max(X),min(Y),max(Y),min(Z),max(Z)
105 106
107 - def getXImage(self):
108 ''' 109 @returns: the x coordinates. 110 ''' 111 xmin,_,_,_,_,_ = self.getRange() 112 113 r,c = self.x.shape 114 115 flags = np.array(self.flags.flatten(),dtype=np.bool) 116 X = self.x.flatten().copy() 117 X[ flags != True ] = xmin 118 119 X = X.reshape(r,c) 120 121 return pv.Image(X)
122 123
124 - def getYImage(self):
125 ''' 126 @returns: the y coordinates. 127 ''' 128 _,_,ymin,_,_,_ = self.getRange() 129 130 r,c = self.x.shape 131 132 flags = np.array(self.flags.flatten(),dtype=np.bool) 133 Y = self.y.flatten().copy() 134 Y[ flags != True ] = ymin 135 136 Y = Y.reshape(r,c) 137 138 return pv.Image(Y)
139 140
141 - def getZImage(self):
142 ''' 143 @returns: the z coordinates. 144 ''' 145 _,_,_,_,zmin,_ = self.getRange() 146 147 r,c = self.x.shape 148 149 flags = np.array(self.flags.flatten(),dtype=np.bool) 150 Z = self.z.flatten().copy() 151 Z[ flags != True ] = zmin 152 153 Z = Z.reshape(r,c) 154 155 return pv.Image(Z)
156
157 - def getMaskImage(self):
158 ''' 159 @returns: the missing value mask. 160 ''' 161 _,_,_,_,zmin,_ = self.getRange() 162 163 r,c = self.x.shape 164 165 flags = np.array(self.flags.flatten(),dtype=np.bool) 166 Z = self.z.flatten().copy() 167 Z[ flags != True ] = zmin 168 169 Z = Z.reshape(r,c) 170 171 return pv.Image(Z)
172
173 - def populateMissingData(self,approach="Smooth",ilog=None):
174 ''' 175 This function is used to interpolate missing data in the image. 176 ''' 177 if approach == 'Smooth': 178 # first run a median filter over the array, then smooth the result. 179 #xmin,xmax,ymin,ymax,zmin,zmax = self.getRange() 180 mask = np.array(self.flags,dtype=np.bool) 181 182 z = self.getZImage().asMatrix2D() 183 median = nd.median_filter(z,size=(15,15)) 184 185 mask = mask.flatten() 186 z = z.flatten() 187 median = median.flatten() 188 189 z[ mask==False ] = median[ mask==False ] 190 191 if ilog != None: 192 ilog.log(pv.Image(median.reshape(self.width,self.height)),label="Median") 193 ilog.log(pv.Image(z.reshape(self.width,self.height)),label="ZMedian") 194 195 mask = mask.flatten() 196 z = z.flatten() 197 median = median.flatten() 198 199 for i in range(5): 200 tmp = z.copy() 201 smooth = nd.gaussian_filter(z.reshape(self.width,self.height),2.0).flatten() 202 z[ mask==False ] = smooth[ mask==False ] 203 print "Iteration:",i,(z-tmp).max(),(z-tmp).min() 204 ilog.log(pv.Image(z.reshape(self.width,self.height)),label="ZSmooth%02d"%i) 205 ilog.log(pv.Image((z-tmp).reshape(self.width,self.height)),label="ZSmooth%02d"%i) 206 207 208 if approach == 'RBF': 209 mask = np.array(self.flags,dtype=np.bool) 210 mask = mask.flatten() 211 212 x = np.arange(self.width).reshape(self.width,1) 213 x = x*np.ones((1,self.height)) 214 x = x.flatten() 215 216 y = np.arange(self.height).reshape(1,self.height) 217 y = y*np.ones((self.width,1)) 218 y = y.flatten() 219 220 z = self.z.copy() 221 z = z.flatten() 222 223 print "Coords:" 224 print len(mask) 225 print len(x[mask]) 226 print len(y[mask]) 227 print len(z[mask]) 228 229 # this produces an error. Probably has too much data 230 it.Rbf(x[mask],y[mask],z[mask]) 231 pass
232 233 234 235 236 237 238 if __name__ == "__main__": 239 ilog = pv.ImageLog() 240 filename = "02463d562.abs.gz" 241 im = pv.Image("02463d563.ppm") 242 243 t = time.time() 244 ri = RangeImage(filename) 245 t = time.time() - t 246 print t 247 248 print ri.getRange() 249 ilog.log(ri.getXImage(),"X_Image") 250 ilog.log(ri.getYImage(),"Y_Image") 251 ilog.log(ri.getZImage(),"Z_Image") 252 ilog.log(im,"Color") 253 254 ri.populateMissingData(ilog=ilog) 255 256 ilog.show() 257