diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index d4a2c44..0000000 --- a/.editorconfig +++ /dev/null @@ -1,21 +0,0 @@ -# http://editorconfig.org - -root = true - -[*] -indent_style = space -indent_size = 4 -trim_trailing_whitespace = true -insert_final_newline = true -charset = utf-8 -end_of_line = lf - -[*.bat] -indent_style = tab -end_of_line = crlf - -[LICENSE] -insert_final_newline = false - -[Makefile] -indent_style = tab diff --git a/AUTHORS.rst b/AUTHORS.rst deleted file mode 100644 index e0f2a04..0000000 --- a/AUTHORS.rst +++ /dev/null @@ -1,13 +0,0 @@ -======= -Credits -======= - -Development Lead ----------------- - -* Hadrien Mariaccia - -Contributors ------------- - -None yet. Why not be the first? diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index b7b9336..0000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,128 +0,0 @@ -.. highlight:: shell - -============ -Contributing -============ - -Contributions are welcome, and they are greatly appreciated! Every little bit -helps, and credit will always be given. - -You can contribute in many ways: - -Types of Contributions ----------------------- - -Report Bugs -~~~~~~~~~~~ - -Report bugs at https://github.com/ykemiche/deepdespeckling/issues. - -If you are reporting a bug, please include: - -* Your operating system name and version. -* Any details about your local setup that might be helpful in troubleshooting. -* Detailed steps to reproduce the bug. - -Fix Bugs -~~~~~~~~ - -Look through the GitHub issues for bugs. Anything tagged with "bug" and "help -wanted" is open to whoever wants to implement it. - -Implement Features -~~~~~~~~~~~~~~~~~~ - -Look through the GitHub issues for features. Anything tagged with "enhancement" -and "help wanted" is open to whoever wants to implement it. - -Write Documentation -~~~~~~~~~~~~~~~~~~~ - -deepdespeckling could always use more documentation, whether as part of the -official deepdespeckling docs, in docstrings, or even on the web in blog posts, -articles, and such. - -Submit Feedback -~~~~~~~~~~~~~~~ - -The best way to send feedback is to file an issue at https://github.com/ykemiche/deepdespeckling/issues. - -If you are proposing a feature: - -* Explain in detail how it would work. -* Keep the scope as narrow as possible, to make it easier to implement. -* Remember that this is a volunteer-driven project, and that contributions - are welcome :) - -Get Started! ------------- - -Ready to contribute? Here's how to set up `deepdespeckling` for local development. - -1. Fork the `deepdespeckling` repo on GitHub. -2. Clone your fork locally:: - - $ git clone git@github.com:your_name_here/deepdespeckling.git - -3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:: - - $ mkvirtualenv deepdespeckling - $ cd deepdespeckling/ - $ python setup.py develop - -4. Create a branch for local development:: - - $ git checkout -b name-of-your-bugfix-or-feature - - Now you can make your changes locally. - -5. When you're done making changes, check that your changes pass flake8 and the - tests, including testing other Python versions with tox:: - - $ flake8 deepdespeckling tests - $ python setup.py test or pytest - $ tox - - To get flake8 and tox, just pip install them into your virtualenv. - -6. Commit your changes and push your branch to GitHub:: - - $ git add . - $ git commit -m "Your detailed description of your changes." - $ git push origin name-of-your-bugfix-or-feature - -7. Submit a pull request through the GitHub website. - -Pull Request Guidelines ------------------------ - -Before you submit a pull request, check that it meets these guidelines: - -1. The pull request should include tests. -2. If the pull request adds functionality, the docs should be updated. Put - your new functionality into a function with a docstring, and add the - feature to the list in README.rst. -3. The pull request should work for Python 3.5, 3.6, 3.7 and 3.8, and for PyPy. Check - https://travis-ci.com/ykemiche/deepdespeckling/pull_requests - and make sure that the tests pass for all supported Python versions. - -Tips ----- - -To run a subset of tests:: - - - $ python -m unittest tests.test_deepdespeckling - -Deploying ---------- - -A reminder for the maintainers on how to deploy. -Make sure all your changes are committed (including an entry in HISTORY.rst). -Then run:: - -$ bump2version patch # possible: major / minor / patch -$ git push -$ git push --tags - -Travis will then deploy to PyPI if tests pass. diff --git a/HISTORY.rst b/HISTORY.rst deleted file mode 100644 index 1d56d92..0000000 --- a/HISTORY.rst +++ /dev/null @@ -1,8 +0,0 @@ -======= -History -======= - -0.1.0 (2022-05-09) ------------------- - -* First release on PyPI. diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 816b7a9..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,15 +0,0 @@ -include AUTHORS.rst -include CONTRIBUTING.rst -include HISTORY.rst -include LICENSE -include README.rst - -recursive-include tests * - -recursive-include deepdespeckling/merlin/test/saved_model * -recursive-include deepdespeckling/merlin/train/saved_model * - -recursive-exclude * __pycache__ -recursive-exclude * *.py[co] - -recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif *.pth diff --git a/Makefile b/Makefile index 236d5ba..4ddecab 100644 --- a/Makefile +++ b/Makefile @@ -1,87 +1,10 @@ -.PHONY: clean clean-build clean-pyc clean-test coverage dist docs help install lint lint/flake8 -.DEFAULT_GOAL := help - -define BROWSER_PYSCRIPT -import os, webbrowser, sys - -from urllib.request import pathname2url - -webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1]))) -endef -export BROWSER_PYSCRIPT - -define PRINT_HELP_PYSCRIPT -import re, sys - -for line in sys.stdin: - match = re.match(r'^([a-zA-Z_-]+):.*?## (.*)$$', line) - if match: - target, help = match.groups() - print("%-20s %s" % (target, help)) -endef -export PRINT_HELP_PYSCRIPT - -BROWSER := python -c "$$BROWSER_PYSCRIPT" - -help: - @python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST) - -clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts - -clean-build: ## remove build artifacts - rm -fr build/ - rm -fr dist/ - rm -fr .eggs/ - find . -name '*.egg-info' -exec rm -fr {} + - find . -name '*.egg' -exec rm -f {} + - -clean-pyc: ## remove Python file artifacts - find . -name '*.pyc' -exec rm -f {} + - find . -name '*.pyo' -exec rm -f {} + - find . -name '*~' -exec rm -f {} + - find . -name '__pycache__' -exec rm -fr {} + - -clean-test: ## remove test and coverage artifacts - rm -fr .tox/ - rm -f .coverage - rm -fr htmlcov/ - rm -fr .pytest_cache - -lint/flake8: ## check style with flake8 - flake8 deepdespeckling tests - -lint: lint/flake8 ## check style - -test: ## run tests quickly with the default Python - python setup.py test - -test-all: ## run tests on every Python version with tox - tox - -coverage: ## check code coverage quickly with the default Python - coverage run --source deepdespeckling setup.py test - coverage report -m - coverage html - $(BROWSER) htmlcov/index.html - -docs: ## generate Sphinx HTML documentation, including API docs - rm -f docs/deepdespeckling.rst - rm -f docs/modules.rst - sphinx-apidoc -o docs/ deepdespeckling - $(MAKE) -C docs clean - $(MAKE) -C docs html - $(BROWSER) docs/_build/html/index.html - -servedocs: docs ## compile the docs watching for changes - watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D . - -release: dist ## package and upload a release - twine upload dist/* - -dist: clean ## builds source and wheel package - python setup.py sdist - python setup.py bdist_wheel - ls -l dist - -install: clean ## install the package to the active Python's site-packages - python setup.py install +# this target runs checks on all files +quality: + isort . -c + flake8 + mypy + black --check . +# this target runs checks on all files and potentially modifies some of them +style: + isort . + black . \ No newline at end of file diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index bf630ee..0000000 --- a/docs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = python -msphinx -SPHINXPROJ = deepdespeckling -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/authors.rst b/docs/authors.rst deleted file mode 100644 index e122f91..0000000 --- a/docs/authors.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../AUTHORS.rst diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index 0f79b23..0000000 --- a/docs/conf.py +++ /dev/null @@ -1,162 +0,0 @@ -#!/usr/bin/env python -# -# deepdespeckling documentation build configuration file, created by -# sphinx-quickstart on Fri Jun 9 13:47:02 2017. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# If extensions (or modules to document with autodoc) are in another -# directory, add these directories to sys.path here. If the directory is -# relative to the documentation root, use os.path.abspath to make it -# absolute, like shown here. -# -import os -import sys -sys.path.insert(0, os.path.abspath('..')) - -import deepdespeckling - -# -- General configuration --------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = 'deepdespeckling' -copyright = "2022, youcef kemiche" -author = "youcef kemiche" - -# The version info for the project you're documenting, acts as replacement -# for |version| and |release|, also used in various other places throughout -# the built documents. -# -# The short X.Y version. -version = deepdespeckling.__version__ -# The full version, including alpha/beta/rc tags. -release = deepdespeckling.__version__ - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = False - - -# -- Options for HTML output ------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'alabaster' - -# Theme options are theme-specific and customize the look and feel of a -# theme further. For a list of options available for each theme, see the -# documentation. -# -# html_theme_options = {} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - - -# -- Options for HTMLHelp output --------------------------------------- - -# Output file base name for HTML help builder. -htmlhelp_basename = 'deepdespecklingdoc' - - -# -- Options for LaTeX output ------------------------------------------ - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass -# [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'deepdespeckling.tex', - 'deepdespeckling Documentation', - 'youcef kemiche', 'manual'), -] - - -# -- Options for manual page output ------------------------------------ - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'deepdespeckling', - 'deepdespeckling Documentation', - [author], 1) -] - - -# -- Options for Texinfo output ---------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'deepdespeckling', - 'deepdespeckling Documentation', - author, - 'deepdespeckling', - 'One line description of project.', - 'Miscellaneous'), -] - - - diff --git a/docs/contributing.rst b/docs/contributing.rst deleted file mode 100644 index e582053..0000000 --- a/docs/contributing.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../CONTRIBUTING.rst diff --git a/docs/history.rst b/docs/history.rst deleted file mode 100644 index 2506499..0000000 --- a/docs/history.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../HISTORY.rst diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index 5a14e24..0000000 --- a/docs/index.rst +++ /dev/null @@ -1,20 +0,0 @@ -Welcome to deepdespeckling's documentation! -====================================== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - readme - installation - usage - modules - contributing - authors - history - -Indices and tables -================== -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/installation.rst b/docs/installation.rst deleted file mode 100644 index 5ff1d16..0000000 --- a/docs/installation.rst +++ /dev/null @@ -1,51 +0,0 @@ -.. highlight:: shell - -============ -Installation -============ - - -Stable release --------------- - -To install deepdespeckling, run this command in your terminal: - -.. code-block:: console - - $ pip install deepdespeckling - -This is the preferred method to install deepdespeckling, as it will always install the most recent stable release. - -If you don't have `pip`_ installed, this `Python installation guide`_ can guide -you through the process. - -.. _pip: https://pip.pypa.io -.. _Python installation guide: http://docs.python-guide.org/en/latest/starting/installation/ - - -From sources ------------- - -The sources for deepdespeckling can be downloaded from the `Github repo`_. - -You can either clone the public repository: - -.. code-block:: console - - $ git clone git://github.com/ykemiche/deepdespeckling - -Or download the `tarball`_: - -.. code-block:: console - - $ curl -OJL https://github.com/ykemiche/deepdespeckling/tarball/master - -Once you have a copy of the source, you can install it with: - -.. code-block:: console - - $ python setup.py install - - -.. _Github repo: https://github.com/ykemiche/deepdespeckling -.. _tarball: https://github.com/ykemiche/deepdespeckling/tarball/master diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index ec3bf90..0000000 --- a/docs/make.bat +++ /dev/null @@ -1,36 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=python -msphinx -) -set SOURCEDIR=. -set BUILDDIR=_build -set SPHINXPROJ=deepdespeckling - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The Sphinx module was not found. Make sure you have Sphinx installed, - echo.then set the SPHINXBUILD environment variable to point to the full - echo.path of the 'sphinx-build' executable. Alternatively you may add the - echo.Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% - -:end -popd diff --git a/docs/readme.rst b/docs/readme.rst deleted file mode 100644 index 72a3355..0000000 --- a/docs/readme.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../README.rst diff --git a/docs/usage.rst b/docs/usage.rst deleted file mode 100644 index 00ed3b1..0000000 --- a/docs/usage.rst +++ /dev/null @@ -1,7 +0,0 @@ -===== -Usage -===== - -To use deepdespeckling in a project:: - - import deepdespeckling diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 9a2e744..0000000 --- a/requirements.txt +++ /dev/null @@ -1,55 +0,0 @@ -appnope==0.1.3 -asttokens==2.4.0 -backcall==0.2.0 -black==23.10.1 -click==8.1.7 -comm==0.1.4 -debugpy==1.8.0 -decorator==5.1.1 --e git+https://github.com/hi-paris/deepdespeckling.git@9d9c36b063ace2282e35b6c91e3791271a60c887#egg=deepdespeckling -exceptiongroup==1.1.3 -executing==2.0.0 -filelock==3.12.4 -fsspec==2023.10.0 -GDAL==3.8.1 -importlib-metadata==6.8.0 -ipykernel==6.26.0 -ipython==8.16.1 -jedi==0.19.1 -Jinja2==3.1.2 -jupyter_client==8.5.0 -jupyter_core==5.4.0 -MarkupSafe==2.1.3 -matplotlib-inline==0.1.6 -mpmath==1.3.0 -mypy-extensions==1.0.0 -nest-asyncio==1.5.8 -networkx==3.2 -numpy==1.26.1 -opencv-python==4.8.1.78 -packaging==23.2 -parso==0.8.3 -pathspec==0.11.2 -pexpect==4.8.0 -pickleshare==0.7.5 -Pillow==10.1.0 -platformdirs==3.11.0 -prompt-toolkit==3.0.39 -psutil==5.9.6 -ptyprocess==0.7.0 -pure-eval==0.2.2 -Pygments==2.16.1 -python-dateutil==2.8.2 -pyzmq==25.1.1 -scipy==1.11.3 -six==1.16.0 -stack-data==0.6.3 -sympy==1.12 -tomli==2.0.1 -torch==2.1.0 -tornado==6.3.3 -tqdm==4.66.1 -traitlets==5.12.0 -typing_extensions==4.8.0 -wcwidth==0.2.8 -zipp==3.17.0 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index efc7f3a..0000000 --- a/setup.cfg +++ /dev/null @@ -1,18 +0,0 @@ -[bumpversion] -current_version = 0.2.0 -commit = True -tag = True - -[bumpversion:file:setup.py] -search = version='{current_version}' -replace = version='{new_version}' - -[bumpversion:file:deepdespeckling/__init__.py] -search = __version__ = '{current_version}' -replace = __version__ = '{new_version}' - -[bdist_wheel] -universal = 1 - -[flake8] -exclude = docs diff --git a/setup.py b/setup.py index 12c1f17..c9ed90e 100644 --- a/setup.py +++ b/setup.py @@ -4,15 +4,12 @@ from setuptools import setup, find_packages -with open('HISTORY.rst') as history_file: - history = history_file.read() - requirements = [] test_requirements = [] setup( author="Emanuele Dalsasso, Youcef Kemiche, Pierre Blanchard, Hadrien Mariaccia", - author_email='y.kemiche06@hotmail.com', + author_email='engineer@hi-paris.fr', python_requires='>=3.6', classifiers=[ 'Development Status :: 2 - Pre-Alpha', @@ -29,6 +26,7 @@ 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', ], description="Python Boilerplate contains all the boilerplate you need to create a Python package.", entry_points={ @@ -36,7 +34,8 @@ 'deepdespeckling=deepdespeckling.cli:main', ], }, - install_requires=["numpy","Pillow","scipy","torch","opencv-python","tqdm"], + install_requires=["numpy", "Pillow", "scipy", + "torch", "opencv-python", "tqdm", "GDAL==3.8.1"], license="MIT license", include_package_data=True, keywords='deepdespeckling', diff --git a/tests/merlin/test/test_utils.py b/tests/merlin/test/test_utils.py deleted file mode 100644 index 918d91b..0000000 --- a/tests/merlin/test/test_utils.py +++ /dev/null @@ -1,478 +0,0 @@ -import numpy as np -from PIL import Image -from scipy import special -from scipy import signal -from deepdespeckling.merlin.inference.load_cosar import cos2mat -import cv2 -from PIL import Image -import numpy as np -from numpy import asarray - - -# DEFINE PARAMETERS OF SPECKLE AND NORMALIZATION FACTOR -M = 10.089038980848645 -m = -1.429329123112601 -L = 1 -c = (1 / 2) * (special.psi(L) - np.log(L)) -cn = c / (M - m) # normalized (0,1) mean of log speckle - - -def normalize_sar(im): - """ Description - ---------- - Normalization of a numpy-stored image - - Parameters - ---------- - im : an image object - - Returns - ---------- - - """ - if not isinstance(im, np.ndarray): - raise TypeError('Please provide a .npy argument') - return ((np.log(im + np.spacing(1)) - m) * 255 / (M - m)).astype('float32') - - -def denormalize_sar(im): - """ Description - ---------- - Denormalization of a numpy image - - Parameters - ---------- - im : an image object - - Returns - ---------- - - """ - if not isinstance(im, np.ndarray): - raise TypeError('Please provide a .npy argument') - return np.exp((M - m) * (np.squeeze(im)).astype('float32') + m) - - -def symetrisation_patch_test(real_part, imag_part): - if not isinstance(real_part, np.ndarray): - raise TypeError('Please provide a .npy argument') - if not isinstance(imag_part, np.ndarray): - raise TypeError('Please provide a .npy argument') - S = np.fft.fftshift(np.fft.fft2( - real_part[0, :, :, 0] + 1j * imag_part[0, :, :, 0])) - p = np.zeros((S.shape[0])) # azimut (ncol) - for i in range(S.shape[0]): - p[i] = np.mean(np.abs(S[i, :])) - sp = p[::-1] - c = np.real(np.fft.ifft(np.fft.fft(p) * np.conjugate(np.fft.fft(sp)))) - d1 = np.unravel_index(c.argmax(), p.shape[0]) - d1 = d1[0] - shift_az_1 = int(round(-(d1 - 1) / 2)) % p.shape[0] + int(p.shape[0] / 2) - p2_1 = np.roll(p, shift_az_1) - shift_az_2 = int( - round(-(d1 - 1 - p.shape[0]) / 2)) % p.shape[0] + int(p.shape[0] / 2) - p2_2 = np.roll(p, shift_az_2) - window = signal.gaussian(p.shape[0], std=0.2 * p.shape[0]) - test_1 = np.sum(window * p2_1) - test_2 = np.sum(window * p2_2) - # make sure the spectrum is symetrized and zeo-Doppler centered - if test_1 >= test_2: - p2 = p2_1 - shift_az = shift_az_1 / p.shape[0] - else: - p2 = p2_2 - shift_az = shift_az_2 / p.shape[0] - S2 = np.roll(S, int(shift_az * p.shape[0]), axis=0) - - q = np.zeros((S.shape[1])) # range (nlin) - for j in range(S.shape[1]): - q[j] = np.mean(np.abs(S[:, j])) - sq = q[::-1] - # correlation - cq = np.real(np.fft.ifft(np.fft.fft(q) * np.conjugate(np.fft.fft(sq)))) - d2 = np.unravel_index(cq.argmax(), q.shape[0]) - d2 = d2[0] - shift_range_1 = int(round(-(d2 - 1) / 2) - ) % q.shape[0] + int(q.shape[0] / 2) - q2_1 = np.roll(q, shift_range_1) - shift_range_2 = int( - round(-(d2 - 1 - q.shape[0]) / 2)) % q.shape[0] + int(q.shape[0] / 2) - q2_2 = np.roll(q, shift_range_2) - window_r = signal.gaussian(q.shape[0], std=0.2 * q.shape[0]) - test_1 = np.sum(window_r * q2_1) - test_2 = np.sum(window_r * q2_2) - if test_1 >= test_2: - q2 = q2_1 - shift_range = shift_range_1 / q.shape[0] - else: - q2 = q2_2 - shift_range = shift_range_2 / q.shape[0] - - Sf = np.roll(S2, int(shift_range * q.shape[0]), axis=1) - ima2 = np.fft.ifft2(np.fft.ifftshift(Sf)) - ima2 = ima2.reshape(1, np.size(ima2, 0), np.size(ima2, 1), 1) - return np.real(ima2), np.imag(ima2) - - -def load_sar_images(filelist): - """ Description - ---------- - Loads files , resize them and append them into a list called data - - Parameters - ---------- - filelist : a path to a folder containing the images - - Returns - ---------- - A list of images - - """ - if not isinstance(filelist, list): - im = np.load(filelist) - return np.array(im).reshape(1, np.size(im, 0), np.size(im, 1), 2) - data = [] - for file in filelist: - im = np.load(file) - data.append(np.array(im).reshape(1, np.size(im, 0), np.size(im, 1), 2)) - return data - - -def store_data_and_plot(im, threshold, filename): - """ Description - ---------- - Creates an image memory from an object exporting the array interface and returns a - converted copy of this image into greyscale mode ("L") - - However, there is not plotting functions' call ? - - Parameters - ---------- - im : the image to store - threshold: clip a maximum value in the image array i.e values are to be between 0 and threshold - filename: the path to store the result array image in .png - - Returns - ---------- - None - - """ - if not isinstance(im, np.ndarray): - raise TypeError('Please provide a .npy argument') - im = np.clip(im, 0, threshold) - - im = im / threshold * 255 - im = Image.fromarray(im.astype('float64')).convert('L') - im.save(filename.replace('npy', 'png')) - return filename - - -def save_sar_images(denoised, noisy, imagename, save_dir, groundtruth=None): - choices = {'marais1': 190.92, 'marais2': 168.49, 'saclay': 470.92, 'lely': 235.90, 'ramb': 167.22, - 'risoul': 306.94, 'limagne': 178.43, 'saintgervais': 560, 'Serreponcon': 450.0, - 'Sendai': 600.0, 'Paris': 1291.0, 'Berlin': 1036.0, 'Bergen': 553.71, - 'SDP_Lambesc': 349.53, 'Grand_Canyon': 287.0, 'domancy': 560, 'Brazil': 103.0} - threshold = None - for x in choices: - if x in imagename: - threshold = choices.get(x) - if threshold is None: - threshold = np.mean(noisy) + 3 * np.std(noisy) - - #### - imagename = imagename.split('\\')[-1] - #### - - if groundtruth: - groundtruthfilename = save_dir + "/groundtruth_" + imagename - np.save(groundtruthfilename, groundtruth) - store_data_and_plot(groundtruth, threshold, groundtruthfilename) - - denoisedfilename = save_dir + "/denoised_" + imagename - np.save(denoisedfilename, denoised) - store_data_and_plot(denoised, threshold, denoisedfilename) - - noisyfilename = save_dir + "/noisy_" + imagename - np.save(noisyfilename, noisy) - store_data_and_plot(noisy, threshold, noisyfilename) - - -def save_real_imag_images(real_part, imag_part, imagename, save_dir): - choices = {'marais1': 190.92, 'marais2': 168.49, 'saclay': 470.92, 'lely': 235.90, 'ramb': 167.22, - 'risoul': 306.94, 'limagne': 178.43, 'saintgervais': 560, 'Serreponcon': 450.0, - 'Sendai': 600.0, 'Paris': 1291.0, 'Berlin': 1036.0, 'Bergen': 553.71, - 'SDP_Lambesc': 349.53, 'Grand_Canyon': 287.0, 'Brazil': 103.0} - threshold = None - for x in choices: - if x in imagename: - threshold = choices.get(x) - if threshold is None: - threshold = np.mean(imag_part) + 3 * np.std(imag_part) - - #### - imagename = imagename.split('\\')[-1] - #### - - realfilename = save_dir + "/denoised_real_" + imagename - np.save(realfilename, real_part) - store_data_and_plot(real_part, threshold, realfilename) - - imagfilename = save_dir + "/denoised_imag_" + imagename - np.save(imagfilename, imag_part) - store_data_and_plot(imag_part, threshold, imagfilename) - - -def save_real_imag_images_noisy(real_part, imag_part, imagename, save_dir): - choices = {'marais1': 190.92, 'marais2': 168.49, 'saclay': 470.92, 'lely': 235.90, 'ramb': 167.22, - 'risoul': 306.94, 'limagne': 178.43, 'saintgervais': 560, 'Serreponcon': 450.0, - 'Sendai': 600.0, 'Paris': 1291.0, 'Berlin': 1036.0, 'Bergen': 553.71, - 'SDP_Lambesc': 349.53, 'Grand_Canyon': 287.0, 'Brazil': 103.0} - threshold = None - for x in choices: - if x in imagename: - threshold = choices.get(x) - if threshold is None: - threshold = np.mean(np.abs(imag_part)) + 3 * np.std(np.abs(imag_part)) - - #### - imagename = imagename.split('\\')[-1] - #### - - realfilename = save_dir + "/noisy_real_" + imagename - np.save(realfilename, real_part) - store_data_and_plot(np.sqrt(2) * np.abs(real_part), - threshold, realfilename) - - imagfilename = save_dir + "/noisy_imag_" + imagename - np.save(imagfilename, imag_part) - store_data_and_plot(np.sqrt(2) * np.abs(imag_part), - threshold, imagfilename) - - -def cal_psnr(Shat, S): - # takes amplitudes in input - # Shat: a SAR amplitude image - # S: a reference SAR image - P = np.quantile(S, 0.99) - res = 10 * np.log10((P ** 2) / np.mean(np.abs(Shat - S) ** 2)) - return res - - -def crop(image_png, image_data_real, image_data_imag, destination_directory, test_data): - """ A crapping tool for despeckling only the selection of the user, made with OpenCV - Parameters - ---------- - image_png: .png file - the image to be cropped in png format - image_data_real: nd.array - the real part of the image stored in an array - image_data_imag: nd.array - the imaginary part of the image stored in an array - destination_directory: string - the path for saving results in - test_data: string - the path for saving results in - cropping: bool - A boolean stating if the user wants to crop the image or not - Returns - ---------- - None - """ - # HERE I READ THE PNG FILE - oriImage = image_png.copy() - cropping = False - x_start, y_start, x_end, y_end = 0, 0, 0, 0 - - # CV2 CROPPING IN WINDOW - def mouse_crop(event, x, y, flags, param): - """ The callback function of crop() to deal with user's events - """ - global x_start, y_start, x_end, y_end, cropping - cropping = False - - if event == cv2.EVENT_LBUTTONDOWN: - x_start, y_start, x_end, y_end = x, y, x, y - cropping = True - - # Mouse is Moving - elif event == cv2.EVENT_MOUSEMOVE: - x_end, y_end = x, y - - # if the left mouse button was released - elif event == cv2.EVENT_LBUTTONUP: - # record the ending (x, y) coordinates - x_end, y_end = x, y - # cropping is finished - cv2.rectangle(image, (x_start, y_start), (x, y), (255, 0, 0), 2) - cropping = False - - refPoint = [(x_start, y_start), (x_end, y_end)] - - if len(refPoint) == 2: # when two points were found - image_data_real_cropped = image_data_real[refPoint[0][1] * 8:refPoint[1][1] * 8, - refPoint[0][0] * 8:refPoint[1][0] * 8] - image_data_imag_cropped = image_data_imag[refPoint[0][1] * 8:refPoint[1][1] * 8, - refPoint[0][0] * 8:refPoint[1][0] * 8] - - roi = oriImage[refPoint[0][1] * 8:refPoint[1][1] - * 8, refPoint[0][0] * 8:refPoint[1][0] * 8] - roi = cv2.resize( - roi, (8 * (x_end - x_start), 8 * (y_end - y_start))) - - cv2.imwrite(destination_directory + - '\\cropped_npy_to_png.png', roi) - cv2.imshow("Cropped", roi) - cropped_img_png = Image.open( - destination_directory + '\\cropped_npy_to_png.png') - numpy_crop = asarray(cropped_img_png) - np.save(destination_directory + '\\cropped.npy', numpy_crop) - np.save(test_data + '\\image_data_real_cropped.npy', - image_data_real_cropped) - np.save(test_data + '\\image_data_imag_cropped.npy', - image_data_imag_cropped) - - h, w, c = image_png.shape - # resizing image - image = cv2.resize(image_png, (int(w / 8), int(h / 8))) - cv2.namedWindow("image") - cv2.setMouseCallback("image", mouse_crop) - - while True: - i = image.copy() - - if not cropping: - cv2.imshow("image", image) - - elif cropping: - cv2.imshow("image", i) - cv2.rectangle(i, (x_start, y_start), - (x_end, y_end), (255, 0, 0), 2) - - key = cv2.waitKey(10) - if key == ord('q'): - cv2.destroyAllWindows() - return - - -def crop_fixed(image_png, image_data_real, image_data_imag, destination_directory, test_data): - """ A crapping tool for despeckling only the selection of the user, made with OpenCV - Parameters - ---------- - image_png: .png file - the image to be cropped in png format - image_data_real: nd.array - the real part of the image stored in an array - image_data_imag: nd.array - the imaginary part of the image stored in an array - destination_directory: string - the path for saving results in - test_data: string - the path for saving results in - cropping: bool - A boolean stating if the user wants to crop the image or not - Returns - ---------- - None - """ - # HERE I READ THE PNG FILE - oriImage = image_png.copy() - cropping = False - x_start, y_start, x_end, y_end = 0, 0, 0, 0 - - # CV2 CROPPING IN WINDOW - def mouse_crop_fixed(event, x, y, flags, param): - """ The callback function of crop() to deal with user's events - """ - global x_start, y_start, x_end, y_end, cropping - cropping = False - if event == cv2.EVENT_LBUTTONDOWN: - x_start, y_start, x_end, y_end = x, y, x, y - cropping = True - - # Mouse is Moving - elif event == cv2.EVENT_MOUSEMOVE: - cv2.rectangle(image, (x_start, y_start), - (x_start + 32, y_start + 32), (255, 0, 0), 2) - x_end, y_end = x, y - - # if the left mouse button was released - elif event == cv2.EVENT_LBUTTONUP: - # record the ending (x, y) coordinates - x_end, y_end = x_start + 32, y_start + 32 - cropping = False # cropping is finished - - refPoint = [(x_start, y_start), (x_end, y_end)] - - if len(refPoint) == 2: # when two points were found - image_data_real_cropped = image_data_real[refPoint[0][1] * 8:refPoint[1][1] * 8, - refPoint[0][0] * 8:refPoint[1][0] * 8] - image_data_imag_cropped = image_data_imag[refPoint[0][1] * 8:refPoint[1][1] * 8, - refPoint[0][0] * 8:refPoint[1][0] * 8] - roi = oriImage[refPoint[0][1] * 8:refPoint[1][1] - * 8, refPoint[0][0] * 8:refPoint[1][0] * 8] - roi = cv2.resize(roi, (256, 256)) - cv2.imwrite(destination_directory + - '\\cropped_npy_to_png.png', roi) - cv2.imshow("Cropped", roi) - cropped_img_png = Image.open( - destination_directory + '\\cropped_npy_to_png.png') - numpy_crop = asarray(cropped_img_png) - np.save(destination_directory + '\\cropped.npy', numpy_crop) - np.save(test_data + '\\image_data_real_cropped.npy', - image_data_real_cropped) - np.save(test_data + '\\image_data_imag_cropped.npy', - image_data_imag_cropped) - - h, w, c = image_png.shape - # resizing image - image = cv2.resize(image_png, (int(w / 8), int(h / 8))) - cv2.namedWindow("image") - cv2.setMouseCallback("image", mouse_crop_fixed) - - while True: - i = image.copy() - - if not cropping: - cv2.imshow("image", image) - - elif cropping: - cv2.imshow("image", i) - - key = cv2.waitKey(10) - if key == ord('q'): - cv2.destroyAllWindows() - return - - -def get_info_image(image_path, destination_directory): - """ A function for retrieving informations on the CoSar stored image such as its png equivalent, its real and - imaginary part and the threshold to be applied later - Parameters - ---------- - image_path: string - the path leading to image in CoSar format - destination_directory: string - the path for saving results in - Returns - ---------- - None - """ - image_data = cos2mat(image_path) - - # GET THE TWO PARTS - image_data_real = image_data[:, :, 0] - image_data_imag = image_data[:, :, 1] - - # GET NOISY FOR THRESHOLD - image = np.squeeze( - np.sqrt(np.square(image_data_real) + np.square(image_data_imag))) - threshold = np.mean(image) + 3 * np.std(image) - - # DISPLAY FULL PICTURE - filename = store_data_and_plot( - image, threshold, destination_directory + '\\image_provided.npy') - print('full picture in png is saved') - image_png = cv2.imread(filename.replace('npy', 'png')) - print('full picture in png has a dimension of {size}'.format( - size=image_png.shape)) - return image_png, image_data, image_data_real, image_data_imag, threshold, filename diff --git a/tests/sar2sar/test/__init__.py b/tests/sar2sar/test/__init__.py deleted file mode 100644 index cc2be44..0000000 --- a/tests/sar2sar/test/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -"""Top-level package for merlin.""" - -__author__ = """youcef kemiche""" -__email__ = 'y.kemiche06@hotmail.com' -__version__ = '0.1.0' - -from merlinsar.test.utils import * -from merlinsar.test.load_cosar import * -from merlinsar.test.model import * -from merlinsar.test.model_test import * -from merlinsar.test.spotlight import* \ No newline at end of file diff --git a/tests/sar2sar/test/load_cosar.py b/tests/sar2sar/test/load_cosar.py deleted file mode 100644 index f3da7d9..0000000 --- a/tests/sar2sar/test/load_cosar.py +++ /dev/null @@ -1,46 +0,0 @@ -import struct -import numpy as np - -def cos2mat(imgName): - print('Converting CoSAR to numpy array of size [ncolumns,nlines,2]') - - try: - fin = open(imgName, 'rb'); - except IOError: - legx = imgName + ': it is a not openable file' - print(legx) - print(u'failed to call cos2mat') - return 0, 0, 0, 0 - - ibib = struct.unpack(">i", fin.read(4))[0] - irsri = struct.unpack(">i", fin.read(4))[0] - irs = struct.unpack(">i", fin.read(4))[0] - ias = struct.unpack(">i", fin.read(4))[0] - ibi = struct.unpack(">i", fin.read(4))[0] - irtnb = struct.unpack(">i", fin.read(4))[0] - itnl = struct.unpack(">i", fin.read(4))[0] - - nlig = struct.unpack(">i", fin.read(4))[0] - ncoltot = int(irtnb / 4) - ncol = ncoltot - 2 - nlig = ias - - print(u'Reading image in CoSAR format. ncolumns=%d nlines=%d' % (ncol, nlig)) - - firm = np.zeros(4 * ncoltot, dtype=np.byte()) - imgcxs = np.empty([nlig, ncol], dtype=np.complex64()) - - fin.seek(0) - firm = fin.read(4 * ncoltot) - firm = fin.read(4 * ncoltot) - firm = fin.read(4 * ncoltot) - firm = fin.read(4 * ncoltot) - # - for iut in range(nlig): - firm = fin.read(4 * ncoltot) - imgligne = np.ndarray(2 * ncoltot, '>h', firm) - imgcxs[iut, :] = imgligne[4:2 * ncoltot:2] + 1j * imgligne[5:2 * ncoltot:2] - - print('[:,:,0] contains the real part of the SLC image data') - print('[:,:,1] contains the imaginary part of the SLC image data') - return np.stack((np.real(imgcxs), np.imag(imgcxs)), axis=2) \ No newline at end of file diff --git a/tests/sar2sar/test/model.py b/tests/sar2sar/test/model.py deleted file mode 100644 index 6cda078..0000000 --- a/tests/sar2sar/test/model.py +++ /dev/null @@ -1,154 +0,0 @@ -import time -import numpy as np -import os - -from merlinsar.test.utils import * -from scipy import special -import argparse - - -# DEFINE PARAMETERS OF SPECKLE AND NORMALIZATION FACTOR -M = 10.089038980848645 -m = -1.429329123112601 -L = 1 -c = (1 / 2) * (special.psi(L) - np.log(L)) -cn = c / (M - m) # normalized (0,1) mean of log speckle - -import torch -import numpy as np - - - - -class Model(torch.nn.Module): - - def __init__(self,height,width,device): - super().__init__() - - self.device=device - - self.height = height - self.width = width - - - self.pool = torch.nn.MaxPool2d(kernel_size=2, stride=2) - self.leaky = torch.nn.LeakyReLU(0.1) - - self.enc0 = torch.nn.Conv2d(in_channels=1, out_channels=48, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.enc1 = torch.nn.Conv2d(in_channels=48, out_channels=48, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.enc2 = torch.nn.Conv2d(in_channels=48, out_channels=48, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.enc3 = torch.nn.Conv2d(in_channels=48, out_channels=48, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.enc4 = torch.nn.Conv2d(in_channels=48, out_channels=48, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.enc5 = torch.nn.Conv2d(in_channels=48, out_channels=48, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.enc6 = torch.nn.Conv2d(in_channels=48, out_channels=48, kernel_size=(3, 3), stride=(1, 1), - padding='same') - - self.dec5 = torch.nn.Conv2d(in_channels=96, out_channels=96, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.dec5b = torch.nn.Conv2d(in_channels=96, out_channels=96, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.dec4 = torch.nn.Conv2d(in_channels=144, out_channels=96, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.dec4b = torch.nn.Conv2d(in_channels=96, out_channels=96, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.dec3 = torch.nn.Conv2d(in_channels=144, out_channels=96, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.dec3b = torch.nn.Conv2d(in_channels=96, out_channels=96, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.dec2 = torch.nn.Conv2d(in_channels=144, out_channels=96, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.dec2b = torch.nn.Conv2d(in_channels=96, out_channels=96, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.dec1a = torch.nn.Conv2d(in_channels=97, out_channels=64, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.dec1b = torch.nn.Conv2d(in_channels=64, out_channels=32, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.dec1 = torch.nn.Conv2d(in_channels=32, out_channels=1, kernel_size=(3, 3), stride=(1, 1), - padding='same') - - self.upscale2d = torch.nn.UpsamplingNearest2d(scale_factor=2) - - - def forward(self,x): - """ Defines a class for an autoencoder algorithm for an object (image) x - - An autoencoder is a specific type of feedforward neural networks where the - input is the same as the - output. It compresses the input into a lower-dimensional code and then - reconstruct the output from this representattion. It is a dimensionality - reduction algorithm - - Parameters - ---------- - x : np.array - a numpy array containing image - - Returns - ---------- - x-n : np.array - a numpy array containing the denoised image i.e the image itself minus the noise - - """ - x=torch.reshape(x, [1, 1, self.height, self.width]) - skips = [x] - - n = x - - # ENCODER - n = self.leaky(self.enc0(n)) - n = self.leaky(self.enc1(n)) - n = self.pool(n) - skips.append(n) - - n = self.leaky(self.enc2(n)) - n = self.pool(n) - skips.append(n) - - n = self.leaky(self.enc3(n)) - n = self.pool(n) - skips.append(n) - - n = self.leaky(self.enc4(n)) - n = self.pool(n) - skips.append(n) - - n = self.leaky(self.enc5(n)) - n = self.pool(n) - n = self.leaky(self.enc6(n)) - - - # DECODER - n = self.upscale2d(n) - n = torch.cat((n, skips.pop()), dim=1) - n = self.leaky(self.dec5(n)) - n = self.leaky(self.dec5b(n)) - - n = self.upscale2d(n) - n = torch.cat((n, skips.pop()), dim=1) - n = self.leaky(self.dec4(n)) - n = self.leaky(self.dec4b(n)) - - n = self.upscale2d(n) - n = torch.cat((n, skips.pop()), dim=1) - n = self.leaky(self.dec3(n)) - n = self.leaky(self.dec3b(n)) - - n = self.upscale2d(n) - n = torch.cat((n, skips.pop()), dim=1) - n = self.leaky(self.dec2(n)) - n = self.leaky(self.dec2b(n)) - - n = self.upscale2d(n) - n = torch.cat((n, skips.pop()), dim=1) - n = self.leaky(self.dec1a(n)) - n = self.leaky(self.dec1b(n)) - - n = self.dec1(n) - - return x - n diff --git a/tests/sar2sar/test/model_test.py b/tests/sar2sar/test/model_test.py deleted file mode 100644 index 6324592..0000000 --- a/tests/sar2sar/test/model_test.py +++ /dev/null @@ -1,166 +0,0 @@ -from merlinsar.test.utils import * -from merlinsar.test.model import * -import torch -import numpy as np -from tqdm import tqdm - -M = 10.089038980848645 -m = -1.429329123112601 - -class Denoiser(object): - """ Description - ---------- - A set of initial conditions, and transformations on the Y - - Parameters - ---------- - denoiser : an object - - Returns - ---------- - """ - - - def __init__(self, input_c_dim=1): - - self.input_c_dim = input_c_dim - - - def load(self,model,weights_path): - """ Description - ---------- - Restores a checkpoint located in a checkpoint repository - - Parameters - ---------- - checkpoint_dir : a path leading to the checkpoint file - - Returns - ---------- - True : Restoration is a success - False: Restoration has failed - """ - print("[*] Loading the model...") - - model.load_state_dict(torch.load(weights_path)) - - return model - - - def test(self,test_files, weights_path, save_dir,stride,patch_size,height,width): - - """ Description - ---------- - The function that does the job. Should be merged with main.py ? - - Parameters - ---------- - test_files : a path leading to the checkpoint file - ckpt_dir : repository containing the checkpoint (and weights) - save_dir : repository to save sar images, real images and noisy images - dataset_dir : the path to the test data - stride : number of bytes from one row of pixels in memory to the next row of pixels in memory - - Returns - ---------- - True : Restoration is a success - False: Restoration has failed - - """ - - """Test MERLIN""" - - assert len(test_files) != 0, 'No testing data!' - - loaded_model = Model(height,width,torch.device("cuda:0" if torch.cuda.is_available() else "cpu")) - loaded_model.load_state_dict(torch.load(weights_path, map_location=torch.device('cpu'))) - - # loaded_model = self.load(model,weights_path) - print() - print(" [*] Load weights SUCCESS...") - print("[*] start testing...") - - for idx in range(len(test_files)): - real_image = load_sar_images(test_files[idx]).astype(np.float32) - i_real_part = (real_image[:, :, :, 0]).reshape(real_image.shape[0], real_image.shape[1], - real_image.shape[2], 1) - i_imag_part = (real_image[:, :, :, 1]).reshape(real_image.shape[0], real_image.shape[1], - real_image.shape[2], 1) - - - - # Pad the image - im_h = np.size(real_image, 1) - im_w = np.size(real_image, 2) - - count_image = np.zeros(i_real_part.shape) - output_clean_image_1 = np.zeros(i_real_part.shape) - output_clean_image_2 = np.zeros(i_real_part.shape) - - if im_h == patch_size: - x_range = list(np.array([0])) - - else: - x_range = list(range(0, im_h - patch_size, stride)) - if (x_range[-1] + patch_size) < im_h: x_range.extend(range(im_h - patch_size, im_h - patch_size + 1)) - - if im_w == patch_size: - y_range = list(np.array([0])) - - else: - y_range = list(range(0, im_w - patch_size, stride)) - if (y_range[-1] + patch_size) < im_w: y_range.extend(range(im_w - patch_size, im_w - patch_size + 1)) - - for x in tqdm(x_range): - for y in y_range: - - real_to_denoise, imag_to_denoise = symetrisation_patch_test(i_real_part[:, x:x + patch_size, y:y + patch_size, :],i_imag_part[:, x:x + patch_size, y:y + patch_size, :]) - - real_to_denoise =torch.tensor(real_to_denoise) - imag_to_denoise=torch.tensor(imag_to_denoise) - - real_to_denoise = real_to_denoise.type(torch.float32) - imag_to_denoise = imag_to_denoise.type(torch.float32) - - real_to_denoise=(torch.log(torch.square(real_to_denoise)+1e-3)-2*m)/(2*(M-m)) - imag_to_denoise=(torch.log(torch.square(imag_to_denoise)+1e-3)-2*m)/(2*(M-m)) - - - tmp_clean_image_real = loaded_model.forward(real_to_denoise).detach().numpy() - tmp_clean_image_real=np.moveaxis(tmp_clean_image_real, 1, -1) - - output_clean_image_1[:, x:x + patch_size, y:y + patch_size, :] = output_clean_image_1[:, x:x + patch_size, - y:y + patch_size, - :] + tmp_clean_image_real - - - - tmp_clean_image_imag = loaded_model.forward(imag_to_denoise).detach().numpy() - tmp_clean_image_imag=np.moveaxis(tmp_clean_image_imag, 1, -1) - - output_clean_image_2[:, x:x + patch_size, y:y + patch_size, :] = output_clean_image_2[:, x:x + patch_size, - y:y + patch_size, - :] + tmp_clean_image_imag - count_image[:, x:x + patch_size, y:y + patch_size, :] = count_image[:, x:x + patch_size, y:y + patch_size, - :] + np.ones((1, patch_size, patch_size, 1)) - - - output_clean_image_1 = output_clean_image_1 / count_image - output_clean_image_2 = output_clean_image_2 / count_image - output_clean_image = 0.5 * (np.square(denormalize_sar(output_clean_image_1)) + np.square( - denormalize_sar(output_clean_image_2))) # combine the two estimation - - - noisyimage = np.squeeze(np.sqrt(i_real_part ** 2 + i_imag_part ** 2)) - outputimage = np.sqrt(np.squeeze(output_clean_image)) - - # imagename = test_files[idx].replace(dataset_dir, "") test_image_data - imagename = "test_image_data.npy" - - print("Denoised image %s" % imagename) - - save_sar_images(outputimage, noisyimage, imagename, save_dir) - save_real_imag_images( denormalize_sar(output_clean_image_1), denormalize_sar(output_clean_image_2), - imagename, save_dir) - - save_real_imag_images_noisy( np.squeeze(i_real_part), np.squeeze(i_imag_part), imagename, save_dir) \ No newline at end of file diff --git a/tests/sar2sar/test/results/denoised_imag_test_image_data.png b/tests/sar2sar/test/results/denoised_imag_test_image_data.png deleted file mode 100644 index 8aa904a..0000000 Binary files a/tests/sar2sar/test/results/denoised_imag_test_image_data.png and /dev/null differ diff --git a/tests/sar2sar/test/saved_model/model.pth b/tests/sar2sar/test/saved_model/model.pth deleted file mode 100644 index 827285b..0000000 Binary files a/tests/sar2sar/test/saved_model/model.pth and /dev/null differ diff --git a/tests/sar2sar/test/spotlight.py b/tests/sar2sar/test/spotlight.py deleted file mode 100644 index 226f28f..0000000 --- a/tests/sar2sar/test/spotlight.py +++ /dev/null @@ -1,159 +0,0 @@ -import torch - -from merlinsar.test.model import * -from merlinsar.test.utils import * -from merlinsar.test.model_test import * -import os -from glob import glob - -import numpy as np -from merlinsar.test.load_cosar import cos2mat - -M = 10.089038980848645 -m = -1.429329123112601 - -this_dir, this_filename = os.path.split(__file__) - - -def despeckle(image_path,destination_directory,stride_size=64, - model_weights_path= os.path.join(this_dir, "saved_model", "model.pth"),patch_size=256,height=256,width=256): - - """ Description - ---------- - Runs a test instance by calling the test function defined in model.py on a few samples - - Parameters - ---------- - denoiser : an object - - Returns - ---------- - - """ - - denoiser=Denoiser() - - if not os.path.exists(destination_directory+'/processed_image'): - os.mkdir(destination_directory+'/processed_image') - - test_data=destination_directory+'/processed_image' - - filelist = glob(os.path.join(test_data, "*")) - for f in filelist: - os.remove(f) - - image_data = cos2mat(image_path) - - np.save(test_data+'/test_image_data.npy',image_data) - - print( - "[*] Start testing on real data. Working directory: %s. Collecting data from %s and storing test results in %s" % ( - os.getcwd(), destination_directory, destination_directory)) - - test_files = glob((test_data + '/*.npy')) - print(test_files) - - denoiser.test(test_files,model_weights_path, save_dir=destination_directory, - stride=stride_size,patch_size=patch_size,height=height,width=width) - - -def despeckle_from_coordinates(image_path,coordinates_dict,destination_directory,stride_size=64, - model_weights_path= os.path.join(this_dir, "saved_model", "model.pth"),patch_size=256,height=256,width=256): - """ Description - ---------- - Runs a test instance by calling the test function defined in model.py on a few samples - - Parameters - ---------- - denoiser : an object - - Returns - ---------- - - """ - - x_start=coordinates_dict["x_start"] - x_end=coordinates_dict["x_end"] - y_start=coordinates_dict["y_start"] - y_end=coordinates_dict["y_end"] - - denoiser=Denoiser() - - if not os.path.exists(destination_directory+'/processed_image'): - os.mkdir(destination_directory+'/processed_image') - - test_data=destination_directory+'/processed_image' - - filelist = glob(os.path.join(test_data, "*")) - for f in filelist: - os.remove(f) - - image_data = cos2mat(image_path) - - np.save(test_data+'/test_image_data.npy',image_data[x_start:x_end,y_start:y_end,:]) - - print( - "[*] Start testing on real data. Working directory: %s. Collecting data from %s and storing test results in %s" % ( - os.getcwd(), destination_directory, destination_directory)) - - test_files = glob((test_data + '/*.npy')) - print(test_files) - denoiser.test(test_files,model_weights_path, save_dir=destination_directory, - stride=stride_size,patch_size=patch_size,height=height,width=width) - - - -def despeckle_from_crop(image_path,destination_directory,stride_size=64, - model_weights_path= os.path.join(this_dir, "saved_model", "model.pth"),patch_size=256,height=256,width=256): - """ Description - ---------- - Runs a test instance by calling the test function defined in model.py on a few samples - - Parameters - ---------- - denoiser : an object - - Returns - ---------- - - """ - - denoiser=Denoiser() - - if not os.path.exists(destination_directory+'\\processed_image'): - os.mkdir(destination_directory+'\\processed_image') - - test_data=destination_directory+'\\processed_image' - - filelist = glob(os.path.join(test_data, "*")) - for f in filelist: - os.remove(f) - - - # FROM IMAGE PATH RETRIEVE PNG, NPY, REAL , IMAG, THRESHOLD, FILENAME - image_png , image_data, image_data_real , image_data_imag, threshold, filename = get_info_image(image_path,destination_directory) - - # CROPPING OUR PNG AND REFLECT THE CROP ON REAL AND IMAG - cropping = False - crop(image_png,image_data_real, image_data_imag, destination_directory,test_data,cropping) - - - image_data_real_cropped = np.load(test_data+'\\image_data_real_cropped.npy') - store_data_and_plot(image_data_real_cropped, threshold, test_data+'\\image_data_real_cropped.npy') - image_data_imag_cropped =np.load(test_data+'\\image_data_imag_cropped.npy') - store_data_and_plot(image_data_imag_cropped, threshold, test_data+'\\image_data_imag_cropped.npy') - - image_data_real_cropped= image_data_real_cropped.reshape(image_data_real_cropped.shape[0],image_data_real_cropped.shape[1],1) - image_data_imag_cropped = image_data_imag_cropped.reshape(image_data_imag_cropped.shape[0], - image_data_imag_cropped.shape[1], 1) - - np.save(test_data + '/test_image_data_cropped.npy', np.concatenate((image_data_real_cropped, image_data_imag_cropped), axis=2)) - - print( - "[*] Start testing on real data. Working directory: %s. Collecting data from %s and storing test results in %s" % ( - os.getcwd(), destination_directory, destination_directory)) - - test_files = glob((test_data +'/test_image_data_cropped.npy')) - print(test_files) - denoiser.test(test_files,model_weights_path, save_dir=destination_directory, - stride=stride_size,patch_size=patch_size,height=height,width=width) diff --git a/tests/sar2sar/test/utils.py b/tests/sar2sar/test/utils.py deleted file mode 100644 index 8e16f73..0000000 --- a/tests/sar2sar/test/utils.py +++ /dev/null @@ -1,325 +0,0 @@ -import numpy as np -from PIL import Image -from scipy import special -from scipy import signal -from merlinsar.test.load_cosar import cos2mat -import cv2 -from PIL import Image -import numpy as np -from numpy import asarray - - -# DEFINE PARAMETERS OF SPECKLE AND NORMALIZATION FACTOR -M = 10.089038980848645 -m = -1.429329123112601 -L = 1 -c = (1 / 2) * (special.psi(L) - np.log(L)) -cn = c / (M - m) # normalized (0,1) mean of log speckle - - -def normalize_sar(im): - """ Description - ---------- - Normalization of a numpy-stored image - - Parameters - ---------- - im : an image object - - Returns - ---------- - - """ - if not isinstance(im, np.ndarray): - raise TypeError('Please provide a .npy argument') - return ((np.log(im + np.spacing(1)) - m) * 255 / (M - m)).astype('float32') - - -def denormalize_sar(im): - """ Description - ---------- - Denormalization of a numpy image - - Parameters - ---------- - im : an image object - - Returns - ---------- - - """ - if not isinstance(im, np.ndarray): - raise TypeError('Please provide a .npy argument') - return np.exp((M - m) * (np.squeeze(im)).astype('float32') + m) - - -def symetrisation_patch_test(real_part, imag_part): - if not isinstance(real_part, np.ndarray): - raise TypeError('Please provide a .npy argument') - if not isinstance(imag_part, np.ndarray): - raise TypeError('Please provide a .npy argument') - S = np.fft.fftshift(np.fft.fft2(real_part[0, :, :, 0] + 1j * imag_part[0, :, :, 0])) - p = np.zeros((S.shape[0])) # azimut (ncol) - for i in range(S.shape[0]): - p[i] = np.mean(np.abs(S[i, :])) - sp = p[::-1] - c = np.real(np.fft.ifft(np.fft.fft(p) * np.conjugate(np.fft.fft(sp)))) - d1 = np.unravel_index(c.argmax(), p.shape[0]) - d1 = d1[0] - shift_az_1 = int(round(-(d1 - 1) / 2)) % p.shape[0] + int(p.shape[0] / 2) - p2_1 = np.roll(p, shift_az_1) - shift_az_2 = int(round(-(d1 - 1 - p.shape[0]) / 2)) % p.shape[0] + int(p.shape[0] / 2) - p2_2 = np.roll(p, shift_az_2) - window = signal.gaussian(p.shape[0], std=0.2 * p.shape[0]) - test_1 = np.sum(window * p2_1) - test_2 = np.sum(window * p2_2) - # make sure the spectrum is symetrized and zeo-Doppler centered - if test_1 >= test_2: - p2 = p2_1 - shift_az = shift_az_1 / p.shape[0] - else: - p2 = p2_2 - shift_az = shift_az_2 / p.shape[0] - S2 = np.roll(S, int(shift_az * p.shape[0]), axis=0) - - q = np.zeros((S.shape[1])) # range (nlin) - for j in range(S.shape[1]): - q[j] = np.mean(np.abs(S[:, j])) - sq = q[::-1] - # correlation - cq = np.real(np.fft.ifft(np.fft.fft(q) * np.conjugate(np.fft.fft(sq)))) - d2 = np.unravel_index(cq.argmax(), q.shape[0]) - d2 = d2[0] - shift_range_1 = int(round(-(d2 - 1) / 2)) % q.shape[0] + int(q.shape[0] / 2) - q2_1 = np.roll(q, shift_range_1) - shift_range_2 = int(round(-(d2 - 1 - q.shape[0]) / 2)) % q.shape[0] + int(q.shape[0] / 2) - q2_2 = np.roll(q, shift_range_2) - window_r = signal.gaussian(q.shape[0], std=0.2 * q.shape[0]) - test_1 = np.sum(window_r * q2_1) - test_2 = np.sum(window_r * q2_2) - if test_1 >= test_2: - q2 = q2_1 - shift_range = shift_range_1 / q.shape[0] - else: - q2 = q2_2 - shift_range = shift_range_2 / q.shape[0] - - Sf = np.roll(S2, int(shift_range * q.shape[0]), axis=1) - ima2 = np.fft.ifft2(np.fft.ifftshift(Sf)) - ima2 = ima2.reshape(1, np.size(ima2, 0), np.size(ima2, 1), 1) - return np.real(ima2), np.imag(ima2) - - -def load_sar_images(filelist): - """ Description - ---------- - Loads files , resize them and append them into a list called data - - Parameters - ---------- - filelist : a path to a folder containing the images - - Returns - ---------- - A list of images - - """ - if not isinstance(filelist, list): - im = np.load(filelist) - return np.array(im).reshape(1, np.size(im, 0), np.size(im, 1), 2) - data = [] - for file in filelist: - im = np.load(file) - data.append(np.array(im).reshape(1, np.size(im, 0), np.size(im, 1), 2)) - return data - - -def store_data_and_plot(im, threshold, filename): - """ Description - ---------- - Creates an image memory from an object exporting the array interface and returns a - converted copy of this image into greyscale mode ("L") - - However, there is not plotting functions' call ? - - Parameters - ---------- - im : the image to store - threshold: clip a maximum value in the image array i.e values are to be between 0 and threshold - filename: the path to store the result array image in .png - - Returns - ---------- - None - - """ - if not isinstance(im, np.ndarray): - raise TypeError('Please provide a .npy argument') - im = np.clip(im, 0, threshold) - - im = im / threshold * 255 - im = Image.fromarray(im.astype('float64')).convert('L') - im.save(filename.replace('npy', 'png')) - return filename - -def save_sar_images(denoised, noisy, imagename, save_dir, groundtruth=None): - choices = {'marais1': 190.92, 'marais2': 168.49, 'saclay': 470.92, 'lely': 235.90, 'ramb': 167.22, - 'risoul': 306.94, 'limagne': 178.43, 'saintgervais': 560, 'Serreponcon': 450.0, - 'Sendai': 600.0, 'Paris': 1291.0, 'Berlin': 1036.0, 'Bergen': 553.71, - 'SDP_Lambesc': 349.53, 'Grand_Canyon': 287.0, 'domancy': 560, 'Brazil': 103.0} - threshold = None - for x in choices: - if x in imagename: - threshold = choices.get(x) - if threshold is None: threshold = np.mean(noisy) + 3 * np.std(noisy) - - #### - imagename = imagename.split('\\')[-1] - #### - - if groundtruth: - groundtruthfilename = save_dir + "/groundtruth_" + imagename - np.save(groundtruthfilename, groundtruth) - store_data_and_plot(groundtruth, threshold, groundtruthfilename) - - denoisedfilename = save_dir + "/denoised_" + imagename - np.save(denoisedfilename, denoised) - store_data_and_plot(denoised, threshold, denoisedfilename) - - noisyfilename = save_dir + "/noisy_" + imagename - np.save(noisyfilename, noisy) - store_data_and_plot(noisy, threshold, noisyfilename) - - -def save_real_imag_images(real_part, imag_part, imagename, save_dir): - choices = {'marais1': 190.92, 'marais2': 168.49, 'saclay': 470.92, 'lely': 235.90, 'ramb': 167.22, - 'risoul': 306.94, 'limagne': 178.43, 'saintgervais': 560, 'Serreponcon': 450.0, - 'Sendai': 600.0, 'Paris': 1291.0, 'Berlin': 1036.0, 'Bergen': 553.71, - 'SDP_Lambesc': 349.53, 'Grand_Canyon': 287.0, 'Brazil': 103.0} - threshold = None - for x in choices: - if x in imagename: - threshold = choices.get(x) - if threshold is None: threshold = np.mean(imag_part) + 3 * np.std(imag_part) - - #### - imagename = imagename.split('\\')[-1] - #### - - realfilename = save_dir + "/denoised_real_" + imagename - np.save(realfilename, real_part) - store_data_and_plot(real_part, threshold, realfilename) - - imagfilename = save_dir + "/denoised_imag_" + imagename - np.save(imagfilename, imag_part) - store_data_and_plot(imag_part, threshold, imagfilename) - - -def save_real_imag_images_noisy(real_part, imag_part, imagename, save_dir): - choices = {'marais1': 190.92, 'marais2': 168.49, 'saclay': 470.92, 'lely': 235.90, 'ramb': 167.22, - 'risoul': 306.94, 'limagne': 178.43, 'saintgervais': 560, 'Serreponcon': 450.0, - 'Sendai': 600.0, 'Paris': 1291.0, 'Berlin': 1036.0, 'Bergen': 553.71, - 'SDP_Lambesc': 349.53, 'Grand_Canyon': 287.0, 'Brazil': 103.0} - threshold = None - for x in choices: - if x in imagename: - threshold = choices.get(x) - if threshold is None: threshold = np.mean(np.abs(imag_part)) + 3 * np.std(np.abs(imag_part)) - - #### - imagename = imagename.split('\\')[-1] - #### - - realfilename = save_dir + "/noisy_real_" + imagename - np.save(realfilename, real_part) - store_data_and_plot(np.sqrt(2) * np.abs(real_part), threshold, realfilename) - - imagfilename = save_dir + "/noisy_imag_" + imagename - np.save(imagfilename, imag_part) - store_data_and_plot(np.sqrt(2) * np.abs(imag_part), threshold, imagfilename) - -def cal_psnr(Shat, S): - # takes amplitudes in input - # Shat: a SAR amplitude image - # S: a reference SAR image - P = np.quantile(S, 0.99) - res = 10 * np.log10((P ** 2) / np.mean(np.abs(Shat - S) ** 2)) - return res - -def crop(image_png,image_data_real, image_data_imag,destination_directory,test_data, cropping): - # HERE I READ THE PNG FILE - oriImage = image_png.copy() - cropping = False - x_start, y_start, x_end, y_end = 0, 0, 0, 0 - - # CV2 CROPPING IN WINDOW - def mouse_crop(event, x, y, flags, param): - global x_start, y_start, x_end, y_end, cropping - cropping = False - if event == cv2.EVENT_LBUTTONDOWN: - x_start, y_start, x_end, y_end = x, y, x, y - cropping = True - - # Mouse is Moving - elif event == cv2.EVENT_MOUSEMOVE: - cropping = True - if cropping: - cv2.rectangle(image, (x_start, y_start), (x_start + 32, y_start + 32), (255, 0, 0), 2) - x_end, y_end = x, y - - # if the left mouse button was released - elif event == cv2.EVENT_LBUTTONUP: - # record the ending (x, y) coordinates - x_end, y_end = x_start + 32, y_start + 32 - cropping = False # cropping is finished - - refPoint = [(x_start, y_start), (x_end, y_end)] - - if len(refPoint) == 2: # when two points were found - image_data_real_cropped = image_data_real[refPoint[0][1] * 8:refPoint[1][1] * 8, refPoint[0][0] * 8:refPoint[1][0] * 8] - image_data_imag_cropped = image_data_imag[refPoint[0][1] * 8:refPoint[1][1] * 8, refPoint[0][0] * 8:refPoint[1][0] * 8] - roi = oriImage[refPoint[0][1] * 8:refPoint[1][1] * 8, refPoint[0][0] * 8:refPoint[1][0] * 8] - roi = cv2.resize(roi, (256, 256)) - cv2.imwrite(destination_directory+'\\cropped_npy_to_png.png', roi) - cv2.imshow("Cropped", roi) - cropped_img_png = Image.open(destination_directory+'\\cropped_npy_to_png.png') - numpy_crop = asarray(cropped_img_png) - np.save(destination_directory+'\\cropped.npy', numpy_crop) - np.save(test_data+'\\image_data_real_cropped.npy', image_data_real_cropped) - np.save(test_data + '\\image_data_imag_cropped.npy', image_data_imag_cropped) - - h, w , c = image_png.shape - image = cv2.resize(image_png, (int(w / 8), int(h / 8))) - cv2.namedWindow("image") - cv2.setMouseCallback("image", mouse_crop) - - while True: - i = image.copy() - - if not cropping: - cv2.imshow("image", image) - - elif cropping: - cv2.imshow("image", i) - - key = cv2.waitKey(10) - if key == ord('q'): - return - -def get_info_image(image_path,destination_directory): - image_data = cos2mat(image_path) - - # GET THE TWO PARTS - image_data_real = image_data[:, :, 0] - image_data_imag = image_data[:, :, 1] - - # GET NOISY FOR THRESHOLD - image = np.squeeze(np.sqrt(np.square(image_data_real) + np.square(image_data_imag))) - threshold = np.mean(image) + 3 * np.std(image) - - # DISPLAY FULL PICTURE - filename = store_data_and_plot(image, threshold, destination_directory + '\\image_provided.npy') - print('full picture in png is saved') - image_png = cv2.imread(filename.replace('npy', 'png')) - print('full picture in png has a dimension of {size}'.format(size=image_png.shape)) - return image_png , image_data, image_data_real , image_data_imag, threshold, filename diff --git a/tests/sar2sar/train/.directory b/tests/sar2sar/train/.directory deleted file mode 100644 index 3fa4480..0000000 --- a/tests/sar2sar/train/.directory +++ /dev/null @@ -1,4 +0,0 @@ -[Dolphin] -Timestamp=2022,4,5,17,1,21 -Version=4 -ViewMode=1 diff --git a/tests/sar2sar/train/Dataset.py b/tests/sar2sar/train/Dataset.py deleted file mode 100644 index c7148c5..0000000 --- a/tests/sar2sar/train/Dataset.py +++ /dev/null @@ -1,53 +0,0 @@ -import numpy as np -import torch -from merlinsar.train.utils import * - - - -class Dataset(torch.utils.data.Dataset): - 'characterizes a dataset for pytorch' - def __init__(self, patche): - self.patches = patche - - def __len__(self): - 'denotes the total number of samples' - return len(self.patches) - - def __getitem__(self, index): - 'Generates one sample of data' - #select sample - batch_real = (self.patches[index,:, :, 0]) - batch_imag = (self.patches[index,:, :, 1]) - - x = torch.tensor(batch_real) - y = torch.tensor(batch_imag) - - x = x.unsqueeze(0) - y = y.unsqueeze(0) - - return x, y - - -class ValDataset(torch.utils.data.Dataset): - 'characterizes a dataset for pytorch' - def __init__(self, test_set): - self.files = glob(test_set+'/*.npy') - - def __len__(self): - 'denotes the total number of samples' - return len(self.files) - - def __getitem__(self, index): - 'Generates one sample of data' - #select sample - eval_data = load_sar_images(self.files) - - current_test=eval_data[index] - - current_test[0,:,:,:] = symetrisation_patch(current_test[0,:,:,:]) - image_real_part = (current_test[:, :, :, 0]).reshape(current_test.shape[0], current_test.shape[1], - current_test.shape[2], 1) - image_imag_part = (current_test[:, :, :, 1]).reshape(current_test.shape[0], current_test.shape[1], - current_test.shape[2], 1) - - return torch.tensor(image_real_part).type(torch.float) , torch.tensor(image_imag_part).type(torch.float) diff --git a/tests/sar2sar/train/GenerateDataset.py b/tests/sar2sar/train/GenerateDataset.py deleted file mode 100644 index c605613..0000000 --- a/tests/sar2sar/train/GenerateDataset.py +++ /dev/null @@ -1,165 +0,0 @@ -import glob -import random -import os -import numpy as np -from scipy import signal -from scipy import special - - -''' -Generate patches for the images in the folder dataset/data/Train -The code scans among the training images and then for data_aug_times -''' - -class GenerateDataset(): - def data_augmentation(self, image, mode): - if mode == 0: - # original - return image - elif mode == 1: - # flip up and down - return np.flipud(image) - elif mode == 2: - # rotate counterwise 90 degree - return np.rot90(image) - elif mode == 3: - # rotate 90 degree and flip up and down - image = np.rot90(image) - return np.flipud(image) - elif mode == 4: - # rotate 180 degree - return np.rot90(image, k=2) - elif mode == 5: - # rotate 180 degree and flip - image = np.rot90(image, k=2) - return np.flipud(image) - elif mode == 6: - # rotate 270 degree - return np.rot90(image, k=3) - elif mode == 7: - # rotate 270 degree and flip - image = np.rot90(image, k=3) - return np.flipud(image) - - def symetrisation_patch_gen(self, ima): - S = np.fft.fftshift(np.fft.fft2(ima[:,:,0]+1j*ima[:,:,1])) - p = np.zeros((S.shape[0])) # azimut (ncol) - for i in range(S.shape[0]): - p[i] = np.mean(np.abs(S[i,:])) - sp = p[::-1] - c = np.real(np.fft.ifft(np.fft.fft(p)*np.conjugate(np.fft.fft(sp)))) - d1 = np.unravel_index(c.argmax(),p.shape[0]) - d1 = d1[0] - shift_az_1 = int(round(-(d1-1)/2))%p.shape[0]+int(p.shape[0]/2) - p2_1 = np.roll(p,shift_az_1) - shift_az_2 = int(round(-(d1-1-p.shape[0])/2))%p.shape[0]+int(p.shape[0]/2) - p2_2 = np.roll(p,shift_az_2) - window = signal.gaussian(p.shape[0], std=0.2*p.shape[0]) - test_1 = np.sum(window*p2_1) - test_2 = np.sum(window*p2_2) - # make sure the spectrum is symetrized and zeo-Doppler centered - if test_1>=test_2: - p2 = p2_1 - shift_az = shift_az_1/p.shape[0] - else: - p2 = p2_2 - shift_az = shift_az_2/p.shape[0] - S2 = np.roll(S,int(shift_az*p.shape[0]),axis=0) - - - - - q = np.zeros((S.shape[1])) # range (nlin) - for j in range(S.shape[1]): - q[j] = np.mean(np.abs(S[:,j])) - sq = q[::-1] - #correlation - cq = np.real(np.fft.ifft(np.fft.fft(q)*np.conjugate(np.fft.fft(sq)))) - d2 = np.unravel_index(cq.argmax(),q.shape[0]) - d2=d2[0] - shift_range_1 = int(round(-(d2-1)/2))%q.shape[0]+int(q.shape[0]/2) - q2_1 = np.roll(q,shift_range_1) - shift_range_2 = int(round(-(d2-1-q.shape[0])/2))%q.shape[0]+int(q.shape[0]/2) - q2_2 = np.roll(q,shift_range_2) - window_r = signal.gaussian(q.shape[0], std=0.2*q.shape[0]) - test_1 = np.sum(window_r*q2_1) - test_2 = np.sum(window_r*q2_2) - if test_1>=test_2: - q2 = q2_1 - shift_range = shift_range_1/q.shape[0] - else: - q2 = q2_2 - shift_range = shift_range_2/q.shape[0] - - - Sf = np.roll(S2,int(shift_range*q.shape[0]),axis=1) - ima2 = np.fft.ifft2(np.fft.ifftshift(Sf)) - return np.stack((np.real(ima2),np.imag(ima2)),axis=2) - - - - - - def generate_patches(self,src_dir="./dataset/data/Train",pat_size=256,step=0,stride=64,bat_size=4,data_aug_times=1,n_channels=2): - count = 0 - filepaths = glob.glob(src_dir + '/*.npy') - print("number of training data %d" % len(filepaths)) - - # calculate the number of patches - for i in range(len(filepaths)): - img = np.load(filepaths[i]) - - im_h = np.size(img, 0) - im_w = np.size(img, 1) - for x in range(0+step, (im_h - pat_size), stride): - for y in range(0+step, (im_w - pat_size), stride): - count += 1 - origin_patch_num = count * data_aug_times - - if origin_patch_num % bat_size != 0: - numPatches = (origin_patch_num / bat_size + 1) * bat_size - else: - numPatches = origin_patch_num - print("total patches = %d , batch size = %d, total batches = %d" % \ - (numPatches, bat_size, numPatches / bat_size)) - - # data matrix 4-D - numPatches=int(numPatches) - inputs = np.zeros((numPatches, pat_size, pat_size, n_channels), dtype="float32") - - - count = 0 - # generate patches - for i in range(len(filepaths)): #scan through images - img = np.load(filepaths[i]) - img_s = img - - - # If data_aug_times = 8 then perform them all, otherwise pick one at random or do nothing - for j in range(data_aug_times): - im_h = np.size(img, 0) - im_w = np.size(img, 1) - if data_aug_times == 8: - for x in range(0 + step, im_h - pat_size, stride): - for y in range(0 + step, im_w - pat_size, stride): - inputs[count, :, :, :] = self.data_augmentation(img_s[x:x + pat_size, y:y + pat_size, :], \ - j) - count += 1 - else: - for x in range(0 + step, im_h - pat_size, stride): - for y in range(0 + step, im_w - pat_size, stride): - # to pick one at random, uncomment this line and comment the one below - """inputs[count, :, :, :] = self.data_augmentation(img_s[x:x + pat_size, y:y + pat_size, :], \ - random.randint(0, 7))""" - - inputs[count, :, :, :] = self.data_augmentation(self.symetrisation_patch_gen(img_s[x:x + pat_size, y:y + pat_size, :]),0) - - count += 1 - - - # pad the batch - if count < numPatches: - to_pad = numPatches - count - inputs[-to_pad:, :, :, :] = inputs[:to_pad, :, :, :] - - return inputs diff --git a/tests/sar2sar/train/__init__.py b/tests/sar2sar/train/__init__.py deleted file mode 100644 index 7f787ab..0000000 --- a/tests/sar2sar/train/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -"""Top-level package for merlin.""" - -__author__ = """youcef kemiche""" -__email__ = 'y.kemiche06@hotmail.com' -__version__ = '0.1.0' - - -from merlinsar.train.utils import * -from merlinsar.train.Dataset import * -from merlinsar.train.GenerateDataset import * -from merlinsar.train.model import * -from merlinsar.train.merlin import* \ No newline at end of file diff --git a/tests/sar2sar/train/merlin.py b/tests/sar2sar/train/merlin.py deleted file mode 100644 index bd3025b..0000000 --- a/tests/sar2sar/train/merlin.py +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -import argparse -from glob import glob -import os - -import numpy as np -import torch - -from merlinsar.train.Dataset import * -from merlinsar.train.model import * -from merlinsar.train.utils import * - - -def evaluate(model, loader): - outputs = [model.validation_step(batch) for batch in loader] - outputs = torch.tensor(outputs).T - loss, accuracy = torch.mean(outputs, dim=1) - return {"loss": loss.item(), "accuracy": accuracy.item()} - - -def save_model(model,destination_folder): - """ - save the ".pth" model in destination_folder - """ - # Check whether the specified path exists or not - isExist = os.path.exists(destination_folder) - - if not isExist: - - # Create a new directory because it does not exist - os.makedirs(destination_folder) - print("The new directory is created!") - - torch.save(model.state_dict(),destination_folder+"/model.pth") - - else: - torch.save(model.state_dict(),destination_folder+"/model.pth") - - -def fit(model,train_loader,val_loader,epochs,lr_list,eval_files,eval_set,clip_by_norm,sample_dir): - """ Fit the model according to the given evaluation data and parameters. - - Parameters - ---------- - model : model as defined in main - train_loader : Pytorch's DataLoader of training data - val_loader : Pytorch's DataLoader of validation data - lr_list : list of learning rates - eval_files : .npy files used for evaluation in training - eval_set : directory of dataset used for evaluation in training - - Returns - ---------- - self : object - Fitted estimator. - - """ - - train_losses = [] - history={} - epoch_num=0 - for epoch in range(epochs): - epoch_num=epoch_num+1 - print("\nEpoch", epoch+1) - print("***************** \n") - optimizer=torch.optim.Adam(model.parameters(), lr=lr_list[epoch]) - - #Train - for i, batch in enumerate(train_loader, 0): - - optimizer.zero_grad() - loss = model.training_step(batch,i) - train_losses.append(loss) - - loss.backward() - - if(clip_by_norm==True): - - torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=5.0) - - optimizer.step() - - #running_loss += loss.item() # extract the loss value - print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, loss)) - # zero the loss - - # #Validate - with torch.no_grad(): - image_num=0 - for batch in val_loader: - val_loss=model.validation_step(batch,image_num,epoch_num,eval_files,eval_set,sample_dir) - image_num=image_num+1 - - history["train_loss"]=train_losses - - return history - - -def create_model(height=256,width=256,batch_size=12,val_batch_size=1,device=torch.device("cuda:0" if torch.cuda.is_available() else "cpu"),from_pretrained=False): - """ Runs the denoiser algorithm for the training and evaluation dataset - - - """ - this_dir, this_filename = os.path.split(__file__) - weights_path = os.path.join(this_dir, "saved_model", "model.pth") - - model = Model(height,width,batch_size,val_batch_size,device) - model.to(device) - - if from_pretrained == True: - - model.load_state_dict(torch.load(weights_path, map_location=torch.device('cpu'))) - - return model - -def fit_model(model,lr_list,nb_epoch,training_set_directory,validation_set_directory,sample_directory,save_directory,patch_size=256,batch_size=12,val_batch_size=1,stride_size=128,n_data_augmentation=1,seed=2,clip_by_norm=True): - """ Runs the denoiser algorithm for the training and evaluation dataset - - Parameters - ---------- - model : model as defined in main - lr_list : list of learning rates - - Returns - ---------- - history : list of both training and validation loss - - """ - torch.manual_seed(seed) - - - # Prepare train DataLoader - train_data = load_train_data(training_set_directory,patch_size,batch_size,stride_size,n_data_augmentation) # range [0; 1] - train_dataset = Dataset(train_data) - train_loader = torch.utils.data.DataLoader(train_dataset,batch_size=batch_size,shuffle=True,drop_last=True) - - # Prepare Validation DataLoader - eval_dataset = ValDataset(validation_set_directory) - eval_loader = torch.utils.data.DataLoader(eval_dataset,batch_size=val_batch_size,shuffle=False,drop_last=True) - - eval_files = glob(validation_set_directory+'/*.npy') - # Train the model - history =fit(model,train_loader,eval_loader,nb_epoch,lr_list,eval_files,validation_set_directory,clip_by_norm,sample_directory) - - # Save the model - save_model(model,save_directory) - print("\n model saved at :",save_directory) - - return history diff --git a/tests/sar2sar/train/model.py b/tests/sar2sar/train/model.py deleted file mode 100644 index 5f4c2bd..0000000 --- a/tests/sar2sar/train/model.py +++ /dev/null @@ -1,306 +0,0 @@ -import numpy as np - -from merlinsar.train.utils import * -from scipy import special - - -# DEFINE PARAMETERS OF SPECKLE AND NORMALIZATION FACTOR -M = 10.089038980848645 -m = -1.429329123112601 -L = 1 -c = (1 / 2) * (special.psi(L) - np.log(L)) -cn = c / (M - m) # normalized (0,1) mean of log speckle - -import torch -import numpy as np - - -# Nearest-neighbor up-scaling layer. -'''def upscale2d(x, factor=2): - """ Description - ---------- - Run a nearest-neighbor up-scaling layer for a given factor on an object (image) x - - This is a common quality-enhancing algorithm that doubles the dimensions of the input. - - Every pixel in low-res is thereafter transformed into 4 pixels. - - Parameters - ---------- - x : an image object - - factor : figure by how many times ou want to multiply the input's initial dimensions - - Returns - ---------- - x if factor is 1 - or - a reshaped x if factor is different from 1 - """ - assert isinstance(factor, int) and factor >= 1 - if factor == 1: - return x - # with tf.compat.v1.variable_scope('Upscale2D'): - s = x.shape - x = torch.reshape(x, [-1, s[1], 1, s[2], 1, s[3]]) - x = torch.tile(x, [1, 1, factor, 1, factor, 1]) - x = torch.reshape(x, [-1, s[1] , s[2] * factor, s[3]* factor]) - - - s = x.shape - x = torch.reshape(x, [-1, s[1], s[2], 1, s[3], 1]) - x = torch.tile(x, [1, 1, 1, factor, 1, factor]) - x = torch.reshape(x, [-1, s[1], s[2] * factor, s[3] * factor]) - - return x''' - - - -class Model(torch.nn.Module): - - def __init__(self,height,width,batch_size,eval_batch_size,device): - super().__init__() - - self.batch_size=batch_size - self.eval_batch_size=eval_batch_size - self.device=device - - self.height = height - self.width = width - - self.pool = torch.nn.MaxPool2d(kernel_size=2, stride=2) - self.leaky = torch.nn.LeakyReLU(0.1) - - self.enc0 = torch.nn.Conv2d(in_channels=1, out_channels=48, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.enc1 = torch.nn.Conv2d(in_channels=48, out_channels=48, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.enc2 = torch.nn.Conv2d(in_channels=48, out_channels=48, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.enc3 = torch.nn.Conv2d(in_channels=48, out_channels=48, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.enc4 = torch.nn.Conv2d(in_channels=48, out_channels=48, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.enc5 = torch.nn.Conv2d(in_channels=48, out_channels=48, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.enc6 = torch.nn.Conv2d(in_channels=48, out_channels=48, kernel_size=(3, 3), stride=(1, 1), - padding='same') - - self.dec5 = torch.nn.Conv2d(in_channels=96, out_channels=96, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.dec5b = torch.nn.Conv2d(in_channels=96, out_channels=96, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.dec4 = torch.nn.Conv2d(in_channels=144, out_channels=96, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.dec4b = torch.nn.Conv2d(in_channels=96, out_channels=96, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.dec3 = torch.nn.Conv2d(in_channels=144, out_channels=96, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.dec3b = torch.nn.Conv2d(in_channels=96, out_channels=96, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.dec2 = torch.nn.Conv2d(in_channels=144, out_channels=96, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.dec2b = torch.nn.Conv2d(in_channels=96, out_channels=96, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.dec1a = torch.nn.Conv2d(in_channels=97, out_channels=64, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.dec1b = torch.nn.Conv2d(in_channels=64, out_channels=32, kernel_size=(3, 3), stride=(1, 1), - padding='same') - self.dec1 = torch.nn.Conv2d(in_channels=32, out_channels=1, kernel_size=(3, 3), stride=(1, 1), - padding='same') - - self.upscale2d = torch.nn.UpsamplingNearest2d(scale_factor=2) - - - def forward(self,x ,batch_size): - """ Defines a class for an autoencoder algorithm for an object (image) x - - An autoencoder is a specific type of feedforward neural networks where the - input is the same as the - output. It compresses the input into a lower-dimensional code and then - reconstruct the output from this representattion. It is a dimensionality - reduction algorithm - - Parameters - ---------- - x : np.array - a numpy array containing image - - Returns - ---------- - x-n : np.array - a numpy array containing the denoised image i.e the image itself minus the noise - - """ - - x=torch.reshape(x, [batch_size, 1, self.height, self.width]) - skips = [x] - - n = x - - # ENCODER - n = self.leaky(self.enc0(n)) - n = self.leaky(self.enc1(n)) - n = self.pool(n) - skips.append(n) - - n = self.leaky(self.enc2(n)) - n = self.pool(n) - skips.append(n) - - n = self.leaky(self.enc3(n)) - n = self.pool(n) - skips.append(n) - - n = self.leaky(self.enc4(n)) - n = self.pool(n) - skips.append(n) - - n = self.leaky(self.enc5(n)) - n = self.pool(n) - n = self.leaky(self.enc6(n)) - - - # DECODER - n = self.upscale2d(n) - n = torch.cat((n, skips.pop()), dim=1) - n = self.leaky(self.dec5(n)) - n = self.leaky(self.dec5b(n)) - - n = self.upscale2d(n) - n = torch.cat((n, skips.pop()), dim=1) - n = self.leaky(self.dec4(n)) - n = self.leaky(self.dec4b(n)) - - n = self.upscale2d(n) - n = torch.cat((n, skips.pop()), dim=1) - n = self.leaky(self.dec3(n)) - n = self.leaky(self.dec3b(n)) - - n = self.upscale2d(n) - n = torch.cat((n, skips.pop()), dim=1) - n = self.leaky(self.dec2(n)) - n = self.leaky(self.dec2b(n)) - - n = self.upscale2d(n) - n = torch.cat((n, skips.pop()), dim=1) - n = self.leaky(self.dec1a(n)) - n = self.leaky(self.dec1b(n)) - - n = self.dec1(n) - - return x - n - - def loss_function(self,output,target,batch_size): - """ Defines and runs the loss function - - Parameters - ---------- - output : - target : - batch_size : - - Returns - ---------- - loss: float - The value of loss given your output, target and batch_size - - """ - - M = 10.089038980848645 - m = -1.429329123112601 - - # ----- loss ----- - log_hat_R = 2*(output*(M-m)+m) - hat_R = torch.exp(log_hat_R)+1e-6 # must be nonzero - b_square = torch.square(target) - loss = (1/batch_size)*torch.mean( 0.5*log_hat_R+b_square/hat_R ) #+ tf.losses.get_regularization_loss() - return loss - - def training_step(self, batch,batch_number): - - """ Train the model with the training set - - Parameters - ---------- - batch : a subset of the training date - batch_number : ID identifying the batch - - Returns - ------- - loss : float - The value of loss given the batch - - """ - M = 10.089038980848645 - m = -1.429329123112601 - - x, y = batch - x=x.to(self.device) - y=y.to(self.device) - - - - - if (batch_number%2==0): - x=(torch.log(torch.square(x)+1e-3)-2*m)/(2*(M-m)) - out = self.forward(x,self.batch_size) - loss = self.loss_function(out, y,self.batch_size) - - else: - y=(torch.log(torch.square(y)+1e-3)-2*m)/(2*(M-m)) - out = self.forward(y,self.batch_size) - loss = self.loss_function(out,x,self.batch_size) - - return loss - - def validation_step(self, batch,image_num,epoch_num,eval_files,eval_set,sample_dir): - """ Test the model with the validation set - - Parameters - ---------- - batch : a subset of data - image_num : an ID identifying the feeded image - epoch_num : an ID identifying the epoch - eval_files : .npy files used for evaluation in training - eval_set : directory of dataset used for evaluation in training - - Returns - ---------- - output_clean_image : a np.array - - """ - - image_real_part,image_imaginary_part = batch - - image_real_part=image_real_part.to(self.device) - image_imaginary_part=image_imaginary_part.to(self.device) - - # Normalization - image_real_part_normalized=(torch.log(torch.square(image_real_part)+1e-3)-2*m)/(2*(M-m)) - image_imaginary_part_normalized=(torch.log(torch.square(image_imaginary_part)+1e-3)-2*m)/(2*(M-m)) - - out_real = self.forward(image_real_part_normalized,self.eval_batch_size) - out_imaginary = self.forward(image_imaginary_part_normalized,self.eval_batch_size) - - output_clean_image = 0.5*(np.square(denormalize_sar(out_real.cpu().numpy()))+np.square(denormalize_sar(out_imaginary.cpu().numpy()))) - # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # - - noisyimage = np.squeeze(np.sqrt(np.square(image_real_part.cpu().numpy())+np.square(image_imaginary_part.cpu().numpy()))) - outputimage = np.sqrt(np.squeeze(output_clean_image)) - - # calculate PSNR - psnr = cal_psnr(outputimage, noisyimage) - print("img%d PSNR: %.2f" % (image_num , psnr)) - - # rename and save - imagename = eval_files[image_num].replace(eval_set, "") - imagename = imagename.replace('.npy', '_epoch_' + str(epoch_num) + '.npy') - - save_sar_images(outputimage, noisyimage, imagename,sample_dir) - - return output_clean_image - - - # def optimizer(self): - # return torch.optim.Adam \ No newline at end of file diff --git a/tests/sar2sar/train/sample/denoised_lely0_epoch_1.png b/tests/sar2sar/train/sample/denoised_lely0_epoch_1.png deleted file mode 100644 index 7766b6b..0000000 Binary files a/tests/sar2sar/train/sample/denoised_lely0_epoch_1.png and /dev/null differ diff --git a/tests/sar2sar/train/utils.py b/tests/sar2sar/train/utils.py deleted file mode 100644 index a9fdcb7..0000000 --- a/tests/sar2sar/train/utils.py +++ /dev/null @@ -1,271 +0,0 @@ -import gc -import os -import sys - -import numpy as np -from PIL import Image -from scipy import special -from scipy import signal -from glob import glob -from merlinsar.train.GenerateDataset import GenerateDataset - -basedir = '.' - -# DEFINE PARAMETERS OF SPECKLE AND NORMALIZATION FACTOR -M = 10.089038980848645 -m = -1.429329123112601 -L = 1 -c = (1 / 2) * (special.psi(L) - np.log(L)) -cn = c / (M - m) # normalized (0,1) mean of log speckle - - -def symetrisation_patch(ima): - S = np.fft.fftshift(np.fft.fft2(ima[:,:,0]+1j*ima[:,:,1])) - p = np.zeros((S.shape[0])) # azimut (ncol) - for i in range(S.shape[0]): - p[i] = np.mean(np.abs(S[i,:])) - sp = p[::-1] - c = np.real(np.fft.ifft(np.fft.fft(p)*np.conjugate(np.fft.fft(sp)))) - d1 = np.unravel_index(c.argmax(),p.shape[0]) - d1 = d1[0] - shift_az_1 = int(round(-(d1-1)/2))%p.shape[0]+int(p.shape[0]/2) - p2_1 = np.roll(p,shift_az_1) - shift_az_2 = int(round(-(d1-1-p.shape[0])/2))%p.shape[0]+int(p.shape[0]/2) - p2_2 = np.roll(p,shift_az_2) - window = signal.gaussian(p.shape[0], std=0.2*p.shape[0]) - test_1 = np.sum(window*p2_1) - test_2 = np.sum(window*p2_2) - # make sure the spectrum is symetrized and zeo-Doppler centered - if test_1>=test_2: - p2 = p2_1 - shift_az = shift_az_1/p.shape[0] - else: - p2 = p2_2 - shift_az = shift_az_2/p.shape[0] - S2 = np.roll(S,int(shift_az*p.shape[0]),axis=0) - - q = np.zeros((S.shape[1])) # range (nlin) - for j in range(S.shape[1]): - q[j] = np.mean(np.abs(S[:,j])) - sq = q[::-1] - #correlation - cq = np.real(np.fft.ifft(np.fft.fft(q)*np.conjugate(np.fft.fft(sq)))) - d2 = np.unravel_index(cq.argmax(),q.shape[0]) - d2=d2[0] - shift_range_1 = int(round(-(d2-1)/2))%q.shape[0]+int(q.shape[0]/2) - q2_1 = np.roll(q,shift_range_1) - shift_range_2 = int(round(-(d2-1-q.shape[0])/2))%q.shape[0]+int(q.shape[0]/2) - q2_2 = np.roll(q,shift_range_2) - window_r = signal.gaussian(q.shape[0], std=0.2*q.shape[0]) - test_1 = np.sum(window_r*q2_1) - test_2 = np.sum(window_r*q2_2) - if test_1>=test_2: - q2 = q2_1 - shift_range = shift_range_1/q.shape[0] - else: - q2 = q2_2 - shift_range = shift_range_2/q.shape[0] - - - Sf = np.roll(S2,int(shift_range*q.shape[0]),axis=1) - ima2 = np.fft.ifft2(np.fft.ifftshift(Sf)) - return np.stack((np.real(ima2),np.imag(ima2)),axis=2) - - -def symetrisation_patch_test(real_part,imag_part): - S = np.fft.fftshift(np.fft.fft2(real_part[0,:,:,0]+1j*imag_part[0,:,:,0])) - p = np.zeros((S.shape[0])) # azimut (ncol) - for i in range(S.shape[0]): - p[i] = np.mean(np.abs(S[i,:])) - sp = p[::-1] - c = np.real(np.fft.ifft(np.fft.fft(p)*np.conjugate(np.fft.fft(sp)))) - d1 = np.unravel_index(c.argmax(),p.shape[0]) - d1 = d1[0] - shift_az_1 = int(round(-(d1-1)/2))%p.shape[0]+int(p.shape[0]/2) - p2_1 = np.roll(p,shift_az_1) - shift_az_2 = int(round(-(d1-1-p.shape[0])/2))%p.shape[0]+int(p.shape[0]/2) - p2_2 = np.roll(p,shift_az_2) - window = signal.gaussian(p.shape[0], std=0.2*p.shape[0]) - test_1 = np.sum(window*p2_1) - test_2 = np.sum(window*p2_2) - # make sure the spectrum is symetrized and zeo-Doppler centered - if test_1>=test_2: - p2 = p2_1 - shift_az = shift_az_1/p.shape[0] - else: - p2 = p2_2 - shift_az = shift_az_2/p.shape[0] - S2 = np.roll(S,int(shift_az*p.shape[0]),axis=0) - - q = np.zeros((S.shape[1])) # range (nlin) - for j in range(S.shape[1]): - q[j] = np.mean(np.abs(S[:,j])) - sq = q[::-1] - #correlation - cq = np.real(np.fft.ifft(np.fft.fft(q)*np.conjugate(np.fft.fft(sq)))) - d2 = np.unravel_index(cq.argmax(),q.shape[0]) - d2=d2[0] - shift_range_1 = int(round(-(d2-1)/2))%q.shape[0]+int(q.shape[0]/2) - q2_1 = np.roll(q,shift_range_1) - shift_range_2 = int(round(-(d2-1-q.shape[0])/2))%q.shape[0]+int(q.shape[0]/2) - q2_2 = np.roll(q,shift_range_2) - window_r = signal.gaussian(q.shape[0], std=0.2*q.shape[0]) - test_1 = np.sum(window_r*q2_1) - test_2 = np.sum(window_r*q2_2) - if test_1>=test_2: - q2 = q2_1 - shift_range = shift_range_1/q.shape[0] - else: - q2 = q2_2 - shift_range = shift_range_2/q.shape[0] - - - Sf = np.roll(S2,int(shift_range*q.shape[0]),axis=1) - ima2 = np.fft.ifft2(np.fft.ifftshift(Sf)) - ima2 = ima2.reshape(1, np.size(ima2, 0), np.size(ima2, 1), 1) - return np.real(ima2), np.imag(ima2) - - -class train_data(): - def __init__(self, filepath="%s/data/image_clean_pat.npy" % basedir): - self.filepath = filepath - assert '.npy' in filepath - if not os.path.exists(filepath): - print("[!] Data file not exists") - sys.exit(1) - - def __enter__(self): - print("[*] Loading data...") - self.data = np.load(self.filepath) - np.random.shuffle(self.data) - print("[*] Load successfully...") - return self.data - - def __exit__(self, type, value, trace): - del self.data - gc.collect() - print("In __exit__()") - - -def load_data(filepath="%s/data/image_clean_pat.npy" % basedir): - return train_data(filepath=filepath) - - -def normalize_sar(im): - return ((np.log(im+1e-6)-m)/(M-m)).astype(np.float32) - -def denormalize_sar(im): - return np.exp((np.clip(np.squeeze(im),0,1))*(M-m)+m) - -def load_train_data(filepath, patch_size, batch_size, stride_size, n_data_augmentation): #TODO: add control on training data: exit if does not exists - datagen = GenerateDataset() - imgs = datagen.generate_patches(src_dir=filepath, pat_size=patch_size, step=0, - stride=stride_size, bat_size=batch_size, data_aug_times=n_data_augmentation) - return imgs - -def load_sar_images(filelist): - if not isinstance(filelist, list): - im = np.load(filelist) - return np.array(im).reshape(1, np.size(im, 0), np.size(im, 1), 2) - data = [] - for file in filelist: - im = np.load(file) - data.append(np.array(im).reshape(1, np.size(im, 0), np.size(im, 1), 2)) - return data - - - -def store_data_and_plot(im, threshold, filename): - im = np.clip(im, 0, threshold) - im = im / threshold * 255 - im = Image.fromarray(im.astype('float64')).convert('L') - im.save(filename.replace('npy','png')) - - -def save_sar_images(denoised, noisy, imagename, save_dir, groundtruth=None): - choices = {'marais1':190.92, 'marais2': 168.49, 'saclay':470.92, 'lely':235.90, 'ramb':167.22, - 'risoul':306.94, 'limagne':178.43, 'saintgervais':560, 'Serreponcon': 450.0, - 'Sendai':600.0, 'Paris': 1291.0, 'Berlin': 1036.0, 'Bergen': 553.71, - 'SDP_Lambesc': 349.53, 'Grand_Canyon': 287.0, 'domancy': 560, 'Brazil': 103.0} - threshold = None - for x in choices: - if x in imagename: - threshold = choices.get(x) - if threshold is None: threshold = np.mean(noisy) + 3 * np.std(noisy) - - if groundtruth: - groundtruthfilename = save_dir+"/groundtruth_"+imagename - groundtruthfilename=groundtruthfilename.replace("\\","") - - np.save(groundtruthfilename,groundtruth) - store_data_and_plot(groundtruth, threshold, groundtruthfilename) - - denoisedfilename = save_dir + "/denoised_" + imagename - denoisedfilename=denoisedfilename.replace("\\","") - - np.save(denoisedfilename, denoised) - store_data_and_plot(denoised, threshold, denoisedfilename) - - noisyfilename = save_dir + "/noisy_" + imagename - noisyfilename=noisyfilename.replace("\\","") - - np.save(noisyfilename, noisy) - store_data_and_plot(noisy, threshold, noisyfilename) - - -def save_real_imag_images(real_part, imag_part, imagename, save_dir): - choices = {'marais1': 190.92, 'marais2': 168.49, 'saclay': 470.92, 'lely': 235.90, 'ramb': 167.22, - 'risoul': 306.94, 'limagne': 178.43, 'saintgervais': 560, 'Serreponcon': 450.0, - 'Sendai': 600.0, 'Paris': 1291.0, 'Berlin': 1036.0, 'Bergen': 553.71, - 'SDP_Lambesc': 349.53, 'Grand_Canyon': 287.0, 'Brazil': 103.0} - threshold = None - for x in choices: - if x in imagename: - threshold = choices.get(x) - if threshold is None: threshold = np.mean(imag_part) + 3 * np.std(imag_part) - - realfilename = save_dir + "/denoised_real_" + imagename - realfilename=realfilename.replace("\\","") - - np.save(realfilename, real_part) - store_data_and_plot(real_part, threshold, realfilename) - - imagfilename = save_dir + "/denoised_imag_" + imagename - imagfilename=imagfilename.replace("\\","") - - np.save(imagfilename, imag_part) - store_data_and_plot(imag_part, threshold, imagfilename) - -def save_real_imag_images_noisy(real_part, imag_part, imagename, save_dir): - choices = {'marais1': 190.92, 'marais2': 168.49, 'saclay': 470.92, 'lely': 235.90, 'ramb': 167.22, - 'risoul': 306.94, 'limagne': 178.43, 'saintgervais': 560, 'Serreponcon': 450.0, - 'Sendai': 600.0, 'Paris': 1291.0, 'Berlin': 1036.0, 'Bergen': 553.71, - 'SDP_Lambesc': 349.53, 'Grand_Canyon': 287.0, 'Brazil': 103.0} - threshold = None - for x in choices: - if x in imagename: - threshold = choices.get(x) - if threshold is None: threshold = np.mean(np.abs(imag_part)) + 3 * np.std(np.abs(imag_part)) - - realfilename = save_dir + "/noisy_real_" + imagename - realfilename=realfilename.replace("\\","") - - np.save(realfilename, real_part) - store_data_and_plot(np.sqrt(2)*np.abs(real_part), threshold, realfilename) - - imagfilename = save_dir + "/noisy_imag_" + imagename - imagfilename=imagfilename.replace("\\","") - - np.save(imagfilename, imag_part) - store_data_and_plot(np.sqrt(2)*np.abs(imag_part), threshold, imagfilename) - - -def cal_psnr(Shat, S): - # takes amplitudes in input - # Shat: a SAR amplitude image - # S: a reference SAR image - P = np.quantile(S, 0.99) - res = 10 * np.log10((P ** 2) / np.mean(np.abs(Shat - S) ** 2)) - return res - - diff --git a/tox.ini b/tox.ini index 91d6dbd..a6e0426 100644 --- a/tox.ini +++ b/tox.ini @@ -1,8 +1,9 @@ [tox] -envlist = py36, py37, py38, flake8 +envlist = py36, py37, py38, py39, flake8 [travis] python = + 3.9: py39 3.8: py38 3.7: py37 3.6: py36