batoolset 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. batoolset/GUI/__init__.py +0 -0
  2. batoolset/GUI/list_gui.py +513 -0
  3. batoolset/GUI/multi_image_display.py +989 -0
  4. batoolset/GUI/open.py +325 -0
  5. batoolset/GUI/overlay_hints.py +45 -0
  6. batoolset/GUI/paint2.py +1345 -0
  7. batoolset/GUI/scrollablepaint.py +1152 -0
  8. batoolset/IJ_ROIs/__init__.py +0 -0
  9. batoolset/IJ_ROIs/tools.py +40 -0
  10. batoolset/PATH/__init__.py +0 -0
  11. batoolset/PATH/tools.py +79 -0
  12. batoolset/SQLite_tools/__init__.py +0 -0
  13. batoolset/SQLite_tools/tools.py +840 -0
  14. batoolset/__init__.py +0 -0
  15. batoolset/binary/__init__.py +0 -0
  16. batoolset/binary/tools.py +123 -0
  17. batoolset/binarytools/__init__.py +0 -0
  18. batoolset/binarytools/cell_center_detector.py +290 -0
  19. batoolset/clipboard_tools/__init__.py +0 -0
  20. batoolset/clipboard_tools/tools.py +7 -0
  21. batoolset/colors/__init__.py +0 -0
  22. batoolset/colors/colorgen.py +193 -0
  23. batoolset/colors/tools.py +22 -0
  24. batoolset/command_line/__init__.py +0 -0
  25. batoolset/command_line/tools.py +18 -0
  26. batoolset/dialogs/__init__.py +0 -0
  27. batoolset/dialogs/opensave.py +228 -0
  28. batoolset/dicts/__init__.py +0 -0
  29. batoolset/dicts/tools.py +299 -0
  30. batoolset/dims/__init__.py +0 -0
  31. batoolset/dims/tools.py +83 -0
  32. batoolset/draw/__init__.py +0 -0
  33. batoolset/draw/shapes/Position.py +183 -0
  34. batoolset/draw/shapes/__init__.py +0 -0
  35. batoolset/draw/shapes/automated_alignment_drawing_refactored.py +346 -0
  36. batoolset/draw/shapes/circle2d.py +99 -0
  37. batoolset/draw/shapes/compute_optimal_size_all_merged.py +317 -0
  38. batoolset/draw/shapes/ellipse2d.py +336 -0
  39. batoolset/draw/shapes/freehand2d.py +235 -0
  40. batoolset/draw/shapes/group.py +1830 -0
  41. batoolset/draw/shapes/image2d.py +2469 -0
  42. batoolset/draw/shapes/line2d.py +575 -0
  43. batoolset/draw/shapes/point2d.py +257 -0
  44. batoolset/draw/shapes/polygon2d.py +357 -0
  45. batoolset/draw/shapes/polyline2d.py +235 -0
  46. batoolset/draw/shapes/rect2d.py +388 -0
  47. batoolset/draw/shapes/rectangle2d.py +601 -0
  48. batoolset/draw/shapes/scalebar.py +304 -0
  49. batoolset/draw/shapes/serializablefont.py +126 -0
  50. batoolset/draw/shapes/serializableguiparams.py +10 -0
  51. batoolset/draw/shapes/square2d.py +103 -0
  52. batoolset/draw/shapes/textorientation.py +45 -0
  53. batoolset/draw/shapes/tools.py +467 -0
  54. batoolset/draw/shapes/transform2D.py +350 -0
  55. batoolset/draw/shapes/txt2d.py +550 -0
  56. batoolset/draw/widgets/__init__.py +0 -0
  57. batoolset/draw/widgets/col.py +343 -0
  58. batoolset/draw/widgets/image_group.py +248 -0
  59. batoolset/draw/widgets/image_organizer.py +96 -0
  60. batoolset/draw/widgets/paint.py +184 -0
  61. batoolset/draw/widgets/vectorial.py +257 -0
  62. batoolset/figure/__init__.py +0 -0
  63. batoolset/figure/alignment.py +814 -0
  64. batoolset/figure/column.py +1117 -0
  65. batoolset/figure/fig_tools.py +285 -0
  66. batoolset/figure/minimal_debugger_scale_etc.py +139 -0
  67. batoolset/figure/panel.py +697 -0
  68. batoolset/figure/row.py +852 -0
  69. batoolset/figure/user_selection.py +287 -0
  70. batoolset/files/__init__.py +0 -0
  71. batoolset/files/tools.py +1321 -0
  72. batoolset/images/__init__.py +0 -0
  73. batoolset/images/tools.py +81 -0
  74. batoolset/img.py +5216 -0
  75. batoolset/linux/__init__.py +0 -0
  76. batoolset/linux/tools.py +72 -0
  77. batoolset/lists/__init__.py +0 -0
  78. batoolset/lists/tools.py +436 -0
  79. batoolset/luts/__init__.py +0 -0
  80. batoolset/luts/lut_minimal_test.py +1207 -0
  81. batoolset/matplolib/__init__.py +0 -0
  82. batoolset/matplolib/tools.py +44 -0
  83. batoolset/np_tools/__init__.py +0 -0
  84. batoolset/np_tools/tools.py +252 -0
  85. batoolset/np_tools/trash.py +15 -0
  86. batoolset/pandas_tools/__init__.py +0 -0
  87. batoolset/pandas_tools/tools.py +880 -0
  88. batoolset/partials/__init__.py +0 -0
  89. batoolset/partials/tools.py +83 -0
  90. batoolset/plot_tools/__init__.py +0 -0
  91. batoolset/plot_tools/tools.py +70 -0
  92. batoolset/pyqt/__init__.py +0 -0
  93. batoolset/pyqt/tools.py +691 -0
  94. batoolset/re_tools/__init__.py +0 -0
  95. batoolset/re_tools/tools.py +35 -0
  96. batoolset/serialization/__init__.py +0 -0
  97. batoolset/serialization/tools.py +1192 -0
  98. batoolset/sets/__init__.py +0 -0
  99. batoolset/sets/tools.py +109 -0
  100. batoolset/settings/__init__.py +0 -0
  101. batoolset/settings/global_settings.py +134 -0
  102. batoolset/strings/__init__.py +0 -0
  103. batoolset/strings/tools.py +225 -0
  104. batoolset/ta/__init__.py +0 -0
  105. batoolset/ta/database/__init__.py +0 -0
  106. batoolset/ta/database/advanced_sql_plotter.py +1170 -0
  107. batoolset/ta/database/my_qt_table.py +79 -0
  108. batoolset/ta/database/preview_and_edit_sqlite_db.py +405 -0
  109. batoolset/ta/database/sql.py +2141 -0
  110. batoolset/ta/database/sql_column_name_dialog.py +122 -0
  111. batoolset/ta/measurements/TAmeasures.py +2226 -0
  112. batoolset/ta/measurements/__init__.py +0 -0
  113. batoolset/ta/measurements/measurements3D/__init__.py +0 -0
  114. batoolset/ta/measurements/measurements3D/get_point_on_surface_if_centroid_is_bad.py +175 -0
  115. batoolset/ta/measurements/measurements3D/height_map_to_projection.py +82 -0
  116. batoolset/ta/measurements/measurements3D/measures3D.py +208 -0
  117. batoolset/ta/measurements/measurements3D/triangulate.py +331 -0
  118. batoolset/ta/measurements/nematic.py +562 -0
  119. batoolset/ta/measurements/nematic_measurements.py +107 -0
  120. batoolset/ta/segmentation/__init__.py +0 -0
  121. batoolset/ta/segmentation/neo_wshed.py +314 -0
  122. batoolset/ta/selections/__init__.py +0 -0
  123. batoolset/ta/selections/selection.py +329 -0
  124. batoolset/ta/tracking/__init__.py +0 -0
  125. batoolset/ta/tracking/last_tracking_based_on_matching_or_on_translation_from_mermaid_warp.py +653 -0
  126. batoolset/ta/tracking/local_to_track_correspondance.py +138 -0
  127. batoolset/ta/tracking/rapid_detection_of_vertices.py +517 -0
  128. batoolset/ta/tracking/registration.py +108 -0
  129. batoolset/ta/tracking/swap_detector_and_fixer.py +296 -0
  130. batoolset/ta/tracking/track_correction.py +238 -0
  131. batoolset/ta/tracking/tracking_error_detector_and_fixer.py +3099 -0
  132. batoolset/ta/tracking/tracking_yet_another_approach_pyramidal_registration_n_neo_swapping_correction.py +725 -0
  133. batoolset/ta/utils/TA_tools.py +43 -0
  134. batoolset/ta/utils/__init__.py +0 -0
  135. batoolset/ta/utils/rps_tools.py +1783 -0
  136. batoolset/tests/__init__.py +0 -0
  137. batoolset/tests/rps_tools.py +51 -0
  138. batoolset/tests/tools.py +10 -0
  139. batoolset/tools/__init__.py +0 -0
  140. batoolset/tools/early_stopper_class.py +9 -0
  141. batoolset/tools/guided_data_recoverer.py +110 -0
  142. batoolset/tools/logger.py +100 -0
  143. batoolset/tools/mytimer.py +31 -0
  144. batoolset/tools/prompt_color.py +160 -0
  145. batoolset/tools/qthandler.py +118 -0
  146. batoolset/uitools/__init__.py +0 -0
  147. batoolset/uitools/blinker.py +56 -0
  148. batoolset/unsafe/__init__.py +0 -0
  149. batoolset/unsafe/tools.py +115 -0
  150. batoolset/utils/__init__.py +0 -0
  151. batoolset/utils/commontools.py +158 -0
  152. batoolset/utils/loadlist.py +728 -0
  153. batoolset/version.py +10 -0
  154. batoolset/xml/__init__.py +0 -0
  155. batoolset/xml/tools.py +65 -0
  156. batoolset/zip_tools/__init__.py +0 -0
  157. batoolset/zip_tools/tools.py +76 -0
  158. batoolset-0.1.0.dist-info/LICENSE +24 -0
  159. batoolset-0.1.0.dist-info/METADATA +45 -0
  160. batoolset-0.1.0.dist-info/RECORD +162 -0
  161. batoolset-0.1.0.dist-info/WHEEL +5 -0
  162. batoolset-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1207 @@
