volumeimage.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. from collections import namedtuple
  2. from utils.path import path
  3. import numpy as np
  4. class Dimension(object):
  5. def __init__(self):
  6. self.scale = 1.0
  7. self.x = self.y = self.z = 0 # dimensions of world (resolution)
  8. self.sx = self.sy = self.sz = 0. #voxel thickness in m
  9. self.tx = self.ty = self.tz = 0. # world center
  10. def __eq__ (self, other):
  11. ''' support for comparing Dimension equality'''
  12. return (self.scale == other.scale and
  13. self.x == other.x and self.y == other.y and self.z == other.z and
  14. self.sx == other.sx and self.sy == other.sy and self.sz == other.sz and
  15. self.tx == other.tx and self.ty == other.ty and self.tz == other.tz)
  16. def __neq__ (self, other):
  17. return not self.__eq__(other)
  18. Source = namedtuple('Source', 'x y z')
  19. class VolumeImage(object):
  20. #cdef public fname # name of .dat file
  21. #cdef public rawfile_name # name of .raw file
  22. #cdef public coeff_name # unknown file
  23. #cdef public mode # datatype of scalars - only 32bit floats atm
  24. #cdef public np.ndarray data # the 3d numpy data with the scalars
  25. #cdef public source # 3-tuple with source coordinates
  26. def __init__(self, fname=None):
  27. self.di = Dimension()
  28. self.data = np.zeros((0, 0, 0))
  29. self.rawfile_name = ""
  30. self.coeff_name = ""
  31. self.mode = "UCHAR"
  32. self.source = Source(0, 0, 0)
  33. if fname is not None:
  34. self.read(fname)
  35. def getVoxel(self, x, y, z):
  36. if x < 0 or y < 0 or z < 0 or x >= self.di.x or y >= self.di.y or z >= self.di.z:
  37. return None
  38. else:
  39. return self.data[x][y][z] * self.di.scale
  40. def getPoint(self, x, y, z):
  41. return self.getVoxel(*self.translate(x, y, z))
  42. def translate(self, x, y, z):
  43. '''translate float real world coordinates into int coordinates
  44. for space (self.di.x, self.di.y, self.di.z)'''
  45. return (int(round((x - self.di.tx) / self.di.sx)),
  46. int(round((y - self.di.ty) / self.di.sy)),
  47. int(round((z - self.di.tz) / self.di.sz)))
  48. def asDecibelData(self, clamp):
  49. dbdata = 10 * np.log10(self.data)
  50. # filter values that are -inf'ed by np.log(0)
  51. dbdata[np.isinf(dbdata)] = clamp
  52. return dbdata
  53. def read(self, fname, offset=1):
  54. ''' parse header file (.dat) into self.di and
  55. read the content of the data file (.raw) into self.data (a numpy array)
  56. '''
  57. self.fname = path(fname).abspath()
  58. assert self.fname.ext == '.dat'
  59. with open(self.fname) as f:
  60. for line in f:
  61. buf = line.split()
  62. if buf[0] == "ObjectFileName:":
  63. self.rawfile_name = buf[1]
  64. elif buf[0] == "CoeffFileName:":
  65. self.coeff_name = buf[1]
  66. elif buf[0] == "Resolution:":
  67. self.di.x = int(buf[1])
  68. self.di.y = int(buf[2])
  69. self.di.z = int(buf[3])
  70. elif buf[0] == "SliceThickness:":
  71. self.di.sx = float(buf[1])
  72. self.di.sy = float(buf[2])
  73. self.di.sz = float(buf[3])
  74. elif buf[0] == "Origin:":
  75. self.di.tx = float(buf[1])
  76. self.di.ty = float(buf[2])
  77. self.di.tz = float(buf[3])
  78. elif buf[0] == "Format:":
  79. self.mode = buf[1]
  80. elif buf[0] == "Scale:":
  81. self.di.scale = float(buf[1])
  82. elif buf[0] == "Source":
  83. # like Source 0: 0.000000 0.000000 0.000000
  84. self.source = Source(float(buf[2]), float(buf[3]), float(buf[4]))
  85. datafile = self.fname.parent.joinpath(self.rawfile_name)
  86. if datafile.namebase != self.fname.namebase:
  87. datafile = self.fname.parent.joinpath(self.fname.namebase + '.raw')
  88. print 'adapting datafile from to %s' % (datafile.name)
  89. assert datafile.exists(), '%s does not exists' % datafile
  90. assert self.mode == "FLOAT"
  91. shape = (self.di.x, self.di.y, self.di.z)
  92. self.data = np.reshape(np.fromfile(datafile, np.float32, -1), shape, 'F')
  93. if offset > 0:
  94. # TODO: Why is everything shifted by one unit
  95. self.data = np.roll(np.roll(np.roll(self.data,offset,axis=0),offset,axis=1),offset,axis=2)
  96. #make first offset row(s) and collum(s) zero
  97. self.data[0:,0:,:offset] = self.data[0:,:offset,0:] = self.data[:offset,0:,0:] = 0