microeye 2.3.3__tar.gz → 2.3.4__tar.gz
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.
- {microeye-2.3.3/src/microeye.egg-info → microeye-2.3.4}/PKG-INFO +5 -5
- {microeye-2.3.3 → microeye-2.3.4}/README.md +4 -4
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/_version.py +1 -1
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/filters/__init__.py +3 -4
- microeye-2.3.4/src/microEye/analysis/filters/base.py +62 -0
- microeye-2.3.4/src/microEye/analysis/filters/spatial.py +576 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/filters/temporal.py +2 -2
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/fit.py +9 -9
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/viewer/image_options_widget.py +62 -112
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/viewer/images.py +1 -1
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/camera_list.py +9 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/camera_options.py +1 -1
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/camera_panel.py +104 -8
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/dummy/dummy_panel.py +3 -68
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/pco/pco_panel.py +0 -68
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/shortcuts.py +8 -1
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/thorlabs/thorlabs_panel.py +0 -68
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/ueye/ueye_panel.py +0 -68
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/vimba/vimba_panel.py +0 -68
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/mieye/devices_manager.py +37 -16
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/mieye/miEye.py +4 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/pycromanager/devices.py +53 -20
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/pycromanager/widgets/pycro_panel.py +8 -68
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/stages/__init__.py +2 -7
- microeye-2.3.4/src/microEye/hardware/stages/piezo_concept.py +141 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/stages/stabilizer.py +1 -1
- microeye-2.3.4/src/microEye/hardware/stages/stage.py +849 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/widgets/controller.py +19 -9
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/widgets/devices.py +8 -1
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/widgets/focusWidget.py +1 -1
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/widgets/scan_acquisition.py +1 -1
- microeye-2.3.4/src/microEye/tools/__init__.py +0 -0
- microeye-2.3.4/src/microEye/tools/microscopy.py +731 -0
- microeye-2.3.4/src/microEye/utils/display.py +278 -0
- microeye-2.3.4/src/microEye/utils/hid_utils/__init__.py +8 -0
- {microeye-2.3.3/src/microEye/utils/hid → microeye-2.3.4/src/microEye/utils/hid_utils}/controller.py +7 -3
- {microeye-2.3.3 → microeye-2.3.4/src/microeye.egg-info}/PKG-INFO +5 -5
- {microeye-2.3.3 → microeye-2.3.4}/src/microeye.egg-info/SOURCES.txt +8 -5
- microeye-2.3.3/src/microEye/analysis/filters/base.py +0 -21
- microeye-2.3.3/src/microEye/analysis/filters/spatial.py +0 -338
- microeye-2.3.3/src/microEye/hardware/stages/piezo_concept.py +0 -607
- microeye-2.3.3/src/microEye/hardware/stages/stage.py +0 -89
- microeye-2.3.3/src/microEye/utils/hid/__init__.py +0 -8
- {microeye-2.3.3 → microeye-2.3.4}/LICENSE +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/MANIFEST.in +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/pyproject.toml +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/setup.cfg +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/setup.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/checklist_dialog.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/cmosMaps.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/nena.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/phasor_fit.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/processing.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/psf/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/psf/extract.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/psf/rubost_mean.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/psf/spline.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/psf/stats/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/psf/stats/core.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/psf/stats/curve_fit.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/psf/stats/io.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/psf/stats/slope_fit.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/psf/temp.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/psf/test.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/pyfit3Dcspline/CPU/CPUfunctions.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/pyfit3Dcspline/CPU/CPUmleFit_LM.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/pyfit3Dcspline/CPU/CPUsplineLib.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/pyfit3Dcspline/CPU/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUfunctions.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUmleFit_LM_EMCCD.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUmleFit_LM_sCMOS.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUsplineLib.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/pyfit3Dcspline/GPU/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/pyfit3Dcspline/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/pyfit3Dcspline/constants.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/pyfit3Dcspline/mainfunctions.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/results.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/results_stats.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/fitting/tardis.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/multi_viewer.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/processing/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/processing/frc.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/rendering/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/rendering/base.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/rendering/cloud.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/rendering/core.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/rendering/volumetric.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/tools/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/tools/kymograms.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/tools/roi_selectors.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/utils/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/utils/coordinates.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/utils/images.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/utils/windows.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/viewer/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/viewer/layers_widget.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/viewer/localizations.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/viewer/psf.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/analysis/viewer/volume.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/camera_calibration.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/dummy/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/jobs.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/line_profiler.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/linescan/IR_Cam.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/linescan/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/micam.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/pco/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/pco/enums.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/pco/pco_cam.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/thorlabs/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/thorlabs/thorlabs.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/ueye/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/ueye/ueye_camera.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/vimba/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/cams/vimba/vimba_cam.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/device.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/lasers/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/lasers/io_matchbox.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/lasers/io_params.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/lasers/io_single_laser.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/lasers/laser_relay.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/mieye/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/mieye/acquisition_manager.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/misc/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/misc/acquisition_view.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/misc/reglo.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/misc/temp.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/port_config.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/protocols/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/protocols/actions.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/protocols/actions_items.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/protocols/designer.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/protocols/scene_manager.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/protocols/serialization.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/pycromanager/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/pycromanager/core.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/pycromanager/enums.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/pycromanager/headless.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/pycromanager/utils.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/pycromanager/widgets/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/pycromanager/widgets/bridges.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/pycromanager/widgets/headless_manager.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/pycromanager/widgets/headless_options.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/stages/elliptec/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/stages/elliptec/baseDevice.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/stages/elliptec/device.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/stages/elliptec/deviceID.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/stages/elliptec/devicePort.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/stages/elliptec/deviceStatus.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/stages/elliptec/devicesView.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/stages/elliptec/ellDevices.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/stages/elliptec/messageUpdater.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/stages/elliptec/motorInfo.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/stages/elliptec/stage.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/stages/elliptec/test.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/stages/kinesis/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/stages/kinesis/kdc101/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/stages/kinesis/kdc101/enums.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/stages/kinesis/kdc101/factory.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/stages/kinesis/kdc101/kdc101.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/stages/kinesis/kinesis.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/widgets/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/hardware/widgets/qlist_slider.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/icons/1024.png +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/icons/128.png +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/icons/16.png +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/icons/24.png +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/icons/256.png +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/icons/32.png +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/icons/48.png +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/icons/512.png +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/icons/64.png +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/icons/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/icons/close.svg +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/icons/mieye.png +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/icons/min.svg +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/icons/viewer.png +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/launcher.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/qt.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/utils/__init__.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/utils/enum_encoder.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/utils/expandable_groupbox.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/utils/gui_helper.py +0 -0
- {microeye-2.3.3/src/microEye/utils/hid → microeye-2.3.4/src/microEye/utils/hid_utils}/device.py +0 -0
- {microeye-2.3.3/src/microEye/utils/hid → microeye-2.3.4/src/microEye/utils/hid_utils}/enums.py +0 -0
- {microeye-2.3.3/src/microEye/utils/hid → microeye-2.3.4/src/microEye/utils/hid_utils}/utils.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/utils/labelled_slider.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/utils/metadata.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/utils/metadata_tree.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/utils/micro_launcher.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/utils/parameter_tree.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/utils/pyscripting.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/utils/retry_exec.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/utils/start_gui.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/utils/thread_worker.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microEye/utils/uImage.py +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microeye.egg-info/dependency_links.txt +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microeye.egg-info/entry_points.txt +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microeye.egg-info/requires.txt +0 -0
- {microeye-2.3.3 → microeye-2.3.4}/src/microeye.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: microeye
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.4
|
|
4
4
|
Summary: A python toolkit for fluorescence microscopy that features hardware control, data analysis and vizualization for super-resolution single-molecule localization microscopy and single-partical tracking.
|
|
5
5
|
Home-page: https://github.com/samhitech/microEye
|
|
6
6
|
Author: Mohammad Nour Alsamsam
|
|
@@ -96,10 +96,10 @@ This toolkit is compatible with the [hardware](#hardware) used in our microscope
|
|
|
96
96
|

|
|
97
97
|
|
|
98
98
|
```bash
|
|
99
|
-
__ ____ ____ ___ ____
|
|
100
|
-
/ |/ (_)__________ / __/_ _____ _ __|_ | |_ /
|
|
101
|
-
/ /|_/ / / __/ __/ _ \/ _// // / -_) | |/ / __/_ _/_
|
|
102
|
-
/_/ /_/_/\__/_/ \___/___/\_, /\__/ |___/____(_)____(_)
|
|
99
|
+
__ ____ ____ ___ ____ ____
|
|
100
|
+
/ |/ (_)__________ / __/_ _____ _ __|_ | |_ // / /
|
|
101
|
+
/ /|_/ / / __/ __/ _ \/ _// // / -_) | |/ / __/_ _/_ </_ _/
|
|
102
|
+
/_/ /_/_/\__/_/ \___/___/\_, /\__/ |___/____(_)____(_)_/
|
|
103
103
|
/___/
|
|
104
104
|
```
|
|
105
105
|
|
|
@@ -31,10 +31,10 @@ This toolkit is compatible with the [hardware](#hardware) used in our microscope
|
|
|
31
31
|

|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
|
-
__ ____ ____ ___ ____
|
|
35
|
-
/ |/ (_)__________ / __/_ _____ _ __|_ | |_ /
|
|
36
|
-
/ /|_/ / / __/ __/ _ \/ _// // / -_) | |/ / __/_ _/_
|
|
37
|
-
/_/ /_/_/\__/_/ \___/___/\_, /\__/ |___/____(_)____(_)
|
|
34
|
+
__ ____ ____ ___ ____ ____
|
|
35
|
+
/ |/ (_)__________ / __/_ _____ _ __|_ | |_ // / /
|
|
36
|
+
/ /|_/ / / __/ __/ _ \/ _// // / -_) | |/ / __/_ _/_ </_ _/
|
|
37
|
+
/_/ /_/_/\__/_/ \___/___/\_, /\__/ |___/____(_)____(_)_/
|
|
38
38
|
/___/
|
|
39
39
|
```
|
|
40
40
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
version_info = (2, 3,
|
|
1
|
+
version_info = (2, 3, 4)
|
|
2
2
|
__version__ = '.'.join(map(str, version_info))
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
from microEye.analysis.filters.base import AbstractFilter
|
|
1
|
+
from microEye.analysis.filters.base import AbstractFilter, SpatialFilter, TemporalFilter
|
|
2
2
|
from microEye.analysis.filters.spatial import (
|
|
3
|
-
|
|
4
|
-
BandpassFilter,
|
|
3
|
+
BackgroundReduction,
|
|
5
4
|
DoG_Filter,
|
|
6
|
-
|
|
5
|
+
FourierFilter,
|
|
7
6
|
PassFilter,
|
|
8
7
|
)
|
|
9
8
|
from microEye.analysis.filters.temporal import TemporalMedianFilter
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
from PyQt5 import QtWidgets
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AbstractFilter(ABC):
|
|
9
|
+
def __init__(self, name: str = 'Abstract Base Filter', parameters: dict = None):
|
|
10
|
+
self._name = name
|
|
11
|
+
self._parameters = parameters or {}
|
|
12
|
+
self._show_filter = False
|
|
13
|
+
|
|
14
|
+
@abstractmethod
|
|
15
|
+
def run(self, image: np.ndarray) -> np.ndarray:
|
|
16
|
+
'''Apply the filter to the input image.'''
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
def getWidget(self):
|
|
20
|
+
'''Return the QWidget for configuring the filter.'''
|
|
21
|
+
return QtWidgets.QWidget()
|
|
22
|
+
|
|
23
|
+
def get_metadata(self) -> dict:
|
|
24
|
+
'''Return metadata about the filter.'''
|
|
25
|
+
return {
|
|
26
|
+
'name': self.name,
|
|
27
|
+
'parameters': self._parameters,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def get_tree_parameters(cls) -> dict:
|
|
32
|
+
'''Return the parameters for the pyqtgraph tree view.'''
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def name(self):
|
|
37
|
+
return self._name
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def parameters(self) -> Optional[dict]:
|
|
41
|
+
return self._parameters
|
|
42
|
+
|
|
43
|
+
class SpatialFilter(AbstractFilter):
|
|
44
|
+
'''Base class for spatial filters.'''
|
|
45
|
+
def __init__(self, name: str = 'Spatial Filter', parameters: dict = None):
|
|
46
|
+
super().__init__(name=name, parameters=parameters)
|
|
47
|
+
|
|
48
|
+
@abstractmethod
|
|
49
|
+
def run(self, image: np.ndarray) -> np.ndarray:
|
|
50
|
+
'''Apply the spatial filter to the input image.'''
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class TemporalFilter(AbstractFilter):
|
|
55
|
+
'''Base class for temporal filters.'''
|
|
56
|
+
def __init__(self, name: str = 'Temporal Filter', parameters: dict = None):
|
|
57
|
+
super().__init__(name=name, parameters=parameters)
|
|
58
|
+
|
|
59
|
+
@abstractmethod
|
|
60
|
+
def run(self, image: np.ndarray) -> np.ndarray:
|
|
61
|
+
'''Apply the temporal filter to the input image.'''
|
|
62
|
+
pass
|
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
import math
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
import cv2
|
|
6
|
+
import numpy as np
|
|
7
|
+
from scipy import signal
|
|
8
|
+
from scipy.fftpack import fft2, fftshift, ifft2, ifftshift
|
|
9
|
+
from skimage import filters
|
|
10
|
+
from skimage.morphology import disk, white_tophat
|
|
11
|
+
from skimage.restoration import rolling_ball
|
|
12
|
+
|
|
13
|
+
from microEye.analysis.filters.base import SpatialFilter
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class PassFilter(SpatialFilter):
|
|
17
|
+
def __init__(self) -> None:
|
|
18
|
+
'''Pass filter initialization.'''
|
|
19
|
+
super().__init__(name='No Filter (Pass)')
|
|
20
|
+
|
|
21
|
+
def run(self, image: np.ndarray) -> np.ndarray:
|
|
22
|
+
return image
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class DoG_Filter(SpatialFilter):
|
|
26
|
+
def __init__(self, sigma: float = 1, factor: float = 2.5) -> None:
|
|
27
|
+
'''Difference of Gauss init
|
|
28
|
+
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
sigma : float, optional
|
|
32
|
+
sigma_min, by default 1
|
|
33
|
+
factor : float, optional
|
|
34
|
+
factor = sigma_max/sigma_min, by default 2.5
|
|
35
|
+
'''
|
|
36
|
+
params = {
|
|
37
|
+
'sigma': sigma,
|
|
38
|
+
'factor': factor,
|
|
39
|
+
}
|
|
40
|
+
super().__init__(name='Difference of Gaussians', parameters=params)
|
|
41
|
+
self.set_params(sigma, factor)
|
|
42
|
+
|
|
43
|
+
def set_params(self, sigma: float, factor: float):
|
|
44
|
+
'''Set filter parameters.
|
|
45
|
+
|
|
46
|
+
Parameters
|
|
47
|
+
----------
|
|
48
|
+
sigma : float
|
|
49
|
+
sigma_min
|
|
50
|
+
factor : float
|
|
51
|
+
factor = sigma_max/sigma_min
|
|
52
|
+
'''
|
|
53
|
+
self._show_filter = False
|
|
54
|
+
self.parameters['sigma'] = sigma
|
|
55
|
+
self.parameters['factor'] = factor
|
|
56
|
+
self.rsize = max(math.ceil(6 * sigma + 1), 3)
|
|
57
|
+
self.dog = DoG_Filter.gaussian_kernel(
|
|
58
|
+
self.rsize, sigma
|
|
59
|
+
) - DoG_Filter.gaussian_kernel(self.rsize, max(1, factor * sigma))
|
|
60
|
+
|
|
61
|
+
def gaussian_kernel(dim, sigma):
|
|
62
|
+
x = cv2.getGaussianKernel(dim, sigma)
|
|
63
|
+
kernel = x.dot(x.T)
|
|
64
|
+
return kernel
|
|
65
|
+
|
|
66
|
+
def run(self, image: np.ndarray) -> np.ndarray:
|
|
67
|
+
rows, cols = image.shape
|
|
68
|
+
nrows = cv2.getOptimalDFTSize(rows)
|
|
69
|
+
ncols = cv2.getOptimalDFTSize(cols)
|
|
70
|
+
pad_rows = nrows - rows
|
|
71
|
+
pad_cols = ncols - cols
|
|
72
|
+
|
|
73
|
+
# Ensure that pad_cols[1] and pad_rows[1] are at least 1
|
|
74
|
+
pad_rows = (pad_rows // 2, max(1, pad_rows - pad_rows // 2))
|
|
75
|
+
pad_cols = (pad_cols // 2, max(1, pad_cols - pad_cols // 2))
|
|
76
|
+
|
|
77
|
+
nimg = np.pad(image, (pad_rows, pad_cols), mode='reflect')
|
|
78
|
+
|
|
79
|
+
res = cv2.normalize(
|
|
80
|
+
signal.convolve2d(nimg, np.rot90(self.dog), mode='same')[
|
|
81
|
+
pad_rows[0] : -pad_rows[1], pad_cols[0] : -pad_cols[1]
|
|
82
|
+
],
|
|
83
|
+
None,
|
|
84
|
+
0,
|
|
85
|
+
255,
|
|
86
|
+
cv2.NORM_MINMAX,
|
|
87
|
+
cv2.CV_8U,
|
|
88
|
+
)
|
|
89
|
+
return res
|
|
90
|
+
|
|
91
|
+
def get_tree_parameters(self):
|
|
92
|
+
'''Return the parameters for the pyqtgraph tree view.'''
|
|
93
|
+
return {
|
|
94
|
+
'name': self.name,
|
|
95
|
+
'type': 'group',
|
|
96
|
+
'visible': False,
|
|
97
|
+
'children': [
|
|
98
|
+
{
|
|
99
|
+
'name': 'Sigma',
|
|
100
|
+
'type': 'float',
|
|
101
|
+
'value': self.parameters['sigma'],
|
|
102
|
+
'limits': [0.0, 100.0],
|
|
103
|
+
'step': 0.1,
|
|
104
|
+
'decimals': 2,
|
|
105
|
+
'tip': 'Standard deviation (\u03c3) min for the filter',
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
'name': 'Factor',
|
|
109
|
+
'type': 'float',
|
|
110
|
+
'value': self.parameters['factor'],
|
|
111
|
+
'limits': [0.0, 100.0],
|
|
112
|
+
'step': 0.1,
|
|
113
|
+
'decimals': 2,
|
|
114
|
+
'tip': 'Ratio of max \u03c3 to min \u03c3.',
|
|
115
|
+
},
|
|
116
|
+
],
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
# class GaussFilter(SpatialFilter):
|
|
121
|
+
# def __init__(self, sigma=1) -> None:
|
|
122
|
+
# '''Gaussian filter initialization.'''
|
|
123
|
+
# params = {'sigma': sigma}
|
|
124
|
+
# super().__init__(name='Gaussian Filter', parameters=params)
|
|
125
|
+
# self.set_params(sigma)
|
|
126
|
+
|
|
127
|
+
# def set_params(self, sigma):
|
|
128
|
+
# '''Set the sigma parameter for the Gaussian filter.'''
|
|
129
|
+
# self._show_filter = False
|
|
130
|
+
# self.parameters['sigma'] = sigma
|
|
131
|
+
# self.gauss = GaussFilter.gaussian_kernel(
|
|
132
|
+
# max(3, math.ceil(3 * sigma + 1)), sigma
|
|
133
|
+
# )
|
|
134
|
+
|
|
135
|
+
# def gaussian_kernel(dim, sigma):
|
|
136
|
+
# x = cv2.getGaussianKernel(dim, sigma)
|
|
137
|
+
# kernel = x.dot(x.T)
|
|
138
|
+
# return kernel
|
|
139
|
+
|
|
140
|
+
# def run(self, image: np.ndarray) -> np.ndarray:
|
|
141
|
+
# return cv2.normalize(
|
|
142
|
+
# signal.convolve2d(image, np.rot90(self.gauss), mode='same'),
|
|
143
|
+
# None,
|
|
144
|
+
# 0,
|
|
145
|
+
# 255,
|
|
146
|
+
# cv2.NORM_MINMAX,
|
|
147
|
+
# cv2.CV_8U,
|
|
148
|
+
# )
|
|
149
|
+
|
|
150
|
+
# def get_tree_parameters(self):
|
|
151
|
+
# '''Return the parameters for the pyqtgraph tree view.'''
|
|
152
|
+
# return {
|
|
153
|
+
# 'name': self.name,
|
|
154
|
+
# 'type': 'group',
|
|
155
|
+
# 'visible': False,
|
|
156
|
+
# 'children': [
|
|
157
|
+
# {
|
|
158
|
+
# 'name': 'Sigma',
|
|
159
|
+
# 'type': 'float',
|
|
160
|
+
# 'value': self.parameters['sigma'],
|
|
161
|
+
# 'limits': [0.0, 100.0],
|
|
162
|
+
# 'step': 0.1,
|
|
163
|
+
# 'decimals': 2,
|
|
164
|
+
# 'tip': 'Standard deviation (\u03c3) for the filter',
|
|
165
|
+
# },
|
|
166
|
+
# ],
|
|
167
|
+
# }
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class FourierFilter(SpatialFilter):
|
|
171
|
+
class PROFILES(Enum):
|
|
172
|
+
Gaussian = 1
|
|
173
|
+
Butterworth = 2
|
|
174
|
+
Ideal = 3
|
|
175
|
+
|
|
176
|
+
@classmethod
|
|
177
|
+
def from_string(cls, s: str):
|
|
178
|
+
for column in cls:
|
|
179
|
+
if column.name.lower() == s.lower() or s.lower() in column.name.lower():
|
|
180
|
+
return column
|
|
181
|
+
raise ValueError(f'{cls.__name__} has no value matching "{s}"')
|
|
182
|
+
|
|
183
|
+
@classmethod
|
|
184
|
+
def values(cls):
|
|
185
|
+
return [column.name for column in cls]
|
|
186
|
+
|
|
187
|
+
class PASS_TYPES(Enum):
|
|
188
|
+
Band = 0
|
|
189
|
+
Low = 1
|
|
190
|
+
High = 2
|
|
191
|
+
|
|
192
|
+
@classmethod
|
|
193
|
+
def from_string(cls, s: str):
|
|
194
|
+
for column in cls:
|
|
195
|
+
if column.name.lower() == s.lower() or s.lower() in column.name.lower():
|
|
196
|
+
return column
|
|
197
|
+
raise ValueError(f'{cls.__name__} has no value matching "{s}"')
|
|
198
|
+
|
|
199
|
+
@classmethod
|
|
200
|
+
def values(cls):
|
|
201
|
+
return [column.name for column in cls]
|
|
202
|
+
|
|
203
|
+
def __init__(
|
|
204
|
+
self,
|
|
205
|
+
center=40.0,
|
|
206
|
+
width=90.0,
|
|
207
|
+
filter_type=PROFILES.Gaussian,
|
|
208
|
+
pass_type=PASS_TYPES.Band,
|
|
209
|
+
order=5,
|
|
210
|
+
show_filter=False,
|
|
211
|
+
) -> None:
|
|
212
|
+
'''Fourier filter initialization.'''
|
|
213
|
+
params = {
|
|
214
|
+
'center': center,
|
|
215
|
+
'width': width,
|
|
216
|
+
'type': filter_type.name
|
|
217
|
+
if isinstance(filter_type, FourierFilter.PROFILES)
|
|
218
|
+
else filter_type,
|
|
219
|
+
'pass_type': pass_type.name
|
|
220
|
+
if isinstance(pass_type, FourierFilter.PASS_TYPES)
|
|
221
|
+
else pass_type,
|
|
222
|
+
'order': order,
|
|
223
|
+
}
|
|
224
|
+
super().__init__(name='Fourier Filter', parameters=params)
|
|
225
|
+
self._radial_coordinates = None
|
|
226
|
+
self._filter: Optional[np.ndarray] = None
|
|
227
|
+
self._show_filter = show_filter
|
|
228
|
+
self._refresh = True
|
|
229
|
+
|
|
230
|
+
def radial_coordinates(self, shape):
|
|
231
|
+
'''Generates a 2D array with radial cordinates
|
|
232
|
+
with according to the first two axis of the
|
|
233
|
+
supplied shape tuple
|
|
234
|
+
|
|
235
|
+
Returns
|
|
236
|
+
-------
|
|
237
|
+
R, Rsq
|
|
238
|
+
Radius 2d matrix (R) and radius squared matrix (Rsq)
|
|
239
|
+
'''
|
|
240
|
+
y_len = np.arange(-shape[0] // 2, shape[0] // 2)
|
|
241
|
+
x_len = np.arange(-shape[1] // 2, shape[1] // 2)
|
|
242
|
+
|
|
243
|
+
X, Y = np.meshgrid(x_len, y_len)
|
|
244
|
+
|
|
245
|
+
Rsq = X**2 + Y**2
|
|
246
|
+
|
|
247
|
+
self._radial_coordinates = (np.sqrt(Rsq), Rsq)
|
|
248
|
+
|
|
249
|
+
return self._radial_coordinates
|
|
250
|
+
|
|
251
|
+
def ideal_filter(self, shape, cutoff, cuton):
|
|
252
|
+
'''Generates an ideal pass filter of shape
|
|
253
|
+
|
|
254
|
+
Params
|
|
255
|
+
-------
|
|
256
|
+
shape
|
|
257
|
+
the shape of filter matrix
|
|
258
|
+
cutoff
|
|
259
|
+
the cutoff frequency (low)
|
|
260
|
+
cuton
|
|
261
|
+
the cuton frequency (high)
|
|
262
|
+
|
|
263
|
+
Returns
|
|
264
|
+
-------
|
|
265
|
+
filter (np.ndarray)
|
|
266
|
+
the filter in fourier space
|
|
267
|
+
'''
|
|
268
|
+
|
|
269
|
+
cir_filter = np.zeros((shape[0], shape[1]), dtype=np.float32)
|
|
270
|
+
cir_center = (shape[1] // 2, shape[0] // 2)
|
|
271
|
+
|
|
272
|
+
if self.parameters['pass_type'] == FourierFilter.PASS_TYPES.Low.name:
|
|
273
|
+
cir_filter = cv2.circle(cir_filter, cir_center, cutoff, 1, -1)
|
|
274
|
+
elif self.parameters['pass_type'] == FourierFilter.PASS_TYPES.High.name:
|
|
275
|
+
cir_filter = cv2.circle(1 + cir_filter, cir_center, cutoff, 0, -1)
|
|
276
|
+
else:
|
|
277
|
+
cir_filter = cv2.circle(cir_filter, cir_center, cuton, 1, -1)
|
|
278
|
+
cir_filter = cv2.circle(cir_filter, cir_center, cutoff, 0, -1)
|
|
279
|
+
|
|
280
|
+
return cir_filter
|
|
281
|
+
|
|
282
|
+
def gaussian_filter(self, shape, center, width):
|
|
283
|
+
'''Generates a Gaussian pass filter of shape
|
|
284
|
+
|
|
285
|
+
Params
|
|
286
|
+
-------
|
|
287
|
+
shape
|
|
288
|
+
the shape of filter matrix
|
|
289
|
+
center
|
|
290
|
+
the center frequency
|
|
291
|
+
width
|
|
292
|
+
the filter bandwidth
|
|
293
|
+
|
|
294
|
+
Returns
|
|
295
|
+
-------
|
|
296
|
+
filter (np.ndarray)
|
|
297
|
+
the filter in fourier space
|
|
298
|
+
'''
|
|
299
|
+
if self._radial_coordinates is None:
|
|
300
|
+
R, Rsq = self.radial_coordinates(shape)
|
|
301
|
+
elif self._radial_coordinates[0].shape != shape[:2]:
|
|
302
|
+
R, Rsq = self.radial_coordinates(shape)
|
|
303
|
+
else:
|
|
304
|
+
R, Rsq = self._radial_coordinates
|
|
305
|
+
|
|
306
|
+
with np.errstate(divide='ignore', invalid='ignore'):
|
|
307
|
+
if self.parameters['pass_type'] == FourierFilter.PASS_TYPES.Low.name:
|
|
308
|
+
filter = np.exp(-(Rsq) / (2 * (center**2)))
|
|
309
|
+
elif self.parameters['pass_type'] == FourierFilter.PASS_TYPES.High.name:
|
|
310
|
+
filter = 1 - np.exp(-(Rsq) / (2 * (center**2)))
|
|
311
|
+
else:
|
|
312
|
+
filter = np.exp(-(((Rsq - center**2) / (R * width)) ** 2))
|
|
313
|
+
|
|
314
|
+
filter[filter == np.inf] = 0
|
|
315
|
+
|
|
316
|
+
a, b = np.unravel_index(R.argmin(), R.shape)
|
|
317
|
+
|
|
318
|
+
filter[a, b] = 1
|
|
319
|
+
|
|
320
|
+
return filter
|
|
321
|
+
|
|
322
|
+
def butterworth_filter(self, shape, center, width, order=5):
|
|
323
|
+
'''Generates a Gaussian pass filter of shape
|
|
324
|
+
|
|
325
|
+
Params
|
|
326
|
+
-------
|
|
327
|
+
shape
|
|
328
|
+
the shape of filter matrix
|
|
329
|
+
center
|
|
330
|
+
the center frequency
|
|
331
|
+
width
|
|
332
|
+
the filter bandwidth
|
|
333
|
+
|
|
334
|
+
Returns
|
|
335
|
+
-------
|
|
336
|
+
filter (np.ndarray)
|
|
337
|
+
the filter in fourier space
|
|
338
|
+
'''
|
|
339
|
+
if self._radial_coordinates is None:
|
|
340
|
+
R, Rsq = self.radial_coordinates(shape)
|
|
341
|
+
elif self._radial_coordinates[0].shape != shape[:2]:
|
|
342
|
+
R, Rsq = self.radial_coordinates(shape)
|
|
343
|
+
else:
|
|
344
|
+
R, Rsq = self._radial_coordinates
|
|
345
|
+
|
|
346
|
+
with np.errstate(divide='ignore', invalid='ignore'):
|
|
347
|
+
if self.parameters['pass_type'] == FourierFilter.PASS_TYPES.Low.name:
|
|
348
|
+
filter = 1 / (1 + (R / center) ** (2 * order))
|
|
349
|
+
elif self.parameters['pass_type'] == FourierFilter.PASS_TYPES.High.name:
|
|
350
|
+
filter = 1 / (1 + (center / np.where(R == 0, 1e-10, R)) ** (2 * order))
|
|
351
|
+
else:
|
|
352
|
+
filter = 1 - (
|
|
353
|
+
1 / (1 + ((R * width) / (Rsq - center**2)) ** (2 * order))
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
filter[filter == np.inf] = 0
|
|
357
|
+
|
|
358
|
+
a, b = np.unravel_index(R.argmin(), R.shape)
|
|
359
|
+
|
|
360
|
+
filter[a, b] = 1
|
|
361
|
+
|
|
362
|
+
return filter
|
|
363
|
+
|
|
364
|
+
def run(self, image: np.ndarray):
|
|
365
|
+
'''Applies an FFT pass filter to the 2D image.
|
|
366
|
+
|
|
367
|
+
Params
|
|
368
|
+
-------
|
|
369
|
+
image (np.ndarray)
|
|
370
|
+
the image to be filtered.
|
|
371
|
+
'''
|
|
372
|
+
|
|
373
|
+
# time = QDateTime.currentDateTime()
|
|
374
|
+
|
|
375
|
+
rows, cols = image.shape
|
|
376
|
+
nrows = cv2.getOptimalDFTSize(rows)
|
|
377
|
+
ncols = cv2.getOptimalDFTSize(cols)
|
|
378
|
+
pad_rows = nrows - rows
|
|
379
|
+
pad_cols = ncols - cols
|
|
380
|
+
|
|
381
|
+
# Ensure that pad_cols[1] and pad_rows[1] are at least 1
|
|
382
|
+
pad_rows = (pad_rows // 2, max(1, pad_rows - pad_rows // 2))
|
|
383
|
+
pad_cols = (pad_cols // 2, max(1, pad_cols - pad_cols // 2))
|
|
384
|
+
|
|
385
|
+
nimg = np.pad(image, (pad_rows, pad_cols), mode='reflect')
|
|
386
|
+
# nimg = np.zeros((nrows, ncols))
|
|
387
|
+
# nimg[:rows, :cols] = image
|
|
388
|
+
|
|
389
|
+
ft = fftshift(cv2.dft(np.float64(nimg), flags=cv2.DFT_COMPLEX_OUTPUT))
|
|
390
|
+
|
|
391
|
+
filter = np.ones(ft.shape[:2])
|
|
392
|
+
|
|
393
|
+
refresh = self._refresh
|
|
394
|
+
|
|
395
|
+
if self._filter is None:
|
|
396
|
+
refresh = True
|
|
397
|
+
elif self._filter.shape != ft.shape[:2]:
|
|
398
|
+
refresh = True
|
|
399
|
+
|
|
400
|
+
if refresh:
|
|
401
|
+
if self.parameters['type'] == FourierFilter.PROFILES.Gaussian.name:
|
|
402
|
+
filter = self.gaussian_filter(
|
|
403
|
+
ft.shape, self.parameters['center'], self.parameters['width']
|
|
404
|
+
)
|
|
405
|
+
elif self.parameters['type'] == FourierFilter.PROFILES.Butterworth.name:
|
|
406
|
+
filter = self.butterworth_filter(
|
|
407
|
+
ft.shape,
|
|
408
|
+
self.parameters['center'],
|
|
409
|
+
self.parameters['width'],
|
|
410
|
+
self.parameters['order'],
|
|
411
|
+
)
|
|
412
|
+
else:
|
|
413
|
+
cutoff = int(
|
|
414
|
+
max(0, self.parameters['center'] - self.parameters['width'] // 2)
|
|
415
|
+
)
|
|
416
|
+
cuton = int(self.parameters['center'] + self.parameters['width'] // 2)
|
|
417
|
+
filter = self.ideal_filter(ft.shape, cutoff, cuton)
|
|
418
|
+
|
|
419
|
+
self._filter = filter
|
|
420
|
+
else:
|
|
421
|
+
filter = self._filter
|
|
422
|
+
|
|
423
|
+
if self._show_filter:
|
|
424
|
+
cv2.namedWindow(self.name, cv2.WINDOW_NORMAL)
|
|
425
|
+
cv2.imshow(self.name, (filter * 255).astype(np.uint8))
|
|
426
|
+
|
|
427
|
+
img = np.zeros(nimg.shape, dtype=np.uint8)
|
|
428
|
+
ft[:, :, 0] *= filter
|
|
429
|
+
ft[:, :, 1] *= filter
|
|
430
|
+
idft = cv2.idft(ifftshift(ft))
|
|
431
|
+
idft = cv2.magnitude(idft[:, :, 0], idft[:, :, 1])
|
|
432
|
+
cv2.normalize(idft, img, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)
|
|
433
|
+
|
|
434
|
+
# exex = time.msecsTo(QDateTime.currentDateTime())
|
|
435
|
+
return img[pad_rows[0] : -pad_rows[1], pad_cols[0] : -pad_cols[1]]
|
|
436
|
+
|
|
437
|
+
def set_params(
|
|
438
|
+
self,
|
|
439
|
+
center: float,
|
|
440
|
+
width: float,
|
|
441
|
+
filter_type: PROFILES,
|
|
442
|
+
pass_type: PASS_TYPES,
|
|
443
|
+
show_filter: bool,
|
|
444
|
+
order: int = 5,
|
|
445
|
+
):
|
|
446
|
+
'''
|
|
447
|
+
Set the parameters for the filter.
|
|
448
|
+
'''
|
|
449
|
+
self.parameters['center'] = center
|
|
450
|
+
self.parameters['width'] = width
|
|
451
|
+
self.parameters['order'] = order
|
|
452
|
+
self.parameters['type'] = (
|
|
453
|
+
filter_type.name
|
|
454
|
+
if isinstance(filter_type, FourierFilter.PROFILES)
|
|
455
|
+
else filter_type
|
|
456
|
+
)
|
|
457
|
+
self.parameters['pass_type'] = (
|
|
458
|
+
pass_type.name
|
|
459
|
+
if isinstance(pass_type, FourierFilter.PASS_TYPES)
|
|
460
|
+
else pass_type
|
|
461
|
+
)
|
|
462
|
+
self._show_filter = show_filter
|
|
463
|
+
|
|
464
|
+
def get_tree_parameters(self):
|
|
465
|
+
return {
|
|
466
|
+
'name': self.name,
|
|
467
|
+
'type': 'group',
|
|
468
|
+
'visible': False,
|
|
469
|
+
'children': [
|
|
470
|
+
{
|
|
471
|
+
'name': 'Filter Type',
|
|
472
|
+
'type': 'list',
|
|
473
|
+
'limits': FourierFilter.PROFILES.values(),
|
|
474
|
+
'value': FourierFilter.PROFILES.Gaussian.name,
|
|
475
|
+
'tip': 'Select the type of fourier filter',
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
'name': 'Pass Type',
|
|
479
|
+
'type': 'list',
|
|
480
|
+
'limits': FourierFilter.PASS_TYPES.values(),
|
|
481
|
+
'value': FourierFilter.PASS_TYPES.Band.name,
|
|
482
|
+
'tip': 'Select the type of pass filter',
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
'name': 'Center',
|
|
486
|
+
'type': 'float',
|
|
487
|
+
'value': self.parameters['center'],
|
|
488
|
+
'limits': [0.0, 2096.0],
|
|
489
|
+
'step': 0.5,
|
|
490
|
+
'decimals': 2,
|
|
491
|
+
'tip': 'Center frequency in pixels.',
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
'name': 'Width',
|
|
495
|
+
'type': 'float',
|
|
496
|
+
'value': 90,
|
|
497
|
+
'limits': [0.0, 2096.0],
|
|
498
|
+
'step': 0.5,
|
|
499
|
+
'decimals': 2,
|
|
500
|
+
'tip': 'The width of the band in pixels',
|
|
501
|
+
},
|
|
502
|
+
{
|
|
503
|
+
'name': 'Order',
|
|
504
|
+
'type': 'int',
|
|
505
|
+
'value': 5,
|
|
506
|
+
'limits': [1, 10],
|
|
507
|
+
'step': 1,
|
|
508
|
+
'tip': 'The order of the Butterworth filter',
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
'name': 'Show Filter',
|
|
512
|
+
'type': 'bool',
|
|
513
|
+
'value': self._show_filter,
|
|
514
|
+
'tip': 'Toggle to show or hide the filter',
|
|
515
|
+
},
|
|
516
|
+
],
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
class BackgroundReduction(SpatialFilter):
|
|
521
|
+
METHODS = [
|
|
522
|
+
'Rolling Ball',
|
|
523
|
+
'White Top Hat',
|
|
524
|
+
]
|
|
525
|
+
|
|
526
|
+
def __init__(self, radius: float = 30.0) -> None:
|
|
527
|
+
'''Rolling ball filter initialization.'''
|
|
528
|
+
params = {
|
|
529
|
+
'radius': radius,
|
|
530
|
+
'method': 'Rolling Ball',
|
|
531
|
+
}
|
|
532
|
+
super().__init__(name='Background Reduction', parameters=params)
|
|
533
|
+
self.set_params(radius)
|
|
534
|
+
|
|
535
|
+
def set_params(self, radius: float, method='Rolling Ball'):
|
|
536
|
+
'''Set the radius parameter fand the method.'''
|
|
537
|
+
self.parameters['radius'] = radius
|
|
538
|
+
|
|
539
|
+
if method not in self.METHODS:
|
|
540
|
+
raise ValueError(f'Method {method} not supported.')
|
|
541
|
+
|
|
542
|
+
self.parameters['method'] = method
|
|
543
|
+
|
|
544
|
+
def run(self, image: np.ndarray) -> np.ndarray:
|
|
545
|
+
if self.parameters['method'] == self.METHODS[0]:
|
|
546
|
+
return image - rolling_ball(image, radius=self.parameters['radius'])
|
|
547
|
+
elif self.parameters['method'] == self.METHODS[1]:
|
|
548
|
+
return white_tophat(image, disk(self.parameters['radius']))
|
|
549
|
+
|
|
550
|
+
return image
|
|
551
|
+
|
|
552
|
+
def get_tree_parameters(self):
|
|
553
|
+
'''Return the parameters for the pyqtgraph tree view.'''
|
|
554
|
+
return {
|
|
555
|
+
'name': self.name,
|
|
556
|
+
'type': 'group',
|
|
557
|
+
'visible': False,
|
|
558
|
+
'children': [
|
|
559
|
+
{
|
|
560
|
+
'name': 'Radius',
|
|
561
|
+
'type': 'float',
|
|
562
|
+
'value': self.parameters['radius'],
|
|
563
|
+
'limits': [0.0, 250.0],
|
|
564
|
+
'step': 0.1,
|
|
565
|
+
'decimals': 2,
|
|
566
|
+
'tip': 'Radius of the rolling ball in pixels',
|
|
567
|
+
},
|
|
568
|
+
{
|
|
569
|
+
'name': 'Method',
|
|
570
|
+
'type': 'list',
|
|
571
|
+
'limits': self.METHODS,
|
|
572
|
+
'value': self.parameters['method'],
|
|
573
|
+
'tip': 'Select the method for background reduction',
|
|
574
|
+
},
|
|
575
|
+
],
|
|
576
|
+
}
|