1
+ # TODO could easily do a lut browser and editor --> would be really easy and may be useful too --> some day do it but not now !!!
2
+ # this is a minimal but already quite good version of the TA LUT class
3
+ import random
4
+ import traceback
5
+ from matplotlib.colors import ListedColormap
6
+ import math
7
+ from batoolset.img import int24_to_RGB
8
+ import matplotlib.pyplot as plt
9
+ import numpy as np
10
+ from matplotlib.backends.backend_agg import FigureCanvasAgg
11
+ from matplotlib.figure import Figure
12
+ from batoolset.img import fig_to_numpy
13
+ import base64
14
+
15
+ def serialize_lut(lut_256_3):
16
+ # see also /home/aigouy/mon_prog/Python/epyseg_pkg/personal/FigGen_EzFig2/trash/tst_base64_encode_the_whole_np_array.py
17
+ # this generates a string that can be serialized
18
+ encoded_data = base64.b64encode(lut_256_3).decode()
19
+ return encoded_data
20
+
21
+ def deserialize_lut(string_lut, make_editable=True):
22
+ # see also /home/aigouy/mon_prog/Python/epyseg_pkg/personal/FigGen_EzFig2/trash/tst_base64_encode_the_whole_np_array.py
23
+ decoded_data = np.frombuffer(base64.b64decode(string_lut), dtype=np.uint8)
24
+ decoded_data = decoded_data.reshape((256, 3))
25
+ if make_editable:
26
+ decoded_data = decoded_data.copy() # required to make it editable
27
+ return decoded_data
28
+
29
+
30
+ def cmap_to_numpy(lut):
31
+ """
32
+ Converts a colormap to a NumPy array.
33
+
34
+ Args:
35
+ lut (Union[str, numpy.ndarray]): The colormap as a string name or a NumPy array.
36
+
37
+ Returns:
38
+ numpy.ndarray: The NumPy array representing the colormap.
39
+
40
+ Examples:
41
+ >>> colormap = 'hot'
42
+ >>> result = cmap_to_numpy(colormap)
43
+ >>> print(result[:1])
44
+ [[10 0 0]]
45
+
46
+ """
47
+ if isinstance(lut, str):
48
+ cm = plt.get_cmap(lut)
49
+ else:
50
+ cm = lut
51
+ out = cm(range(256)) * 255
52
+ out = out[..., 0:3].astype(np.uint8)
53
+ return out
54
+
55
+
56
+ def numpy_to_cmap(lut):
57
+ """
58
+ Converts a NumPy array to a colormap.
59
+
60
+ Args:
61
+ lut (numpy.ndarray): The NumPy array representing the colormap.
62
+
63
+ Returns:
64
+ matplotlib.colors.ListedColormap: The colormap created from the NumPy array.
65
+
66
+ # Examples:
67
+ # >>> colormap_array = np.array([[255, 0, 0], [0, 255, 0], [0, 0, 255]])
68
+ # >>> result = numpy_to_cmap(colormap_array)
69
+ # >>> print(result)
70
+ # <matplotlib.colors.ListedColormap object at 0x...>
71
+
72
+ """
73
+ lut_cp = np.copy(lut)
74
+ if lut_cp.max() > 1:
75
+ lut_cp = lut_cp / 255.
76
+
77
+ if lut_cp.shape[-1] == 3:
78
+ tmp = np.ones((256, 4), dtype=np.float64)
79
+ tmp[..., 0:3] = lut_cp[..., :]
80
+ lut_cp = tmp
81
+ newcmp = ListedColormap(lut_cp)
82
+ return newcmp
83
+
84
+
85
+ def create_ramp(min_val, max_val, lut, orientation='vertical'):
86
+ """
87
+ Creates a color ramp image using a colormap.
88
+
89
+ Args:
90
+ min_val (float): The minimum value of the color ramp.
91
+ max_val (float): The maximum value of the color ramp.
92
+ lut (Union[str, numpy.ndarray]): The colormap as a string name or a NumPy array.
93
+ orientation (str, optional): The orientation of the color ramp. Defaults to 'vertical'.
94
+
95
+ Returns:
96
+ numpy.ndarray: The color ramp image.
97
+
98
+ # Examples:
99
+ # >>> min_value = 0
100
+ # >>> max_value = 255
101
+ # >>> colormap = 'hot'
102
+ # >>> result = create_ramp(min_value, max_value, colormap)
103
+ # >>> print(result)
104
+
105
+
106
+ """
107
+ img = np.zeros((2, 1))
108
+ img[0] = min_val
109
+ img[1] = max_val
110
+ fig = Figure(tight_layout=True)
111
+ canvas = FigureCanvasAgg(fig)
112
+ ax = fig.subplots()
113
+
114
+ cmap = lut
115
+ if isinstance(lut, np.ndarray):
116
+ cmap = numpy_to_cmap(lut)
117
+
118
+ im = ax.imshow(img, cmap=cmap)
119
+ fig.colorbar(im, ax=ax, orientation=orientation)
120
+ ax.set_axis_off()
121
+ ax.remove()
122
+ canvas.draw()
123
+ img = fig_to_numpy(fig)
124
+ return img
125
+
126
+
127
+ def list_available_luts(return_matplotlib_lib_luts_in_separate_database=False):
128
+ """
129
+ Returns a dictionary of available colormaps.
130
+
131
+ Args:
132
+ return_matplotlib_lib_luts_in_separate_database (bool, optional): Whether to include matplotlib library colormaps separately. Defaults to False.
133
+
134
+ Returns:
135
+ dict: A dictionary containing the available colormaps.
136
+
137
+ Examples:
138
+ >>> result = list_available_luts()
139
+ >>> print(result)
140
+ {'DEFAULT': '22,13,-23', 'AFM_HOT': '34,35,36', 'GREEN': '0,3,0', 'RED': '3,0,0', 'BLUE': '0,0,3', 'GRAY': '3,3,3', 'GREY': '3,3,3', 'PACKING': 'PACKING', 'RED_HOT': '21,22,23', 'GREEN_HOT': '35,34,23', 'BLUE_HOT': '23,22,21', 'OCEAN': '23,28,3', 'GREEN_RED_VIOLET': '3,11,6', 'COLOR_PRINTABLE_ON_GRAY': '30,31,32', 'HI_LO': '3,3,3hl', 'DNA': '22,13,-23', 'RAINBOW_1': '22,13,-31', 'RAINBOW_2': '35,13,-35', 'RAINBOW_3': '33,13,10', 'RAINBOW_LIGHT': '33,13,-31', 'RAINBOW_ARTIFICIAL': '10,13,33', 'BLUE_WHITE_RED': '34,-13,-34', 'BROWN': '7,4,27', 'GREEN_FIRE_BLUE': '31,34,11', 'GREEN_FIRE_BLUE2': '31,34,29', 'ORANGE': '3,5,0', 'ORANGE_HOT': '21,-10,23', 'YELLOW_HOT': '34,-10,23', 'YELLOW': '3,3,0', 'YELLOW_PALE': '34,34,4', 'PURPLE_HOT': '34,36,34', 'PURPLE': '3,0,3', 'MAGENTA_HOT': '34,36,34', 'MAGENTA': '3,0,3', 'CYAN': '0,3,3', 'CYAN_HOT': '36,34,34', 'PM3D': '7,5,15', 'HSV': '3,2,2', 'HSV2': '7,5,15', 'YING_YANG': '13,13,13', 'YING_YANG2': '14,14,14', 'CYCLIC': '19,19,19', 'METEO1': '34,-35,-36', 'METEO2': '22,13,-31', 'DIABOLO_MENTHE': '-7,2,-7', 'DIABOLO_GRENADINE': '2,-7,-7', 'BLACK_PURPLE_PINK_WHITE': '30,31,32', 'RED_BLACK_BLUE': '-36,0,36', 'MATPLOTLIB_magma': 'magma', 'MATPLOTLIB_inferno': 'inferno', 'MATPLOTLIB_plasma': 'plasma', 'MATPLOTLIB_viridis': 'viridis', 'MATPLOTLIB_cividis': 'cividis', 'MATPLOTLIB_twilight': 'twilight', 'MATPLOTLIB_twilight_shifted': 'twilight_shifted', 'MATPLOTLIB_turbo': 'turbo', 'MATPLOTLIB_Blues': 'Blues', 'MATPLOTLIB_BrBG': 'BrBG', 'MATPLOTLIB_BuGn': 'BuGn', 'MATPLOTLIB_BuPu': 'BuPu', 'MATPLOTLIB_CMRmap': 'CMRmap', 'MATPLOTLIB_GnBu': 'GnBu', 'MATPLOTLIB_Greens': 'Greens', 'MATPLOTLIB_Greys': 'Greys', 'MATPLOTLIB_OrRd': 'OrRd', 'MATPLOTLIB_Oranges': 'Oranges', 'MATPLOTLIB_PRGn': 'PRGn', 'MATPLOTLIB_PiYG': 'PiYG', 'MATPLOTLIB_PuBu': 'PuBu', 'MATPLOTLIB_PuBuGn': 'PuBuGn', 'MATPLOTLIB_PuOr': 'PuOr', 'MATPLOTLIB_PuRd': 'PuRd', 'MATPLOTLIB_Purples': 'Purples', 'MATPLOTLIB_RdBu': 'RdBu', 'MATPLOTLIB_RdGy': 'RdGy', 'MATPLOTLIB_RdPu': 'RdPu', 'MATPLOTLIB_RdYlBu': 'RdYlBu', 'MATPLOTLIB_RdYlGn': 'RdYlGn', 'MATPLOTLIB_Reds': 'Reds', 'MATPLOTLIB_Spectral': 'Spectral', 'MATPLOTLIB_Wistia': 'Wistia', 'MATPLOTLIB_YlGn': 'YlGn', 'MATPLOTLIB_YlGnBu': 'YlGnBu', 'MATPLOTLIB_YlOrBr': 'YlOrBr', 'MATPLOTLIB_YlOrRd': 'YlOrRd', 'MATPLOTLIB_afmhot': 'afmhot', 'MATPLOTLIB_autumn': 'autumn', 'MATPLOTLIB_binary': 'binary', 'MATPLOTLIB_bone': 'bone', 'MATPLOTLIB_brg': 'brg', 'MATPLOTLIB_bwr': 'bwr', 'MATPLOTLIB_cool': 'cool', 'MATPLOTLIB_coolwarm': 'coolwarm', 'MATPLOTLIB_copper': 'copper', 'MATPLOTLIB_cubehelix': 'cubehelix', 'MATPLOTLIB_flag': 'flag', 'MATPLOTLIB_gist_earth': 'gist_earth', 'MATPLOTLIB_gist_gray': 'gist_gray', 'MATPLOTLIB_gist_heat': 'gist_heat', 'MATPLOTLIB_gist_ncar': 'gist_ncar', 'MATPLOTLIB_gist_rainbow': 'gist_rainbow', 'MATPLOTLIB_gist_stern': 'gist_stern', 'MATPLOTLIB_gist_yarg': 'gist_yarg', 'MATPLOTLIB_gnuplot': 'gnuplot', 'MATPLOTLIB_gnuplot2': 'gnuplot2', 'MATPLOTLIB_gray': 'gray', 'MATPLOTLIB_hot': 'hot', 'MATPLOTLIB_hsv': 'hsv', 'MATPLOTLIB_jet': 'jet', 'MATPLOTLIB_nipy_spectral': 'nipy_spectral', 'MATPLOTLIB_ocean': 'ocean', 'MATPLOTLIB_pink': 'pink', 'MATPLOTLIB_prism': 'prism', 'MATPLOTLIB_rainbow': 'rainbow', 'MATPLOTLIB_seismic': 'seismic', 'MATPLOTLIB_spring': 'spring', 'MATPLOTLIB_summer': 'summer', 'MATPLOTLIB_terrain': 'terrain', 'MATPLOTLIB_winter': 'winter', 'MATPLOTLIB_Accent': 'Accent', 'MATPLOTLIB_Dark2': 'Dark2', 'MATPLOTLIB_Paired': 'Paired', 'MATPLOTLIB_Pastel1': 'Pastel1', 'MATPLOTLIB_Pastel2': 'Pastel2', 'MATPLOTLIB_Set1': 'Set1', 'MATPLOTLIB_Set2': 'Set2', 'MATPLOTLIB_Set3': 'Set3', 'MATPLOTLIB_tab10': 'tab10', 'MATPLOTLIB_tab20': 'tab20', 'MATPLOTLIB_tab20b': 'tab20b', 'MATPLOTLIB_tab20c': 'tab20c', 'MATPLOTLIB_magma_r': 'magma_r', 'MATPLOTLIB_inferno_r': 'inferno_r', 'MATPLOTLIB_plasma_r': 'plasma_r', 'MATPLOTLIB_viridis_r': 'viridis_r', 'MATPLOTLIB_cividis_r': 'cividis_r', 'MATPLOTLIB_twilight_r': 'twilight_r', 'MATPLOTLIB_twilight_shifted_r': 'twilight_shifted_r', 'MATPLOTLIB_turbo_r': 'turbo_r', 'MATPLOTLIB_Blues_r': 'Blues_r', 'MATPLOTLIB_BrBG_r': 'BrBG_r', 'MATPLOTLIB_BuGn_r': 'BuGn_r', 'MATPLOTLIB_BuPu_r': 'BuPu_r', 'MATPLOTLIB_CMRmap_r': 'CMRmap_r', 'MATPLOTLIB_GnBu_r': 'GnBu_r', 'MATPLOTLIB_Greens_r': 'Greens_r', 'MATPLOTLIB_Greys_r': 'Greys_r', 'MATPLOTLIB_OrRd_r': 'OrRd_r', 'MATPLOTLIB_Oranges_r': 'Oranges_r', 'MATPLOTLIB_PRGn_r': 'PRGn_r', 'MATPLOTLIB_PiYG_r': 'PiYG_r', 'MATPLOTLIB_PuBu_r': 'PuBu_r', 'MATPLOTLIB_PuBuGn_r': 'PuBuGn_r', 'MATPLOTLIB_PuOr_r': 'PuOr_r', 'MATPLOTLIB_PuRd_r': 'PuRd_r', 'MATPLOTLIB_Purples_r': 'Purples_r', 'MATPLOTLIB_RdBu_r': 'RdBu_r', 'MATPLOTLIB_RdGy_r': 'RdGy_r', 'MATPLOTLIB_RdPu_r': 'RdPu_r', 'MATPLOTLIB_RdYlBu_r': 'RdYlBu_r', 'MATPLOTLIB_RdYlGn_r': 'RdYlGn_r', 'MATPLOTLIB_Reds_r': 'Reds_r', 'MATPLOTLIB_Spectral_r': 'Spectral_r', 'MATPLOTLIB_Wistia_r': 'Wistia_r', 'MATPLOTLIB_YlGn_r': 'YlGn_r', 'MATPLOTLIB_YlGnBu_r': 'YlGnBu_r', 'MATPLOTLIB_YlOrBr_r': 'YlOrBr_r', 'MATPLOTLIB_YlOrRd_r': 'YlOrRd_r', 'MATPLOTLIB_afmhot_r': 'afmhot_r', 'MATPLOTLIB_autumn_r': 'autumn_r', 'MATPLOTLIB_binary_r': 'binary_r', 'MATPLOTLIB_bone_r': 'bone_r', 'MATPLOTLIB_brg_r': 'brg_r', 'MATPLOTLIB_bwr_r': 'bwr_r', 'MATPLOTLIB_cool_r': 'cool_r', 'MATPLOTLIB_coolwarm_r': 'coolwarm_r', 'MATPLOTLIB_copper_r': 'copper_r', 'MATPLOTLIB_cubehelix_r': 'cubehelix_r', 'MATPLOTLIB_flag_r': 'flag_r', 'MATPLOTLIB_gist_earth_r': 'gist_earth_r', 'MATPLOTLIB_gist_gray_r': 'gist_gray_r', 'MATPLOTLIB_gist_heat_r': 'gist_heat_r', 'MATPLOTLIB_gist_ncar_r': 'gist_ncar_r', 'MATPLOTLIB_gist_rainbow_r': 'gist_rainbow_r', 'MATPLOTLIB_gist_stern_r': 'gist_stern_r', 'MATPLOTLIB_gist_yarg_r': 'gist_yarg_r', 'MATPLOTLIB_gnuplot_r': 'gnuplot_r', 'MATPLOTLIB_gnuplot2_r': 'gnuplot2_r', 'MATPLOTLIB_gray_r': 'gray_r', 'MATPLOTLIB_hot_r': 'hot_r', 'MATPLOTLIB_hsv_r': 'hsv_r', 'MATPLOTLIB_jet_r': 'jet_r', 'MATPLOTLIB_nipy_spectral_r': 'nipy_spectral_r', 'MATPLOTLIB_ocean_r': 'ocean_r', 'MATPLOTLIB_pink_r': 'pink_r', 'MATPLOTLIB_prism_r': 'prism_r', 'MATPLOTLIB_rainbow_r': 'rainbow_r', 'MATPLOTLIB_seismic_r': 'seismic_r', 'MATPLOTLIB_spring_r': 'spring_r', 'MATPLOTLIB_summer_r': 'summer_r', 'MATPLOTLIB_terrain_r': 'terrain_r', 'MATPLOTLIB_winter_r': 'winter_r', 'MATPLOTLIB_Accent_r': 'Accent_r', 'MATPLOTLIB_Dark2_r': 'Dark2_r', 'MATPLOTLIB_Paired_r': 'Paired_r', 'MATPLOTLIB_Pastel1_r': 'Pastel1_r', 'MATPLOTLIB_Pastel2_r': 'Pastel2_r', 'MATPLOTLIB_Set1_r': 'Set1_r', 'MATPLOTLIB_Set2_r': 'Set2_r', 'MATPLOTLIB_Set3_r': 'Set3_r', 'MATPLOTLIB_tab10_r': 'tab10_r', 'MATPLOTLIB_tab20_r': 'tab20_r', 'MATPLOTLIB_tab20b_r': 'tab20b_r', 'MATPLOTLIB_tab20c_r': 'tab20c_r'}
141
+
142
+ """
143
+ hash_pal = {
144
+ "DEFAULT": "22,13,-23",
145
+ "GREEN": "0,3,0",
146
+ "RED": "3,0,0",
147
+ "BLUE": "0,0,3",
148
+ "GRAY": "3,3,3",
149
+ "GREY": "3,3,3",
150
+ "AFM_HOT": "34,35,36",
151
+ "PACKING": "PACKING",
152
+ "RED_HOT": "21,22,23",
153
+ "GREEN_HOT": "35,34,23",
154
+ "BLUE_HOT": "23,22,21",
155
+ "OCEAN": "23,28,3",
156
+ "GREEN_RED_VIOLET": "3,11,6",
157
+ "COLOR_PRINTABLE_ON_GRAY": "30,31,32",
158
+ "HI_LO": "3,3,3hl",
159
+ "DNA": "22,13,-23",
160
+ "RAINBOW_1": "22,13,-31",
161
+ "RAINBOW_2": "35,13,-35",
162
+ "RAINBOW_3": "33,13,10",
163
+ "RAINBOW_LIGHT": "33,13,-31",
164
+ "RAINBOW_ARTIFICIAL": "10,13,33",
165
+ "BLUE_WHITE_RED": "34,-13,-34",
166
+ "BROWN": "7,4,27",
167
+ "GREEN_FIRE_BLUE": "31,34,11",
168
+ "GREEN_FIRE_BLUE2": "31,34,29",
169
+ "ORANGE": "3,5,0",
170
+ "ORANGE_HOT": "21,-10,23",
171
+ "YELLOW_HOT": "34,-10,23",
172
+ "YELLOW": "3,3,0",
173
+ "YELLOW_PALE": "34,34,4",
174
+ "PURPLE_HOT": "34,36,34",
175
+ "PURPLE": "3,0,3",
176
+ "MAGENTA_HOT": "34,36,34",
177
+ "MAGENTA": "3,0,3",
178
+ "CYAN": "0,3,3",
179
+ "CYAN_HOT": "36,34,34",
180
+ "PM3D": "7,5,15",
181
+ "HSV": "3,2,2",
182
+ "HSV2": "7,5,15",
183
+ "YING_YANG": "13,13,13",
184
+ "YING_YANG2": "14,14,14",
185
+ "CYCLIC": "19,19,19",
186
+ "METEO1": "34,-35,-36",
187
+ "METEO2": "22,13,-31",
188
+ "DIABOLO_MENTHE": "-7,2,-7",
189
+ "DIABOLO_GRENADINE": "2,-7,-7",
190
+ "BLACK_PURPLE_PINK_WHITE": "30,31,32",
191
+ "RED_BLACK_BLUE": "-36,0,36"
192
+ }
193
+
194
+ matplot_lib_luts = []
195
+ try:
196
+ # Get the available colormaps from matplotlib
197
+ matplot_lib_luts = get_matplotlib_available_luts()
198
+
199
+ # Add matplotlib colormaps to the dictionary
200
+ for matplotlib in matplot_lib_luts:
201
+ hash_pal['MATPLOTLIB_' + str(matplotlib)] = str(matplotlib)
202
+ except:
203
+ # no big deal if fails because I have enough luts already
204
+ # traceback.print_exc()
205
+ pass
206
+
207
+ # Check if separate matplotlib colormaps are requested
208
+ if return_matplotlib_lib_luts_in_separate_database:
209
+ return matplot_lib_luts, hash_pal
210
+
211
+ # Return the dictionary of colormaps
212
+ return hash_pal
213
+
214
+
215
+ class PaletteCreator:
216
+ PALETTE_IRFAN = 0
217
+ PALETTE_IRFANVIEW = 0
218
+ PALETTE_IMAGEJ_EXPORTED = 1
219
+ PALETTE_IMAGEJ_RAW = 2
220
+ PALETTE_UNKNOWN = 3
221
+ currentPalette = "DEFAULT"
222
+
223
+ def __init__(self):
224
+ self.__list_palettes()
225
+
226
+ def __list_palettes(self):
227
+ """
228
+ Retrieves the list of available palettes, including matplotlib library colormaps.
229
+ """
230
+ self.matplot_lib_luts, self.list = list_available_luts(return_matplotlib_lib_luts_in_separate_database=True)
231
+
232
+ def get_packing_lut(self):
233
+ """
234
+ Returns the packing lookup table.
235
+
236
+ Returns:
237
+ numpy.ndarray: The packing lookup table.
238
+
239
+ # Examples:
240
+ # >>> palette_creator = PaletteCreator()
241
+ # >>> result = palette_creator.get_packing_lut()
242
+ # >>> print(result)
243
+ # [[ 64 64 64]
244
+ # [100 190 40]
245
+ # [190 190 30]
246
+ # [128 128 128]
247
+ # [ 0 0 175]
248
+ # [175 0 0]
249
+ # [100 0 170]
250
+ # [250 36 0]
251
+ # [150 75 0]
252
+ # ...
253
+ # ]
254
+ """
255
+ Sided3_or_less = (64, 64, 64)
256
+ Sided4 = (100, 190, 40)
257
+ Sided5 = (190, 190, 30)
258
+ Sided6 = (128, 128, 128)
259
+ Sided7 = (0, 0, 175)
260
+ Sided8 = (175, 0, 0)
261
+ Sided9 = (100, 0, 170)
262
+ Sided10 = (250, 36, 0)
263
+ Sided11_or_more = (150, 75, 0)
264
+
265
+ packing_lut = np.zeros((256, 3), dtype=np.uint8)
266
+
267
+ packing_lut[0] = Sided3_or_less
268
+ packing_lut[1] = Sided3_or_less
269
+ packing_lut[2] = Sided3_or_less
270
+ packing_lut[3] = Sided3_or_less
271
+ packing_lut[4] = Sided4
272
+ packing_lut[5] = Sided5
273
+ packing_lut[6] = Sided6
274
+ packing_lut[7] = Sided7
275
+ packing_lut[8] = Sided8
276
+ packing_lut[9] = Sided9
277
+ packing_lut[10] = Sided10
278
+ packing_lut[11] = Sided11_or_more
279
+ for iii in range(10, 256):
280
+ packing_lut[iii] = Sided11_or_more
281
+
282
+ return packing_lut
283
+
284
+ def count(self, strg, char2count):
285
+ """
286
+ Counts the number of occurrences of a character in a string.
287
+
288
+ Args:
289
+ strg (str): The input string.
290
+ char2count (str): The character to count.
291
+
292
+ Returns:
293
+ int: The count of the character in the string.
294
+
295
+ Examples:
296
+ >>> palette_creator = PaletteCreator()
297
+ >>> result = palette_creator.count("Hello world!", "o")
298
+ >>> print(result)
299
+ 2
300
+ """
301
+ if char2count is None:
302
+ return 0
303
+ if strg is None or strg == "":
304
+ return 0
305
+ nb = 0
306
+ for c in strg:
307
+ if c == char2count:
308
+ nb += 1
309
+ return nb
310
+
311
+ def convertAbs(self, txt):
312
+ """
313
+ Converts absolute value notation in a string.
314
+
315
+ Args:
316
+ txt (str): The input string.
317
+
318
+ Returns:
319
+ str: The string with absolute value notation converted.
320
+
321
+ # Examples:
322
+ # >>> palette_creator = PaletteCreator()
323
+ # >>> result = palette_creator.convertAbs("|-5| + 10")
324
+ # >>> print(result)
325
+ # "abs(-5) + 10"
326
+ """
327
+ try:
328
+ while "|" in txt:
329
+ size = len(txt)
330
+ pos = txt.index("|")
331
+ begin_pos = pos + 1
332
+ end_pos = pos
333
+
334
+ for i in range(pos + 1, size + 1):
335
+ c = txt[i]
336
+ if c == '|':
337
+ end_pos = i
338
+ break
339
+ end_pos = i + 1
340
+ power_equa = txt[begin_pos:end_pos]
341
+ beginning_of_word = txt[0:begin_pos - 1]
342
+ end_of_word = txt[end_pos + 1]
343
+ txt = beginning_of_word + "abs(" + power_equa + ")" + end_of_word
344
+ except:
345
+ traceback.print_exc()
346
+ return txt
347
+
348
+ def convertPowers(self, txt):
349
+ """
350
+ Converts power notation in a string.
351
+
352
+ Args:
353
+ txt (str): The input string.
354
+
355
+ Returns:
356
+ str: The string with power notation converted.
357
+
358
+ # Examples:
359
+ # >>> palette_creator = PaletteCreator()
360
+ # >>> result = palette_creator.convertPowers("2^3 + 4^2")
361
+ # >>> print(result)
362
+ # "2**3 + 4**2"
363
+ """
364
+ try:
365
+ while "^" in txt:
366
+ size = len(txt)
367
+ pos = txt.index("^")
368
+ begin_pos = pos
369
+ end_pos = pos
370
+ for i in range(pos, size):
371
+ c = txt[i]
372
+ if c == '+' or c == '-' or c == '/' or c == '*':
373
+ end_pos = i
374
+ break
375
+ end_pos = i + 1
376
+ for i in range(pos, 0, -1):
377
+ c = txt[i]
378
+ if c == '+' or c == '-' or c == '/' or c == '*':
379
+ begin_pos = i + 1
380
+ break
381
+ begin_pos = i
382
+ power_equa = txt[begin_pos:end_pos]
383
+ beginning_of_word = txt[0:begin_pos]
384
+ end_of_word = txt[end_pos:]
385
+ txt = beginning_of_word + self.power_parser(power_equa) + end_of_word
386
+ except:
387
+ traceback.print_exc()
388
+ return txt
389
+
390
+ # do cut left or right of pattern
391
+ # TODO --> do all of there
392
+ def power_parser(self, equation):
393
+ nb, power = equation.split("^", 1) # CommonClasses.strCutLeftFirst(equation, "^")
394
+ # power = CommonClasses.strCutRightFisrt(equation, "^")
395
+ return "math.pow(" + nb + "," + power + ")"
396
+
397
+ def javaifyEquation(self, equation):
398
+ """
399
+ Converts an equation into a Java-friendly format.
400
+
401
+ Args:
402
+ equation (str): The input equation.
403
+
404
+ Returns:
405
+ str: The equation in a Java-friendly format.
406
+
407
+ Raises:
408
+ Exception: If the equation has an incorrect number of absolute value bars or brackets.
409
+
410
+ # Examples:
411
+ # >>> palette_creator = PaletteCreator()
412
+ # >>> result = palette_creator.javaifyEquation("|x+y|")
413
+ # >>> print(result)
414
+ """
415
+ # print(equation)
416
+ equation = equation.replace(" ", "")
417
+
418
+ if "|" in equation:
419
+ nb_of_norm_bars = self.count(equation, "|")
420
+ if nb_of_norm_bars % 2 != 0:
421
+ raise Exception("equation is incorrect, nb of norm bars is not even")
422
+ return
423
+
424
+ equation = self.convertAbs(equation)
425
+
426
+ if "^" in equation:
427
+ equation = self.convertPowers(equation)
428
+
429
+ equation = equation.replace("[", "(")
430
+ equation = equation.replace("]", ")")
431
+ equation = equation.replace("{", "(")
432
+ equation = equation.replace("}", ")")
433
+
434
+ equation = equation.replace("math.sin(", "sin(")
435
+ equation = equation.replace("math.sin(", "sin(")
436
+ equation = equation.replace("math.cos(", "cos(")
437
+ equation = equation.replace("math.cos(", "cos(")
438
+ equation = equation.replace("math.tan(", "tan(")
439
+ equation = equation.replace("math.tan(", "tan(")
440
+ equation = equation.replace("math.sqrt(", "sqrt(")
441
+ equation = equation.replace("math.sqrt(", "sqrt(")
442
+ equation = equation.replace("sin(", "math.sin(")
443
+ equation = equation.replace("cos(", "math.cos(")
444
+ equation = equation.replace("tan(", "math.tan(")
445
+ equation = equation.replace("sqrt(", "math.sqrt(")
446
+ nb_of_open_brackets = self.count(equation, "(")
447
+ nb_of_closing_brackets = self.count(equation, ")")
448
+
449
+ if nb_of_open_brackets != nb_of_closing_brackets:
450
+ raise Exception("equation is incorrect, nb of opened and closed brackets don't match")
451
+
452
+ return equation
453
+
454
+ def computeEquation(self, equation, variable, val):
455
+ """
456
+ Computes the result of an equation using the numexpr library.
457
+
458
+ Args:
459
+ equation (str): The equation to compute.
460
+ variable (str): The variable name in the equation.
461
+ val: The value for the variable.
462
+
463
+ Returns:
464
+ float: The computed result of the equation.
465
+
466
+ # Examples:
467
+ # >>> palette_creator = PaletteCreator()
468
+ # >>> result = palette_creator.computeEquation("2*a*(b/c)**2", "a", [1, 2, 2])
469
+ # >>> print(result)
470
+ # array([0.88888889, 0.44444444, 4.])
471
+ """
472
+ import numexpr as ne
473
+ var = {'a': np.array([1, 2, 2]), 'b': np.array([2, 1, 3]), 'c': np.array([3])}
474
+ print('TOO', ne.evaluate('2*a*(b/c)**2', local_dict=var))
475
+ try:
476
+ for i in range(10):
477
+ equation = equation.replace(str(i) + variable, str(i) + "*" + variable)
478
+ for i in range(10):
479
+ equation = equation.replace(variable + str(i), variable + "*" + str(i))
480
+
481
+ equation = equation.replace(variable, "(double)" + variable)
482
+ print(equation)
483
+ except:
484
+ traceback.print_exc()
485
+ return 0
486
+
487
+ def create5(self, red, green, blue):
488
+ """
489
+ Creates a palette using the RGB components.
490
+
491
+ Args:
492
+ red (float): The red component value.
493
+ green (float): The green component value.
494
+ blue (float): The blue component value.
495
+
496
+ Returns:
497
+ numpy.ndarray: The created palette.
498
+
499
+ # Examples:
500
+ # >>> palette_creator = PaletteCreator()
501
+ # >>> result = palette_creator.create5(0.5, -0.2, 0.8)
502
+ # >>> print(result)
503
+ # array([[127, 0, 0],
504
+ # [136, 0, 0],
505
+ # [146, 0, 0],
506
+ # ...
507
+ # [ 0, 76, 153],
508
+ # [ 0, 76, 153],
509
+ # [ 0, 76, 153]], dtype=uint8)
510
+ """
511
+ l = 0
512
+ palette = np.zeros((256, 3), dtype=np.uint8)
513
+ R = np.zeros((256,), dtype=np.uint8)
514
+ G = np.zeros((256,), dtype=np.uint8)
515
+ B = np.zeros((256,), dtype=np.uint8)
516
+
517
+ for i in range(256):
518
+ R[i] = int(self.RGB_formula(i, red) * 255.0)
519
+ G[i] = int(self.RGB_formula(i, green) * 255.0)
520
+ B[i] = int(self.RGB_formula(i, blue) * 255.0)
521
+
522
+ if red < 0:
523
+ R = self.reverse_ramp(R)
524
+
525
+ if green < 0:
526
+ G = self.reverse_ramp(G)
527
+
528
+ if blue < 0:
529
+ B = self.reverse_ramp(B)
530
+
531
+ for i in range(len(B)):
532
+ palette[l, 0] = R[i]
533
+ palette[l, 1] = G[i]
534
+ palette[l, 2] = B[i]
535
+ l += 1
536
+
537
+ return palette
538
+
539
+ # # /*
540
+ # # * computes a color for each gray value between 0 and 255
541
+ # # */
542
+ def RGB_formula(self, i, equation):
543
+ """
544
+ Computes a color for each gray value between 0 and 255 based on the given equation.
545
+
546
+ Args:
547
+ i (int): The gray value.
548
+ equation (int): The equation index.
549
+
550
+ Returns:
551
+ float: The computed color value.
552
+
553
+ """
554
+ val = 0
555
+ cur_eq = abs(equation)
556
+
557
+ if cur_eq == 0 or cur_eq == 37 or cur_eq == 38 or cur_eq == 39:
558
+ # case 0:
559
+ # case 37:
560
+ # case 38:
561
+ # case 39:
562
+ val = 0
563
+ # break
564
+ elif cur_eq == 1:
565
+ val = 0.5
566
+ elif cur_eq == 2:
567
+ val = 1.0
568
+ elif cur_eq == 3:
569
+ val = i / 255.
570
+ elif cur_eq == 4:
571
+ val = (i / 255.) * (i / 255.)
572
+ elif cur_eq == 5:
573
+ val = (i / 255.) * (i / 255.) * (i / 255.)
574
+ elif cur_eq == 6:
575
+ val = (i / 255.) * (i / 255.) * (i / 255.) * (i / 255.)
576
+ elif cur_eq == 7:
577
+ val = math.sqrt(i / 255.)
578
+ elif cur_eq == 8:
579
+ val = math.sqrt(math.sqrt(i / 255.))
580
+ elif cur_eq == 9:
581
+ val = math.sin(i / 255. * 90. * math.pi / 180.)
582
+ elif cur_eq == 10:
583
+ val = math.cos(i / 255. * 90. * math.pi / 180.)
584
+ elif cur_eq == 11:
585
+ val = abs((i / 255.) - 0.5)
586
+ elif cur_eq == 12:
587
+ val = (2. * ((i / 255.) - 1.)) * (2. * ((i / 255.) - 1.))
588
+ elif cur_eq == 13:
589
+ val = math.sin(i / 255. * 180. * math.pi / 180.)
590
+ elif cur_eq == 14:
591
+ val = abs(math.cos(i / 255. * 90. * math.pi / 180.))
592
+ elif cur_eq == 15:
593
+ val = math.sin(i / 255. * 360. * math.pi / 180.)
594
+ elif cur_eq == 16:
595
+ val = math.cos(i / 255. * 360. * math.pi / 180.)
596
+ elif cur_eq == 17:
597
+ val = abs(math.sin(i / 255. * 360. * math.pi / 180.))
598
+ elif cur_eq == 18:
599
+ val = abs(math.cos(i / 255. * 360. * math.pi / 180.))
600
+ elif cur_eq == 19:
601
+ val = abs(math.sin(i / 255. * 720. * math.pi / 180.))
602
+ elif cur_eq == 20:
603
+ val = abs(math.cos(i / 255. * 720. * math.pi / 180.))
604
+ elif cur_eq == 21:
605
+ val = 3. * (i / 255.)
606
+ elif cur_eq == 22:
607
+ val = 3. * (i / 255.0) - 1.
608
+ elif cur_eq == 23:
609
+ val = 3. * (i / 255.0) - 2.
610
+ elif cur_eq == 24:
611
+ val = abs(3. * (i / 255.0) - 1.)
612
+ elif cur_eq == 25:
613
+ val = abs(3. * (i / 255.0) - 2.)
614
+ elif cur_eq == 26:
615
+ val = (3. * (i / 255.) - 1.) / 2.
616
+ elif cur_eq == 27:
617
+ val = (3. * (i / 255.) - 2.) / 2.
618
+ elif cur_eq == 28:
619
+ val = abs((3. * (i / 255.) - 1.) / 2.)
620
+ elif cur_eq == 29:
621
+ val = abs((3. * (i / 255.) - 2.) / 2.)
622
+ elif cur_eq == 30:
623
+ val = (i / 255.) / 0.32 - 0.78125
624
+ elif cur_eq == 31:
625
+ val = 2. * (i / 255.) - 0.84
626
+ elif cur_eq == 32:
627
+ val = (i / 255.)
628
+ # val = 4x1-2x+1.84x/0.08-11.5--> ? #show palette rgbformulae pr comprendre comment ils ont fait pr celui la ds gnuplot
629
+ elif cur_eq == 33:
630
+ val = abs(2. * (i / 255.) - 0.5)
631
+ elif cur_eq == 34:
632
+ val = 2. * (i / 255.)
633
+ elif cur_eq == 35:
634
+ val = 2. * (i / 255.) - 0.5
635
+ elif cur_eq == 36:
636
+ val = 2. * (i / 255.) - 1.
637
+
638
+ if val < 0.0:
639
+ val = 0.0
640
+
641
+ if val > 1.0:
642
+ val = 1.0
643
+
644
+ return val
645
+
646
+ def create_from_formula(self, red, green, blue):
647
+ """
648
+ Creates a color palette using formulas for the red, green, and blue channels.
649
+
650
+ Args:
651
+ red (str): The equation for the red channel.
652
+ green (str): The equation for the green channel.
653
+ blue (str): The equation for the blue channel.
654
+
655
+ Returns:
656
+ numpy.ndarray: The color palette as a NumPy array.
657
+
658
+ """
659
+ l = 0
660
+ palette = np.zeros((256, 3), dtype=np.uint8)
661
+ R = np.zeros((256,), dtype=np.uint8)
662
+ G = np.zeros((256,), dtype=np.uint8)
663
+ B = np.zeros((256,), dtype=np.uint8)
664
+
665
+ if red != "":
666
+ javaified_equation = self.javaifyEquation(red[0:1])
667
+ for i in range(256):
668
+ R[i] = (self.computeEquation(javaified_equation, "x", i / 255.) * 255.)
669
+
670
+ if green != "":
671
+ javaified_equation = self.javaifyEquation(green[0:1])
672
+ for i in range(256):
673
+ G[i] = (self.computeEquation(javaified_equation, "x", i / 255.) * 255.)
674
+
675
+ if blue != "":
676
+ javaified_equation = self.javaifyEquation(blue[0:1])
677
+ for i in range(256):
678
+ B[i] = (self.computeEquation(javaified_equation, "x", i / 255.) * 255.)
679
+
680
+ for i in range(256):
681
+ val = R[i]
682
+ if val < 0:
683
+ val = 0
684
+ if val > 255:
685
+ val = 255
686
+ R[i] = val
687
+
688
+ val = G[i]
689
+ if val < 0:
690
+ val = 0
691
+ if val > 255:
692
+ val = 255
693
+ G[i] = val
694
+
695
+ val = B[i]
696
+ if val < 0:
697
+ val = 0
698
+ if val > 255:
699
+ val = 255
700
+ B[i] = val
701
+
702
+ if red != "":
703
+ if red[0] == '-':
704
+ R = self.reverse_ramp(R)
705
+
706
+ if green != "":
707
+ if green[0] == '-':
708
+ G = self.reverse_ramp(G)
709
+
710
+ if blue != "":
711
+ if blue[0] == '-':
712
+ B = self.reverse_ramp(B)
713
+
714
+ for i in range(len(B)):
715
+ palette[l, 0] = R[i]
716
+ palette[l, 1] = G[i]
717
+ palette[l, 2] = B[i]
718
+ l += 1
719
+
720
+ return palette
721
+
722
+ def reverse_ramp(self, pal):
723
+ """
724
+ Reverses the color ramp by taking the negative of the intensity (255 - intensity).
725
+
726
+ Args:
727
+ pal (numpy.ndarray): The color ramp to be reversed.
728
+
729
+ Returns:
730
+ numpy.ndarray: The reversed color ramp.
731
+
732
+ """
733
+ tmp = np.zeros_like(pal)
734
+ for i in range(256):
735
+ tmp[255 - i] = pal[i]
736
+ return tmp
737
+
738
+ def createEmptyPalette(self):
739
+ """
740
+ Creates an empty palette.
741
+
742
+ Returns:
743
+ numpy.ndarray: The empty palette array.
744
+
745
+ """
746
+ return np.zeros((256, 3), dtype=np.uint8)
747
+
748
+ def create2(self, palette_name, equa1, equa2, equa3):
749
+ """
750
+ Creates a palette from a series of equations.
751
+
752
+ Args:
753
+ palette_name (str): The name of the palette.
754
+ equa1 (str): The equation for the first color channel.
755
+ equa2 (str): The equation for the second color channel.
756
+ equa3 (str): The equation for the third color channel.
757
+
758
+ Returns:
759
+ numpy.ndarray: The created palette.
760
+
761
+ # Examples:
762
+ # >>> palette_name = '37,38,-39'
763
+ # >>> equa1 = 'x + y'
764
+ # >>> equa2 = '2 * x - y'
765
+ # >>> equa3 = 'x - 2 * y'
766
+ # >>> result = PaletteCreator.create2(palette_name, equa1, equa2, equa3)
767
+ # >>> print(result)
768
+ # [[ 0 0 0]
769
+ # [255 0 0]
770
+ # [ 0 255 0]]
771
+
772
+ """
773
+ final_palette = None
774
+ try:
775
+ r = g = b = 3
776
+ if "," in palette_name:
777
+ formula_size = len(palette_name.split(","))
778
+ if formula_size == 3:
779
+ r = int(palette_name.split(",")[0])
780
+ new_equa1 = self.create_compatible_equation(equa1, equa2, equa3, r)
781
+ g = int(palette_name.split(",")[1])
782
+ new_equa2 = self.create_compatible_equation(equa1, equa2, equa3, g)
783
+ b = int(palette_name.split(",")[2])
784
+ new_equa3 = self.create_compatible_equation(equa1, equa2, equa3, b)
785
+ equa1 = new_equa1
786
+ equa2 = new_equa2
787
+ equa3 = new_equa3
788
+
789
+ if abs(r) < 37 and abs(g) < 37 and abs(b) < 37:
790
+ return self.create3(palette_name)
791
+
792
+ if abs(r) >= 37 and abs(g) >= 37 and abs(b) >= 37:
793
+ palette1 = self.createEmptyPalette()
794
+ else:
795
+ palette1 = self.create(palette_name)
796
+
797
+ palette2 = self.create_from_formula(equa1, equa2, equa3)
798
+ final_palette = np.zeros((palette1.shape[0], palette1.shape[1]), dtype=np.uint8)
799
+ l = 0
800
+ l1 = 0
801
+ l2 = 0
802
+ for i in range(256):
803
+ red1 = palette1[l1]
804
+ green1 = palette1[l1]
805
+ blue1 = palette1[l1]
806
+ l1 += 1
807
+ red2 = palette2[l2]
808
+ green2 = palette2[l2]
809
+ blue2 = palette2[l2]
810
+ l2 += 1
811
+ red = red2 if abs(r) >= 37 and abs(r) <= 39 else red1
812
+ green = green2 if abs(g) >= 37 and abs(g) <= 39 else green1
813
+ blue = blue2 if abs(b) >= 37 and abs(b) <= 39 else blue1
814
+
815
+ final_palette[l, 0] = red
816
+ final_palette[l, 1] = green
817
+ final_palette[l, 2] = blue
818
+ l += 1
819
+ except:
820
+ traceback.print_exc()
821
+
822
+ return final_palette
823
+
824
+ def create_compatible_equation(self, equa1, equa2, equa3, col):
825
+ """
826
+ Creates a compatible equation.
827
+
828
+ Args:
829
+ equa1 (str): The equation for the first color channel.
830
+ equa2 (str): The equation for the second color channel.
831
+ equa3 (str): The equation for the third color channel.
832
+ col (int): The color value.
833
+
834
+ Returns:
835
+ str: The compatible equation.
836
+
837
+ """
838
+ equa = ""
839
+ if col == 37:
840
+ equa = "+" + equa1
841
+ elif col == -37:
842
+ equa = "-(" + equa1 + ")"
843
+ elif col == 38:
844
+ equa = "+" + equa2
845
+ elif col == -38:
846
+ equa = "-(" + equa2 + ")"
847
+ elif col == 39:
848
+ equa = "+" + equa3
849
+ elif col == -39:
850
+ equa = "-(" + equa3 + ")"
851
+
852
+ return equa
853
+
854
+ def create3(self, palette_formula):
855
+ """
856
+ Creates a palette from its formula.
857
+
858
+ Args:
859
+ palette_formula (str): The formula for creating the palette.
860
+
861
+ Returns:
862
+ numpy.ndarray: The created palette.
863
+
864
+ Examples:
865
+ >>> p = PaletteCreator()
866
+ >>> result = p.create3('PACKING')
867
+ >>> print(result[:4])
868
+ [[64 64 64]
869
+ [64 64 64]
870
+ [64 64 64]
871
+ [64 64 64]]
872
+
873
+ """
874
+
875
+ if palette_formula in self.matplot_lib_luts:
876
+ return cmap_to_numpy(palette_formula)
877
+
878
+ r = g = b = 3
879
+ if palette_formula is None:
880
+ palette = self.create5(r, g, b)
881
+ return palette
882
+
883
+ if "," in palette_formula.replace("hl", ""):
884
+ formula_size = len(palette_formula.split(","))
885
+ if formula_size == 3:
886
+ r = int(palette_formula.replace("hl", "").split(",")[0])
887
+ g = int(palette_formula.replace("hl", "").split(",")[1])
888
+ b = int(palette_formula.replace("hl", "").split(",")[2])
889
+ palette = self.create5(r, g, b)
890
+ else:
891
+ if palette_formula == 'PACKING':
892
+ return self.get_packing_lut()
893
+
894
+ palette = self.create5(r, g, b)
895
+
896
+ if palette_formula == self.list['HI_LO']:
897
+ palette[0, 0] = 0
898
+ palette[0, 1] = 0
899
+ palette[0, 2] = 255
900
+ palette[255, 0] = 255
901
+ palette[255, 1] = 0
902
+ palette[255, 2] = 0
903
+
904
+ return palette
905
+
906
+ def __show_lut(lut, title=None):
907
+ """
908
+ Displays the lookup table (LUT) as an image.
909
+
910
+ Args:
911
+ lut (numpy.ndarray): The lookup table.
912
+ title (str, optional): The title of the displayed image.
913
+
914
+ Returns:
915
+ None
916
+
917
+ # Examples:
918
+ # >>> lut = np.random.randint(0, 256, size=(256, 3), dtype=np.uint8)
919
+ # >>> __show_lut(lut, title='LUT Image')
920
+
921
+ """
922
+
923
+ image = np.linspace(0, 255, 256, dtype=np.uint8)
924
+ image = np.tile(image, (32, 1))
925
+ image = apply_lut(image, lut, convert_to_RGB=True)
926
+
927
+ plt.imshow(image)
928
+ if title is not None:
929
+ plt.title(title)
930
+ plt.show()
931
+
932
+ def lsm_LUT_to_numpy(lut):
933
+ """
934
+ Converts an LSM lookup table (LUT) to a NumPy array.
935
+
936
+ Args:
937
+ lut (list): The LSM lookup table.
938
+
939
+ Returns:
940
+ numpy.ndarray: The converted NumPy array representing the LUT.
941
+
942
+ Examples:
943
+ >>> lut = [255, 0, 0, 0]
944
+ >>> result = lsm_LUT_to_numpy(lut)
945
+ >>> print(result[:3])
946
+ [[0 0 0]
947
+ [1 0 0]
948
+ [2 0 0]]
949
+
950
+ """
951
+
952
+ R = np.linspace(0, lut[0], 256, dtype=np.uint8)
953
+ G = np.linspace(0, lut[1], 256, dtype=np.uint8)
954
+ B = np.linspace(0, lut[2], 256, dtype=np.uint8)
955
+ lut = np.stack([R, G, B], axis=-1)
956
+ return lut
957
+
958
+ def R_G_B_lut_to_int24_lut(lut):
959
+ """
960
+ Converts an RGB lookup table (LUT) to an int24 LUT.
961
+
962
+ Args:
963
+ lut (numpy.ndarray): The RGB lookup table.
964
+
965
+ Returns:
966
+ numpy.ndarray: The converted int24 LUT.
967
+
968
+ Examples:
969
+ >>> lut = np.array([[255, 0, 0], [0, 255, 0], [0, 0, 255]], dtype=np.uint8)
970
+ >>> result = R_G_B_lut_to_int24_lut(lut)
971
+ >>> print(result)
972
+ [16711680 65280 255]
973
+
974
+ """
975
+
976
+ if lut is None:
977
+ return None
978
+
979
+ if isinstance(lut, list):
980
+ lut = lsm_LUT_to_numpy(lut)
981
+
982
+ if len(lut.shape) == 1:
983
+ return lut
984
+
985
+ if lut.shape[-1] == 3:
986
+ return lut[..., 0].astype(np.uint32) << 16 | lut[..., 1].astype(np.uint32) << 8 | lut[..., 2].astype(
987
+ np.uint32)
988
+ else:
989
+ return lut[0, ...].astype(np.uint32) << 16 | lut[1, ...].astype(np.uint32) << 8 | lut[2, ...].astype(
990
+ np.uint32)
991
+
992
+ def apply_lut(img, lut, convert_to_RGB=False, min=None, max=None, do_not_interpolate=False):
993
+ """
994
+ Applies a lookup table (LUT) to an image.
995
+
996
+ Args:
997
+ img (numpy.ndarray): The input image.
998
+ lut (numpy.ndarray or list): The lookup table.
999
+ convert_to_RGB (bool, optional): Flag indicating whether to convert the image to RGB.
1000
+ min (float, optional): The minimum value for color coding.
1001
+ max (float, optional): The maximum value for color coding.
1002
+
1003
+ Returns:
1004
+ numpy.ndarray: The image with the LUT applied.
1005
+
1006
+ Examples:
1007
+ >>> img = np.random.randint(0, 256, size=(100, 100), dtype=np.uint8)
1008
+ >>> lut = np.random.randint(0, 256, size=(256, 3), dtype=np.uint8)
1009
+ >>> result = apply_lut(img, lut, convert_to_RGB=True)
1010
+ >>> print(result.shape)
1011
+ (100, 100, 3)
1012
+
1013
+ """
1014
+
1015
+ real_max = img.max()
1016
+ real_min = img.min()
1017
+
1018
+ if do_not_interpolate:
1019
+ pass
1020
+ else:
1021
+ if min is not None and max is not None:
1022
+ if img.max() > max:
1023
+ img[img > max] = max
1024
+ if img.min() < min:
1025
+ img[img < min] = min
1026
+
1027
+ img = np.interp(img, (real_min if real_min > min else min, real_max if real_max < max else max), (
1028
+ real_min if real_min > min else min,
1029
+ real_max if real_max < max else max))
1030
+
1031
+ img = np.interp(img, (min, max), (0, 255)).astype(np.uint8)
1032
+
1033
+ else:
1034
+ img = np.interp(img, (img.min(), img.max()), (0, 255)).astype(np.uint8)
1035
+
1036
+ if lut is None:
1037
+ return img
1038
+
1039
+ int24_lut = R_G_B_lut_to_int24_lut(lut)
1040
+
1041
+ image = int24_lut[img]
1042
+ if convert_to_RGB:
1043
+ image = int24_to_RGB(image)
1044
+
1045
+ return image
1046
+
1047
+
1048
+ def convert_ome_lut(original_lut):
1049
+ """
1050
+ Convert a 3-element 16-bit LUT to a (256, 3) 8-bit LUT.
1051
+
1052
+ Parameters:
1053
+ original_lut (list or np.array): A 3-element list or array representing R, G, B values in 16-bit range.
1054
+
1055
+ Returns:
1056
+ np.array: A (256, 3) numpy array representing the 8-bit LUT.
1057
+ """
1058
+ # Ensure input is a numpy array and of correct type
1059
+ original_lut = np.array(original_lut, dtype=np.uint16)
1060
+
1061
+ # Check if input has correct shape
1062
+ if original_lut.shape != (3,):
1063
+ raise ValueError("Input LUT must have exactly 3 elements")
1064
+
1065
+ # Scale down to 8-bit range (0-255)
1066
+ scaled_lut = (original_lut / 65535 * 255).astype(np.uint8)
1067
+
1068
+ # Create a (256, 3) array
1069
+ full_lut = np.zeros((256, 3), dtype=np.uint8)
1070
+
1071
+ # Fill each channel with a gradient
1072
+ for i in range(3):
1073
+ full_lut[:, i] = np.linspace(0, scaled_lut[i], 256, dtype=np.uint8)
1074
+
1075
+ return full_lut
1076
+
1077
+
1078
+ def matplotlib_to_TA(lut_name='viridis'):
1079
+ """
1080
+ Converts a Matplotlib colormap to a lookup table (LUT) compatible with TA software.
1081
+
1082
+ Args:
1083
+ lut_name (str, optional): The name of the Matplotlib colormap.
1084
+
1085
+ Returns:
1086
+ numpy.ndarray: The converted lookup table (LUT).
1087
+
1088
+ Examples:
1089
+ >>> lut = matplotlib_to_TA('viridis')
1090
+ >>> print(lut.shape)
1091
+ (256, 3)
1092
+
1093
+ """
1094
+
1095
+ cm = plt.get_cmap(lut_name)
1096
+ cm = cm(range(256)) * 255
1097
+ cm = cm[..., 0:3].astype(np.uint8)
1098
+ return cm
1099
+
1100
+
1101
+ def get_matplotlib_available_luts():
1102
+ """
1103
+ Returns a list of available Matplotlib colormaps.
1104
+
1105
+ Returns:
1106
+ list: The list of available colormaps.
1107
+
1108
+ Examples:
1109
+ >>> colormaps = get_matplotlib_available_luts()
1110
+ >>> print(colormaps[:2])
1111
+ ['magma', 'inferno']
1112
+
1113
+ """
1114
+
1115
+ return plt.colormaps()
1116
+
1117
+
1118
+ if __name__ == '__main__':
1119
+ # keep to avoid bugs
1120
+ import matplotlib
1121
+ matplotlib.use('TkAgg')
1122
+
1123
+ if True:
1124
+ # lsm type of Lut --> may need be changed
1125
+ lut = [255,128,255]
1126
+ lut = lsm_LUT_to_numpy(lut)
1127
+ print(lut)
1128
+ print(type(lut))
1129
+ img = create_ramp(300, 1800, lut)
1130
+ plt.imshow(img)
1131
+ plt.show()
1132
+ import sys
1133
+ sys.exit(0)
1134
+
1135
+ if True:
1136
+ lutcreator = PaletteCreator()
1137
+ lut = lutcreator.create3(lutcreator.list['MAGENTA_HOT']) #MAGENTA --> create it --> PURPLE instead
1138
+
1139
+ img = create_ramp(300, 1800,lut) # maybe ask at some point for the bg color --> TODO but almost all ok in fact
1140
+ plt.imshow(img)
1141
+ plt.show()
1142
+ import sys
1143
+ sys.exit(0)
1144
+
1145
+ if True:
1146
+ lutcreator = PaletteCreator()
1147
+ lut = lutcreator.create3(lutcreator.list['PACKING'])
1148
+
1149
+ img = create_ramp(300, 1800,lut) # maybe ask at some point for the bg color --> TODO but almost all ok in fact
1150
+ plt.imshow(img)
1151
+ plt.show()
1152
+ import sys
1153
+ sys.exit(0)
1154
+
1155
+
1156
+ if False:
1157
+ # create a ramp
1158
+ lutcreator = PaletteCreator()
1159
+ lut = lutcreator.create3(lutcreator.list['DNA'])
1160
+
1161
+ img = create_ramp(300, 1800,lut) # maybe ask at some point for the bg color --> TODO but almost all ok in fact
1162
+ plt.imshow(img)
1163
+ plt.show()
1164
+
1165
+ if False:
1166
+
1167
+ print(cmap_to_numpy('gray')) # 'viridis' 'rainbow' 'gray'
1168
+
1169
+
1170
+ if True:
1171
+ lutcreator = PaletteCreator()
1172
+
1173
+ luts = lutcreator.list
1174
+
1175
+ # lut.create_from_formula('22','13','-23')
1176
+ lut = lutcreator.create2('34,35,36', 'x', 'x', 'x') # bingo ça marche enfin!!!
1177
+ # print(lut)
1178
+ # print(lut.shape, lut.max(), lut.min())
1179
+
1180
+ lut = lutcreator.create3(lutcreator.list['DNA'])
1181
+ # print(lut)
1182
+ # print(lut.shape, lut.max(), lut.min())
1183
+
1184
+ # random lut each time
1185
+ # print(list(luts.keys()))
1186
+
1187
+ random_lut = random.choice(list(luts.keys()))
1188
+ # print('random.lut', random_lut)
1189
+
1190
+ # random_lut = 'HI_LO'
1191
+ lut = lutcreator.create3(luts[random_lut])
1192
+
1193
+ # TODO maybe do a loop over all luts maybe also on an image --> easy way to select best luts
1194
+
1195
+ __show_lut(lut, title=random_lut)
1196
+ # all seems ok now
1197
+ # plt.imshow(create_ramp(0,255, lut))
1198
+ # plt.show()
1199
+
1200
+
1201
+ # print(get_matplotlib_available_luts()) # --> y en a vraiment bcp --> je pourrais aussi les ajouter à ma db de luts
1202
+
1203
+ # can i do a visual lut selector or something that applies luts to the image à la tinder so that one can select the most appropriate LUT --> in fact that is not so hard to do now that everything is done through indexing
1204
+ # img = create_ramp(0, 255, None)
1205
+ # img = create_ramp(-1, 1, None) # --> super easy instead
1206
+
1207
+