From 6176fb6ceaae307647c3b70dbd17382a519c9eb4 Mon Sep 17 00:00:00 2001 From: kushalkolar Date: Thu, 16 Jan 2025 03:50:20 -0500 Subject: [PATCH 1/3] add fft example --- examples/selection_tools/fft.py | 97 +++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 examples/selection_tools/fft.py diff --git a/examples/selection_tools/fft.py b/examples/selection_tools/fft.py new file mode 100644 index 000000000..b819d1281 --- /dev/null +++ b/examples/selection_tools/fft.py @@ -0,0 +1,97 @@ +""" +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 imageio.v3 as iio + +image = iio.imread("imageio:camera.png") + +# compute discrete fourier transform of image +img_fft = np.fft.fftshift(np.fft.fft2(image)) + +# image to just visualize absolute magnitudes +log_abs_img_fft = np.log(np.abs(img_fft + 1)) + +# 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_img_fft, 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": (700, 1340)}, + histogram_widget=False, +) + +# viridis cmap for the fft images +iw.cmap = "viridis" + +# gray for the non-fft images +iw.managed_graphics[0].cmap = "gray" +iw.managed_graphics[3].cmap = "gray" +iw.managed_graphics[-1].cmap = "gray" + +# 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_img_fft.min(), log_abs_img_fft.max() +iw.figure["not-selected"].graphics[0].vmin, iw.figure["not-selected"].graphics[0].vmax = log_abs_img_fft.min(), log_abs_img_fft.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 + 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[row_slice, col_slice] = img_fft[row_slice, col_slice] + + # update image graphic with the current fft selection + iw.managed_graphics[2].data = np.log(np.abs(selected_fft + 1)) + + # inverse fft to reconstruct image using only the selection + iw.managed_graphics[3].data = np.fft.ifft2(np.fft.fftshift(selected_fft)) + iw.managed_graphics[3].reset_vmin_vmax() + + # fft of the region outside the selection + unselected_fft = img_fft.copy() + 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 + 1)) + + # inverse fft to reconstruct image using only the unselected part of the fft + iw.managed_graphics[5].data = np.fft.ifft2(np.fft.fftshift(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.loop.run() \ No newline at end of file From d486e852ed53f031fc1464e29ce8d8062e9df3c4 Mon Sep 17 00:00:00 2001 From: kushalkolar Date: Thu, 16 Jan 2025 03:58:13 -0500 Subject: [PATCH 2/3] github actions has texture size limit of 2048 --- examples/selection_tools/fft.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/selection_tools/fft.py b/examples/selection_tools/fft.py index b819d1281..a101b7bf1 100644 --- a/examples/selection_tools/fft.py +++ b/examples/selection_tools/fft.py @@ -28,10 +28,14 @@ data=[image, log_abs_img_fft, 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": (700, 1340)}, + figure_kwargs={"size": (700, 1024)}, histogram_widget=False, ) +# we don't need the toolbars here, unclutter the figure +for subplot in iw.figure: + subplot.toolbar = False + # viridis cmap for the fft images iw.cmap = "viridis" @@ -94,4 +98,4 @@ def update_images(ev): # please see our docs for using fastplotlib interactively in ipython and jupyter if __name__ == "__main__": print(__doc__) - fpl.loop.run() \ No newline at end of file + fpl.loop.run() From b08d3a401844330cd1b3c058c0c5dcc79097bda4 Mon Sep 17 00:00:00 2001 From: kushalkolar Date: Thu, 16 Jan 2025 04:09:12 -0500 Subject: [PATCH 3/3] position selector to center --- examples/selection_tools/fft.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/selection_tools/fft.py b/examples/selection_tools/fft.py index a101b7bf1..f249f2c11 100644 --- a/examples/selection_tools/fft.py +++ b/examples/selection_tools/fft.py @@ -26,7 +26,7 @@ # create an ImageWidget to display all the images iw = fpl.ImageWidget( data=[image, log_abs_img_fft, zeros, zeros, zeros, zeros], - names=["image", "DFT", "selected", "IDFT of selected", "not-selected", "IDFT of not-selected"], + names=["image", "DFT", "selected", "FFT of selected", "not-selected", "IFFT of not-selected"], figure_shape=(3, 2), # so we can see image and fft side by side figure_kwargs={"size": (700, 1024)}, histogram_widget=False, @@ -51,7 +51,7 @@ iw.show() # create a rectangle selector -rs = iw.managed_graphics[1].add_rectangle_selector() +rs = iw.managed_graphics[1].add_rectangle_selector(edge_color="w", edge_thickness=2.0) @rs.add_event_handler("selection") @@ -88,8 +88,8 @@ def update_images(ev): iw.managed_graphics[5].reset_vmin_vmax() -# set initial selection to top right corner -rs.selection = (400, 512, 0, 100) +# set initial selection to the center +rs.selection = (225, 285, 225, 285) figure = iw.figure