SliceGenerator.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. import re
  2. import sys
  3. from django.conf import settings
  4. from volumes.models import Volume
  5. from volumes.processing.models import AutomaticProcessing
  6. from skimage import img_as_int
  7. import numpy as np
  8. from imageprocessing import tiffPreparer, sliceMapCreator, binary_preparer
  9. from . import MultiProcessUByte, Normalizer
  10. import logging, pdb
  11. logger = logging.getLogger(__name__)
  12. def generateListOfVolumes(volumesToProcess):
  13. automaticProcessing = AutomaticProcessing()
  14. automaticProcessing.finished = False
  15. automaticProcessing = automaticProcessing.save()
  16. for volumeId in volumesToProcess:
  17. AutomaticProcessing.objects(id=automaticProcessing.id).update_one(inc__processed=1)
  18. Volume.objects(id=volumeId).update_one(set__generateSlicesStatus='running')
  19. volume = Volume.objects(id=volumeId).first()
  20. sliceGeneratorPlain({}, volume.id)
  21. if 'successful' in Volume.objects(id=volume.id).first().generateSlicesStatus:
  22. AutomaticProcessing.objects(id=automaticProcessing.id).update_one(inc__succeeded=1)
  23. else:
  24. AutomaticProcessing.objects(id=automaticProcessing.id).update_one(inc__errored=1)
  25. AutomaticProcessing.objects(id=automaticProcessing.id).update_one(push__erroredPaths=volume.path)
  26. def sliceGenerator(request, volumeId):
  27. sliceGeneratorPlain(request.POST, volumeId)
  28. def sliceGeneratorPlain(data, volumeId):
  29. '''
  30. This file generates the needed information and images to
  31. render a volume.
  32. For that, the volume has to be located in the local filesystem.
  33. The workflow to preprocess volume data is as follows:
  34. 1. read volume data from filesystem
  35. 2. make each slice in the volume to be square by cutting
  36. the edges
  37. 3. if float image, normalize it, and covert it to int16
  38. 4. save this data as rawframes to volume, to access it later
  39. 5. convert image to ubyte for first preview slice maps
  40. 6. generate slice maps
  41. 7. save slice maps to volume
  42. 8. save json information to volume
  43. '''
  44. sliceFrom = ''
  45. sliceTo = ''
  46. imgFormat = ''
  47. if 'sliceFrom' in data:
  48. sliceFrom = data['sliceFrom']
  49. if 'sliceTo' in data:
  50. sliceTo = data['sliceTo']
  51. if 'imgFormat' in data:
  52. imgFormat = data['imgFormat']
  53. size = None
  54. fileChanged = 'fileChanged' in data
  55. volume = Volume.objects(id=volumeId)[0]
  56. frames = []
  57. try:
  58. if volume.imageSequence is True:
  59. logger.debug('volId: %s, reading imagesequence' % (volumeId))
  60. frames = tiffPreparer.prepareImageSequence(volume.path)
  61. elif re.search(r'.tif(f|)$', volume.path):
  62. logger.debug('volId: %s, reading tiff file' % (volumeId))
  63. frames = tiffPreparer.processTiffFile(volume.path)
  64. elif volume.rawData:
  65. logger.debug('volId: %s, reading raw data' % (volumeId))
  66. frames = binary_preparer.process_binary(volume.path, (volume.width, volume.height), little_endian=volume.littleEndian)
  67. else:
  68. raise ValueError('sorry, file currently not supported, is it a raw file?')
  69. except Exception as e:
  70. logger.error('volId: %s, exception: %s)' % (volumeId, str(e)))
  71. volume.generateSlicesStatus = str(e)
  72. volume.save()
  73. return
  74. try:
  75. sliceFrom, sliceTo = __defineSliceRange(frames, sliceFrom, sliceTo)
  76. except Exception:
  77. logger.error('volId: %s, please provide integers or "" for "sliceFrom" and "sliceTo"' % (volumeId))
  78. Volume.objects(id=volume.id).update_one(set__generateSlicesStatus='generation failed, please read the logs')
  79. return
  80. if len(frames.shape) is not 4:
  81. raise ValueError('read input file shall have dim of 4, please check the used fileparser')
  82. if frames.dtype == np.float32 or frames.dtype == np.float16:
  83. try:
  84. Normalizer.normalize_image(frames, volumeId)
  85. except Exception as e:
  86. logger.error('volId: %s, error while normalization: ' % (str(e)))
  87. Volume.objects(id=volume.id).update_one(set__generateSlicesStatus='generation failed, please read the logs')
  88. return
  89. else:
  90. logger.debug('volId: %s, frames do NOT have to be normalized, dtype is %s' % (volumeId, str(frames.dtype)))
  91. logger.debug('volId: %s, cropping images to be square' % volumeId)
  92. try:
  93. pixelOffset, newSize = sliceMapCreator.calculateXYDimensions(frames[0])
  94. squared_frames = sliceMapCreator.crop_frames(frames, pixelOffset, newSize)
  95. except Exception as e:
  96. logger.error('volId: %s, error while cropping: ' % (str(e)))
  97. Volume.objects(id=volume.id).update_one(set__generateSlicesStatus='generation failed, %s' % str(e))
  98. return
  99. del frames
  100. logger.debug('volId: %s, memory freed, frames deleted, keeping squared squared_frames' % volumeId)
  101. if squared_frames.dtype != np.int16 and squared_frames.dtype != np.uint8:
  102. logger.debug('volId: %s, frames are not int16 and not uint8, convert them to int' % volumeId)
  103. squared_frames = img_as_int(squared_frames)
  104. else:
  105. logger.debug('volId: %s, frames are not converted because of dtype %s' % (volumeId, str(squared_frames.dtype)))
  106. rawFrame = None
  107. # the file on disk has changed, we have to save it in the database
  108. if fileChanged or len(volume.rawFrames) == 0:
  109. if settings.REDUCE_HARDDISK_ACCESS_FOR_DEV is False:
  110. logger.debug('volId: %s, deleting rawframes from volume' % volumeId)
  111. volume.remove_frames()
  112. else:
  113. logger.debug('volId: %s, not deleting rawframes from volume --> reducing harddisk access' % volumeId)
  114. logger.debug('volId: %s, setting rawframes' % volumeId)
  115. try:
  116. for frameNumber in range(0, len(squared_frames)):
  117. logger.debug('volId: %s, rawFrame: %d, sizeInMemory: %d' % (volumeId, frameNumber, sys.getsizeof(squared_frames[frameNumber])))
  118. rawFrame = volume.add_frame(squared_frames[frameNumber], frameNumber)
  119. except Exception as e:
  120. logger.error('volId: %s, please provide integers or "" for "sliceFrom" and "sliceTo" exception was: %s' % (volumeId, str(e)))
  121. Volume.objects(id=volume.id).update_one(set__generateSlicesStatus='generation failed, please read the logs')
  122. return
  123. else:
  124. rawFrame = volume.rawFrames[0]
  125. logger.debug('volId: %s, rawframes have been appended to volume' % volumeId)
  126. try:
  127. logger.debug('volId: %s, convert images to ubyte for generating preview textures' % volumeId)
  128. framesUByte = MultiProcessUByte.multiprocess_img_as_ubyte(squared_frames)
  129. del squared_frames
  130. logger.debug('volId: %s, memory freed, squared_frames deleted, keeping ubyte frames' % volumeId)
  131. except Exception as e:
  132. logger.error('volId: %s, exception: %s' % (volumeId, str(e)))
  133. Volume.objects(id=volume.id).update_one(set__generateSlicesStatus=str(e))
  134. return
  135. logger.debug('volId: %s, converting ended' % volumeId)
  136. originalSize = rawFrame.originalSize
  137. # free more memory
  138. logger.debug('volId: %s, del volume object now from RAM, free memory' % volumeId)
  139. del volume
  140. volume = Volume.objects(id=volumeId)[0]
  141. try:
  142. logger.debug('volId: %s, processing the image now' % volumeId)
  143. sprites = sliceMapCreator.processFrames(framesUByte, 0, len(framesUByte - 1), sliceFrom, sliceTo, imgFormat, size)
  144. infoObject = sliceMapCreator.generateInfo(sprites, 0, len(framesUByte) - 1, sliceFrom, sliceTo)
  145. except Exception as e:
  146. logger.error('volId: %s, exception: %s' % (volumeId, str(e)))
  147. Volume.objects(id=volume.id).update_one(set__generateSlicesStatus=str(e))
  148. return
  149. try:
  150. volume.clear_textures()
  151. except Exception as e:
  152. logger.error('volId: %s, exception: %s' % (volumeId, str(e)))
  153. Volume.objects(id=volume.id).update_one(set__generateSlicesStatus=str(e))
  154. return
  155. try:
  156. logger.debug('volId: %s, save sprites in volume' % volumeId)
  157. for key in sprites:
  158. volume.add_slice_maps(int(key), sprites[key], originalSize, infoObject)
  159. except Exception as e:
  160. logger.error('volId: %s, exception: %s' % (volumeId, str(e)))
  161. Volume.objects(id=volume.id).update_one(set__generateSlicesStatus=str(e))
  162. return
  163. Volume.objects(id=volume.id).update_one(set__generateSlicesStatus='generation successful')
  164. logger.debug('volId: %s, generation successful' % volumeId)
  165. def __defineSliceRange(frames, sliceFrom, sliceTo):
  166. '''
  167. This method returns the range of slices, that
  168. shall be generated
  169. '''
  170. if sliceFrom != '':
  171. sliceFrom = int(sliceFrom)
  172. else:
  173. sliceFrom = 0
  174. if sliceTo != '':
  175. sliceTo = int(sliceTo)
  176. else:
  177. dim = len(frames.shape)
  178. # accessing shape in z dim
  179. sliceTo = frames.shape[dim - 3] - 1
  180. return (sliceFrom, sliceTo)