From 57702ac398e61f58a86f4cfd2965ed48a7f9ab95 Mon Sep 17 00:00:00 2001 From: kushalkolar Date: Mon, 17 Jun 2024 20:48:38 -0400 Subject: [PATCH 1/5] ndarray.ptp -> np.ptp for numpy v2 --- fastplotlib/widgets/histogram_lut.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastplotlib/widgets/histogram_lut.py b/fastplotlib/widgets/histogram_lut.py index a3edffcbd..02c21aa38 100644 --- a/fastplotlib/widgets/histogram_lut.py +++ b/fastplotlib/widgets/histogram_lut.py @@ -163,7 +163,7 @@ def _calculate_histogram(self, data): # used if data ptp <= 10 because event things get weird # with tiny world objects due to floating point error # so if ptp <= 10, scale up by a factor - self._scale_factor: int = max(1, 100 * int(10 / data_ss.ptp())) + self._scale_factor: int = max(1, 100 * int(10 / np.ptp(data_ss))) edges = edges * self._scale_factor From 16c3d824b7b9ff959482831eb59feb09c660b3f1 Mon Sep 17 00:00:00 2001 From: kushalkolar Date: Thu, 12 Sep 2024 00:42:44 -0400 Subject: [PATCH 2/5] add fft example --- examples/desktop/selectors/fft.py | 90 +++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 examples/desktop/selectors/fft.py diff --git a/examples/desktop/selectors/fft.py b/examples/desktop/selectors/fft.py new file mode 100644 index 000000000..a9df78f96 --- /dev/null +++ b/examples/desktop/selectors/fft.py @@ -0,0 +1,90 @@ +""" +Explore fourier transform of images +=================================== +Example showing how to use a `RectangleSelector` to interactively reconstruct +an image using portions of it fourier transform +""" + +# test_example = false +# sphinx_gallery_pygfx_docs = 'screenshot' + +import numpy as np +import fastplotlib as fpl +import scipy +import imageio.v3 as iio + +image = iio.imread("imageio:camera.png") + +# compute discrete fourier transform of image +dft = scipy.fftpack.fft2(image) + +# image to just visualize absolute magnitudes +log_abs_dft = np.log(np.abs(dft)) + +# placeholders for displaying fft and inverse fft of selections +zeros = np.zeros(image.shape) + +# create an ImageWidget to display all the images +iw = fpl.ImageWidget( + data=[image, log_abs_dft, zeros, zeros, zeros, zeros], + names=["image", "DFT", "selected", "IDFT of selected", "not-selected", "IDFT of not-selected"], + figure_shape=(3, 2), # so we can see image and fft side by side + figure_kwargs={"size": (600, 900)}, + histogram_widget=False, +) + +# set contrast limits based on the full DFT for the DFT-selection images +iw.figure["selected"].graphics[0].vmin, iw.figure["selected"].graphics[0].vmax = log_abs_dft.min(), log_abs_dft.max() +iw.figure["not-selected"].graphics[0].vmin, iw.figure["not-selected"].graphics[0].vmax = log_abs_dft.min(), log_abs_dft.max() + +iw.show() + +# create a rectangle selector +rs = iw.managed_graphics[1].add_rectangle_selector() + + +@rs.add_event_handler("selection") +def update_images(ev): + """ + Updates the images when the selection changes + """ + + # get the bbox of the selection + ixs = ev.get_selected_indices() + r0, r1 = ixs[1][0], ixs[1][-1] + c0, c1 = ixs[0][0], ixs[0][-1] + + # fft of the selection + selected_fft = np.zeros(image.shape, dtype=np.complex64) + selected_fft[r0:r1, c0:c1] = dft[r0:r1, c0:c1] + + # update image graphic with the current fft selection + iw.managed_graphics[2].data = np.log(np.abs(selected_fft)) + + # inverse fft to reconstruct image using only the selection + iw.managed_graphics[3].data = scipy.fftpack.ifft2(selected_fft) + iw.managed_graphics[3].reset_vmin_vmax() + + # fft of the region outside the selection + unselected_fft = dft.copy() + unselected_fft[r0:r1, c0:c1] = 0 + + # update image graphic with unselected fft area + iw.managed_graphics[4].data = np.log(np.abs(unselected_fft)) + + # inverse fft to reconstruct image using only the unselected part of the fft + iw.managed_graphics[5].data = scipy.fftpack.ifft2(unselected_fft) + iw.managed_graphics[5].reset_vmin_vmax() + + +# set initial selection to top right corner +rs.selection = (400, 512, 0, 100) + + +figure = iw.figure + +# NOTE: `if __name__ == "__main__"` is NOT how to use fastplotlib interactively +# please see our docs for using fastplotlib interactively in ipython and jupyter +if __name__ == "__main__": + print(__doc__) + fpl.run() From 5a7adfd6e02658def2626f5acddb7e54bfd3fd2a Mon Sep 17 00:00:00 2001 From: kushalkolar Date: Thu, 12 Sep 2024 00:42:44 -0400 Subject: [PATCH 3/5] add fft example --- examples/desktop/selectors/fft.py | 90 +++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 examples/desktop/selectors/fft.py diff --git a/examples/desktop/selectors/fft.py b/examples/desktop/selectors/fft.py new file mode 100644 index 000000000..a9df78f96 --- /dev/null +++ b/examples/desktop/selectors/fft.py @@ -0,0 +1,90 @@ +""" +Explore fourier transform of images +=================================== +Example showing how to use a `RectangleSelector` to interactively reconstruct +an image using portions of it fourier transform +""" + +# test_example = false +# sphinx_gallery_pygfx_docs = 'screenshot' + +import numpy as np +import fastplotlib as fpl +import scipy +import imageio.v3 as iio + +image = iio.imread("imageio:camera.png") + +# compute discrete fourier transform of image +dft = scipy.fftpack.fft2(image) + +# image to just visualize absolute magnitudes +log_abs_dft = np.log(np.abs(dft)) + +# placeholders for displaying fft and inverse fft of selections +zeros = np.zeros(image.shape) + +# create an ImageWidget to display all the images +iw = fpl.ImageWidget( + data=[image, log_abs_dft, zeros, zeros, zeros, zeros], + names=["image", "DFT", "selected", "IDFT of selected", "not-selected", "IDFT of not-selected"], + figure_shape=(3, 2), # so we can see image and fft side by side + figure_kwargs={"size": (600, 900)}, + histogram_widget=False, +) + +# set contrast limits based on the full DFT for the DFT-selection images +iw.figure["selected"].graphics[0].vmin, iw.figure["selected"].graphics[0].vmax = log_abs_dft.min(), log_abs_dft.max() +iw.figure["not-selected"].graphics[0].vmin, iw.figure["not-selected"].graphics[0].vmax = log_abs_dft.min(), log_abs_dft.max() + +iw.show() + +# create a rectangle selector +rs = iw.managed_graphics[1].add_rectangle_selector() + + +@rs.add_event_handler("selection") +def update_images(ev): + """ + Updates the images when the selection changes + """ + + # get the bbox of the selection + ixs = ev.get_selected_indices() + r0, r1 = ixs[1][0], ixs[1][-1] + c0, c1 = ixs[0][0], ixs[0][-1] + + # fft of the selection + selected_fft = np.zeros(image.shape, dtype=np.complex64) + selected_fft[r0:r1, c0:c1] = dft[r0:r1, c0:c1] + + # update image graphic with the current fft selection + iw.managed_graphics[2].data = np.log(np.abs(selected_fft)) + + # inverse fft to reconstruct image using only the selection + iw.managed_graphics[3].data = scipy.fftpack.ifft2(selected_fft) + iw.managed_graphics[3].reset_vmin_vmax() + + # fft of the region outside the selection + unselected_fft = dft.copy() + unselected_fft[r0:r1, c0:c1] = 0 + + # update image graphic with unselected fft area + iw.managed_graphics[4].data = np.log(np.abs(unselected_fft)) + + # inverse fft to reconstruct image using only the unselected part of the fft + iw.managed_graphics[5].data = scipy.fftpack.ifft2(unselected_fft) + iw.managed_graphics[5].reset_vmin_vmax() + + +# set initial selection to top right corner +rs.selection = (400, 512, 0, 100) + + +figure = iw.figure + +# NOTE: `if __name__ == "__main__"` is NOT how to use fastplotlib interactively +# please see our docs for using fastplotlib interactively in ipython and jupyter +if __name__ == "__main__": + print(__doc__) + fpl.run() From 036befb19ffb8c027e3e8500c09bc4f05fd78cb2 Mon Sep 17 00:00:00 2001 From: kushalkolar Date: Tue, 17 Sep 2024 14:00:50 -0400 Subject: [PATCH 4/5] simplify --- examples/desktop/selectors/fft.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/desktop/selectors/fft.py b/examples/desktop/selectors/fft.py index a9df78f96..df947982a 100644 --- a/examples/desktop/selectors/fft.py +++ b/examples/desktop/selectors/fft.py @@ -50,13 +50,13 @@ def update_images(ev): """ # get the bbox of the selection - ixs = ev.get_selected_indices() - r0, r1 = ixs[1][0], ixs[1][-1] - c0, c1 = ixs[0][0], ixs[0][-1] + row_ixs, col_ixs = ev.get_selected_indices() + row_slice = slice(row_ixs[0], row_ixs[-1] + 1) + col_slice = slice(col_ixs[0], col_ixs[-1] + 1) # fft of the selection selected_fft = np.zeros(image.shape, dtype=np.complex64) - selected_fft[r0:r1, c0:c1] = dft[r0:r1, c0:c1] + selected_fft[row_slice, col_slice] = dft[row_slice, col_slice] # update image graphic with the current fft selection iw.managed_graphics[2].data = np.log(np.abs(selected_fft)) @@ -67,7 +67,7 @@ def update_images(ev): # fft of the region outside the selection unselected_fft = dft.copy() - unselected_fft[r0:r1, c0:c1] = 0 + unselected_fft[row_slice, col_slice] = 0 # update image graphic with unselected fft area iw.managed_graphics[4].data = np.log(np.abs(unselected_fft)) From 77ed481fe6f72f26c28691078804f7445d8e7fa0 Mon Sep 17 00:00:00 2001 From: kushalkolar Date: Tue, 17 Sep 2024 17:16:20 -0400 Subject: [PATCH 5/5] see if it won't complain about smaller size --- examples/desktop/selectors/fft.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/desktop/selectors/fft.py b/examples/desktop/selectors/fft.py index df947982a..52f0a9afd 100644 --- a/examples/desktop/selectors/fft.py +++ b/examples/desktop/selectors/fft.py @@ -29,7 +29,7 @@ data=[image, log_abs_dft, zeros, zeros, zeros, zeros], names=["image", "DFT", "selected", "IDFT of selected", "not-selected", "IDFT of not-selected"], figure_shape=(3, 2), # so we can see image and fft side by side - figure_kwargs={"size": (600, 900)}, + figure_kwargs={"size": (700, 400)}, histogram_widget=False, )