__init__.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. from .pixelwise import bleach_correct_pixelwise
  2. from ...idl_translation_core.bleach_correction import fitlogdecay, get_bleach_weights
  3. import numpy as np
  4. import platform
  5. import multiprocessing as mp
  6. class NoBleachCompensator(object):
  7. def __init__(self):
  8. super().__init__()
  9. def apply(self, stack_xyt: np.ndarray, area_mask: np.ndarray):
  10. """
  11. Apply bleach correction to the movie `stack_xyt`
  12. :param numpy.ndarray stack_xyt: 3D, format XYT
  13. :param numpy.ndarray area: 2D, formay XY
  14. :return: bleach corrected movie
  15. :rtype: numpy.ndarray, same shape and format as `stack_xyt`
  16. """
  17. return stack_xyt, None
  18. class BaseBleachCompensator(NoBleachCompensator):
  19. def __init__(self, flags, p1_metadata, movie_size):
  20. """
  21. :param FlagsManager flags:
  22. :param pandas.Series p1_metadata: experimental metadata
  23. :param tuple movie_size: raw data size, format XYT
  24. :return: an object that can be used to apply bleach compensation
  25. """
  26. super().__init__()
  27. self.weights = get_bleach_weights(
  28. flags=flags, p1_metadata=p1_metadata, movie_size=movie_size,
  29. exclude_stimulus=flags["LE_BleachExcludeStimulus"])
  30. class PixelWiseBleachCompensatorParallel(BaseBleachCompensator):
  31. def __init__(self, flags, p1_metadata, movie_size):
  32. """
  33. :param FlagsManager flags:
  34. :param pandas.Series p1_metadata: experimental metadata
  35. :return: an object that can be used to apply bleach compensation
  36. """
  37. super().__init__(flags, p1_metadata, movie_size)
  38. self.ncpu = mp.cpu_count()
  39. def apply(self, stack_xyt: np.ndarray, area_mask: np.ndarray):
  40. """
  41. Apply bleach correction to the movie `stack_xyt`
  42. :param numpy.ndarray stack_xyt: 3D, format XYT
  43. :param numpy.ndarray area_mask: 2D, formay XY
  44. :return: bleach corrected movie
  45. :rtype: numpy.ndarray, same shape and format as `stack_xyt`
  46. """
  47. return bleach_correct_pixelwise(
  48. movie=stack_xyt, weights=self.weights, area=area_mask, ncpu=self.ncpu)
  49. class PixelWiseBleachCompensator1CPU(PixelWiseBleachCompensatorParallel):
  50. def __init__(self, flags, p1_metadata, movie_size):
  51. """
  52. :param FlagsManager flags:
  53. :param pandas.Series p1_metadata: experimental metadata
  54. :return: an object that can be used to apply bleach compensation
  55. """
  56. super().__init__(flags, p1_metadata, movie_size)
  57. self.ncpu = 1
  58. class UniformBleachCompensator(BaseBleachCompensator):
  59. def __init__(self, flags, p1_metadata, movie_size):
  60. super().__init__(flags, p1_metadata, movie_size)
  61. self.background_frames = p1_metadata.background_frames
  62. self.show_results = not flags["VIEW_batchmode"]
  63. self.measurement_label = p1_metadata['ex_name']
  64. def apply(self, stack_xyt: np.ndarray, area_mask: np.ndarray):
  65. # converting data temporarily to txy format as it is easier to divide the movie by
  66. # a frame in this format
  67. stack_txy = np.moveaxis(stack_xyt, source=-1, destination=0)
  68. # take average over background frames for all pixels
  69. F0_frame = stack_xyt[:, :, self.background_frames[0]: self.background_frames[1] + 1].mean(axis=2)
  70. # divide each frame by F0_frame (background frame)
  71. F_by_F0_txy = stack_txy / F0_frame
  72. # apply area_mask
  73. F_by_F0_txy_masked = F_by_F0_txy * area_mask.astype(int)
  74. # average each frame to make a curve
  75. # (some pixels in F0_frame might have values of 0, so F_by_F0_txy might have nans)
  76. curve = np.nanmean(F_by_F0_txy_masked, axis=(1, 2))
  77. # apply bleach correction to curve and return the parameters A, K and C
  78. fitted_curve, (A, K, C) = fitlogdecay(lineIn=curve, weights=self.weights, showresults=self.show_results, measurement_label=self.measurement_label)
  79. # converting to xyt as it is easier to subtract a trace from all pixels in this format
  80. F_by_F0_xyt = np.moveaxis(F_by_F0_txy, source=0, destination=-1)
  81. # the third component ensures that the average intensity of each pixel is not
  82. # affected by the bleach correction applied
  83. corrected_F_by_F0_xyt = F_by_F0_xyt - fitted_curve + fitted_curve.mean()
  84. # converting to txy as it easier to multiply by a frame in this format
  85. corrected_F_by_F0_txy = np.moveaxis(corrected_F_by_F0_xyt, source=-1, destination=0)
  86. corrected_raw_txy = corrected_F_by_F0_txy * F0_frame
  87. # converting back to our stadard format xyt
  88. raw_corrected = np.moveaxis(corrected_raw_txy, source=0, destination=-1)
  89. return raw_corrected, (A, K, C)
  90. def get_bleach_compensator(flags, p1_metadata, movie_size):
  91. """
  92. Get an object whose "apply" method can apply bleach compensation to a movie
  93. :param FlagsManager flags:
  94. :param pandas.Series p1_metadata: experimental metadata
  95. :return: an object that can be used to apply bleach compensation
  96. """
  97. if flags["LE_BleachCorrMethod"] == "None":
  98. return NoBleachCompensator()
  99. if flags["LE_BleachCorrMethod"] == "log_pixelwise_1cpu":
  100. return PixelWiseBleachCompensator1CPU(flags, p1_metadata, movie_size)
  101. if flags["LE_BleachCorrMethod"] == "log_pixelwise_parallel":
  102. return PixelWiseBleachCompensatorParallel(flags, p1_metadata, movie_size)
  103. elif flags["LE_BleachCorrMethod"] == "log_uniform":
  104. return UniformBleachCompensator(flags, p1_metadata, movie_size)
  105. else:
  106. raise NotImplementedError