tomwer 1.3.26__py3-none-any.whl → 1.4.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.
- orangecontrib/tomwer/orange/managedprocess.py +1 -29
- orangecontrib/tomwer/orange/settings.py +2 -28
- orangecontrib/tomwer/tests/TestAcquisition.py +220 -0
- orangecontrib/tomwer/tutorials/append_raw_darks_and_flats_frames_to_NXtomos.ows +2 -2
- orangecontrib/tomwer/tutorials/copy_reduced_darks_and_flats_meth1.ows +1 -1
- orangecontrib/tomwer/tutorials/{icat_publication.ows → drac_publication.ows} +7 -21
- orangecontrib/tomwer/tutorials/id16b/ID16b_full_volume.ows +22 -0
- orangecontrib/tomwer/tutorials/id16b/ID16b_insitu.ows +302 -0
- orangecontrib/tomwer/tutorials/id16b/ID16b_normalization.ows +218 -0
- orangecontrib/tomwer/tutorials/simple_volume_to_slurm_reconstruction.ows +29 -24
- orangecontrib/tomwer/tutorials/test_cor.ows +19 -0
- orangecontrib/tomwer/tutorials/volume_casting_on_slurm.ows +54 -0
- orangecontrib/tomwer/widgets/__init__.py +3 -5
- orangecontrib/tomwer/widgets/cluster/FutureSupervisorOW.py +35 -54
- orangecontrib/tomwer/widgets/cluster/SlurmClusterOW.py +1 -31
- orangecontrib/tomwer/widgets/control/AdvancementOW.py +1 -29
- orangecontrib/tomwer/widgets/control/DataDiscoveryOW.py +5 -4
- orangecontrib/tomwer/widgets/control/DataListenerOW.py +1 -29
- orangecontrib/tomwer/widgets/control/DataSelectorOW.py +11 -30
- orangecontrib/tomwer/widgets/control/DataTransfertOW.py +2 -28
- orangecontrib/tomwer/widgets/control/DataValidatorOW.py +1 -28
- orangecontrib/tomwer/widgets/control/DataWatcherOW.py +1 -28
- orangecontrib/tomwer/widgets/control/EDF2NXTomomillOW.py +48 -51
- orangecontrib/tomwer/widgets/control/EmailOW.py +12 -2
- orangecontrib/tomwer/widgets/control/FilterOW.py +1 -28
- orangecontrib/tomwer/widgets/control/NXTomomillOW.py +37 -53
- orangecontrib/tomwer/widgets/control/NXtomoConcatenate.py +21 -20
- orangecontrib/tomwer/widgets/control/NotifierOW.py +9 -28
- orangecontrib/tomwer/widgets/control/ReduceDarkFlatSelectorOW.py +3 -2
- orangecontrib/tomwer/widgets/control/SingleTomoObjOW.py +1 -27
- orangecontrib/tomwer/widgets/control/TimerOW.py +9 -28
- orangecontrib/tomwer/widgets/control/TomoObjSeriesOW.py +58 -0
- orangecontrib/tomwer/widgets/control/VolumeSelector.py +8 -30
- orangecontrib/tomwer/widgets/control/icons/nxtomomill.svg +173 -119
- orangecontrib/tomwer/widgets/control/icons/reduced_darkflat_selector.png +0 -0
- orangecontrib/tomwer/widgets/control/icons/reduced_darkflat_selector.svg +55 -195
- orangecontrib/tomwer/widgets/control/icons/{tomoobjserie.svg → tomoobjseries.svg} +2 -2
- orangecontrib/tomwer/widgets/dataportal/PublishProcessedDataOW.py +172 -0
- orangecontrib/tomwer/widgets/{icat → dataportal}/__init__.py +2 -2
- orangecontrib/tomwer/widgets/debugtools/DatasetGeneratorOW.py +2 -29
- orangecontrib/tomwer/widgets/debugtools/ObjectInspectorOW.py +1 -29
- orangecontrib/tomwer/widgets/edit/DarkFlatPatchOW.py +48 -73
- orangecontrib/tomwer/widgets/edit/ImageKeyEditorOW.py +48 -75
- orangecontrib/tomwer/widgets/edit/ImageKeyUpgraderOW.py +5 -30
- orangecontrib/tomwer/widgets/edit/NXtomoEditorOW.py +51 -52
- orangecontrib/tomwer/widgets/other/PythonScriptOW.py +22 -10
- orangecontrib/tomwer/widgets/reconstruction/AxisOW.py +51 -60
- orangecontrib/tomwer/widgets/reconstruction/CastNabuVolumeOW.py +22 -68
- orangecontrib/tomwer/widgets/reconstruction/DarkRefAndCopyOW.py +3 -30
- orangecontrib/tomwer/widgets/reconstruction/NabuHelicalPrepareWeightsDoubleOW.py +21 -19
- orangecontrib/tomwer/widgets/reconstruction/NabuOW.py +7 -70
- orangecontrib/tomwer/widgets/reconstruction/NabuVolumeOW.py +41 -84
- orangecontrib/tomwer/widgets/reconstruction/SAAxisOW.py +15 -40
- orangecontrib/tomwer/widgets/reconstruction/SADeltaBetaOW.py +13 -35
- orangecontrib/tomwer/widgets/reconstruction/SinoNormOW.py +2 -30
- orangecontrib/tomwer/widgets/stitching/ZStitchingConfigOW.py +11 -11
- orangecontrib/tomwer/widgets/utils.py +2 -29
- orangecontrib/tomwer/widgets/visualization/DataViewerOW.py +1 -27
- orangecontrib/tomwer/widgets/visualization/DiffViewerOW.py +1 -27
- orangecontrib/tomwer/widgets/visualization/NXtomoMetadataViewerOW.py +1 -1
- orangecontrib/tomwer/widgets/visualization/RadioStackOW.py +2 -28
- orangecontrib/tomwer/widgets/visualization/SampleMovedOW.py +1 -27
- orangecontrib/tomwer/widgets/visualization/SinogramViewerOW.py +1 -27
- orangecontrib/tomwer/widgets/visualization/SliceStackOW.py +2 -28
- tomwer/__init__.py +3 -28
- tomwer/__main__.py +8 -4
- tomwer/app/__init__.py +2 -0
- tomwer/app/axis.py +8 -10
- tomwer/app/canvas.py +23 -29
- tomwer/app/canvas_launcher/config.py +14 -102
- tomwer/app/canvas_launcher/environ.py +5 -8
- tomwer/app/canvas_launcher/mainwindow.py +175 -69
- tomwer/app/canvas_launcher/splash.py +1 -3
- tomwer/app/canvas_launcher/utils.py +47 -0
- tomwer/app/canvas_launcher/widgetsscheme.py +3 -10
- tomwer/app/diffframe.py +2 -0
- tomwer/app/imagekeyeditor.py +2 -1
- tomwer/app/imagekeyupgrader.py +2 -0
- tomwer/app/multicor.py +5 -2
- tomwer/app/multipag.py +16 -5
- tomwer/app/nabuapp.py +2 -1
- tomwer/app/nxtomoeditor.py +17 -12
- tomwer/app/patchrawdarkflat.py +2 -0
- tomwer/app/radiostack.py +3 -2
- tomwer/app/reducedarkflat.py +3 -0
- tomwer/app/samplemoved.py +2 -0
- tomwer/app/scanviewer.py +2 -0
- tomwer/app/sinogramviewer.py +2 -0
- tomwer/app/slicestack.py +11 -13
- tomwer/app/stitching/common.py +431 -0
- tomwer/app/stopdatalistener.py +3 -0
- tomwer/app/ystitching.py +26 -0
- tomwer/app/zstitching.py +8 -363
- tomwer/core/__init__.py +2 -28
- tomwer/core/cluster/__init__.py +3 -0
- tomwer/core/cluster/cluster.py +10 -26
- tomwer/core/futureobject.py +17 -43
- tomwer/core/log/__init__.py +2 -0
- tomwer/core/log/processlog.py +0 -28
- tomwer/core/process/cluster/supervisor.py +52 -34
- tomwer/core/process/conditions/filters.py +3 -28
- tomwer/core/process/control/datalistener/datalistener.py +7 -75
- tomwer/core/process/control/datalistener/rpcserver.py +8 -38
- tomwer/core/process/control/datawatcher/datawatcher.py +11 -40
- tomwer/core/process/control/datawatcher/datawatcherobserver.py +30 -64
- tomwer/core/process/control/datawatcher/datawatcherprocess.py +11 -32
- tomwer/core/process/control/datawatcher/edfdwprocess.py +2 -27
- tomwer/core/process/control/datawatcher/hdf5dwprocess.py +1 -26
- tomwer/core/process/control/datawatcher/status.py +1 -26
- tomwer/core/process/control/emailnotifier.py +11 -23
- tomwer/core/process/control/nxtomoconcatenate.py +20 -18
- tomwer/core/process/control/nxtomomill.py +9 -44
- tomwer/core/process/control/scanlist.py +0 -27
- tomwer/core/process/control/scantransfer.py +15 -13
- tomwer/core/process/control/scanvalidator.py +4 -30
- tomwer/core/process/control/{test → tests}/test_concatenate_nxtomos.py +5 -5
- tomwer/core/process/control/timer.py +1 -27
- tomwer/core/process/control/tomoobjseries.py +12 -0
- tomwer/core/process/drac/binning.py +37 -0
- tomwer/core/process/drac/dracbase.py +170 -0
- tomwer/core/process/drac/gallery.py +109 -0
- tomwer/core/process/drac/output.py +12 -0
- tomwer/core/process/drac/processeddataset.py +147 -0
- tomwer/core/process/drac/publish.py +118 -0
- tomwer/core/process/drac/rawdataset.py +142 -0
- tomwer/core/process/drac/tests/test_gallery.py +71 -0
- tomwer/core/process/drac/tests/test_icat_processed_dataset.py +80 -0
- tomwer/core/process/drac/tests/test_icat_raw_dataset.py +90 -0
- tomwer/core/process/edit/darkflatpatch.py +1 -28
- tomwer/core/process/edit/imagekeyeditor.py +4 -32
- tomwer/core/process/edit/nxtomoeditor.py +307 -0
- tomwer/core/process/edit/tests/test_darkflatpatch.py +243 -0
- tomwer/core/process/edit/tests/test_imagekey_editor.py +99 -0
- tomwer/core/process/output.py +9 -2
- tomwer/core/process/reconstruction/__init__.py +0 -26
- tomwer/core/process/reconstruction/axis/anglemode.py +1 -29
- tomwer/core/process/reconstruction/axis/axis.py +47 -804
- tomwer/core/process/reconstruction/axis/mode.py +89 -25
- tomwer/core/process/reconstruction/axis/params.py +131 -283
- tomwer/core/process/reconstruction/axis/projectiontype.py +0 -28
- tomwer/core/process/reconstruction/axis/side.py +8 -0
- tomwer/core/process/reconstruction/darkref/darkrefs.py +14 -39
- tomwer/core/process/reconstruction/darkref/darkrefscopy.py +7 -39
- tomwer/core/process/reconstruction/darkref/params.py +1 -28
- tomwer/core/process/reconstruction/nabu/castvolume.py +19 -34
- tomwer/core/process/reconstruction/nabu/nabucommon.py +18 -43
- tomwer/core/process/reconstruction/nabu/nabuscores.py +64 -68
- tomwer/core/process/reconstruction/nabu/nabuslices.py +63 -105
- tomwer/core/process/reconstruction/nabu/nabuvolume.py +44 -70
- tomwer/core/process/reconstruction/nabu/plane.py +10 -0
- tomwer/core/process/reconstruction/nabu/settings.py +1 -28
- tomwer/core/process/reconstruction/nabu/target.py +0 -28
- tomwer/core/process/reconstruction/nabu/test/test_castvolume.py +116 -0
- tomwer/core/process/reconstruction/nabu/test/test_nabu_utils.py +277 -0
- tomwer/core/process/reconstruction/nabu/test/test_nabunormalization.py +199 -0
- tomwer/core/process/reconstruction/nabu/utils.py +11 -60
- tomwer/core/process/reconstruction/normalization/normalization.py +2 -32
- tomwer/core/process/reconstruction/normalization/params.py +3 -35
- tomwer/core/process/reconstruction/output.py +14 -19
- tomwer/core/process/reconstruction/paramsbase.py +4 -33
- tomwer/core/process/reconstruction/saaxis/params.py +5 -33
- tomwer/core/process/reconstruction/saaxis/saaxis.py +22 -51
- tomwer/core/process/reconstruction/sadeltabeta/params.py +2 -31
- tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +18 -46
- tomwer/core/process/reconstruction/scores/params.py +9 -39
- tomwer/core/process/reconstruction/scores/scores.py +10 -42
- tomwer/core/process/reconstruction/tests/__init__.py +0 -0
- tomwer/core/process/reconstruction/tests/test_axis.py +46 -0
- tomwer/core/process/reconstruction/tests/test_darkref.py +33 -0
- tomwer/core/process/reconstruction/{test → tests}/test_saaxis.py +1 -27
- tomwer/core/process/reconstruction/tests/test_sadeltabeta.py +48 -0
- tomwer/core/process/reconstruction/{test → tests}/test_utils.py +4 -4
- tomwer/core/process/reconstruction/utils/cor.py +8 -4
- tomwer/core/process/script/python.py +1 -27
- tomwer/core/process/script/tests/test_script.py +41 -0
- tomwer/core/process/stitching/metadataholder.py +5 -4
- tomwer/core/process/stitching/nabustitcher.py +35 -5
- tomwer/core/process/stitching/tests/test_metadataholder.py +17 -0
- tomwer/core/process/task.py +20 -63
- tomwer/core/process/tests/__init__.py +0 -0
- tomwer/core/process/{test → tests}/test_conditions.py +1 -28
- tomwer/core/process/{test → tests}/test_dark_and_flat.py +1 -27
- tomwer/core/process/{test → tests}/test_data_listener.py +1 -27
- tomwer/core/process/{test → tests}/test_data_transfer.py +2 -28
- tomwer/core/process/{test → tests}/test_data_watcher.py +1 -27
- tomwer/core/process/{test → tests}/test_nabu.py +2 -33
- tomwer/core/process/{test → tests}/test_normalization.py +1 -26
- tomwer/core/process/{test → tests}/test_timer.py +1 -27
- tomwer/core/process/utils.py +2 -31
- tomwer/core/process/visualization/dataviewer.py +1 -26
- tomwer/core/process/visualization/diffviewer.py +1 -26
- tomwer/core/process/visualization/imagestackviewer.py +0 -26
- tomwer/core/process/visualization/radiostack.py +0 -26
- tomwer/core/process/visualization/samplemoved.py +0 -28
- tomwer/core/process/visualization/sinogramviewer.py +0 -27
- tomwer/core/process/visualization/slicestack.py +0 -28
- tomwer/core/process/visualization/tests/test_data_viewer.py +12 -0
- tomwer/core/process/visualization/tests/test_diff_viewer.py +12 -0
- tomwer/core/process/visualization/tests/test_image_stack_viewer.py +14 -0
- tomwer/core/process/visualization/tests/test_radio_stack.py +12 -0
- tomwer/core/process/visualization/tests/test_sample_moved.py +14 -0
- tomwer/core/process/visualization/tests/test_sinogram_viewer.py +13 -0
- tomwer/core/process/visualization/tests/test_slice_stack.py +13 -0
- tomwer/core/process/visualization/tests/test_volume_viewer.py +12 -0
- tomwer/core/process/visualization/volumeviewer.py +0 -29
- tomwer/core/scan/__init__.py +3 -27
- tomwer/core/scan/blissscan.py +5 -34
- tomwer/core/scan/edfscan.py +19 -53
- tomwer/core/scan/hdf5scan.py +2 -2
- tomwer/core/scan/nxtomoscan.py +48 -54
- tomwer/core/scan/scanbase.py +107 -203
- tomwer/core/scan/scanfactory.py +11 -41
- tomwer/core/scan/tests/__init__.py +0 -0
- tomwer/core/scan/tests/test_edf.py +25 -0
- tomwer/core/scan/tests/test_future_scan.py +35 -0
- tomwer/core/scan/tests/test_nxtomoscan.py +143 -0
- tomwer/core/scan/tests/test_process_registration.py +64 -0
- tomwer/core/settings.py +18 -40
- tomwer/core/tests/__init__.py +0 -0
- tomwer/core/tests/test_scanutils.py +26 -0
- tomwer/core/{test → tests}/test_utils.py +1 -28
- tomwer/core/tomwer_object.py +4 -0
- tomwer/core/utils/__init__.py +2 -0
- tomwer/core/utils/char.py +0 -28
- tomwer/core/utils/deprecation.py +12 -38
- tomwer/core/utils/dictutils.py +1 -3
- tomwer/core/utils/ftseriesutils.py +1 -27
- tomwer/core/utils/gpu.py +0 -28
- tomwer/core/utils/image.py +8 -39
- tomwer/core/utils/locker.py +1 -28
- tomwer/core/utils/logconfig.py +0 -27
- tomwer/core/utils/normalization.py +4 -31
- tomwer/core/utils/nxtomoutils.py +8 -38
- tomwer/core/utils/resource.py +0 -26
- tomwer/core/utils/scanutils.py +23 -52
- tomwer/core/utils/slurm.py +7 -30
- tomwer/core/utils/spec.py +6 -6
- tomwer/core/utils/tests/__init__.py +0 -0
- tomwer/core/utils/tests/test_image.py +30 -0
- tomwer/core/utils/tests/test_nxtomo.py +38 -0
- tomwer/core/utils/tests/test_scan_utils.py +46 -0
- tomwer/core/utils/tests/test_time.py +6 -0
- tomwer/core/utils/threads.py +0 -26
- tomwer/core/utils/time.py +0 -27
- tomwer/core/volume/__init__.py +4 -0
- tomwer/core/volume/edfvolume.py +1 -28
- tomwer/core/volume/hdf5volume.py +1 -28
- tomwer/core/volume/jp2kvolume.py +1 -27
- tomwer/core/volume/rawvolume.py +1 -28
- tomwer/core/volume/tests/test_volumes.py +21 -0
- tomwer/core/volume/tiffvolume.py +1 -28
- tomwer/core/volume/volumebase.py +5 -0
- tomwer/core/volume/volumefactory.py +7 -33
- tomwer/gui/__init__.py +0 -28
- tomwer/gui/cluster/__init__.py +2 -0
- tomwer/gui/cluster/slurm.py +297 -95
- tomwer/gui/cluster/supervisor.py +1 -27
- tomwer/gui/cluster/tests/__init__.py +0 -0
- tomwer/gui/cluster/{test → tests}/test_cluster.py +21 -26
- tomwer/gui/cluster/{test → tests}/test_supervisor.py +1 -27
- tomwer/gui/conditions/__init__.py +2 -0
- tomwer/gui/conditions/filter.py +1 -26
- tomwer/gui/configuration/__init__.py +2 -0
- tomwer/gui/control/__init__.py +2 -0
- tomwer/gui/control/actions.py +2 -28
- tomwer/gui/control/datadiscovery.py +4 -3
- tomwer/gui/control/datalist.py +64 -69
- tomwer/gui/control/datalistener.py +1 -39
- tomwer/gui/control/datareacheractions.py +1 -28
- tomwer/gui/control/datatransfert.py +2 -29
- tomwer/gui/control/datavalidator.py +3 -37
- tomwer/gui/control/datawatcher/__init__.py +0 -28
- tomwer/gui/control/datawatcher/configuration.py +1 -28
- tomwer/gui/control/datawatcher/datawatcher.py +3 -32
- tomwer/gui/control/datawatcher/datawatcherobserver.py +2 -28
- tomwer/gui/control/history.py +5 -35
- tomwer/gui/control/nxtomomill.py +3 -30
- tomwer/gui/control/observations.py +61 -55
- tomwer/gui/control/reducedarkflatselector.py +24 -20
- tomwer/gui/control/scanselectorwidget.py +2 -28
- tomwer/gui/control/selectorwidgetbase.py +17 -17
- tomwer/gui/control/series/__init__.py +0 -0
- tomwer/gui/control/{serie/seriecreator.py → series/seriescreator.py} +214 -235
- tomwer/gui/control/series/serieswaiter.py +0 -0
- tomwer/gui/control/series/test/test_creator.py +424 -0
- tomwer/gui/control/series/test/test_nxtomo_concatenate.py +21 -0
- tomwer/gui/control/singletomoobj.py +1 -1
- tomwer/gui/control/tests/__init__.py +0 -0
- tomwer/gui/control/tests/test_datalist.py +47 -0
- tomwer/gui/control/{test → tests}/test_datalistener.py +1 -28
- tomwer/gui/control/tests/test_datavalidator.py +27 -0
- tomwer/gui/control/{test → tests}/test_inputwidget.py +1 -27
- tomwer/gui/control/tests/test_process_manager.py +38 -0
- tomwer/gui/control/tests/test_scan_observations.py +23 -0
- tomwer/gui/control/tests/test_scanselector.py +42 -0
- tomwer/gui/control/{test → tests}/test_scanvalidator.py +1 -27
- tomwer/gui/control/{test → tests}/test_volume_dialog.py +2 -30
- tomwer/gui/control/{test → tests}/test_volumeselector.py +1 -27
- tomwer/gui/control/volumeselectorwidget.py +2 -30
- tomwer/gui/dataportal/__init__.py +2 -0
- tomwer/gui/{icat → dataportal}/createscreenshots.py +3 -2
- tomwer/gui/dataportal/gallery.py +133 -0
- tomwer/gui/dataportal/outputformat.py +0 -0
- tomwer/gui/dataportal/publish.py +96 -0
- tomwer/gui/dataportal/tests/test_create_screenshots_gui.py +23 -0
- tomwer/gui/dataportal/tests/test_gallery_gui.py +21 -0
- tomwer/gui/debugtools/__init__.py +2 -0
- tomwer/gui/debugtools/datasetgenerator.py +1 -30
- tomwer/gui/debugtools/objectinspector.py +1 -29
- tomwer/gui/dialog/QDataDialog.py +89 -0
- tomwer/gui/{qfolderdialog.py → dialog/QVolumeDialog.py} +8 -107
- tomwer/gui/dialog/__init__.py +1 -0
- tomwer/gui/edit/__init__.py +2 -0
- tomwer/gui/edit/dkrfpatch.py +52 -87
- tomwer/gui/edit/imagekeyeditor.py +18 -54
- tomwer/gui/edit/nxtomoeditor.py +113 -300
- tomwer/gui/edit/nxtomowarmer.py +3 -2
- tomwer/gui/edit/tests/__init__.py +0 -0
- tomwer/gui/edit/{test → tests}/test_dkrf_patch.py +3 -29
- tomwer/gui/edit/{test → tests}/test_image_key_editor.py +1 -27
- tomwer/gui/edit/{test → tests}/test_nx_editor.py +45 -23
- tomwer/gui/fonts.py +5 -0
- tomwer/gui/icons.py +28 -66
- tomwer/gui/illustrations.py +4 -34
- tomwer/gui/imagefromfile.py +5 -30
- tomwer/gui/metadataloader.py +36 -0
- tomwer/gui/qconfigfile.py +3 -0
- tomwer/gui/qlefilesystem.py +3 -0
- tomwer/gui/reconstruction/__init__.py +2 -0
- tomwer/gui/reconstruction/axis/AxisMainWindow.py +275 -0
- tomwer/gui/reconstruction/axis/AxisOptionsWidget.py +313 -0
- tomwer/gui/reconstruction/axis/AxisSettingsWidget.py +797 -0
- tomwer/gui/reconstruction/axis/AxisWidget.py +534 -0
- tomwer/gui/reconstruction/axis/CalculationWidget.py +218 -0
- tomwer/gui/reconstruction/axis/CompareImages.py +11 -44
- tomwer/gui/reconstruction/axis/ControlWidget.py +285 -0
- tomwer/gui/reconstruction/axis/EstimatedCORWidget.py +394 -0
- tomwer/gui/reconstruction/axis/EstimatedCorComboBox.py +118 -0
- tomwer/gui/reconstruction/axis/InputWidget.py +347 -0
- tomwer/gui/reconstruction/axis/ManualFramesSelection.py +168 -0
- tomwer/gui/reconstruction/axis/__init__.py +2 -2
- tomwer/gui/reconstruction/darkref/__init__.py +0 -27
- tomwer/gui/reconstruction/darkref/darkrefcopywidget.py +5 -34
- tomwer/gui/reconstruction/darkref/darkrefwidget.py +1 -27
- tomwer/gui/reconstruction/nabu/castvolume.py +40 -59
- tomwer/gui/reconstruction/nabu/check.py +7 -33
- tomwer/gui/reconstruction/nabu/nabuconfig/base.py +7 -34
- tomwer/gui/reconstruction/nabu/nabuconfig/ctf.py +6 -5
- tomwer/gui/reconstruction/nabu/nabuconfig/nabuconfig.py +10 -69
- tomwer/gui/reconstruction/nabu/nabuconfig/output.py +3 -47
- tomwer/gui/reconstruction/nabu/nabuconfig/phase.py +54 -36
- tomwer/gui/reconstruction/nabu/nabuconfig/preprocessing.py +103 -54
- tomwer/gui/reconstruction/nabu/nabuconfig/reconstruction.py +116 -65
- tomwer/gui/reconstruction/nabu/nabuflow.py +31 -61
- tomwer/gui/reconstruction/nabu/platform.py +94 -0
- tomwer/gui/reconstruction/nabu/slices.py +81 -45
- tomwer/gui/reconstruction/nabu/slurm.py +1 -27
- tomwer/gui/reconstruction/nabu/test/test_cast_volume.py +82 -0
- tomwer/gui/reconstruction/nabu/test/test_check.py +66 -0
- tomwer/gui/reconstruction/nabu/test/test_ctf.py +46 -0
- tomwer/gui/reconstruction/nabu/test/test_helical.py +21 -0
- tomwer/gui/reconstruction/nabu/test/test_nabu_preprocessing.py +81 -0
- tomwer/gui/reconstruction/nabu/volume.py +62 -90
- tomwer/gui/reconstruction/normalization/intensity.py +5 -32
- tomwer/gui/reconstruction/normalization/test/test_intensity.py +89 -0
- tomwer/gui/reconstruction/saaxis/corrangeselector.py +32 -56
- tomwer/gui/reconstruction/saaxis/dimensionwidget.py +56 -96
- tomwer/gui/reconstruction/saaxis/saaxis.py +17 -38
- tomwer/gui/reconstruction/saaxis/sliceselector.py +8 -39
- tomwer/gui/reconstruction/sadeltabeta/saadeltabeta.py +19 -37
- tomwer/gui/reconstruction/scores/control.py +2 -30
- tomwer/gui/reconstruction/scores/scoreplot.py +23 -49
- tomwer/gui/reconstruction/tests/__init__.py +0 -0
- tomwer/gui/reconstruction/{test → tests}/test_axis.py +23 -49
- tomwer/gui/reconstruction/{test → tests}/test_nabu.py +16 -31
- tomwer/gui/reconstruction/{test → tests}/test_saaxis.py +10 -37
- tomwer/gui/reconstruction/{test → tests}/test_sadeltabeta.py +1 -26
- tomwer/gui/samplemoved/__init__.py +2 -30
- tomwer/gui/samplemoved/selectiontable.py +3 -33
- tomwer/gui/settings.py +7 -0
- tomwer/gui/stackplot.py +33 -661
- tomwer/gui/stacks.py +261 -135
- tomwer/gui/stitching/SingleAxisStitchingWidget.py +326 -0
- tomwer/gui/stitching/StitchingOptionsWidget.py +438 -0
- tomwer/gui/stitching/StitchingWindow.py +586 -0
- tomwer/gui/stitching/__init__.py +2 -0
- tomwer/gui/stitching/alignment.py +90 -0
- tomwer/gui/stitching/axisorderedlist.py +44 -34
- tomwer/gui/stitching/config/axisparams.py +25 -11
- tomwer/gui/stitching/config/output.py +6 -5
- tomwer/gui/stitching/config/positionoveraxis.py +313 -51
- tomwer/gui/stitching/config/stitchingstrategies.py +22 -16
- tomwer/gui/stitching/config/tests/test_axisparams.py +25 -0
- tomwer/gui/stitching/config/tomoobjdetails.py +3 -5
- tomwer/gui/stitching/normalization.py +1 -0
- tomwer/gui/stitching/preview.py +59 -0
- tomwer/gui/stitching/singleaxis.py +57 -0
- tomwer/gui/stitching/stitchandbackground.py +3 -2
- tomwer/gui/stitching/stitching_preview.py +44 -36
- tomwer/gui/stitching/stitching_raw.py +5 -3
- tomwer/gui/stitching/tests/test_ZStitchingWindow.py +88 -0
- tomwer/gui/stitching/tests/test_axis_ordered_list.py +21 -0
- tomwer/gui/stitching/tests/test_normalization.py +27 -0
- tomwer/gui/stitching/tests/test_preview.py +68 -0
- tomwer/gui/stitching/tests/test_stitching_raw.py +110 -0
- tomwer/gui/stitching/tests/utils.py +92 -0
- tomwer/gui/stitching/utils.py +14 -0
- tomwer/gui/stitching/z_stitching/fineestimation.py +5 -33
- tomwer/gui/stitching/z_stitching/tests/test_fine_estimation.py +35 -0
- tomwer/gui/stitching/z_stitching/tests/test_raw_estimation.py +215 -0
- tomwer/gui/stitching/z_stitching/tests/test_stitching_window.py +51 -0
- tomwer/gui/tests/__init__.py +0 -0
- tomwer/gui/tests/test_axis_gui.py +43 -0
- tomwer/gui/{test → tests}/test_qfolder_dialog.py +1 -1
- tomwer/gui/utils/RangeWidget.py +44 -0
- tomwer/gui/utils/buttons.py +4 -3
- tomwer/gui/utils/completer.py +2 -33
- tomwer/gui/utils/flow.py +11 -40
- tomwer/gui/utils/gpu.py +60 -0
- tomwer/gui/utils/illustrations.py +1 -26
- tomwer/gui/utils/inputwidget.py +35 -73
- tomwer/gui/utils/lineselector/lineselector.py +9 -46
- tomwer/gui/utils/loadingmode.py +81 -0
- tomwer/gui/utils/qt_utils.py +9 -0
- tomwer/gui/utils/sandboxes.py +1 -26
- tomwer/gui/utils/scandescription.py +2 -31
- tomwer/gui/utils/scrollarea.py +6 -55
- tomwer/gui/utils/slider.py +4 -28
- tomwer/gui/utils/splashscreen.py +0 -28
- tomwer/gui/utils/step.py +14 -13
- tomwer/gui/utils/tests/test_completer.py +41 -0
- tomwer/gui/utils/tests/test_line_selector.py +21 -0
- tomwer/gui/utils/tests/test_splashscreen.py +8 -0
- tomwer/gui/utils/tests/test_vignettes.py +68 -0
- tomwer/gui/utils/unitsystem.py +15 -69
- tomwer/gui/utils/utils.py +4 -5
- tomwer/gui/utils/vignettes.py +10 -41
- tomwer/gui/utils/waiterthread.py +0 -26
- tomwer/gui/visualization/__init__.py +2 -0
- tomwer/gui/visualization/dataviewer.py +68 -421
- tomwer/gui/visualization/diffviewer/diffviewer.py +2 -30
- tomwer/gui/visualization/diffviewer/shiftwidget.py +4 -29
- tomwer/gui/visualization/fullscreenplot.py +5 -5
- tomwer/gui/visualization/imagestack.py +403 -0
- tomwer/gui/visualization/nxtomometadata.py +0 -4
- tomwer/gui/visualization/reconstructionparameters.py +14 -32
- tomwer/gui/visualization/scanoverview.py +33 -66
- tomwer/gui/visualization/sinogramviewer.py +2 -28
- tomwer/gui/visualization/test/__init__.py +0 -28
- tomwer/gui/visualization/test/test_dataviewer.py +1 -28
- tomwer/gui/visualization/test/test_diffviewer.py +1 -28
- tomwer/gui/visualization/test/test_nx_tomo_metadata_viewer.py +0 -5
- tomwer/gui/visualization/test/test_reconstruction_parameters.py +1 -27
- tomwer/gui/visualization/test/test_sinogramviewer.py +1 -28
- tomwer/gui/visualization/test/test_stacks.py +184 -115
- tomwer/gui/visualization/test/test_volumeviewer.py +3 -2
- tomwer/gui/visualization/tomoobjoverview.py +2 -2
- tomwer/gui/visualization/volumeoverview.py +3 -2
- tomwer/gui/visualization/volumeviewer.py +47 -43
- tomwer/io/__init__.py +2 -0
- tomwer/io/utils/h5pyutils.py +1 -27
- tomwer/io/utils/test/test_raw_and_processed_data.py +10 -0
- tomwer/io/utils/test/test_utils.py +67 -0
- tomwer/io/utils/utils.py +2 -31
- tomwer/resources/__init__.py +13 -33
- tomwer/resources/gui/icons/edit_downstream.svg +114 -0
- tomwer/resources/gui/icons/edit_upstream.svg +112 -0
- tomwer/resources/gui/icons/free_edition.svg +23 -0
- tomwer/resources/gui/icons/icat_gallery_opts.png +0 -0
- tomwer/resources/gui/icons/icat_gallery_opts.svg +80 -0
- tomwer/resources/gui/icons/search.png +0 -0
- tomwer/resources/gui/icons/search.svg +23 -0
- tomwer/resources/gui/icons/warning.png +0 -0
- tomwer/synctools/__init__.py +2 -0
- tomwer/synctools/axis.py +1 -27
- tomwer/synctools/darkref.py +1 -26
- tomwer/synctools/datalistener.py +1 -27
- tomwer/synctools/datatransfert.py +2 -27
- tomwer/synctools/imageloaderthread.py +1 -28
- tomwer/synctools/rsyncmanager.py +1 -25
- tomwer/synctools/saaxis.py +1 -26
- tomwer/synctools/sadeltabeta.py +1 -26
- tomwer/synctools/stacks/control/datalistener.py +1 -26
- tomwer/synctools/stacks/processingstack.py +4 -33
- tomwer/synctools/stacks/reconstruction/axis.py +6 -53
- tomwer/synctools/stacks/reconstruction/castvolume.py +12 -43
- tomwer/synctools/stacks/reconstruction/dkrefcopy.py +4 -27
- tomwer/synctools/stacks/reconstruction/nabu.py +3 -28
- tomwer/synctools/stacks/reconstruction/normalization.py +2 -27
- tomwer/synctools/stacks/reconstruction/saaxis.py +2 -27
- tomwer/synctools/stacks/reconstruction/sadeltabeta.py +2 -27
- tomwer/synctools/tests/__init__.py +0 -0
- tomwer/synctools/{test → tests}/test_darkRefs.py +16 -40
- tomwer/synctools/{test → tests}/test_foldertransfer.py +2 -33
- tomwer/synctools/utils/scanstages.py +2 -31
- tomwer/tests/__init__.py +1 -0
- tomwer/tests/app/test_stitching.py +95 -0
- tomwer/tests/datasets.py +1 -5
- tomwer/tests/orangecontrib/tomwer/widgets/cluster/tests/test_future_supervisorow.py +48 -0
- tomwer/tests/orangecontrib/tomwer/widgets/cluster/tests/test_slurm_clusterow.py +40 -0
- tomwer/tests/orangecontrib/tomwer/widgets/control/tests/test_advancement.py +8 -0
- tomwer/tests/orangecontrib/tomwer/widgets/control/tests/test_data_validator.py +55 -0
- tomwer/tests/orangecontrib/tomwer/widgets/control/tests/test_datadiscovery.py +129 -0
- tomwer/tests/orangecontrib/tomwer/widgets/control/tests/test_datalistener.py +111 -0
- tomwer/tests/orangecontrib/tomwer/widgets/control/tests/test_dataselector.py +69 -0
- tomwer/tests/orangecontrib/tomwer/widgets/control/tests/test_datawatcher.py +411 -0
- tomwer/tests/orangecontrib/tomwer/widgets/control/tests/test_emailow.py +29 -0
- tomwer/tests/orangecontrib/tomwer/widgets/control/tests/test_notifier.py +24 -0
- tomwer/tests/orangecontrib/tomwer/widgets/control/tests/test_nxtomo_concatenate_ow.py +64 -0
- tomwer/tests/orangecontrib/tomwer/widgets/control/tests/test_nxtomomill.py +133 -0
- tomwer/tests/orangecontrib/tomwer/widgets/control/tests/test_reduce_dark_flat_selector.py +40 -0
- tomwer/tests/orangecontrib/tomwer/widgets/control/tests/test_singletomoobj.py +40 -0
- tomwer/tests/orangecontrib/tomwer/widgets/control/tests/test_timerow.py +25 -0
- tomwer/tests/orangecontrib/tomwer/widgets/control/tests/test_tomoobj_series.py +96 -0
- tomwer/tests/orangecontrib/tomwer/widgets/control/tests/test_volume_selector.py +69 -0
- orangecontrib/tomwer/widgets/edit/test/test_image_key_editor.py → tomwer/tests/orangecontrib/tomwer/widgets/debugtools/tests/test_dataset_generator.py +17 -16
- tomwer/tests/orangecontrib/tomwer/widgets/debugtools/tests/test_object_inspector.py +36 -0
- {orangecontrib/tomwer/widgets/edit/test → tomwer/tests/orangecontrib/tomwer/widgets/edit/tests}/test_dark_flat_patch.py +1 -27
- tomwer/tests/orangecontrib/tomwer/widgets/edit/tests/test_image_key_editor.py +30 -0
- tomwer/tests/orangecontrib/tomwer/widgets/edit/tests/test_nxtomo_editor.py +138 -0
- tomwer/tests/orangecontrib/tomwer/widgets/other/tests/test_pythonscript.py +31 -0
- tomwer/tests/orangecontrib/tomwer/widgets/reconstruction/tests/test_axis.py +199 -0
- tomwer/tests/orangecontrib/tomwer/widgets/reconstruction/tests/test_cast_volumeow.py +58 -0
- tomwer/tests/orangecontrib/tomwer/widgets/reconstruction/tests/test_dark_refs_widget.py +136 -0
- tomwer/tests/orangecontrib/tomwer/widgets/reconstruction/tests/test_delta_beta_selector.py +15 -0
- tomwer/tests/orangecontrib/tomwer/widgets/reconstruction/tests/test_i_norm.py +200 -0
- tomwer/tests/orangecontrib/tomwer/widgets/reconstruction/tests/test_nabu_helical_prepare_weights_double.py +20 -0
- tomwer/tests/orangecontrib/tomwer/widgets/reconstruction/tests/test_nabu_volume.py +74 -0
- tomwer/tests/orangecontrib/tomwer/widgets/reconstruction/tests/test_nabu_widget.py +107 -0
- tomwer/tests/orangecontrib/tomwer/widgets/reconstruction/tests/test_sa_delta_beta.py +194 -0
- tomwer/tests/orangecontrib/tomwer/widgets/reconstruction/tests/test_saaxis.py +194 -0
- tomwer/tests/orangecontrib/tomwer/widgets/stitching/tests/test_zstitching.py +313 -0
- tomwer/tests/orangecontrib/tomwer/widgets/tests/test_conditions.py +85 -0
- tomwer/tests/orangecontrib/tomwer/widgets/tests/test_darkref.py +225 -0
- tomwer/tests/orangecontrib/tomwer/widgets/tests/test_foldertransfert.py +105 -0
- tomwer/tests/orangecontrib/tomwer/widgets/visualization/tests/test_dataviewerow.py +57 -0
- tomwer/tests/orangecontrib/tomwer/widgets/visualization/tests/test_diffviewerow.py +39 -0
- tomwer/tests/orangecontrib/tomwer/widgets/visualization/tests/test_nxtomo_metadata_viewer.py +29 -0
- tomwer/tests/orangecontrib/tomwer/widgets/visualization/tests/test_radio_stackow.py +31 -0
- tomwer/tests/orangecontrib/tomwer/widgets/visualization/tests/test_sample_movedow.py +46 -0
- tomwer/tests/orangecontrib/tomwer/widgets/visualization/tests/test_sinogram_viewerow.py +31 -0
- tomwer/tests/orangecontrib/tomwer/widgets/visualization/tests/test_slice_stackow.py +31 -0
- tomwer/tests/orangecontrib/tomwer/widgets/visualization/tests/test_volume_viewerow.py +32 -0
- tomwer/tests/test_ewoks/test_conversion.py +104 -0
- tomwer/tests/test_ewoks/test_single_node_execution.py +87 -0
- tomwer/tests/test_ewoks/test_workflows.py +138 -0
- tomwer/utils.py +11 -39
- tomwer/version.py +2 -2
- {tomwer-1.3.26.dist-info → tomwer-1.4.0.dist-info}/LICENSE +3 -3
- tomwer-1.4.0.dist-info/METADATA +337 -0
- tomwer-1.4.0.dist-info/RECORD +912 -0
- {tomwer-1.3.26.dist-info → tomwer-1.4.0.dist-info}/WHEEL +1 -1
- {tomwer-1.3.26.dist-info → tomwer-1.4.0.dist-info}/entry_points.txt +1 -0
- orangecontrib/tomwer/widgets/control/DataListOW.py +0 -129
- orangecontrib/tomwer/widgets/control/TomoObjSerieOW.py +0 -86
- orangecontrib/tomwer/widgets/control/VolumeSymLinkOW.py +0 -182
- orangecontrib/tomwer/widgets/edit/test/test_nxtomo_editor.py +0 -141
- orangecontrib/tomwer/widgets/icat/PublishProcessedDataOW.py +0 -115
- orangecontrib/tomwer/widgets/icat/RawDataScreenshotCreatorOW.py +0 -98
- orangecontrib/tomwer/widgets/icat/SaveToGalleryAndPublishOW.py +0 -129
- orangecontrib/tomwer/widgets/icat/icons/add_gallery.png +0 -0
- orangecontrib/tomwer/widgets/icat/icons/add_gallery.svg +0 -82
- orangecontrib/tomwer/widgets/icat/icons/raw_screenshots.png +0 -0
- orangecontrib/tomwer/widgets/icat/icons/raw_screenshots.svg +0 -143
- orangecontrib/tomwer/widgets/visualization/LivesliceOW.py +0 -87
- orangecontrib/tomwer/widgets/visualization/icons/liveslice.png +0 -0
- orangecontrib/tomwer/widgets/visualization/icons/liveslice.svg +0 -110
- tomwer/core/log/logger.py +0 -130
- tomwer/core/process/control/test/test_volume_link.py +0 -74
- tomwer/core/process/control/tomoobjserie.py +0 -12
- tomwer/core/process/control/volumesymlink.py +0 -200
- tomwer/core/process/icat/createscreenshots.py +0 -100
- tomwer/core/process/icat/gallery.py +0 -377
- tomwer/core/process/icat/icatbase.py +0 -36
- tomwer/core/process/icat/publish.py +0 -228
- tomwer/core/process/icat/screenshots.py +0 -27
- tomwer/core/process/reconstruction/test/test_darkref.py +0 -60
- tomwer/core/process/reconstruction/test/test_sadeltabeta.py +0 -74
- tomwer/core/process/test/test_axis.py +0 -309
- tomwer/core/process/visualization/liveslice.py +0 -6
- tomwer/core/progress.py +0 -100
- tomwer/core/scan/test/test_edf.py +0 -53
- tomwer/core/scan/test/test_future_scan.py +0 -61
- tomwer/core/scan/test/test_h5.py +0 -96
- tomwer/core/scan/test/test_process_registration.py +0 -109
- tomwer/core/test/test_scanutils.py +0 -53
- tomwer/gui/control/emailnotifier.py +0 -174
- tomwer/gui/control/serie/seriewaiter.py +0 -28
- tomwer/gui/control/test/__init__.py +0 -28
- tomwer/gui/control/test/test_datalist.py +0 -96
- tomwer/gui/control/test/test_datavalidator.py +0 -54
- tomwer/gui/control/test/test_email.py +0 -35
- tomwer/gui/control/test/test_process_manager.py +0 -65
- tomwer/gui/control/test/test_scanselector.py +0 -67
- tomwer/gui/edit/test/__init__.py +0 -28
- tomwer/gui/icat/gallery.py +0 -214
- tomwer/gui/icat/publish.py +0 -187
- tomwer/gui/reconstruction/axis/axis.py +0 -733
- tomwer/gui/reconstruction/axis/radioaxis.py +0 -2467
- tomwer/gui/stitching/stitching.py +0 -1392
- tomwer/gui/test/__init__.py +0 -28
- tomwer/gui/test/test_axis_gui.py +0 -34
- tomwer/synctools/stacks/edit/darkflatpatch.py +0 -169
- tomwer/synctools/stacks/edit/imagekeyeditor.py +0 -135
- tomwer/third_part/WaitingOverlay.py +0 -110
- tomwer-1.3.26-py3.11-nspkg.pth +0 -1
- tomwer-1.3.26.dist-info/METADATA +0 -292
- tomwer-1.3.26.dist-info/RECORD +0 -785
- tomwer-1.3.26.dist-info/namespace_packages.txt +0 -1
- /orangecontrib/tomwer/{widgets/edit/test → tests}/__init__.py +0 -0
- {tomwer/core/process/control/test → orangecontrib/tomwer/tutorials/id16b}/__init__.py +0 -0
- {tomwer/core/process/icat → orangecontrib/tomwer/widgets/cluster/tests}/__init__.py +0 -0
- /orangecontrib/tomwer/widgets/control/icons/{tomoobjserie.png → tomoobjseries.png} +0 -0
- {tomwer/core/process/reconstruction/test → orangecontrib/tomwer/widgets/control/tests}/__init__.py +0 -0
- /orangecontrib/tomwer/widgets/{icat → dataportal}/icons/publish_processed_data.png +0 -0
- /orangecontrib/tomwer/widgets/{icat → dataportal}/icons/publish_processed_data.svg +0 -0
- {tomwer/core/process/test → orangecontrib/tomwer/widgets/debugtools/tests}/__init__.py +0 -0
- {tomwer/core/scan/test → orangecontrib/tomwer/widgets/edit/tests}/__init__.py +0 -0
- {tomwer/core/test → orangecontrib/tomwer/widgets/other/tests}/__init__.py +0 -0
- {tomwer/gui/cluster/test → orangecontrib/tomwer/widgets/reconstruction/tests}/__init__.py +0 -0
- {tomwer/gui/control/serie → orangecontrib/tomwer/widgets/stitching/tests}/__init__.py +0 -0
- {tomwer/gui/icat → orangecontrib/tomwer/widgets/tests}/__init__.py +0 -0
- {tomwer/gui/reconstruction/test → orangecontrib/tomwer/widgets/visualization/tests}/__init__.py +0 -0
- /tomwer/{synctools/stacks/edit → app/stitching}/__init__.py +0 -0
- /tomwer/{synctools/test → core/process/control/tests}/__init__.py +0 -0
- /tomwer/core/process/control/{test → tests}/test_email.py +0 -0
- /tomwer/core/process/control/{test → tests}/test_h52nx_process.py +0 -0
- /tomwer/{third_part → core/process/drac}/__init__.py +0 -0
- /tomwer/core/process/reconstruction/{test → tests}/test_axis_params.py +0 -0
- /tomwer/core/process/reconstruction/{test → tests}/test_darkref_copy.py +0 -0
- /tomwer/core/process/reconstruction/{test → tests}/test_paramsbase.py +0 -0
- /tomwer/core/scan/{test → tests}/test_scan.py +0 -0
- /tomwer/gui/control/{serie → series}/nxtomoconcatenate.py +0 -0
- /tomwer/gui/control/{test → tests}/test_datadiscovery.py +0 -0
- /tomwer/gui/control/{test → tests}/test_reducedarkflat_selector.py +0 -0
- /tomwer/gui/control/{test → tests}/test_single_tomo_obj.py +0 -0
- {orangecontrib/tomwer/widgets/edit/test → tomwer/tests/orangecontrib/tomwer/widgets/edit/tests}/test_image_key_upgrader.py +0 -0
- {tomwer-1.3.26.dist-info → tomwer-1.4.0.dist-info}/top_level.txt +0 -0
@@ -1,1392 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
import os
|
3
|
-
import shutil
|
4
|
-
import tempfile
|
5
|
-
import functools
|
6
|
-
|
7
|
-
from typing import Optional
|
8
|
-
|
9
|
-
from nabu.stitching import config as stitching_config
|
10
|
-
from nabu.stitching.config import StitchingType, dict_to_config_obj
|
11
|
-
from nabu.stitching.z_stitching import (
|
12
|
-
PostProcessZStitcher,
|
13
|
-
PreProcessZStitcher,
|
14
|
-
)
|
15
|
-
from nabu.pipeline.config import generate_nabu_configfile, parse_nabu_config_file
|
16
|
-
from nabu.stitching.alignment import AlignmentAxis1, AlignmentAxis2
|
17
|
-
from nabu.stitching.config import (
|
18
|
-
get_default_stitching_config,
|
19
|
-
identifiers_as_str_to_instances,
|
20
|
-
KEY_RESCALE_MAX_PERCENTILES,
|
21
|
-
KEY_RESCALE_MIN_PERCENTILES,
|
22
|
-
RESCALE_FRAMES,
|
23
|
-
RESCALE_PARAMS,
|
24
|
-
SECTIONS_COMMENTS as _SECTIONS_COMMENTS,
|
25
|
-
STITCHING_SECTION,
|
26
|
-
)
|
27
|
-
|
28
|
-
from nxtomomill.io.utils import (
|
29
|
-
convert_str_to_tuple as _convert_str_to_tuple,
|
30
|
-
convert_str_to_bool as _convert_str_to_bool,
|
31
|
-
)
|
32
|
-
from silx.gui import qt
|
33
|
-
from tomoscan.serie import Serie
|
34
|
-
from tomoscan.scanbase import TomoScanBase as _TomoScanBase
|
35
|
-
from tomoscan.volumebase import VolumeBase as _VolumeBase
|
36
|
-
|
37
|
-
from tomwer.core.scan.nxtomoscan import NXtomoScan, NXtomoScanIdentifier
|
38
|
-
from tomwer.core.scan.scanfactory import ScanFactory
|
39
|
-
from tomwer.core.volume.volumefactory import VolumeFactory
|
40
|
-
from tomwer.core.volume.volumebase import TomwerVolumeBase
|
41
|
-
from tomwer.core.tomwer_object import TomwerObject
|
42
|
-
from tomwer.core.volume.hdf5volume import HDF5Volume, HDF5VolumeIdentifier
|
43
|
-
from tomwer.io.utils.utils import str_to_dict
|
44
|
-
from tomwer.gui.qconfigfile import QConfigFileDialog
|
45
|
-
from tomwer.gui.stitching.config.axisparams import StitcherAxisParams
|
46
|
-
from tomwer.gui.stitching.config.positionoveraxis import PosEditorOverOneAxis
|
47
|
-
from tomwer.gui.stitching.config.output import StitchingOutput
|
48
|
-
from tomwer.gui.stitching.config.stitchingstrategies import StitchingStrategies
|
49
|
-
from tomwer.gui.stitching.stitching_preview import PreviewStitchingPlot
|
50
|
-
from tomwer.gui.stitching.stitching_raw import RawStitchingPlot
|
51
|
-
from tomwer.gui.stitching.axisorderedlist import EditableZOrderedTomoObjWidget
|
52
|
-
from tomwer.gui.stitching.z_stitching.fineestimation import _SliceGetter
|
53
|
-
from tomwer.gui.configuration.action import (
|
54
|
-
BasicConfigurationAction,
|
55
|
-
ExpertConfigurationAction,
|
56
|
-
MinimalisticConfigurationAction,
|
57
|
-
)
|
58
|
-
from tomwer.gui.configuration.level import ConfigurationLevel
|
59
|
-
from tomwer.gui.stitching import action as stitching_action
|
60
|
-
from tomwer.gui.stitching.normalization import NormalizationBySampleGroupBox
|
61
|
-
|
62
|
-
|
63
|
-
_logger = logging.getLogger(__name__)
|
64
|
-
|
65
|
-
|
66
|
-
def convert_str_to_tuple(input_str, none_if_empty):
|
67
|
-
if input_str is None:
|
68
|
-
return None
|
69
|
-
elif isinstance(input_str, (tuple, list)):
|
70
|
-
return tuple(input_str)
|
71
|
-
else:
|
72
|
-
return _convert_str_to_tuple(input_str=input_str, none_if_empty=none_if_empty)
|
73
|
-
|
74
|
-
|
75
|
-
class ZStitchingCentralWidget(qt.QWidget):
|
76
|
-
sigStitchingTypeChanged = qt.Signal(str)
|
77
|
-
"""emit when stitching type changes"""
|
78
|
-
sigTomoObjsLoaded = qt.Signal(tuple)
|
79
|
-
"""Signal emit when during setting a configuration this trigger some addition of tomo object"""
|
80
|
-
|
81
|
-
class _ZStitchingCentralTabWidget(qt.QTabWidget):
|
82
|
-
def __init__(self, parent=None) -> None:
|
83
|
-
super().__init__(parent)
|
84
|
-
self._serieName = None
|
85
|
-
self._zOrderedList = EditableZOrderedTomoObjWidget(parent=self)
|
86
|
-
self.addTab(self._zOrderedList, "axis 0 ordered list")
|
87
|
-
self._previewPlot = PreviewStitchingPlot(parent=self)
|
88
|
-
self.addTab(self._previewPlot, "stitching preview")
|
89
|
-
# TODO: add a raw display to print frame from raw position z positions ...
|
90
|
-
self._rawDisplayPlot = RawStitchingPlot(
|
91
|
-
parent=self,
|
92
|
-
aspectRatio=True,
|
93
|
-
logScale=False,
|
94
|
-
copy=False,
|
95
|
-
save=False,
|
96
|
-
print_=False,
|
97
|
-
grid=False,
|
98
|
-
curveStyle=False,
|
99
|
-
mask=False,
|
100
|
-
alpha_values=True,
|
101
|
-
)
|
102
|
-
self._rawDisplayPlot.setKeepDataAspectRatio(True)
|
103
|
-
self._rawDisplayPlot.setAxesDisplayed(False)
|
104
|
-
self.addTab(self._rawDisplayPlot, "raw display")
|
105
|
-
# add an option to activate / deactivate auto update of the raw display as it can be time consuming.
|
106
|
-
raw_display_idx = self.indexOf(self._rawDisplayPlot)
|
107
|
-
self._rawDisplayCB = qt.QCheckBox(self)
|
108
|
-
self.tabBar().setTabButton(
|
109
|
-
raw_display_idx,
|
110
|
-
qt.QTabBar.LeftSide,
|
111
|
-
self._rawDisplayCB,
|
112
|
-
)
|
113
|
-
self.setTabToolTip(
|
114
|
-
raw_display_idx,
|
115
|
-
"If toggled will keep the raw display up to date from axis 0 modifications",
|
116
|
-
)
|
117
|
-
# set up: turn overlay one by default
|
118
|
-
self._previewPlot._backGroundAction.setChecked(True)
|
119
|
-
|
120
|
-
def _handleRawDisplayconnection(self, toggled: bool):
|
121
|
-
if toggled:
|
122
|
-
self._connectRawDisplayConnection()
|
123
|
-
else:
|
124
|
-
self._disconnectRawDisplayConnection()
|
125
|
-
|
126
|
-
def setSerie(self, serie: Serie):
|
127
|
-
for elmt in serie:
|
128
|
-
self._zOrderedList.addTomoObj(elmt)
|
129
|
-
self.setSerieName(serie.name)
|
130
|
-
|
131
|
-
def addTomoObj(self, tomo_obj: TomwerObject):
|
132
|
-
self._zOrderedList.addTomoObj(tomo_obj)
|
133
|
-
|
134
|
-
def removeTomoObj(self, tomo_obj: TomwerObject):
|
135
|
-
self._zOrderedList.removeTomoObj(tomo_obj=tomo_obj)
|
136
|
-
|
137
|
-
def getSerieName(self) -> str:
|
138
|
-
return self._serieName
|
139
|
-
|
140
|
-
def setSerieName(self, name: str):
|
141
|
-
self._serieName = name
|
142
|
-
|
143
|
-
def getTomoObjs(self) -> tuple:
|
144
|
-
return self._zOrderedList.getTomoObjsZOrdered()
|
145
|
-
|
146
|
-
def clearTomoObjs(self):
|
147
|
-
self._zOrderedList.clearTomoObjs()
|
148
|
-
|
149
|
-
def clean(self) -> None:
|
150
|
-
self.clearTomoObjs()
|
151
|
-
self._previewPlot.clear()
|
152
|
-
|
153
|
-
def close(self):
|
154
|
-
self._previewPlot.close()
|
155
|
-
# requested for the waiting plot update
|
156
|
-
super().close()
|
157
|
-
|
158
|
-
def setAddTomoObjCallbacks(self, *args, **kwargs):
|
159
|
-
self._zOrderedList.setAddTomoObjCallbacks(*args, **kwargs)
|
160
|
-
|
161
|
-
def setRemoveTomoObjCallbacks(self, *args, **kwargs):
|
162
|
-
self._zOrderedList.setRemoveTomoObjCallbacks(*args, **kwargs)
|
163
|
-
|
164
|
-
def __init__(self, parent=None) -> None:
|
165
|
-
super().__init__(parent)
|
166
|
-
self.setLayout(qt.QGridLayout())
|
167
|
-
|
168
|
-
self._stitchingTypeCB = qt.QComboBox(parent=self)
|
169
|
-
for mode in StitchingType.values():
|
170
|
-
self._stitchingTypeCB.addItem(mode)
|
171
|
-
self._stitchingTypeCB.currentIndexChanged.connect(self._stitchingTypeChanged)
|
172
|
-
self.layout().addWidget(qt.QLabel("stitching method:"), 0, 0, 1, 1)
|
173
|
-
self.layout().addWidget(self._stitchingTypeCB, 0, 1, 1, 1)
|
174
|
-
|
175
|
-
self._mainWidget = self._ZStitchingCentralTabWidget(parent=self)
|
176
|
-
self.layout().addWidget(self._mainWidget, 1, 0, 4, 4)
|
177
|
-
|
178
|
-
# set up
|
179
|
-
self.setStitchingType(self.getStitchingType())
|
180
|
-
self._mainWidget.setCurrentWidget(self._mainWidget._previewPlot)
|
181
|
-
|
182
|
-
# conenct signal / slot
|
183
|
-
self._stitchingTypeCB.currentIndexChanged.connect(self._stitchingTypeChanged)
|
184
|
-
|
185
|
-
def close(self):
|
186
|
-
self._mainWidget.close()
|
187
|
-
# requested for the waiting plot update
|
188
|
-
super().close()
|
189
|
-
|
190
|
-
def clean(self):
|
191
|
-
self._mainWidget.clean()
|
192
|
-
|
193
|
-
def _stitchingTypeChanged(self, *args, **kwargs):
|
194
|
-
self.sigStitchingTypeChanged.emit(self.getStitchingType().value)
|
195
|
-
|
196
|
-
def getStitchingType(self):
|
197
|
-
return StitchingType.from_value(self._stitchingTypeCB.currentText())
|
198
|
-
|
199
|
-
def setStitchingType(self, mode):
|
200
|
-
mode = StitchingType.from_value(mode)
|
201
|
-
idx = self._stitchingTypeCB.findText(mode.value)
|
202
|
-
if idx >= 0:
|
203
|
-
self._stitchingTypeCB.setCurrentIndex(idx)
|
204
|
-
|
205
|
-
def addTomoObj(self, tomo_obj: TomwerObject):
|
206
|
-
self._mainWidget.addTomoObj(tomo_obj)
|
207
|
-
self._updatePreviewPixelSize()
|
208
|
-
|
209
|
-
def removeTomoObj(self, tomo_obj: TomwerObject):
|
210
|
-
self._mainWidget.removeTomoObj(tomo_obj)
|
211
|
-
self._updatePreviewPixelSize()
|
212
|
-
|
213
|
-
def _updatePreviewPixelSize(self):
|
214
|
-
"""update the pixel size of the preview from existing tomo obj"""
|
215
|
-
|
216
|
-
def get_pixel_size():
|
217
|
-
tomo_objs = self._mainWidget.getTomoObjs()
|
218
|
-
for tomo_obj in tomo_objs:
|
219
|
-
if (
|
220
|
-
isinstance(tomo_obj, NXtomoScan)
|
221
|
-
and tomo_obj.x_pixel_size is not None
|
222
|
-
and tomo_obj.y_pixel_size is not None
|
223
|
-
):
|
224
|
-
return tomo_obj.x_pixel_size, tomo_obj.y_pixel_size
|
225
|
-
elif (
|
226
|
-
isinstance(tomo_obj, TomwerVolumeBase)
|
227
|
-
and tomo_obj.voxel_size is not None
|
228
|
-
):
|
229
|
-
return tomo_obj.voxel_size[1], tomo_obj.voxel_size[2]
|
230
|
-
return None, None
|
231
|
-
|
232
|
-
pixel_size = get_pixel_size()
|
233
|
-
self._mainWidget._previewPlot.setPixelSize(pixel_size=pixel_size)
|
234
|
-
|
235
|
-
def getConfiguration(self) -> dict:
|
236
|
-
# missing parameters:
|
237
|
-
# * overwrite
|
238
|
-
# * slices
|
239
|
-
# * slurm stuff...
|
240
|
-
|
241
|
-
tomo_objs = self._mainWidget.getTomoObjs()
|
242
|
-
|
243
|
-
def filter_empty_list_and_cast_as_int(elmts):
|
244
|
-
new_list = [int(elmt) for elmt in elmts if elmt is not None]
|
245
|
-
if len(new_list) == 0:
|
246
|
-
return None
|
247
|
-
else:
|
248
|
-
return elmts
|
249
|
-
|
250
|
-
axis_0_pos_px = filter_empty_list_and_cast_as_int(
|
251
|
-
[
|
252
|
-
obj.stitching_metadata.get_abs_position_px(axis=0) or 0
|
253
|
-
for obj in tomo_objs
|
254
|
-
]
|
255
|
-
)
|
256
|
-
axis_2_pos_px = filter_empty_list_and_cast_as_int(
|
257
|
-
[
|
258
|
-
obj.stitching_metadata.get_abs_position_px(axis=2) or 0
|
259
|
-
for obj in tomo_objs
|
260
|
-
]
|
261
|
-
)
|
262
|
-
return {
|
263
|
-
"stitching": {
|
264
|
-
"type": self.getStitchingType().value,
|
265
|
-
"axis_0_pos_px": "" if axis_0_pos_px is None else axis_0_pos_px,
|
266
|
-
"axis_2_pos_px": "" if axis_2_pos_px is None else axis_2_pos_px,
|
267
|
-
},
|
268
|
-
"inputs": {
|
269
|
-
"input_datasets": [obj.get_identifier().to_str() for obj in tomo_objs],
|
270
|
-
},
|
271
|
-
}
|
272
|
-
|
273
|
-
def setConfiguration(self, config: dict) -> None:
|
274
|
-
stitching_type = config.get("stitching", {}).get("type", None)
|
275
|
-
if stitching_type is not None:
|
276
|
-
self.setStitchingType(stitching_type)
|
277
|
-
tomo_obj_ids = config.get("inputs", {}).get("input_datasets", None)
|
278
|
-
tomo_obj_ids = identifiers_as_str_to_instances(tomo_obj_ids)
|
279
|
-
axis_0_pos = convert_str_to_tuple(
|
280
|
-
config.get("stitching", {}).get("axis_0_pos_px", None),
|
281
|
-
none_if_empty=True,
|
282
|
-
)
|
283
|
-
axis_2_pos = convert_str_to_tuple(
|
284
|
-
config.get("stitching", {}).get("axis_2_pos_px", None),
|
285
|
-
none_if_empty=True,
|
286
|
-
)
|
287
|
-
if tomo_obj_ids is not None:
|
288
|
-
self._mainWidget.clearTomoObjs()
|
289
|
-
if axis_0_pos is None:
|
290
|
-
axis_0_pos = [None] * len(tomo_obj_ids)
|
291
|
-
if axis_2_pos is None:
|
292
|
-
axis_2_pos = [None] * len(tomo_obj_ids)
|
293
|
-
if len(axis_0_pos) != len(tomo_obj_ids):
|
294
|
-
_logger.error(
|
295
|
-
"incoherent axis 0 position compared to the number of input datasets. Will ignore those"
|
296
|
-
)
|
297
|
-
axis_0_pos = [None] * len(tomo_obj_ids)
|
298
|
-
if len(axis_2_pos) != len(tomo_obj_ids):
|
299
|
-
_logger.error(
|
300
|
-
"incoherent axis 2 position compared to the number of input datasets. Will ignore those"
|
301
|
-
)
|
302
|
-
axis_2_pos = [None] * len(tomo_obj_ids)
|
303
|
-
|
304
|
-
new_tomo_objs = []
|
305
|
-
for tomo_obj_id, axis_0_v, axis_2_v in zip(
|
306
|
-
tomo_obj_ids, axis_0_pos, axis_2_pos
|
307
|
-
):
|
308
|
-
if isinstance(tomo_obj_id, TomwerObject):
|
309
|
-
tomo_obj = tomo_obj_id
|
310
|
-
elif isinstance(tomo_obj_id, _TomoScanBase):
|
311
|
-
# for now we need to convert it back because object are not the same
|
312
|
-
tomo_obj = ScanFactory.create_tomo_object_from_identifier(
|
313
|
-
tomo_obj_id.get_identifier().to_str()
|
314
|
-
)
|
315
|
-
elif isinstance(tomo_obj_id, _VolumeBase):
|
316
|
-
tomo_obj = VolumeFactory.create_tomo_object_from_identifier(
|
317
|
-
tomo_obj_id.get_identifier().to_str()
|
318
|
-
)
|
319
|
-
else:
|
320
|
-
tomo_obj = ScanFactory.create_tomo_object_from_identifier(
|
321
|
-
tomo_obj_id
|
322
|
-
)
|
323
|
-
self.addTomoObj(tomo_obj=tomo_obj)
|
324
|
-
# set metadata information if any
|
325
|
-
for axis, axis_value in zip((0, 2), (axis_0_v, axis_2_v)):
|
326
|
-
if axis_value is not None:
|
327
|
-
tomo_obj.stitching_metadata.setPxPos(int(axis_value), axis=axis)
|
328
|
-
new_tomo_objs.append(tomo_obj)
|
329
|
-
self.sigTomoObjsLoaded.emit(tuple(new_tomo_objs))
|
330
|
-
|
331
|
-
# expose API
|
332
|
-
def setAddTomoObjCallbacks(self, *args, **kwargs):
|
333
|
-
self._mainWidget.setAddTomoObjCallbacks(*args, **kwargs)
|
334
|
-
|
335
|
-
def setRemoveTomoObjCallbacks(self, *args, **kwargs):
|
336
|
-
self._mainWidget.setRemoveTomoObjCallbacks(*args, **kwargs)
|
337
|
-
|
338
|
-
|
339
|
-
class ZStitchingWindow(qt.QMainWindow):
|
340
|
-
"""
|
341
|
-
Main widget containing all the options to define the stitching to be done
|
342
|
-
|
343
|
-
:param bool with_configuration_action: if True append the load and save stitching configuration tool button.
|
344
|
-
In some cases those can also be part of Menu so we want to avoid having those twice
|
345
|
-
"""
|
346
|
-
|
347
|
-
sigChanged = qt.Signal()
|
348
|
-
"""Signal emit each time the configuration is modified"""
|
349
|
-
|
350
|
-
def __init__(self, parent=None, with_configuration_action=True) -> None:
|
351
|
-
super().__init__(parent)
|
352
|
-
self._previewFolder = None
|
353
|
-
# folder to store files (volume or NXtomo) for previews
|
354
|
-
self._previewThread = None
|
355
|
-
# thread to compute the stitching for preview
|
356
|
-
self._callbackToGetSlurmConfig = None
|
357
|
-
self._callbackToSetSlurmConfig = None
|
358
|
-
# convenient work arounds to avoid having to redefine the n=interface for slurm and the API
|
359
|
-
# to load and save settings
|
360
|
-
# if it is defined upper
|
361
|
-
|
362
|
-
toolbar = qt.QToolBar(self)
|
363
|
-
self.addToolBar(qt.Qt.TopToolBarArea, toolbar)
|
364
|
-
style = qt.QApplication.instance().style()
|
365
|
-
|
366
|
-
# clean option
|
367
|
-
self.__cleanAction = qt.QAction(self)
|
368
|
-
self.__cleanAction.setToolTip("clear")
|
369
|
-
clear_icon = style.standardIcon(qt.QStyle.SP_DialogResetButton)
|
370
|
-
self.__cleanAction.setIcon(clear_icon)
|
371
|
-
toolbar.addAction(self.__cleanAction)
|
372
|
-
self.__cleanAction.triggered.connect(self.clean)
|
373
|
-
|
374
|
-
# separator
|
375
|
-
toolbar.addSeparator()
|
376
|
-
|
377
|
-
if with_configuration_action:
|
378
|
-
# load action
|
379
|
-
self.__loadAction = stitching_action.LoadConfigurationAction(self)
|
380
|
-
toolbar.addAction(self.__loadAction)
|
381
|
-
self.__loadAction.triggered.connect(
|
382
|
-
functools.partial(self._loadSettings, file_path=None)
|
383
|
-
)
|
384
|
-
|
385
|
-
# save action
|
386
|
-
self.__saveAction = stitching_action.SaveConfigurationAction(self)
|
387
|
-
toolbar.addAction(self.__saveAction)
|
388
|
-
self.__saveAction.triggered.connect(
|
389
|
-
functools.partial(self._saveSettings, file_path=None)
|
390
|
-
)
|
391
|
-
|
392
|
-
# separator
|
393
|
-
toolbar.addSeparator()
|
394
|
-
|
395
|
-
# update preview action
|
396
|
-
self.__updatePreviewAction = stitching_action.PreviewAction(self)
|
397
|
-
toolbar.addAction(self.__updatePreviewAction)
|
398
|
-
self.__updatePreviewAction.triggered.connect(self._trigger_update_preview)
|
399
|
-
|
400
|
-
# separator
|
401
|
-
toolbar.addSeparator()
|
402
|
-
|
403
|
-
# configuration level / mode
|
404
|
-
self.__configurationModesAction = qt.QAction(self)
|
405
|
-
self.__configurationModesAction.setCheckable(False)
|
406
|
-
menu = qt.QMenu(self)
|
407
|
-
self.__configurationModesAction.setMenu(menu)
|
408
|
-
toolbar.addAction(self.__configurationModesAction)
|
409
|
-
|
410
|
-
self.__configurationModesGroup = qt.QActionGroup(self)
|
411
|
-
self.__configurationModesGroup.setExclusive(True)
|
412
|
-
self.__configurationModesGroup.triggered.connect(self._userModeChanged)
|
413
|
-
|
414
|
-
self._minimalisticAction = MinimalisticConfigurationAction(toolbar)
|
415
|
-
menu.addAction(self._minimalisticAction)
|
416
|
-
self.__configurationModesGroup.addAction(self._minimalisticAction)
|
417
|
-
self._basicConfigAction = BasicConfigurationAction(toolbar)
|
418
|
-
menu.addAction(self._basicConfigAction)
|
419
|
-
self.__configurationModesGroup.addAction(self._basicConfigAction)
|
420
|
-
self._expertConfiguration = ExpertConfigurationAction(toolbar)
|
421
|
-
menu.addAction(self._expertConfiguration)
|
422
|
-
self.__configurationModesGroup.addAction(self._expertConfiguration)
|
423
|
-
|
424
|
-
# separator
|
425
|
-
toolbar.addSeparator()
|
426
|
-
|
427
|
-
# create central widget
|
428
|
-
self._widget = ZStitchingCentralWidget(parent=self)
|
429
|
-
self.setCentralWidget(self._widget)
|
430
|
-
|
431
|
-
# create Dock widgets
|
432
|
-
## output
|
433
|
-
self._outputWidget = StitchingOutput(parent=self)
|
434
|
-
self._outputWidget.setObjectName("outputSettingsWidget")
|
435
|
-
self._outputDockWidget = qt.QDockWidget(parent=self)
|
436
|
-
self._outputDockWidget.setWindowTitle("output")
|
437
|
-
self._outputDockWidget.layout().setContentsMargins(0, 0, 0, 0)
|
438
|
-
self._outputDockWidget.setFeatures(qt.QDockWidget.DockWidgetMovable)
|
439
|
-
self._outputDockWidget.setWidget(self._outputWidget)
|
440
|
-
self.addDockWidget(qt.Qt.RightDockWidgetArea, self._outputDockWidget)
|
441
|
-
self._outputDockWidget.setToolTip(
|
442
|
-
"options to where and how to save the stitching"
|
443
|
-
)
|
444
|
-
## stitching strategies
|
445
|
-
self._stitchingOptsWidget = StitchingOptions(parent=self)
|
446
|
-
self._stitchingOptsScrollArea = qt.QScrollArea(self)
|
447
|
-
self._stitchingOptsScrollArea.setWidget(self._stitchingOptsWidget)
|
448
|
-
self._stitchingOptsScrollArea.setWidgetResizable(True)
|
449
|
-
self._stitchingOptsScrollArea.setHorizontalScrollBarPolicy(
|
450
|
-
qt.Qt.ScrollBarAlwaysOff
|
451
|
-
)
|
452
|
-
self._stitchingOptsDockWidget = qt.QDockWidget(parent=self)
|
453
|
-
self._stitchingOptsDockWidget.layout().setContentsMargins(0, 0, 0, 0)
|
454
|
-
self._stitchingOptsDockWidget.setFeatures(qt.QDockWidget.DockWidgetMovable)
|
455
|
-
self._stitchingOptsDockWidget.setWidget(self._stitchingOptsScrollArea)
|
456
|
-
self._stitchingOptsDockWidget.setWindowTitle("processing options")
|
457
|
-
self.addDockWidget(qt.Qt.RightDockWidgetArea, self._stitchingOptsDockWidget)
|
458
|
-
|
459
|
-
## all scan z positions
|
460
|
-
self._editTomoObjAxis0PositionsWidget = PosEditorOverOneAxis(
|
461
|
-
parent=self,
|
462
|
-
axis_edited=0,
|
463
|
-
axis_order=0,
|
464
|
-
)
|
465
|
-
self._editTomoObjAxis0PositionsDockWidget = qt.QDockWidget(parent=self)
|
466
|
-
self._editTomoObjAxis0PositionsDockWidget.layout().setContentsMargins(
|
467
|
-
0, 0, 0, 0
|
468
|
-
)
|
469
|
-
self._editTomoObjAxis0PositionsDockWidget.setFeatures(
|
470
|
-
qt.QDockWidget.DockWidgetMovable
|
471
|
-
)
|
472
|
-
self._editTomoObjAxis0PositionsDockWidget.setWidget(
|
473
|
-
self._editTomoObjAxis0PositionsWidget
|
474
|
-
)
|
475
|
-
self._editTomoObjAxis0PositionsDockWidget.setWindowTitle(
|
476
|
-
"edit positions over axis 0 (px) - aka z"
|
477
|
-
)
|
478
|
-
self._editTomoObjAxis0PositionsDockWidget.setToolTip(
|
479
|
-
"This allows to edit tomo objects positions along the axis 0 (also aka z)"
|
480
|
-
)
|
481
|
-
self.addDockWidget(
|
482
|
-
qt.Qt.RightDockWidgetArea, self._editTomoObjAxis0PositionsDockWidget
|
483
|
-
)
|
484
|
-
### add a check box to update position from preview if asked by the user
|
485
|
-
self._updateAxis0PosFromPreviewCalc = qt.QCheckBox(
|
486
|
-
"update position 0 from preview calc",
|
487
|
-
self,
|
488
|
-
)
|
489
|
-
self._updateAxis0PosFromPreviewCalc.setToolTip(
|
490
|
-
"When the user trigger a preview, if some shift search refined over axis 0 is done then will update the axis 0 positions",
|
491
|
-
)
|
492
|
-
self._updateAxis0PosFromPreviewCalc.setChecked(True)
|
493
|
-
self._editTomoObjAxis0PositionsWidget.layout().insertWidget(
|
494
|
-
0, self._updateAxis0PosFromPreviewCalc
|
495
|
-
)
|
496
|
-
|
497
|
-
## all scan axis 2 positions
|
498
|
-
self._editTomoObjAxis2PositionsWidget = PosEditorOverOneAxis(
|
499
|
-
parent=self,
|
500
|
-
axis_edited=2,
|
501
|
-
axis_order=0,
|
502
|
-
)
|
503
|
-
self._editTomoObjAxis2PositionsDockWidget = qt.QDockWidget(parent=self)
|
504
|
-
self._editTomoObjAxis2PositionsDockWidget.layout().setContentsMargins(
|
505
|
-
0, 0, 0, 0
|
506
|
-
)
|
507
|
-
self._editTomoObjAxis2PositionsDockWidget.setFeatures(
|
508
|
-
qt.QDockWidget.DockWidgetMovable
|
509
|
-
)
|
510
|
-
self._editTomoObjAxis2PositionsDockWidget.setWidget(
|
511
|
-
self._editTomoObjAxis2PositionsWidget
|
512
|
-
)
|
513
|
-
self._editTomoObjAxis2PositionsDockWidget.setWindowTitle(
|
514
|
-
"edit positions over axis 2 (px)"
|
515
|
-
)
|
516
|
-
self._editTomoObjAxis2PositionsDockWidget.setToolTip(
|
517
|
-
"This allows to edit tomo objects positions along the axis 2"
|
518
|
-
)
|
519
|
-
self.addDockWidget(
|
520
|
-
qt.Qt.RightDockWidgetArea, self._editTomoObjAxis2PositionsDockWidget
|
521
|
-
)
|
522
|
-
### add a check box to update position from preview if asked by the user
|
523
|
-
self._updateAxis2PosFromPreviewCalc = qt.QCheckBox(
|
524
|
-
"update position 2 from preview calc", self
|
525
|
-
)
|
526
|
-
self._updateAxis2PosFromPreviewCalc.setToolTip(
|
527
|
-
"When the user trigger a preview, if some shift search refined over axis 2 is done then will update the axis 2 positions"
|
528
|
-
)
|
529
|
-
self._updateAxis2PosFromPreviewCalc.setChecked(True)
|
530
|
-
self._editTomoObjAxis2PositionsWidget.layout().insertWidget(
|
531
|
-
0, self._updateAxis2PosFromPreviewCalc
|
532
|
-
)
|
533
|
-
|
534
|
-
self._widget.setAddTomoObjCallbacks(
|
535
|
-
(
|
536
|
-
self._editTomoObjAxis0PositionsWidget.addTomoObj,
|
537
|
-
self._editTomoObjAxis2PositionsWidget.addTomoObj,
|
538
|
-
self.getRawDisplayPlot().addTomoObj,
|
539
|
-
)
|
540
|
-
)
|
541
|
-
self._widget.setRemoveTomoObjCallbacks(
|
542
|
-
(
|
543
|
-
self._editTomoObjAxis0PositionsWidget.removeTomoObj,
|
544
|
-
self._editTomoObjAxis2PositionsWidget.removeTomoObj,
|
545
|
-
self.getRawDisplayPlot().removeTomoObj,
|
546
|
-
)
|
547
|
-
)
|
548
|
-
|
549
|
-
# update layout: for now lets tabify sime widget
|
550
|
-
self.tabifyDockWidget(self._outputDockWidget, self._stitchingOptsDockWidget)
|
551
|
-
self.tabifyDockWidget(
|
552
|
-
self._outputDockWidget, self._editTomoObjAxis2PositionsDockWidget
|
553
|
-
)
|
554
|
-
self.tabifyDockWidget(
|
555
|
-
self._outputDockWidget, self._editTomoObjAxis0PositionsDockWidget
|
556
|
-
)
|
557
|
-
|
558
|
-
# handle raw display plot. By display avoid displaying raw data as this can be ressource consuming
|
559
|
-
self._widget._mainWidget._rawDisplayCB.setChecked(False)
|
560
|
-
self._widget._mainWidget._rawDisplayPlot.setActive(False)
|
561
|
-
|
562
|
-
# connect signal / slot
|
563
|
-
self._widget._mainWidget._rawDisplayCB.toggled.connect(
|
564
|
-
self._handleRawDisplayconnection
|
565
|
-
)
|
566
|
-
self._outputWidget.sigChanged.connect(self._changed)
|
567
|
-
self._stitchingOptsWidget.sigChanged.connect(self._changed)
|
568
|
-
self._widget.sigStitchingTypeChanged.connect(
|
569
|
-
self._outputWidget._updateOutputForStitchingType
|
570
|
-
)
|
571
|
-
self._widget.sigStitchingTypeChanged.connect(
|
572
|
-
self._stitchingOptsWidget._stitchingTypeChanged
|
573
|
-
)
|
574
|
-
|
575
|
-
## handle raw plot preview
|
576
|
-
self._stitchingOptsWidget.sigFlipLRChanged.connect(
|
577
|
-
self.getRawDisplayPlot().setFlipLRFrames
|
578
|
-
)
|
579
|
-
self._stitchingOptsWidget.sigFlipUDChanged.connect(
|
580
|
-
self.getRawDisplayPlot().setFlipUDFrames
|
581
|
-
)
|
582
|
-
self._stitchingOptsWidget.sigSliceForPreviewChanged.connect(
|
583
|
-
self.getRawDisplayPlot().setSliceForPreview
|
584
|
-
)
|
585
|
-
|
586
|
-
## handle tomo obj loading from settings
|
587
|
-
self._widget.sigTomoObjsLoaded.connect(
|
588
|
-
self._editTomoObjAxis0PositionsWidget.setTomoObjs
|
589
|
-
)
|
590
|
-
self._widget.sigTomoObjsLoaded.connect(
|
591
|
-
self._editTomoObjAxis2PositionsWidget.setTomoObjs
|
592
|
-
)
|
593
|
-
self._widget.sigTomoObjsLoaded.connect(self.getRawDisplayPlot().setTomoObjs)
|
594
|
-
|
595
|
-
# set up
|
596
|
-
self._basicConfigAction.setChecked(True)
|
597
|
-
self._userModeChanged(self._basicConfigAction)
|
598
|
-
|
599
|
-
def setCallbackToGetSlurmConfig(self, callback):
|
600
|
-
self._callbackToGetSlurmConfig = callback
|
601
|
-
|
602
|
-
def setCallbackToSetSlurmConfig(self, callback):
|
603
|
-
self._callbackToSetSlurmConfig = callback
|
604
|
-
|
605
|
-
def close(self):
|
606
|
-
# remove folder used for preview
|
607
|
-
shutil.rmtree(self._previewFolder, ignore_errors=True)
|
608
|
-
self._widget.close()
|
609
|
-
# requested for the waiting plot update
|
610
|
-
super().close()
|
611
|
-
|
612
|
-
def getRawDisplayPlot(self):
|
613
|
-
return self._widget._mainWidget._rawDisplayPlot
|
614
|
-
|
615
|
-
def _handleRawDisplayconnection(self, toggled: bool):
|
616
|
-
raw_display_plot = self.getRawDisplayPlot()
|
617
|
-
raw_display_plot.setActive(toggled)
|
618
|
-
|
619
|
-
def getPreviewAction(self):
|
620
|
-
return self.__updatePreviewAction
|
621
|
-
|
622
|
-
def getPreviewFolder(self):
|
623
|
-
if self._previewFolder is None:
|
624
|
-
self._previewFolder = tempfile.mkdtemp(prefix="tomwer_stitcher_preview")
|
625
|
-
return self._previewFolder
|
626
|
-
|
627
|
-
def getVolumeIdentifierPreview(self) -> HDF5VolumeIdentifier:
|
628
|
-
folder = self.getPreviewFolder()
|
629
|
-
# for now use hdf5 by default
|
630
|
-
return HDF5VolumeIdentifier(
|
631
|
-
object=HDF5Volume,
|
632
|
-
hdf5_file=os.path.join(folder, "vol_stitching_preview.hdf5"),
|
633
|
-
entry="my_volume",
|
634
|
-
)
|
635
|
-
|
636
|
-
def getNXtomoIdentifierForPreview(self):
|
637
|
-
folder = self.getPreviewFolder()
|
638
|
-
return NXtomoScanIdentifier(
|
639
|
-
object=NXtomoScan,
|
640
|
-
hdf5_file=os.path.join(folder, "nxtomo_stiching_preview.hdf5"),
|
641
|
-
entry="entry0000",
|
642
|
-
)
|
643
|
-
|
644
|
-
def _changed(self, *args, **kwargs):
|
645
|
-
self.sigChanged.emit()
|
646
|
-
|
647
|
-
def _saveSettings(self, file_path=None, **kwargs):
|
648
|
-
"""
|
649
|
-
dump current configuration into a txt file
|
650
|
-
"""
|
651
|
-
# get a file if necessary
|
652
|
-
if file_path is None:
|
653
|
-
dialog = QConfigFileDialog(self)
|
654
|
-
dialog.setAcceptMode(qt.QFileDialog.AcceptSave)
|
655
|
-
if not dialog.exec_():
|
656
|
-
return
|
657
|
-
|
658
|
-
selected_file = dialog.selectedFiles()
|
659
|
-
if len(selected_file) == 0:
|
660
|
-
return
|
661
|
-
file_path = selected_file[0]
|
662
|
-
|
663
|
-
configuration = self.getConfiguration()
|
664
|
-
if self._callbackToGetSlurmConfig is not None:
|
665
|
-
slurm_config = {"slurm": self._callbackToGetSlurmConfig()}
|
666
|
-
configuration = concatenate_dict(configuration, slurm_config)
|
667
|
-
|
668
|
-
# dump configuration
|
669
|
-
generate_nabu_configfile(
|
670
|
-
fname=file_path,
|
671
|
-
default_config=get_default_stitching_config(self.getStitchingType()),
|
672
|
-
comments=True,
|
673
|
-
sections_comments=_SECTIONS_COMMENTS,
|
674
|
-
options_level="advanced",
|
675
|
-
prefilled_values=configuration,
|
676
|
-
)
|
677
|
-
|
678
|
-
def _loadSettings(self, file_path=None, **kwargs):
|
679
|
-
"""
|
680
|
-
load configuration from a txt file
|
681
|
-
"""
|
682
|
-
# get a file if necessary
|
683
|
-
if file_path is None:
|
684
|
-
dialog = QConfigFileDialog(self)
|
685
|
-
dialog.setAcceptMode(qt.QFileDialog.AcceptOpen)
|
686
|
-
dialog.setFileMode(qt.QFileDialog.ExistingFiles)
|
687
|
-
|
688
|
-
if not dialog.exec_():
|
689
|
-
return
|
690
|
-
|
691
|
-
selected_file = dialog.selectedFiles()
|
692
|
-
if len(selected_file) == 0:
|
693
|
-
return
|
694
|
-
file_path = selected_file[0]
|
695
|
-
|
696
|
-
# Do configuration load
|
697
|
-
conf_dict = parse_nabu_config_file(file_path, allow_no_value=True)
|
698
|
-
self.setConfiguration(config=conf_dict)
|
699
|
-
if self._callbackToSetSlurmConfig is not None:
|
700
|
-
self._callbackToSetSlurmConfig(conf_dict.get("slurm", {}))
|
701
|
-
|
702
|
-
def _trigger_update_preview(self):
|
703
|
-
if self._previewThread is not None:
|
704
|
-
_logger.warning(
|
705
|
-
"some preview is already running. Please wait before relaunching it"
|
706
|
-
)
|
707
|
-
return
|
708
|
-
config = self.getConfiguration()
|
709
|
-
# update the output file to set if from raw...
|
710
|
-
stitching_type = config.get("stitching", {}).get("type", None)
|
711
|
-
if stitching_type == "z-preproc":
|
712
|
-
output_identifier = self.getNXtomoIdentifierForPreview()
|
713
|
-
config["z-preproc"]["location"] = output_identifier.file_path
|
714
|
-
config["z-preproc"]["data_path"] = output_identifier.data_path
|
715
|
-
assert "z-postproc" not in config
|
716
|
-
elif stitching_type == "z-postproc":
|
717
|
-
config["z-postproc"][
|
718
|
-
"output_volume"
|
719
|
-
] = self.getVolumeIdentifierPreview().to_str()
|
720
|
-
assert "z-preproc" not in config
|
721
|
-
else:
|
722
|
-
raise NotImplementedError
|
723
|
-
|
724
|
-
# update the slice to avoid doing the stitching on all the frames
|
725
|
-
config["inputs"]["slices"] = self.getSlicesForPreview()
|
726
|
-
|
727
|
-
# update to force overwrite
|
728
|
-
config["output"]["overwrite_results"] = True
|
729
|
-
|
730
|
-
# clean current preview to notify some calculation is going on
|
731
|
-
preview_plot = self._widget._mainWidget._previewPlot
|
732
|
-
preview_plot._waitingOverlay.show()
|
733
|
-
|
734
|
-
# start sitching on a thread
|
735
|
-
self._previewThread = PreviewThread(stitching_config=config)
|
736
|
-
self._previewThread.finished.connect(self._previewCalculationFinished)
|
737
|
-
self._previewThread.start()
|
738
|
-
|
739
|
-
def getSlicesForPreview(self):
|
740
|
-
return self._stitchingOptsWidget.getSlicesForPreview()
|
741
|
-
|
742
|
-
def _previewCalculationFinished(self):
|
743
|
-
sender = self.sender()
|
744
|
-
assert isinstance(sender, PreviewThread)
|
745
|
-
composition = sender.frame_composition
|
746
|
-
tomo_objs_new_axis_positions = sender.final_tomo_objs_positions
|
747
|
-
assert isinstance(
|
748
|
-
tomo_objs_new_axis_positions, dict
|
749
|
-
), "final_tomo_objs_positions is expected to be a dict with obj identifier as key and the tuple of position as value"
|
750
|
-
# expect it to be a dict with tomo obj identifier as key and a tuple of (axis_2_pos, axis_1_pos, axis_0_pos) as value
|
751
|
-
output_obj_identifier = sender.output_identifier
|
752
|
-
|
753
|
-
preview_plot = self._widget._mainWidget._previewPlot
|
754
|
-
preview_plot._waitingOverlay.hide()
|
755
|
-
|
756
|
-
self._previewThread.finished.disconnect(self._previewCalculationFinished)
|
757
|
-
self._previewThread = None
|
758
|
-
|
759
|
-
if output_obj_identifier is None:
|
760
|
-
_logger.error("preview of stitching failed")
|
761
|
-
else:
|
762
|
-
preview_plot.setStitchedTomoObj(
|
763
|
-
tomo_obj_id=output_obj_identifier,
|
764
|
-
composition=composition,
|
765
|
-
)
|
766
|
-
|
767
|
-
# update object values if requested
|
768
|
-
update_requested = {
|
769
|
-
0: self._updateAxis0PosFromPreviewCalc.isChecked(),
|
770
|
-
2: self._updateAxis2PosFromPreviewCalc.isChecked(),
|
771
|
-
}
|
772
|
-
|
773
|
-
if update_requested[0] or update_requested[2]:
|
774
|
-
existing_tomo_obj = {
|
775
|
-
tomo_obj.get_identifier().to_str(): tomo_obj
|
776
|
-
for tomo_obj in self._widget._mainWidget.getTomoObjs()
|
777
|
-
}
|
778
|
-
|
779
|
-
for tomo_obj_id, value in tomo_objs_new_axis_positions.items():
|
780
|
-
assert (
|
781
|
-
isinstance(value, tuple) and len(value) == 3
|
782
|
-
), "value is expected to be (new_pos_axis_0, new_pos_axis_1, new_pos_axis_2)"
|
783
|
-
new_axis_0_pos, _, new_axis_2_pos = value
|
784
|
-
tomo_obj = existing_tomo_obj.get(tomo_obj_id, None)
|
785
|
-
if tomo_obj is None:
|
786
|
-
continue
|
787
|
-
if update_requested[0]:
|
788
|
-
tomo_obj.stitching_metadata.setPxPos(int(new_axis_0_pos), 0)
|
789
|
-
if update_requested[2]:
|
790
|
-
tomo_obj.stitching_metadata.setPxPos(int(new_axis_2_pos), 2)
|
791
|
-
if update_requested[0]:
|
792
|
-
self._editTomoObjAxis0PositionsWidget._orderedMightHavechanged(
|
793
|
-
force_sb_update=True
|
794
|
-
)
|
795
|
-
if update_requested[2]:
|
796
|
-
self._editTomoObjAxis2PositionsWidget._orderedMightHavechanged(
|
797
|
-
force_sb_update=True
|
798
|
-
)
|
799
|
-
|
800
|
-
def clean(self):
|
801
|
-
self._widget.clean()
|
802
|
-
self._editTomoObjAxis0PositionsWidget.clean()
|
803
|
-
self._editTomoObjAxis2PositionsWidget.clean()
|
804
|
-
|
805
|
-
def setSerie(self, serie):
|
806
|
-
self.clean()
|
807
|
-
self._widget._mainWidget.setSerie(serie)
|
808
|
-
self._editTomoObjAxis0PositionsWidget.clean()
|
809
|
-
self._editTomoObjAxis2PositionsWidget.clean()
|
810
|
-
for tomo_obj in serie:
|
811
|
-
self._editTomoObjAxis0PositionsWidget.addTomoObj(tomo_obj)
|
812
|
-
self._editTomoObjAxis2PositionsWidget.addTomoObj(tomo_obj)
|
813
|
-
self.getRawDisplayPlot().setTomoObjs(tomo_objs=serie[:])
|
814
|
-
|
815
|
-
def addTomoObj(self, tomo_obj):
|
816
|
-
self._widget.addTomoObj(tomo_obj)
|
817
|
-
self._editTomoObjAxis0PositionsWidget.addTomoObj(tomo_obj)
|
818
|
-
self._editTomoObjAxis2PositionsWidget.addTomoObj(tomo_obj)
|
819
|
-
self.getRawDisplayPlot().addTomoObj(tomo_obj=tomo_obj)
|
820
|
-
|
821
|
-
def removeTomoObj(self, tomo_obj):
|
822
|
-
self._widget.removeTomoObj(tomo_obj)
|
823
|
-
self.getRawDisplayPlot().removeTomoObj(tomo_obj=tomo_obj)
|
824
|
-
|
825
|
-
def getConfiguration(self) -> dict:
|
826
|
-
# make sure the sync is fine between the two
|
827
|
-
configs = (
|
828
|
-
self._widget.getConfiguration(),
|
829
|
-
self._outputWidget.getConfiguration(),
|
830
|
-
self._stitchingOptsWidget.getConfiguration(),
|
831
|
-
)
|
832
|
-
result = {}
|
833
|
-
for config in configs:
|
834
|
-
result = concatenate_dict(result, config)
|
835
|
-
return result
|
836
|
-
|
837
|
-
def setConfiguration(self, config: dict):
|
838
|
-
self._widget.setConfiguration(config)
|
839
|
-
self._outputWidget.setConfiguration(config)
|
840
|
-
self._stitchingOptsWidget.setConfiguration(config)
|
841
|
-
|
842
|
-
# expose API
|
843
|
-
def getStitchingType(self) -> StitchingType:
|
844
|
-
return self._widget.getStitchingType()
|
845
|
-
|
846
|
-
def setStitchingType(self, stitching_type: StitchingType):
|
847
|
-
self._widget.setStitchingType(stitching_type)
|
848
|
-
|
849
|
-
def _userModeChanged(self, action):
|
850
|
-
self.__configurationModesAction.setIcon(action.icon())
|
851
|
-
self.__configurationModesAction.setToolTip(action.tooltip())
|
852
|
-
if action is self._basicConfigAction:
|
853
|
-
level = ConfigurationLevel.OPTIONAL
|
854
|
-
elif action is self._expertConfiguration:
|
855
|
-
level = ConfigurationLevel.ADVANCED
|
856
|
-
else:
|
857
|
-
level = ConfigurationLevel.REQUIRED
|
858
|
-
self._stitchingOptsWidget.setConfigurationLevel(level)
|
859
|
-
self._editTomoObjAxis2PositionsDockWidget.setVisible(
|
860
|
-
level >= ConfigurationLevel.ADVANCED
|
861
|
-
)
|
862
|
-
|
863
|
-
def close(self):
|
864
|
-
shutil.rmtree(self._previewFolder, ignore_errors=True)
|
865
|
-
super().close()
|
866
|
-
|
867
|
-
|
868
|
-
def concatenate_dict(dict_1, dict_2) -> dict:
|
869
|
-
"""update dict which has dict as values. And we want concatenate those values to"""
|
870
|
-
res = dict_1.copy()
|
871
|
-
for key in dict_2:
|
872
|
-
if key in dict_1:
|
873
|
-
if key in [f"axis_{axis}_params" for axis in (0, 1, 2)]:
|
874
|
-
res[key] = ";".join((dict_1[key], dict_2[key]))
|
875
|
-
elif isinstance(dict_1[key], dict):
|
876
|
-
res[key] = concatenate_dict(dict_1=dict_1[key], dict_2=dict_2[key])
|
877
|
-
else:
|
878
|
-
res[key].update(dict_2[key])
|
879
|
-
else:
|
880
|
-
res[key] = dict_2[key]
|
881
|
-
return res
|
882
|
-
|
883
|
-
|
884
|
-
class PreviewThread(qt.QThread):
|
885
|
-
"""
|
886
|
-
Thread to compute an overview of the stitching
|
887
|
-
"""
|
888
|
-
|
889
|
-
def __init__(self, stitching_config: dict, *args, **kwargs) -> None:
|
890
|
-
super().__init__(*args, **kwargs)
|
891
|
-
self._stitching_config = dict_to_config_obj(stitching_config)
|
892
|
-
self._output_identifier = None
|
893
|
-
self._frame_composition = None
|
894
|
-
self._final_tomo_objs_positions = None
|
895
|
-
# store position of all the tomo objects (scan, volumes) used for the final stitching (after shift refinement)
|
896
|
-
|
897
|
-
@property
|
898
|
-
def stiching_config(self):
|
899
|
-
return self._stitching_config
|
900
|
-
|
901
|
-
@property
|
902
|
-
def output_identifier(self):
|
903
|
-
return self._output_identifier
|
904
|
-
|
905
|
-
@property
|
906
|
-
def frame_composition(self):
|
907
|
-
return self._frame_composition
|
908
|
-
|
909
|
-
@property
|
910
|
-
def final_tomo_objs_positions(self) -> dict:
|
911
|
-
"""
|
912
|
-
:return: dict with tomo object identifier (str) as key and a tuple of position in pixel (axis_0_pos, axis_1_pos, axis_2_pos)
|
913
|
-
:rtype: dict
|
914
|
-
"""
|
915
|
-
return self._final_tomo_objs_positions
|
916
|
-
|
917
|
-
@property
|
918
|
-
def final_axis_2_pos(self):
|
919
|
-
return self._final_axis_2_pos
|
920
|
-
|
921
|
-
def run(self):
|
922
|
-
stitching_type = self.stiching_config.stitching_type
|
923
|
-
if stitching_type.value == "z-preproc":
|
924
|
-
stitcher = PreProcessZStitcher(configuration=self.stiching_config)
|
925
|
-
elif stitching_type.value == "z-postproc":
|
926
|
-
stitcher = PostProcessZStitcher(configuration=self.stiching_config)
|
927
|
-
else:
|
928
|
-
raise NotImplementedError
|
929
|
-
self._output_identifier = stitcher.stitch()
|
930
|
-
if self._output_identifier is not None:
|
931
|
-
self._output_identifier = self._output_identifier.to_str()
|
932
|
-
# store in cache the frame composition to be able to provide them to the PreviewPlot
|
933
|
-
self._frame_composition = stitcher.frame_composition
|
934
|
-
self._final_tomo_objs_positions = stitcher.get_final_axis_positions_in_px()
|
935
|
-
|
936
|
-
|
937
|
-
class _SlicesSelector(qt.QGroupBox):
|
938
|
-
"""
|
939
|
-
Widget to determine the slices values (to be stitched)
|
940
|
-
"""
|
941
|
-
|
942
|
-
def __init__(self, parent=None) -> None:
|
943
|
-
super().__init__("slices", parent)
|
944
|
-
# start interface
|
945
|
-
self.setLayout(qt.QHBoxLayout())
|
946
|
-
self._startSliceCB = qt.QCheckBox("start", self)
|
947
|
-
self.layout().addWidget(self._startSliceCB)
|
948
|
-
self._startSliceSB = qt.QSpinBox(self)
|
949
|
-
self._startSliceSB.setMinimum(0)
|
950
|
-
self._startSliceSB.setMaximum(9999999)
|
951
|
-
self._startSliceSB.setValue(0)
|
952
|
-
self.layout().addWidget(self._startSliceSB)
|
953
|
-
# stop interface
|
954
|
-
self._stopSliceCB = qt.QCheckBox("stop", self)
|
955
|
-
self.layout().addWidget(self._stopSliceCB)
|
956
|
-
self._stopSliceSB = qt.QSpinBox(self)
|
957
|
-
self._stopSliceSB.setMinimum(-1)
|
958
|
-
self._stopSliceSB.setMaximum(9999999)
|
959
|
-
self._stopSliceSB.setValue(-1)
|
960
|
-
self.layout().addWidget(self._stopSliceSB)
|
961
|
-
# step interface
|
962
|
-
self._stepSliceLabel = qt.QLabel("step", self)
|
963
|
-
self.layout().addWidget(self._stepSliceLabel)
|
964
|
-
self._stepSliceSB = qt.QSpinBox(self)
|
965
|
-
self._stepSliceSB.setMinimum(1)
|
966
|
-
self._stepSliceSB.setMaximum(9999999)
|
967
|
-
self._stepSliceSB.setValue(1)
|
968
|
-
self.layout().addWidget(self._stepSliceSB)
|
969
|
-
|
970
|
-
# connect signal / slot
|
971
|
-
self._startSliceCB.toggled.connect(self._startSliceSB.setDisabled)
|
972
|
-
self._stopSliceCB.toggled.connect(self._stopSliceSB.setDisabled)
|
973
|
-
|
974
|
-
self._startSliceCB.setChecked(True)
|
975
|
-
self._stopSliceCB.setChecked(True)
|
976
|
-
|
977
|
-
def getSlices(self) -> tuple:
|
978
|
-
if self._startSliceCB.isChecked():
|
979
|
-
start = 0
|
980
|
-
else:
|
981
|
-
start = self._startSliceSB.value()
|
982
|
-
if self._stopSliceCB.isChecked():
|
983
|
-
stop = -1
|
984
|
-
else:
|
985
|
-
stop = self._stopSliceSB.value()
|
986
|
-
step = self._stepSliceSB.value()
|
987
|
-
return (start, stop, step)
|
988
|
-
|
989
|
-
def setSlices(self, start: int, stop: int, step: Optional[int] = None):
|
990
|
-
start = int(start)
|
991
|
-
stop = int(stop)
|
992
|
-
if start == 0:
|
993
|
-
self._startSliceCB.setChecked(True)
|
994
|
-
else:
|
995
|
-
self._startSliceCB.setChecked(False)
|
996
|
-
self._startSliceSB.setValue(start)
|
997
|
-
|
998
|
-
if stop == -1:
|
999
|
-
self._stopSliceCB.setChecked(True)
|
1000
|
-
else:
|
1001
|
-
self._stopSliceCB.setChecked(False)
|
1002
|
-
self._stopSliceSB.setValue(stop)
|
1003
|
-
|
1004
|
-
if step is not None:
|
1005
|
-
self._stepSliceSB.setValue(int(step))
|
1006
|
-
|
1007
|
-
|
1008
|
-
class _AlignmentGroupBox(qt.QGroupBox):
|
1009
|
-
DEFAULT_PAD_MODE = "constant"
|
1010
|
-
|
1011
|
-
ALIGNMENT_DOC = (
|
1012
|
-
"https://tomotools.gitlab-pages.esrf.fr/nabu/stitching/alignment.html"
|
1013
|
-
)
|
1014
|
-
|
1015
|
-
DEFAULT_ALIGNMENT_AXIS_1 = AlignmentAxis1.CENTER
|
1016
|
-
DEFAULT_ALIGNMENT_AXIS_2 = AlignmentAxis2.CENTER
|
1017
|
-
|
1018
|
-
_PAD_MODES = (
|
1019
|
-
"constant", # Pads with a constant value.
|
1020
|
-
"edge", # Pads with the edge values of array.
|
1021
|
-
"linear_ramp", # Pads with the linear ramp between end_value and the array edge value.
|
1022
|
-
"maximum", # Pads with the maximum value of all or part of the vector along each axis.
|
1023
|
-
"mean", # Pads with the mean value of all or part of the vector along each axis.
|
1024
|
-
"median", # Pads with the median value of all or part of the vector along each axis.
|
1025
|
-
"minimum", # Pads with the minimum value of all or part of the vector along each axis.
|
1026
|
-
"reflect", # Pads with the reflection of the vector mirrored on the first and last values of the vector along each axis.
|
1027
|
-
"symmetric", # Pads with the reflection of the vector mirrored along the edge of the array.
|
1028
|
-
"wrap", # Pads with the wrap of the vector along the axis. The first values are used to pad the end and the end values are used to pad the beginning.
|
1029
|
-
)
|
1030
|
-
|
1031
|
-
def __init__(self, parent: qt.QWidget = None, title="alignment") -> None:
|
1032
|
-
super().__init__(title, parent)
|
1033
|
-
self.setLayout(qt.QFormLayout())
|
1034
|
-
|
1035
|
-
# alignment axis 1
|
1036
|
-
self._alignmentAxis1CB = qt.QComboBox(self)
|
1037
|
-
for alignment in AlignmentAxis1.values():
|
1038
|
-
self._alignmentAxis1CB.addItem(alignment)
|
1039
|
-
self.layout().addRow("Axis 1 alignment", self._alignmentAxis1CB)
|
1040
|
-
self._alignmentAxis1CB.setToolTip(
|
1041
|
-
f"Alignment to do in case of volumes with different size over axis 1. Only possible for post-processing (reconstructed volume). See {self.ALIGNMENT_DOC} for details."
|
1042
|
-
)
|
1043
|
-
|
1044
|
-
# alignment axis 2
|
1045
|
-
self._alignmentAxis2CB = qt.QComboBox(self)
|
1046
|
-
for alignment in AlignmentAxis2.values():
|
1047
|
-
self._alignmentAxis2CB.addItem(alignment)
|
1048
|
-
self.layout().addRow("Axis 2 alignment", self._alignmentAxis2CB)
|
1049
|
-
self._alignmentAxis2CB.setToolTip(
|
1050
|
-
f"Alignment to do in case of frames with different size over axis 2. See {self.ALIGNMENT_DOC} for details."
|
1051
|
-
)
|
1052
|
-
|
1053
|
-
# pad mode
|
1054
|
-
self._padModeCB = qt.QComboBox(self)
|
1055
|
-
for pad_mode in self._PAD_MODES:
|
1056
|
-
self._padModeCB.addItem(pad_mode)
|
1057
|
-
self.layout().addRow("pad mode", self._padModeCB)
|
1058
|
-
self._padModeCB.setToolTip("padding mode to apply for alignment")
|
1059
|
-
|
1060
|
-
# set up
|
1061
|
-
self.setAlignmentAxis1(self.DEFAULT_ALIGNMENT_AXIS_1)
|
1062
|
-
self.setAlignmentAxis2(self.DEFAULT_ALIGNMENT_AXIS_2)
|
1063
|
-
|
1064
|
-
def getAlignmentAxis1(self) -> AlignmentAxis1:
|
1065
|
-
return AlignmentAxis1.from_value(self._alignmentAxis1CB.currentText())
|
1066
|
-
|
1067
|
-
def setAlignmentAxis1(self, alignment: AlignmentAxis1):
|
1068
|
-
alignment = AlignmentAxis1.from_value(alignment)
|
1069
|
-
self._alignmentAxis1CB.setCurrentIndex(
|
1070
|
-
self._alignmentAxis1CB.findText(alignment.value)
|
1071
|
-
)
|
1072
|
-
|
1073
|
-
def getAlignmentAxis2(self) -> AlignmentAxis2:
|
1074
|
-
return AlignmentAxis2.from_value(self._alignmentAxis2CB.currentText())
|
1075
|
-
|
1076
|
-
def setAlignmentAxis2(self, alignment: AlignmentAxis2):
|
1077
|
-
alignment = AlignmentAxis2.from_value(alignment)
|
1078
|
-
self._alignmentAxis2CB.setCurrentIndex(
|
1079
|
-
self._alignmentAxis2CB.findText(alignment.value)
|
1080
|
-
)
|
1081
|
-
|
1082
|
-
def getPadMode(self) -> str:
|
1083
|
-
return self._padModeCB.currentText()
|
1084
|
-
|
1085
|
-
def setPadMode(self, pad_mode: str):
|
1086
|
-
idx = self._padModeCB.findText(pad_mode)
|
1087
|
-
if idx >= 0:
|
1088
|
-
self._padModeCB.setCurrentIndex(idx)
|
1089
|
-
|
1090
|
-
def setAlignmentAxis1Enabled(self, enabled: bool):
|
1091
|
-
self._alignmentAxis1CB.setEnabled(enabled)
|
1092
|
-
|
1093
|
-
|
1094
|
-
class StitchingOptions(qt.QWidget):
|
1095
|
-
"""
|
1096
|
-
Widget to let the user define the different options for z-stitching such as which algorithm to search shift,
|
1097
|
-
which stitching strategy...
|
1098
|
-
"""
|
1099
|
-
|
1100
|
-
sigChanged = qt.Signal()
|
1101
|
-
"""Signal emit when the options change"""
|
1102
|
-
sigSliceForPreviewChanged = qt.Signal(object)
|
1103
|
-
"""Signal emit when the slice requested for the preview has changed. Parameter is a str or an int"""
|
1104
|
-
sigFlipLRChanged = qt.Signal(bool)
|
1105
|
-
"""Signal emit when the request to flip LR frame has changed"""
|
1106
|
-
sigFlipUDChanged = qt.Signal(bool)
|
1107
|
-
"""Signal emit when the request to flip UD frame has changed"""
|
1108
|
-
|
1109
|
-
def __init__(self, parent=None, *args, **kwargs) -> None:
|
1110
|
-
super().__init__(parent, *args, **kwargs)
|
1111
|
-
# stitching strategy (aka stitcher behavior)
|
1112
|
-
self.setLayout(qt.QFormLayout())
|
1113
|
-
self._stitchingStrategiesWidget = StitchingStrategies(parent=self)
|
1114
|
-
self._stitchingStrategiesWidget.setObjectName("strategy")
|
1115
|
-
self.layout().addRow(self._stitchingStrategiesWidget)
|
1116
|
-
# slice for preview
|
1117
|
-
self._previewSlices = _SliceGetter("middle", parent=self)
|
1118
|
-
self._previewSlices.setPlaceholderText(
|
1119
|
-
"slice index or one of ('middle', 'first', 'last')"
|
1120
|
-
)
|
1121
|
-
self._previewSlices.setToolTip(
|
1122
|
-
"expects a slice index (int > 0) or a str in ('first', 'middle', 'last')"
|
1123
|
-
)
|
1124
|
-
self.layout().addRow("slice for preview", self._previewSlices)
|
1125
|
-
|
1126
|
-
# invert frame up - down
|
1127
|
-
self._flipLR_CB = qt.QCheckBox("flip frame left-right", self)
|
1128
|
-
self._flipLR_CB.setChecked(False)
|
1129
|
-
self._flipLR_CB.setToolTip(
|
1130
|
-
"Flip frame for stitching. This is mostly for volume has no metadata are existing to specify the direction of the frame"
|
1131
|
-
)
|
1132
|
-
self.layout().addRow(self._flipLR_CB)
|
1133
|
-
# invert frame left-right
|
1134
|
-
self._flipUD_CB = qt.QCheckBox("flip frame up-down", self)
|
1135
|
-
self._flipUD_CB.setChecked(False)
|
1136
|
-
self._flipUD_CB.setToolTip(
|
1137
|
-
"Flip frame for stitching. This is mostly for volume has no metadata are existing to specify the direction of the frame"
|
1138
|
-
)
|
1139
|
-
self.layout().addRow(self._flipUD_CB)
|
1140
|
-
|
1141
|
-
# alignment options
|
1142
|
-
self._alignmentGroup = _AlignmentGroupBox(self)
|
1143
|
-
self.layout().addRow(self._alignmentGroup)
|
1144
|
-
|
1145
|
-
# slices to be reconstructed
|
1146
|
-
self._slices = _SlicesSelector(parent=self)
|
1147
|
-
self._slices.setToolTip(
|
1148
|
-
"for pre processing stitchting those are projections and for post prcessing stitching those are volume slices"
|
1149
|
-
)
|
1150
|
-
self.layout().addRow(self._slices)
|
1151
|
-
|
1152
|
-
# axis 0 params for shift search
|
1153
|
-
self._axis0Group = qt.QGroupBox("axis 0 (aka z)", self)
|
1154
|
-
self._axis0Group.setLayout(qt.QVBoxLayout())
|
1155
|
-
self.layout().addRow(self._axis0Group)
|
1156
|
-
self._axis0ShiftSearchParams = StitcherAxisParams(axis=0, parent=self)
|
1157
|
-
self._axis0ShiftSearchParams.layout().setContentsMargins(0, 0, 0, 0)
|
1158
|
-
self._axis0ShiftSearchParams.layout().setSpacing(0)
|
1159
|
-
self._axis0Group.layout().addWidget(self._axis0ShiftSearchParams)
|
1160
|
-
|
1161
|
-
# axis 2 params for shift search
|
1162
|
-
self._axis2Group = qt.QGroupBox("axis 2 (aka x)", self)
|
1163
|
-
self._axis2Group.setLayout(qt.QVBoxLayout())
|
1164
|
-
self.layout().addRow(self._axis2Group)
|
1165
|
-
self._axis2ShiftSearchParams = StitcherAxisParams(axis=2, parent=self)
|
1166
|
-
self._axis2ShiftSearchParams.layout().setContentsMargins(0, 0, 0, 0)
|
1167
|
-
self._axis2ShiftSearchParams.layout().setSpacing(0)
|
1168
|
-
self._axis2Group.layout().addWidget(self._axis2ShiftSearchParams)
|
1169
|
-
# by default avoid doing x shift research
|
1170
|
-
self._axis2ShiftSearchParams.setShiftSearchMethod(None)
|
1171
|
-
|
1172
|
-
# frame rescaling option
|
1173
|
-
self._rescalingWidget = RescalingWidget(parent=self)
|
1174
|
-
self.layout().addRow(self._rescalingWidget)
|
1175
|
-
|
1176
|
-
# normalization by sample
|
1177
|
-
self._normalizationBySampleWidget = NormalizationBySampleGroupBox(parent=self)
|
1178
|
-
self._normalizationBySampleWidget.setChecked(False)
|
1179
|
-
self.layout().addRow(self._normalizationBySampleWidget)
|
1180
|
-
|
1181
|
-
# connect signal / slot
|
1182
|
-
self._stitchingStrategiesWidget.sigChanged.connect(self._updated)
|
1183
|
-
self._previewSlices.editingFinished.connect(self._sliceForPreviewHasChanged)
|
1184
|
-
self._flipLR_CB.toggled.connect(self._flipLRHasChanged)
|
1185
|
-
self._flipUD_CB.toggled.connect(self._flipUDHasChanged)
|
1186
|
-
|
1187
|
-
def _sliceForPreviewHasChanged(self):
|
1188
|
-
slice_for_preview = self.getSlicesForPreview()
|
1189
|
-
try:
|
1190
|
-
slice_for_preview = int(slice_for_preview)
|
1191
|
-
except ValueError:
|
1192
|
-
pass
|
1193
|
-
self.sigSliceForPreviewChanged.emit(slice_for_preview)
|
1194
|
-
self._updated()
|
1195
|
-
|
1196
|
-
def _flipLRHasChanged(self):
|
1197
|
-
self.sigFlipLRChanged.emit(self._flipLR_CB.isChecked())
|
1198
|
-
|
1199
|
-
def _flipUDHasChanged(self):
|
1200
|
-
self.sigFlipUDChanged.emit(self._flipUD_CB.isChecked())
|
1201
|
-
|
1202
|
-
def _updated(self, *args, **kwargs):
|
1203
|
-
self.sigChanged.emit()
|
1204
|
-
|
1205
|
-
def getSlicesForPreview(self):
|
1206
|
-
return self._previewSlices.text()
|
1207
|
-
|
1208
|
-
def getSlices(self):
|
1209
|
-
slices = self._slices.getSlices()
|
1210
|
-
if slices == (0, -1, 1):
|
1211
|
-
return None
|
1212
|
-
else:
|
1213
|
-
return (str(slices[0]), str(slices[1]), str(slices[2]))
|
1214
|
-
|
1215
|
-
def setSlices(self, slices: tuple):
|
1216
|
-
if isinstance(slices, str):
|
1217
|
-
slices = slices.replace(" ", "").split(":")
|
1218
|
-
if len(slices) > 2:
|
1219
|
-
step = int(slices[2])
|
1220
|
-
else:
|
1221
|
-
step = None
|
1222
|
-
self._slices.setSlices(int(slices[0]), int(slices[1]), step)
|
1223
|
-
|
1224
|
-
def getConfiguration(self) -> dict:
|
1225
|
-
slices = self.getSlices()
|
1226
|
-
if slices is None:
|
1227
|
-
slices = ""
|
1228
|
-
else:
|
1229
|
-
slices = ":".join(slices)
|
1230
|
-
res = {
|
1231
|
-
stitching_config.STITCHING_SECTION: {
|
1232
|
-
stitching_config.FLIP_LR: self._flipLR_CB.isChecked(),
|
1233
|
-
stitching_config.FLIP_UD: self._flipUD_CB.isChecked(),
|
1234
|
-
stitching_config.ALIGNMENT_AXIS_1_FIELD: self._alignmentGroup.getAlignmentAxis1().value,
|
1235
|
-
stitching_config.ALIGNMENT_AXIS_2_FIELD: self._alignmentGroup.getAlignmentAxis2().value,
|
1236
|
-
stitching_config.PAD_MODE_FIELD: self._alignmentGroup.getPadMode(),
|
1237
|
-
},
|
1238
|
-
stitching_config.INPUTS_SECTION: {
|
1239
|
-
stitching_config.STITCHING_SLICES: slices,
|
1240
|
-
},
|
1241
|
-
stitching_config.NORMALIZATION_BY_SAMPLE_SECTION: self._normalizationBySampleWidget.getConfiguration(),
|
1242
|
-
}
|
1243
|
-
|
1244
|
-
for ddict in (
|
1245
|
-
self._stitchingStrategiesWidget.getConfiguration(),
|
1246
|
-
self._axis0ShiftSearchParams.getConfiguration(),
|
1247
|
-
self._axis2ShiftSearchParams.getConfiguration(),
|
1248
|
-
self._rescalingWidget.getConfiguration(),
|
1249
|
-
):
|
1250
|
-
res = concatenate_dict(res, ddict)
|
1251
|
-
return res
|
1252
|
-
|
1253
|
-
def setConfiguration(self, config: dict):
|
1254
|
-
self._stitchingStrategiesWidget.setConfiguration(config)
|
1255
|
-
self._axis0ShiftSearchParams.setConfiguration(config)
|
1256
|
-
self._axis2ShiftSearchParams.setConfiguration(config)
|
1257
|
-
self._rescalingWidget.setConfiguration(config)
|
1258
|
-
slices = config.get(stitching_config.STITCHING_SECTION, {}).get(
|
1259
|
-
stitching_config.STITCHING_SLICES, ""
|
1260
|
-
)
|
1261
|
-
# slices
|
1262
|
-
if slices == "":
|
1263
|
-
slices = None
|
1264
|
-
if slices is not None:
|
1265
|
-
self.setSlices(slices)
|
1266
|
-
# flip_lr
|
1267
|
-
flip_lr = config.get(stitching_config.STITCHING_SECTION, {}).get(
|
1268
|
-
stitching_config.FLIP_LR, None
|
1269
|
-
)
|
1270
|
-
if flip_lr is not None:
|
1271
|
-
self._flipLR_CB.setChecked(flip_lr in (True, "True", 1, "1"))
|
1272
|
-
# flip_ud
|
1273
|
-
flip_ud = config.get(stitching_config.STITCHING_SECTION, {}).get(
|
1274
|
-
stitching_config.FLIP_UD, None
|
1275
|
-
)
|
1276
|
-
if flip_ud is not None:
|
1277
|
-
self._flipUD_CB.setChecked(flip_ud in (True, "True", 1, "1"))
|
1278
|
-
# alignment
|
1279
|
-
alignment_axis_1 = config.get(stitching_config.STITCHING_SECTION, {}).get(
|
1280
|
-
stitching_config.ALIGNMENT_AXIS_1_FIELD, None
|
1281
|
-
)
|
1282
|
-
if alignment_axis_1 is not None:
|
1283
|
-
self._alignmentGroup.setAlignmentAxis1(alignment_axis_1)
|
1284
|
-
alignment_axis_2 = config.get(stitching_config.STITCHING_SECTION, {}).get(
|
1285
|
-
stitching_config.ALIGNMENT_AXIS_2_FIELD, None
|
1286
|
-
)
|
1287
|
-
if alignment_axis_2 is not None:
|
1288
|
-
self._alignmentGroup.setAlignmentAxis2(alignment_axis_2)
|
1289
|
-
# pad_mode
|
1290
|
-
pad_mode = config.get(stitching_config.STITCHING_SECTION, {}).get(
|
1291
|
-
stitching_config.PAD_MODE_FIELD, None
|
1292
|
-
)
|
1293
|
-
if pad_mode is not None:
|
1294
|
-
self._alignmentGroup.setPadMode(pad_mode=pad_mode)
|
1295
|
-
|
1296
|
-
# normalization by sample
|
1297
|
-
normalization_by_sample = config.get(
|
1298
|
-
stitching_config.NORMALIZATION_BY_SAMPLE_SECTION, None
|
1299
|
-
)
|
1300
|
-
if normalization_by_sample is not None:
|
1301
|
-
self._normalizationBySampleWidget.setConfiguration(normalization_by_sample)
|
1302
|
-
|
1303
|
-
def _stitchingTypeChanged(self, stiching_type: str):
|
1304
|
-
stiching_type = StitchingType.from_value(stiching_type)
|
1305
|
-
self._alignmentGroup.setAlignmentAxis1Enabled(
|
1306
|
-
stiching_type is StitchingType.Z_POSTPROC
|
1307
|
-
)
|
1308
|
-
|
1309
|
-
def setConfigurationLevel(self, level: ConfigurationLevel):
|
1310
|
-
self._alignmentGroup.setVisible(level >= ConfigurationLevel.ADVANCED)
|
1311
|
-
self._previewSlices.setVisible(level >= ConfigurationLevel.OPTIONAL)
|
1312
|
-
self._flipLR_CB.setVisible(level >= ConfigurationLevel.ADVANCED)
|
1313
|
-
self._flipUD_CB.setVisible(level >= ConfigurationLevel.ADVANCED)
|
1314
|
-
self._rescalingWidget.setVisible(level >= ConfigurationLevel.ADVANCED)
|
1315
|
-
self._axis0ShiftSearchParams.setConfigurationLevel(level)
|
1316
|
-
self._axis2ShiftSearchParams.setConfigurationLevel(level)
|
1317
|
-
self._normalizationBySampleWidget.setVisible(
|
1318
|
-
level >= ConfigurationLevel.ADVANCED
|
1319
|
-
)
|
1320
|
-
|
1321
|
-
|
1322
|
-
class RescalingWidget(qt.QWidget):
|
1323
|
-
DEFAULT_MIN_PERCENTILE = 0
|
1324
|
-
|
1325
|
-
DEFAULT_MAX_PERCENTILE = 100
|
1326
|
-
|
1327
|
-
def __init__(self, parent, *args, **kwargs) -> None:
|
1328
|
-
super().__init__(parent, *args, **kwargs)
|
1329
|
-
self.setLayout(qt.QHBoxLayout())
|
1330
|
-
self._activatedCB = qt.QCheckBox("rescale frames", self)
|
1331
|
-
self.layout().addWidget(self._activatedCB)
|
1332
|
-
|
1333
|
-
self._minPercentileQSB = qt.QSpinBox(self)
|
1334
|
-
self._minPercentileQSB.setRange(0, 100)
|
1335
|
-
self._minPercentileQSB.setPrefix("min:")
|
1336
|
-
self._minPercentileQSB.setSuffix("%")
|
1337
|
-
self._minPercentileQSB.setValue(self.DEFAULT_MIN_PERCENTILE)
|
1338
|
-
self.layout().addWidget(self._minPercentileQSB)
|
1339
|
-
|
1340
|
-
self._maxPercentileQSB = qt.QSpinBox(self)
|
1341
|
-
self._maxPercentileQSB.setRange(0, 100)
|
1342
|
-
self._maxPercentileQSB.setPrefix("max:")
|
1343
|
-
self._maxPercentileQSB.setSuffix("%")
|
1344
|
-
self._maxPercentileQSB.setValue(self.DEFAULT_MAX_PERCENTILE)
|
1345
|
-
self.layout().addWidget(self._maxPercentileQSB)
|
1346
|
-
|
1347
|
-
# set up
|
1348
|
-
self._activatedCB.setChecked(False)
|
1349
|
-
self._minPercentileQSB.setEnabled(False)
|
1350
|
-
self._maxPercentileQSB.setEnabled(False)
|
1351
|
-
|
1352
|
-
# connect signal / slot
|
1353
|
-
self._activatedCB.toggled.connect(self._activationChanged)
|
1354
|
-
self._activatedCB.toggled.connect(self._activationChanged)
|
1355
|
-
|
1356
|
-
def _activationChanged(self):
|
1357
|
-
self._minPercentileQSB.setEnabled(self._activatedCB.isChecked())
|
1358
|
-
self._maxPercentileQSB.setEnabled(self._activatedCB.isChecked())
|
1359
|
-
|
1360
|
-
def getConfiguration(self):
|
1361
|
-
return {
|
1362
|
-
STITCHING_SECTION: {
|
1363
|
-
RESCALE_FRAMES: self._activatedCB.isChecked(),
|
1364
|
-
RESCALE_PARAMS: ";".join(
|
1365
|
-
[
|
1366
|
-
f"{KEY_RESCALE_MIN_PERCENTILES}={self._minPercentileQSB.value()}",
|
1367
|
-
f"{KEY_RESCALE_MAX_PERCENTILES}={self._maxPercentileQSB.value()}",
|
1368
|
-
]
|
1369
|
-
),
|
1370
|
-
}
|
1371
|
-
}
|
1372
|
-
|
1373
|
-
def setConfiguration(self, config: dict):
|
1374
|
-
def cast_percentile(percentile) -> int:
|
1375
|
-
if isinstance(percentile, str):
|
1376
|
-
percentile.replace(" ", "").rstrip("%")
|
1377
|
-
return int(percentile)
|
1378
|
-
|
1379
|
-
stitching_config = config.get(STITCHING_SECTION, {})
|
1380
|
-
rescale_params = str_to_dict(stitching_config.get(RESCALE_PARAMS, {}))
|
1381
|
-
rescale_min_percentile = rescale_params.get(KEY_RESCALE_MIN_PERCENTILES, None)
|
1382
|
-
if rescale_min_percentile is not None:
|
1383
|
-
rescale_min_percentile = cast_percentile(rescale_min_percentile)
|
1384
|
-
self._minPercentileQSB.setValue(rescale_min_percentile)
|
1385
|
-
rescale_max_percentile = rescale_params.get(KEY_RESCALE_MAX_PERCENTILES, None)
|
1386
|
-
if rescale_max_percentile is not None:
|
1387
|
-
rescale_max_percentile = cast_percentile(rescale_max_percentile)
|
1388
|
-
self._maxPercentileQSB.setValue(rescale_max_percentile)
|
1389
|
-
|
1390
|
-
rescale = stitching_config.get(RESCALE_FRAMES, None)
|
1391
|
-
if rescale is not None:
|
1392
|
-
self._activatedCB.setChecked(_convert_str_to_bool(rescale))
|