models.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. import io
  2. import os
  3. from mongoengine import Document, EmbeddedDocument, signals, GridFSProxy
  4. from mongoengine.fields import BooleanField, IntField, FileField, ListField, EmbeddedDocumentField, StringField
  5. from django.conf import settings
  6. from bson.objectid import ObjectId
  7. import numpy as np
  8. import logging
  9. logger = logging.getLogger(__name__)
  10. class OriginalSize(EmbeddedDocument):
  11. sizex = IntField()
  12. sizey = IntField()
  13. sizez = IntField()
  14. class TextureInfo(EmbeddedDocument):
  15. slicesOverX = IntField()
  16. slicesOverY = IntField()
  17. numberOfSlices = IntField()
  18. imgMin = IntField()
  19. imgMax = IntField()
  20. multipleFrames = BooleanField()
  21. frameFrom = IntField()
  22. frameTo = IntField()
  23. slicesPerSprite = IntField()
  24. numberOfSprites = IntField()
  25. thresholdIndex_otsu = IntField()
  26. thresholdIndex_yen = IntField()
  27. thresholdIndex_isodata = IntField()
  28. @staticmethod
  29. def from_info_object(infoObject):
  30. textureInfo = TextureInfo()
  31. textureInfo.slicesOverX = infoObject['slicesOverX']
  32. textureInfo.slicesOverY = infoObject['slicesOverY']
  33. textureInfo.numberOfSlices = infoObject['numberOfSlices']
  34. textureInfo.imgMin = infoObject['imgMin']
  35. textureInfo.imgMax = infoObject['imgMax']
  36. textureInfo.numberOfSprites = infoObject['numberOfSprites']
  37. textureInfo.slicesPerSprite = infoObject['slicesPerSprite']
  38. textureInfo.multipleFrames = infoObject['multipleFrames']
  39. textureInfo.frameFrom = infoObject['frameFrom']
  40. textureInfo.frameTo = infoObject['frameTo']
  41. textureInfo.thresholdIndex_otsu = infoObject['thresholdIndex_otsu']
  42. textureInfo.thresholdIndex_yen = infoObject['thresholdIndex_yen']
  43. textureInfo.thresholdIndex_isodata = infoObject['thresholdIndex_isodata']
  44. return textureInfo
  45. class Texture(EmbeddedDocument):
  46. size = IntField()
  47. info = EmbeddedDocumentField(TextureInfo)
  48. contenttype = StringField()
  49. sprites = ListField(ListField(FileField()))
  50. originalSize = EmbeddedDocumentField(OriginalSize)
  51. def deleteContent(self):
  52. for sprite in self.sprites:
  53. for fileItem in sprite:
  54. fileItem.delete()
  55. def addSpriteBuffers(self, spriteBuffers):
  56. proxies = []
  57. for spriteBuffer in spriteBuffers:
  58. gridFSProxy = GridFSProxy()
  59. gridFSProxy.put(spriteBuffer)
  60. proxies.append(gridFSProxy)
  61. self.sprites.append(proxies)
  62. class RawFrame(EmbeddedDocument):
  63. dataName = StringField()
  64. frameNumber = IntField()
  65. dtype = StringField()
  66. originalSize = EmbeddedDocumentField(OriginalSize)
  67. def setNumpyArray(self, array, frameNumber, pathToStore):
  68. if len(array.shape) != 3:
  69. raise ValueError('array has not dimension of 3')
  70. originalSize = OriginalSize()
  71. originalSize.sizez, originalSize.sizey, originalSize.sizex = array.shape
  72. self.originalSize = originalSize
  73. self.dtype = str(array.dtype)
  74. self.frameNumber = frameNumber
  75. logger.debug('RawFrame.setNumpyArray: write frame to buffer')
  76. mmapId = ObjectId()
  77. self.dataName = str(mmapId) + '.npy'
  78. filepath = self.__getpathtofile(pathToStore)
  79. mmap = np.memmap(filepath, dtype=array.dtype, mode='w+', shape=array.shape)
  80. logger.debug('RawFrame.setNumpyArray: put buffer to file')
  81. mmap[:] = array[:]
  82. def getNumpyArray(self, path):
  83. filepath = self.__getpathtofile(path)
  84. shape = (self.originalSize.sizez, self.originalSize.sizey, self.originalSize.sizex)
  85. mmap = np.memmap(filepath, dtype=self.dtype, mode='r', shape=shape)
  86. return mmap
  87. def deleteContent(self, path):
  88. try:
  89. os.remove(self.__getpathtofile(path))
  90. except OSError:
  91. logger.error('file %s could not be deleted' % self.__getpathtofile(path))
  92. def __getpathtofile(self, path):
  93. return path + self.dataName
  94. class RawFrameGridFsProxy(EmbeddedDocument):
  95. data = FileField()
  96. frameNumber = IntField()
  97. dtype = StringField()
  98. originalSize = EmbeddedDocumentField(OriginalSize)
  99. def setNumpyArray(self, array, frameNumber, pathToStore):
  100. if len(array.shape) != 3:
  101. raise ValueError('array has not dimension of 3')
  102. self.dtype = str(array.dtype)
  103. self.frameNumber = frameNumber
  104. buff = io.BytesIO()
  105. buff.write(array)
  106. buff.seek(0, 0)
  107. gridFSProxy = GridFSProxy()
  108. gridFSProxy.put(buff)
  109. self.data = gridFSProxy
  110. def getNumpyArray(self, path):
  111. array = np.frombuffer(self.data.read(), dtype=np.dtype(self.dtype))
  112. array = np.reshape(array, (self.originalSize.sizez, self.originalSize.sizey, self.originalSize.sizex))
  113. self.data.seek(0, 0)
  114. return array
  115. def deleteContent(self, path):
  116. self.data.delete()
  117. def __getpathtofile(self, path):
  118. return path + self.dataName
  119. class Volume(Document):
  120. name = StringField(max_length=100)
  121. path = StringField(max_length=1000)
  122. rawData = BooleanField()
  123. width = IntField()
  124. height = IntField()
  125. littleEndian = BooleanField()
  126. slices = IntField()
  127. sliceFrom = IntField()
  128. sliceTo = IntField()
  129. textures = ListField(EmbeddedDocumentField(Texture))
  130. rawFrames = ListField(EmbeddedDocumentField(RawFrame))
  131. generateSlicesStatus = StringField()
  132. imageSequence = BooleanField()
  133. automaticProcessing = BooleanField()
  134. @classmethod
  135. def pre_save(cls, sender, document, **kwargs):
  136. if document.sliceFrom is not None and document.sliceTo is not None:
  137. document.slices = document.sliceTo - document.sliceFrom
  138. def clear_textures(self):
  139. for texture in self.textures:
  140. self.remove_texture(texture.size)
  141. def add_slice_maps(self, size, sprites, originalSize, infoObject):
  142. textureSize = int(size)
  143. texture = Texture()
  144. texture.sprites = []
  145. texture.info = TextureInfo.from_info_object(infoObject)
  146. texture.contenttype = None
  147. texture.originalSize = originalSize
  148. texture.size = textureSize
  149. for sprite in sprites:
  150. if texture.contenttype is None:
  151. texture.contenttype = sprite.contenttype
  152. texture.addSpriteBuffers(sprite.buffers)
  153. self.insert_texture(texture)
  154. def insert_texture(self, textureToAdd):
  155. for texture in self.textures:
  156. if texture.size == textureToAdd.size:
  157. self.textures.remove(texture)
  158. return Volume.objects(id=self.id).update_one(push__textures=textureToAdd)
  159. def remove_texture(self, textureSize):
  160. for texture in self.textures:
  161. if texture.size == textureSize:
  162. texture.deleteContent()
  163. break
  164. Volume.objects(id=self.id).update_one(pull__textures={'size': textureSize})
  165. def add_frame(self, frame, frameNumber):
  166. rawFrame = RawFrame()
  167. rawFrame.setNumpyArray(frame, frameNumber, self.get_mmap_path())
  168. if settings.REDUCE_HARDDISK_ACCESS_FOR_DEV is True:
  169. logger.debug('not saving rawframes in volume --> reducing harddisk access')
  170. else:
  171. Volume.objects(id=self.id).update_one(push__rawFrames=rawFrame)
  172. return rawFrame
  173. def get_frame_numpy_array(self, frameNumber):
  174. rawFrame = self.rawFrames[frameNumber]
  175. return rawFrame.getNumpyArray(self.get_mmap_path())
  176. def remove_frames(self):
  177. for frame in self.rawFrames:
  178. frame.deleteContent(self.get_mmap_path())
  179. Volume.objects(id=self.id).update_one(set__rawFrames=[])
  180. def get_mmap_path(self):
  181. path = settings.PATH_MMAP + str(self.id) + '/'
  182. if os.path.exists(path) is False:
  183. os.makedirs(path)
  184. return path
  185. def delete(self):
  186. self.remove_frames()
  187. for texture in self.textures:
  188. self.remove_texture(texture.size)
  189. return super(Volume, self).delete()
  190. @property
  191. def rendering_possible(self):
  192. return 'running' not in self.generateSlicesStatus and len(self.textures) > 0
  193. @staticmethod
  194. def read_sprite(volumeId, spriteId):
  195. spriteId = ObjectId(spriteId)
  196. volume = Volume.objects(id=volumeId)[0]
  197. for texture in volume.textures:
  198. for sprite in texture.sprites:
  199. for fileItem in sprite:
  200. if fileItem._id == spriteId:
  201. return fileItem, texture.contenttype
  202. raise IndexError('sprite with size %s could not be found' % spriteId)
  203. @staticmethod
  204. def read_texture(id, textureSize):
  205. volume = Volume.objects(id=id)[0]
  206. if textureSize is None:
  207. logger.debug('returning texture0 with its size: %d' % volume.textures[0].size)
  208. return volume.textures[0]
  209. textureSize = int(textureSize)
  210. for texture in volume.textures:
  211. if texture.size == textureSize:
  212. logger.debug('texture found, returing')
  213. return texture
  214. raise IndexError('texture with size %s could not be found' % textureSize)
  215. signals.pre_save.connect(Volume.pre_save, sender=Volume)