pottslab 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pottslab-1.0.0/.github/workflows/build_wheels.yml +126 -0
- pottslab-1.0.0/.gitignore +29 -0
- pottslab-1.0.0/Auxiliary/Operators/convop.m +30 -0
- pottslab-1.0.0/Auxiliary/Operators/linop.m +66 -0
- pottslab-1.0.0/Auxiliary/Operators/radonop.m +25 -0
- pottslab-1.0.0/Auxiliary/convkernel.m +46 -0
- pottslab-1.0.0/Auxiliary/countJumps.m +6 -0
- pottslab-1.0.0/Auxiliary/energyL2Potts.m +66 -0
- pottslab-1.0.0/Auxiliary/intmatrix.m +13 -0
- pottslab-1.0.0/Auxiliary/medianw.m +21 -0
- pottslab-1.0.0/Auxiliary/plimage2double.m +7 -0
- pottslab-1.0.0/Auxiliary/plpsnr.m +10 -0
- pottslab-1.0.0/Auxiliary/psnr.m +13 -0
- pottslab-1.0.0/Auxiliary/randidx.m +11 -0
- pottslab-1.0.0/Auxiliary/randl.m +11 -0
- pottslab-1.0.0/Auxiliary/samplesToWeights.m +20 -0
- pottslab-1.0.0/Auxiliary/segToLabel.m +26 -0
- pottslab-1.0.0/Auxiliary/setPLJavaPath.m +40 -0
- pottslab-1.0.0/Auxiliary/showPotts.m +30 -0
- pottslab-1.0.0/Auxiliary/showSparse.m +34 -0
- pottslab-1.0.0/Auxiliary/showdbl.m +46 -0
- pottslab-1.0.0/Auxiliary/softThreshold.m +8 -0
- pottslab-1.0.0/Auxiliary/spconvmatrix.m +21 -0
- pottslab-1.0.0/Auxiliary/spdiffmatrix.m +12 -0
- pottslab-1.0.0/CHANGELOG.md +57 -0
- pottslab-1.0.0/CITATION.cff +113 -0
- pottslab-1.0.0/Cargo.lock +323 -0
- pottslab-1.0.0/Cargo.toml +25 -0
- pottslab-1.0.0/Data/church.jpg +0 -0
- pottslab-1.0.0/Data/colors.png +0 -0
- pottslab-1.0.0/Data/desert.jpg +0 -0
- pottslab-1.0.0/Data/imageSources.txt +11 -0
- pottslab-1.0.0/Data/loadPcwConst.m +151 -0
- pottslab-1.0.0/Data/loadSparse.m +102 -0
- pottslab-1.0.0/Data/lookmickey.jpg +0 -0
- pottslab-1.0.0/Demos/1D/demoL1iPotts_DecImp.m +33 -0
- pottslab-1.0.0/Demos/1D/demoL1iPotts_DecLap.m +32 -0
- pottslab-1.0.0/Demos/1D/demoL1iSpars_DecImp.m +30 -0
- pottslab-1.0.0/Demos/1D/demoL1iSpars_DecLap.m +27 -0
- pottslab-1.0.0/Demos/1D/demoL2iPotts_Deconv.m +26 -0
- pottslab-1.0.0/Demos/1D/demoL2iPotts_Fourier.m +29 -0
- pottslab-1.0.0/Demos/1D/demoL2iPotts_Linop.m +34 -0
- pottslab-1.0.0/Demos/1D/demoL2iSpars_Deconv.m +27 -0
- pottslab-1.0.0/Demos/1D/demoPotts_GaussianNoise.m +19 -0
- pottslab-1.0.0/Demos/1D/demoPotts_ImpulsiveNoise.m +21 -0
- pottslab-1.0.0/Demos/1D/demoPotts_LaplacianNoise.m +19 -0
- pottslab-1.0.0/Demos/2D/demoPotts2DColorDenoising.m +25 -0
- pottslab-1.0.0/Demos/2D/demoPotts2DColorInpainting.m +33 -0
- pottslab-1.0.0/Demos/2D/demoPotts2DColorMissing.m +32 -0
- pottslab-1.0.0/Demos/2D/demoPotts2DColorSegmentation.m +29 -0
- pottslab-1.0.0/Demos/2D/demoPotts2DRadon.m +39 -0
- pottslab-1.0.0/Demos/2D/results/plFigPottsRec7Angles.fig +0 -0
- pottslab-1.0.0/Demos/pottsLabDemo.m +8 -0
- pottslab-1.0.0/Docs/deconv/noisy.png +0 -0
- pottslab-1.0.0/Docs/deconv/uPottsRho.png +0 -0
- pottslab-1.0.0/Docs/potts1d.png +0 -0
- pottslab-1.0.0/Docs/radon/phantom.png +0 -0
- pottslab-1.0.0/Docs/radon/recFBP.png +0 -0
- pottslab-1.0.0/Docs/radon/recFBPRamLak.png +0 -0
- pottslab-1.0.0/Docs/radon/recPotts.png +0 -0
- pottslab-1.0.0/Docs/texture.png +0 -0
- pottslab-1.0.0/Docs/titleImage.png +0 -0
- pottslab-1.0.0/Java/bin/pottslab/Benchmark$Thunk.class +0 -0
- pottslab-1.0.0/Java/bin/pottslab/Benchmark.class +0 -0
- pottslab-1.0.0/Java/bin/pottslab/IndexedLinkedHistogram$HistNode.class +0 -0
- pottslab-1.0.0/Java/bin/pottslab/IndexedLinkedHistogram.class +0 -0
- pottslab-1.0.0/Java/bin/pottslab/IndexedLinkedHistogramUnweighted$HistNode.class +0 -0
- pottslab-1.0.0/Java/bin/pottslab/IndexedLinkedHistogramUnweighted.class +0 -0
- pottslab-1.0.0/Java/bin/pottslab/JavaTools.class +0 -0
- pottslab-1.0.0/Java/bin/pottslab/L2Potts.class +0 -0
- pottslab-1.0.0/Java/bin/pottslab/PLImage$1.class +0 -0
- pottslab-1.0.0/Java/bin/pottslab/PLImage.class +0 -0
- pottslab-1.0.0/Java/bin/pottslab/PLProcessor.class +0 -0
- pottslab-1.0.0/Java/bin/pottslab/PLVector.class +0 -0
- pottslab-1.0.0/Java/bin/pottslab/RunMe.class +0 -0
- pottslab-1.0.0/Java/src/META-INF/MANIFEST.MF +3 -0
- pottslab-1.0.0/Java/src/pottslab/Benchmark.java +184 -0
- pottslab-1.0.0/Java/src/pottslab/IndexedLinkedHistogram.java +349 -0
- pottslab-1.0.0/Java/src/pottslab/IndexedLinkedHistogramUnweighted.java +240 -0
- pottslab-1.0.0/Java/src/pottslab/JavaTools.java +309 -0
- pottslab-1.0.0/Java/src/pottslab/L2Potts.java +136 -0
- pottslab-1.0.0/Java/src/pottslab/PLImage.java +170 -0
- pottslab-1.0.0/Java/src/pottslab/PLProcessor.java +306 -0
- pottslab-1.0.0/Java/src/pottslab/PLVector.java +258 -0
- pottslab-1.0.0/Java/src/pottslab/RunMe.java +38 -0
- pottslab-1.0.0/LICENSE +21 -0
- pottslab-1.0.0/License.txt +21 -0
- pottslab-1.0.0/PKG-INFO +327 -0
- pottslab-1.0.0/PORTED_BY.md +60 -0
- pottslab-1.0.0/Plugins/PottsSegmentationJ_.jar +0 -0
- pottslab-1.0.0/Potts/PottsCore/findBestPartition.m +116 -0
- pottslab-1.0.0/Potts/PottsCore/iPottsADMM.m +147 -0
- pottslab-1.0.0/Potts/PottsCore/reconstructionFromPartition.m +56 -0
- pottslab-1.0.0/Potts/minL1Potts.m +80 -0
- pottslab-1.0.0/Potts/minL1iPotts.m +22 -0
- pottslab-1.0.0/Potts/minL2Potts.m +55 -0
- pottslab-1.0.0/Potts/minL2iPotts.m +22 -0
- pottslab-1.0.0/Potts2D/Core/iPotts2DADMM.m +203 -0
- pottslab-1.0.0/Potts2D/minL2Potts2DADMM.m +68 -0
- pottslab-1.0.0/Potts2D/minL2iPotts2DADMM.m +5 -0
- pottslab-1.0.0/README.md +151 -0
- pottslab-1.0.0/README_PYTHON.md +296 -0
- pottslab-1.0.0/Sparsity/SparsityCore/iSparsADMM.m +138 -0
- pottslab-1.0.0/Sparsity/SparsityCore/iSparsByPottsADMM.m +54 -0
- pottslab-1.0.0/Sparsity/SparsityCore/minSpars.m +14 -0
- pottslab-1.0.0/Sparsity/minL1Spars.m +11 -0
- pottslab-1.0.0/Sparsity/minL1iSpars.m +25 -0
- pottslab-1.0.0/Sparsity/minL2Spars.m +11 -0
- pottslab-1.0.0/Sparsity/minL2iSpars.m +36 -0
- pottslab-1.0.0/Tikhonov/minL1Tikhonov.m +117 -0
- pottslab-1.0.0/Tikhonov/minL2Tikhonov.m +98 -0
- pottslab-1.0.0/Tikhonov/minL2TikhonovFBP.m +57 -0
- pottslab-1.0.0/benchmark.py +316 -0
- pottslab-1.0.0/installPottslab.m +39 -0
- pottslab-1.0.0/pottslab/__init__.py +105 -0
- pottslab-1.0.0/pottslab/_core.pyi +63 -0
- pottslab-1.0.0/pottslab/_core_py.py +349 -0
- pottslab-1.0.0/pottslab/inverse.py +210 -0
- pottslab-1.0.0/pottslab/potts1d.py +159 -0
- pottslab-1.0.0/pottslab/potts2d.py +133 -0
- pottslab-1.0.0/pottslab/sparsity.py +103 -0
- pottslab-1.0.0/pottslab/tikhonov.py +131 -0
- pottslab-1.0.0/pottslab/utils.py +171 -0
- pottslab-1.0.0/pottslab-standalone.jar +0 -0
- pottslab-1.0.0/pyproject.toml +46 -0
- pottslab-1.0.0/src/admm.rs +246 -0
- pottslab-1.0.0/src/l1potts.rs +414 -0
- pottslab-1.0.0/src/l2potts.rs +127 -0
- pottslab-1.0.0/src/lib.rs +131 -0
- pottslab-1.0.0/src/processor.rs +167 -0
- pottslab-1.0.0/tests/conftest.py +47 -0
- pottslab-1.0.0/tests/test_brute_force.py +201 -0
- pottslab-1.0.0/tests/test_edge_cases.py +421 -0
- pottslab-1.0.0/tests/test_hardening.py +590 -0
- pottslab-1.0.0/tests/test_integration.py +204 -0
- pottslab-1.0.0/tests/test_inverse.py +80 -0
- pottslab-1.0.0/tests/test_l1_median_bug.py +282 -0
- pottslab-1.0.0/tests/test_l1_potts_1d.py +92 -0
- pottslab-1.0.0/tests/test_l2_potts_1d.py +195 -0
- pottslab-1.0.0/tests/test_matlab_parity.py +257 -0
- pottslab-1.0.0/tests/test_numerical_precision.py +228 -0
- pottslab-1.0.0/tests/test_potts_2d.py +105 -0
- pottslab-1.0.0/tests/test_properties.py +267 -0
- pottslab-1.0.0/tests/test_sparsity.py +84 -0
- pottslab-1.0.0/tests/test_tikhonov.py +61 -0
- pottslab-1.0.0/tests/test_utils.py +129 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
name: Build and publish wheels
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*" # run on version tags, e.g. v1.0.1
|
|
7
|
+
workflow_dispatch: # allow manual runs from the Actions UI
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
# ── Build platform wheels ──────────────────────────────────────────────────
|
|
11
|
+
build_wheels:
|
|
12
|
+
name: Build ${{ matrix.target }} wheel
|
|
13
|
+
runs-on: ${{ matrix.os }}
|
|
14
|
+
strategy:
|
|
15
|
+
fail-fast: false
|
|
16
|
+
matrix:
|
|
17
|
+
include:
|
|
18
|
+
# Linux — x86_64 (manylinux, covers most servers and desktops)
|
|
19
|
+
- os: ubuntu-latest
|
|
20
|
+
target: x86_64
|
|
21
|
+
manylinux: auto
|
|
22
|
+
|
|
23
|
+
# Linux — aarch64 (Raspberry Pi, AWS Graviton, Apple M-series via
|
|
24
|
+
# emulation; QEMU is set up automatically by maturin-action)
|
|
25
|
+
- os: ubuntu-latest
|
|
26
|
+
target: aarch64
|
|
27
|
+
manylinux: auto
|
|
28
|
+
|
|
29
|
+
# macOS — Apple Silicon
|
|
30
|
+
# Intel macOS (macos-13) was dropped: GitHub-hosted Intel runners are
|
|
31
|
+
# being retired and queue depth made the job time out at the 24h
|
|
32
|
+
# maximum. Intel-Mac users can install from the sdist.
|
|
33
|
+
- os: macos-14
|
|
34
|
+
target: aarch64
|
|
35
|
+
|
|
36
|
+
# Windows — x86_64
|
|
37
|
+
- os: windows-latest
|
|
38
|
+
target: x86_64
|
|
39
|
+
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v4
|
|
42
|
+
|
|
43
|
+
# Native Windows/macOS runners only have one Python on PATH by default,
|
|
44
|
+
# so maturin's --interpreter 3.9..3.13 lookup fails. Pre-installing all
|
|
45
|
+
# five versions via setup-python adds them to PATH. The manylinux
|
|
46
|
+
# container build skips this step (the host setup doesn't reach inside
|
|
47
|
+
# the container, which already ships every CPython we need).
|
|
48
|
+
- name: Set up Python (native runners only)
|
|
49
|
+
if: matrix.manylinux != 'auto'
|
|
50
|
+
uses: actions/setup-python@v5
|
|
51
|
+
with:
|
|
52
|
+
python-version: |
|
|
53
|
+
3.9
|
|
54
|
+
3.10
|
|
55
|
+
3.11
|
|
56
|
+
3.12
|
|
57
|
+
3.13
|
|
58
|
+
|
|
59
|
+
- name: Build wheels
|
|
60
|
+
uses: PyO3/maturin-action@v1
|
|
61
|
+
with:
|
|
62
|
+
target: ${{ matrix.target }}
|
|
63
|
+
manylinux: ${{ matrix.manylinux || '' }}
|
|
64
|
+
# Build for every supported CPython interpreter.
|
|
65
|
+
# PyPy is excluded because PyO3 support requires extra setup.
|
|
66
|
+
args: >-
|
|
67
|
+
--release
|
|
68
|
+
--out dist
|
|
69
|
+
--interpreter 3.9 3.10 3.11 3.12 3.13
|
|
70
|
+
|
|
71
|
+
- name: Upload wheel artifacts
|
|
72
|
+
uses: actions/upload-artifact@v4
|
|
73
|
+
with:
|
|
74
|
+
name: wheels-${{ matrix.target }}-${{ matrix.os }}
|
|
75
|
+
path: dist/*.whl
|
|
76
|
+
|
|
77
|
+
# ── Build source distribution ──────────────────────────────────────────────
|
|
78
|
+
build_sdist:
|
|
79
|
+
name: Build source distribution
|
|
80
|
+
runs-on: ubuntu-latest
|
|
81
|
+
steps:
|
|
82
|
+
- uses: actions/checkout@v4
|
|
83
|
+
|
|
84
|
+
- name: Build sdist
|
|
85
|
+
uses: PyO3/maturin-action@v1
|
|
86
|
+
with:
|
|
87
|
+
command: sdist
|
|
88
|
+
args: --out dist
|
|
89
|
+
|
|
90
|
+
- name: Upload sdist artifact
|
|
91
|
+
uses: actions/upload-artifact@v4
|
|
92
|
+
with:
|
|
93
|
+
name: sdist
|
|
94
|
+
path: dist/*.tar.gz
|
|
95
|
+
|
|
96
|
+
# ── Publish to PyPI ────────────────────────────────────────────────────────
|
|
97
|
+
publish:
|
|
98
|
+
name: Publish to PyPI
|
|
99
|
+
runs-on: ubuntu-latest
|
|
100
|
+
needs: [build_wheels, build_sdist]
|
|
101
|
+
# Only publish on version-tag pushes, not on workflow_dispatch
|
|
102
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
103
|
+
# Requires an environment named "pypi" configured in the repo settings
|
|
104
|
+
# with PyPI as a trusted publisher (no API token needed).
|
|
105
|
+
environment:
|
|
106
|
+
name: pypi
|
|
107
|
+
url: https://pypi.org/project/pottslab/
|
|
108
|
+
permissions:
|
|
109
|
+
id-token: write # required for OIDC trusted publishing
|
|
110
|
+
|
|
111
|
+
steps:
|
|
112
|
+
- name: Download all wheel and sdist artifacts
|
|
113
|
+
uses: actions/download-artifact@v4
|
|
114
|
+
with:
|
|
115
|
+
merge-multiple: true
|
|
116
|
+
path: dist
|
|
117
|
+
|
|
118
|
+
- name: Publish to PyPI
|
|
119
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
120
|
+
# Uses PyPI OIDC trusted publishing — no API token required.
|
|
121
|
+
# Set up at: https://pypi.org/manage/account/publishing/
|
|
122
|
+
# Project name: pottslab
|
|
123
|
+
# Owner: mstorath
|
|
124
|
+
# Repository: Pottslab
|
|
125
|
+
# Workflow: build_wheels.yml
|
|
126
|
+
# Environment: pypi
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Rust build artifacts
|
|
2
|
+
target/
|
|
3
|
+
Cargo.lock.bak
|
|
4
|
+
|
|
5
|
+
# Compiled Python extension (platform-specific; built by CI)
|
|
6
|
+
pottslab/_core*.so
|
|
7
|
+
pottslab/_core*.pyd
|
|
8
|
+
|
|
9
|
+
# Python cache
|
|
10
|
+
__pycache__/
|
|
11
|
+
*.pyc
|
|
12
|
+
*.pyo
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
|
|
15
|
+
# macOS
|
|
16
|
+
.DS_Store
|
|
17
|
+
|
|
18
|
+
# Distribution / packaging
|
|
19
|
+
dist/
|
|
20
|
+
*.egg-info/
|
|
21
|
+
.eggs/
|
|
22
|
+
|
|
23
|
+
# Editors / IDEs
|
|
24
|
+
.vscode/
|
|
25
|
+
.idea/
|
|
26
|
+
*.swp
|
|
27
|
+
|
|
28
|
+
# Jupyter
|
|
29
|
+
.ipynb_checkpoints/
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
classdef convop < double
|
|
2
|
+
%convop A class for circular convolution by FFT
|
|
3
|
+
|
|
4
|
+
% written by M. Storath
|
|
5
|
+
% $Date: 2014-05-07 11:42:11 +0200 (Mi, 07. Mai 2014) $ $Revision: 89 $
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
methods
|
|
9
|
+
% constructor
|
|
10
|
+
function obj = convop(fourier)
|
|
11
|
+
obj = obj@double(fourier);
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
% ctranspose (')
|
|
15
|
+
function C = ctranspose(A)
|
|
16
|
+
C = convop(conj(A));
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
% mtimes (*)
|
|
20
|
+
function C = mtimes( A, B )
|
|
21
|
+
if isa(B, 'convop')
|
|
22
|
+
C = convop( A .* B );
|
|
23
|
+
else
|
|
24
|
+
C = ifftn( A .* fftn(B) );
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
classdef linop
|
|
2
|
+
%linop A class for linear operators
|
|
3
|
+
|
|
4
|
+
% written by M. Storath
|
|
5
|
+
% $Date: 2015-10-15 15:07:43 +0200 (Do, 15. Okt 2015) $ $Revision: 132 $
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
properties
|
|
9
|
+
% function handle for evaluation A * x
|
|
10
|
+
eval;
|
|
11
|
+
% function handle for evaluation A' * x
|
|
12
|
+
ctrans;
|
|
13
|
+
% A'A
|
|
14
|
+
normalOp;
|
|
15
|
+
% true if A'A positive definite
|
|
16
|
+
posdef;
|
|
17
|
+
% true if A'A positive definite
|
|
18
|
+
lseSolver;
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
methods
|
|
22
|
+
% constructor
|
|
23
|
+
function A = linop(eval, ctrans, varargin)
|
|
24
|
+
% if it is a matrix
|
|
25
|
+
if ~isa(eval, 'function_handle')
|
|
26
|
+
A.eval = @(x) eval * x;
|
|
27
|
+
A.ctrans = @(x) eval' * x;
|
|
28
|
+
M = eval' * eval;
|
|
29
|
+
A.normalOp = @(x) M * x;
|
|
30
|
+
else
|
|
31
|
+
A.eval = eval;
|
|
32
|
+
A.ctrans = ctrans;
|
|
33
|
+
A.normalOp = @(x) A.ctrans(A.eval(x));
|
|
34
|
+
end
|
|
35
|
+
ip = inputParser;
|
|
36
|
+
addParamValue(ip, 'posdef', false);
|
|
37
|
+
addParamValue(ip, 'lseSolver', []);
|
|
38
|
+
parse(ip, varargin{:});
|
|
39
|
+
par = ip.Results;
|
|
40
|
+
A.posdef = par.posdef;
|
|
41
|
+
A.lseSolver = par.lseSolver;
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
% ctranspose (')
|
|
45
|
+
function C = ctranspose(A)
|
|
46
|
+
C = linop(A.ctrans, A.eval);
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
% mtimes (*)
|
|
50
|
+
function C = mtimes( A, B )
|
|
51
|
+
if isa(B, 'linop')
|
|
52
|
+
C = linop( @(x) A.eval(B.eval(x)), @(x) B.ctrans(A.ctrans(x)));
|
|
53
|
+
else
|
|
54
|
+
C = A.eval(B);
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
% size
|
|
59
|
+
function s = size(A)
|
|
60
|
+
%warning('Size is deprecated for class linop');
|
|
61
|
+
s = [1 1];
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
classdef radonop < linop
|
|
2
|
+
%radonop A class for Radon transform
|
|
3
|
+
|
|
4
|
+
% written by M. Storath
|
|
5
|
+
% $Date: 2014-09-02 14:56:23 +0200 (Di, 02. Sep 2014) $ $Revision: 105 $
|
|
6
|
+
|
|
7
|
+
properties
|
|
8
|
+
% solution method for prox
|
|
9
|
+
useFBP;
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
methods
|
|
13
|
+
% constructor
|
|
14
|
+
function A = radonop(theta, imgSize)
|
|
15
|
+
|
|
16
|
+
eval = @(x) radon(x, theta);
|
|
17
|
+
ctrans = @(x) iradon(x, theta, 'linear', 'None', 1, imgSize);
|
|
18
|
+
|
|
19
|
+
A = A@linop(eval, ctrans);
|
|
20
|
+
A.posdef = true;
|
|
21
|
+
A.useFBP = false;
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
function h = convkernel( type, n, scale )
|
|
2
|
+
%CONVKERNEL Creates a convolution kernel
|
|
3
|
+
|
|
4
|
+
% written by M. Storath
|
|
5
|
+
% $Date: 2012/10/29 01:19:08 $ $Revision: 0.1 $
|
|
6
|
+
|
|
7
|
+
if not(exist('scale', 'var'))
|
|
8
|
+
scale = 1;
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
% set coordinates
|
|
12
|
+
d = n/2;
|
|
13
|
+
x = linspace(-d, d, n)/scale;
|
|
14
|
+
|
|
15
|
+
switch type
|
|
16
|
+
case 'box'
|
|
17
|
+
h = ones(n, 1);
|
|
18
|
+
|
|
19
|
+
case 'hat'
|
|
20
|
+
h(x >= 0) = 1-x(x >= 0);
|
|
21
|
+
h(x < 0) = 1 + x(x < 0);
|
|
22
|
+
h(abs(x) > 1) = 0;
|
|
23
|
+
|
|
24
|
+
case 'gaussian'
|
|
25
|
+
h = exp(-0.5 * x.^2);
|
|
26
|
+
|
|
27
|
+
case 'doubleexp'
|
|
28
|
+
h = exp(-0.5 * abs(x));
|
|
29
|
+
|
|
30
|
+
case 'mollifier'
|
|
31
|
+
h = exp(-1./(1 - abs(x).^2));
|
|
32
|
+
h(abs(x) > 1) = 0;
|
|
33
|
+
|
|
34
|
+
case 'ramp'
|
|
35
|
+
h(x >= 0) = 1-x(x >= 0);
|
|
36
|
+
h(abs(x) > 1) = 0;
|
|
37
|
+
|
|
38
|
+
otherwise
|
|
39
|
+
error('This option does not exist.')
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
% normalize
|
|
43
|
+
h = h(:)./sum(h);
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
function [energy, jumpPenalty, dataError] = energyL2Potts( u, f, gamma, A, isotropic )
|
|
2
|
+
%energyL2Potts Computes the energy of the L2 Potts functional
|
|
3
|
+
|
|
4
|
+
if exist('A', 'var') && not(isempty(A))
|
|
5
|
+
Au = A * u;
|
|
6
|
+
dataError = sum((Au(:) - f(:)).^2);
|
|
7
|
+
else
|
|
8
|
+
dataError = sum((u(:) - f(:)).^2);
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
if isvector(u)
|
|
13
|
+
% vectors
|
|
14
|
+
jumpPenalty = sum(diff(u(:)) ~= 0);
|
|
15
|
+
else
|
|
16
|
+
% matrices
|
|
17
|
+
nJumpComp = 0; % jumps in compass directions
|
|
18
|
+
nJumpDiag = 0; % jumps in diagonal directions
|
|
19
|
+
|
|
20
|
+
% count jumps
|
|
21
|
+
for i = 1:size(u, 1)
|
|
22
|
+
for j = 1:size(u, 2)-1
|
|
23
|
+
if ~all((u(i,j,:) == u(i,j+1,:)))
|
|
24
|
+
nJumpComp = nJumpComp + 1;
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
for i = 1:size(u, 1)-1
|
|
29
|
+
for j = 1:size(u, 2)
|
|
30
|
+
if ~all((u(i,j,:) == u(i+1,j,:)))
|
|
31
|
+
nJumpComp = nJumpComp + 1;
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
for i = 1:size(u, 1)-1
|
|
36
|
+
for j = 1:size(u, 2)-1
|
|
37
|
+
if ~all((u(i,j,:) == u(i+1,j+1,:)))
|
|
38
|
+
nJumpDiag = nJumpDiag + 1;
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
for i = 1:size(u, 1)-1
|
|
43
|
+
for j = 2:size(u, 2)
|
|
44
|
+
if ~all((u(i,j,:) == u(i+1,j-1,:)))
|
|
45
|
+
nJumpDiag = nJumpDiag + 1;
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
% set weights (isotropic by default)
|
|
51
|
+
if ~exist('isotropic', 'var') || isotropic
|
|
52
|
+
omega1 = sqrt(2) - 1;
|
|
53
|
+
omega2 = 1 - sqrt(2)/2;
|
|
54
|
+
else
|
|
55
|
+
omega1 = 1;
|
|
56
|
+
omega2 = 0;
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
% compute energy
|
|
60
|
+
jumpPenalty = (omega1 * nJumpComp + omega2* nJumpDiag);
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
energy = gamma * jumpPenalty + dataError;
|
|
65
|
+
|
|
66
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
function A = intmatrix( n )
|
|
2
|
+
%INTMATRIX Creates a matrix that acts as integration
|
|
3
|
+
% (cumulative sum) on the input vector
|
|
4
|
+
%
|
|
5
|
+
% Au = cumsum(u)
|
|
6
|
+
|
|
7
|
+
% written by M. Storath
|
|
8
|
+
% $Date: 2012/10/29 01:19:08 $ $Revision: 0.1 $
|
|
9
|
+
|
|
10
|
+
A = tril(ones(n));
|
|
11
|
+
|
|
12
|
+
end
|
|
13
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
function mu = medianw( data, weight )
|
|
2
|
+
% medianw Computes a weighted median of the data
|
|
3
|
+
|
|
4
|
+
% written by M. Storath
|
|
5
|
+
% $Date: 2012/10/29 01:19:08 $ $Revision: 0.1 $
|
|
6
|
+
|
|
7
|
+
if numel(data) == 1
|
|
8
|
+
mu = data;
|
|
9
|
+
else
|
|
10
|
+
[dataSorted, idx] = sort(data);
|
|
11
|
+
weightSorted = weight(idx);
|
|
12
|
+
weightSum = sum(weight);
|
|
13
|
+
cumWeight = cumsum(weightSorted)/weightSum;
|
|
14
|
+
% find first median index
|
|
15
|
+
idx = find(cumWeight < 0.5, 1, 'last' ) + 1;
|
|
16
|
+
if isempty(idx)
|
|
17
|
+
idx = 1;
|
|
18
|
+
end
|
|
19
|
+
mu = dataSorted(idx);
|
|
20
|
+
end
|
|
21
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
function r = plpsnr( groundTruth, signal )
|
|
2
|
+
%plPSNR Computes the peak signal to noise ratio
|
|
3
|
+
|
|
4
|
+
% written by M. Storath
|
|
5
|
+
% $Date: 2014-05-07 14:23:10 +0200 (Mi, 07. Mai 2014) $ $Revision: 90 $
|
|
6
|
+
|
|
7
|
+
mse = mean(abs(signal(:) - groundTruth(:)).^2);
|
|
8
|
+
r = 10 * log10(max(groundTruth(:))^2 / mse);
|
|
9
|
+
|
|
10
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
function r = psnr( groundTruth, signal )
|
|
2
|
+
%PSNR Computes the peak signal to noise ratio
|
|
3
|
+
|
|
4
|
+
% written by M. Storath
|
|
5
|
+
% $Date: 2012/10/29 01:19:08 $ $Revision: 0.1 $
|
|
6
|
+
|
|
7
|
+
warning('The function psnr conflicts with the new function psnr from the image processing toolbox from Matlab v2014a. Use plpsnr instead.')
|
|
8
|
+
|
|
9
|
+
mse = mean(abs(signal(:) - groundTruth(:)).^2);
|
|
10
|
+
r = 10 * log10(max(groundTruth(:))^2 / mse);
|
|
11
|
+
|
|
12
|
+
end
|
|
13
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
function idx = randidx( siz, fraction )
|
|
2
|
+
%randidx Selects randomly a fraction of indices for a matrix of size siz
|
|
3
|
+
|
|
4
|
+
% written by M. Storath
|
|
5
|
+
% $Date: 2012/10/29 01:19:08 $ $Revision: 0.1 $
|
|
6
|
+
|
|
7
|
+
n = prod(siz);
|
|
8
|
+
idx = randperm(n) ;
|
|
9
|
+
idx = idx(1:round(fraction * n));
|
|
10
|
+
end
|
|
11
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
function y = randl( varargin )
|
|
2
|
+
%randl Random normal Laplacian noise, mean = 0, variance sigma^2 = 1
|
|
3
|
+
% pdf: $\frac{1}{\sqrt{2}} e^{- \sqrt{2} |x|}$
|
|
4
|
+
|
|
5
|
+
% written by M. Storath
|
|
6
|
+
% $Date: 2012/10/29 01:19:08 $ $Revision: 0.1 $
|
|
7
|
+
|
|
8
|
+
x = rand( varargin{:} ) - 0.5;
|
|
9
|
+
y = -sign(x) .* log(1 - 2 * abs(x)) / sqrt(2);
|
|
10
|
+
end
|
|
11
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
function weights = samplesToWeights( samples )
|
|
2
|
+
%samplesToWeights Computes weights from a set of sample points
|
|
3
|
+
|
|
4
|
+
% written by M. Storath
|
|
5
|
+
% $Date: 2012/10/29 01:19:08 $ $Revision: 0.1 $
|
|
6
|
+
|
|
7
|
+
%init
|
|
8
|
+
weights = zeros(size(samples));
|
|
9
|
+
|
|
10
|
+
% first and last weight
|
|
11
|
+
weights(1) = samples(2) - samples(1);
|
|
12
|
+
weights(end) = samples(end) - samples(end-1);
|
|
13
|
+
|
|
14
|
+
% central weights
|
|
15
|
+
subs = 2:numel(samples)-1;
|
|
16
|
+
weights(subs) = 0.5 * ( abs(samples(subs) - samples(subs-1)) ...
|
|
17
|
+
+ abs(samples(subs) - samples(subs+1)) );
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
function labelImg = segToLabel(u, conn)
|
|
2
|
+
%SEGTOLABEL Converts the output image of a segmentation function (e.g. minL2Potts2DADMM) to a
|
|
3
|
+
%label image with integer labels (each connected component gets a unique integer)
|
|
4
|
+
% u: image to label (typically the output of minL2Potts2DADMM))
|
|
5
|
+
% conn: connectivity as in bwconncomp (default: 8)
|
|
6
|
+
|
|
7
|
+
if ~exist('conn', 'var')
|
|
8
|
+
conn = 8;
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
[m,n,c] = size(u);
|
|
12
|
+
vals = unique(reshape(u, m*n, c), 'rows');
|
|
13
|
+
labelImg = zeros(m, n);
|
|
14
|
+
labelCounter = 0;
|
|
15
|
+
for i=1:size(vals,1)
|
|
16
|
+
bw_mult = (vals(i,:) == reshape(u, m*n, c));
|
|
17
|
+
bw = bw_mult(:,1);
|
|
18
|
+
CC = bwconncomp(reshape(double(bw), m, n), conn);
|
|
19
|
+
for j = 1:CC.NumObjects
|
|
20
|
+
labelImg(CC.PixelIdxList{j}) = labelCounter;
|
|
21
|
+
labelCounter = labelCounter + 1;
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
function setPLJavaPath(static)
|
|
2
|
+
|
|
3
|
+
% the path
|
|
4
|
+
jpath = fullfile( fileparts(which(mfilename)), '..', 'Java', 'bin');
|
|
5
|
+
|
|
6
|
+
% dynamic path
|
|
7
|
+
javaaddpath(jpath);
|
|
8
|
+
|
|
9
|
+
% static path
|
|
10
|
+
if exist('static', 'var') && static
|
|
11
|
+
% static path (is faster, requires restart to take effect)
|
|
12
|
+
upath = userpath;
|
|
13
|
+
jpathfile = fullfile(upath, 'javaclasspath.txt');
|
|
14
|
+
disp(['Appending java class path to ' jpathfile]);
|
|
15
|
+
pathExists = false;
|
|
16
|
+
% check if path exists
|
|
17
|
+
currentPath = javaclasspath('-static');
|
|
18
|
+
|
|
19
|
+
for i = 1:numel(currentPath)
|
|
20
|
+
pathExists = strcmp(currentPath{i}, jpath) || pathExists;
|
|
21
|
+
end
|
|
22
|
+
% append path to classpath
|
|
23
|
+
if ~pathExists
|
|
24
|
+
try
|
|
25
|
+
fid = fopen(jpathfile, 'at');
|
|
26
|
+
fprintf(fid, '\n');
|
|
27
|
+
% windows path need double backslash
|
|
28
|
+
jpath = strrep(jpath,'\','\\');
|
|
29
|
+
fprintf(fid, jpath);
|
|
30
|
+
fclose(fid);
|
|
31
|
+
catch
|
|
32
|
+
warning('Failed to add java path to static class path. Using dynamic classpath instead. This requires you to call setPLJavaPath.m each time you use Pottslab.')
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
function showPotts(data, rec, groundTruth, method)
|
|
2
|
+
%showPotts Display result of Potts reconstructions
|
|
3
|
+
|
|
4
|
+
subplot(1,2,1)
|
|
5
|
+
plot(data, '.', 'MarkerSize', 10)
|
|
6
|
+
title('Data')
|
|
7
|
+
|
|
8
|
+
% reconstruction
|
|
9
|
+
subplot(1,2,2)
|
|
10
|
+
plot(rec, '.', 'MarkerSize', 10)
|
|
11
|
+
|
|
12
|
+
% legend
|
|
13
|
+
if ~exist('method', 'var')
|
|
14
|
+
leg = {'Reconstruction'};
|
|
15
|
+
else
|
|
16
|
+
leg = {method};
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
% add groundTruth
|
|
20
|
+
if exist('groundTruth', 'var')
|
|
21
|
+
hold on
|
|
22
|
+
plot(groundTruth, '--r')
|
|
23
|
+
hold off
|
|
24
|
+
leg = [leg, {'Ground truth'}];
|
|
25
|
+
title(['PSNR: ' num2str(plpsnr(groundTruth, rec)), ', #Jumps: ', num2str(countJumps(rec))] );
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
legend(leg);
|
|
29
|
+
|
|
30
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
function showSparse(data, rec, groundTruth, method)
|
|
2
|
+
%showSparse Display result of sparse reconstructions
|
|
3
|
+
|
|
4
|
+
% written by M. Storath
|
|
5
|
+
% $Date: 2012/10/29 01:19:08 $ $Revision: 0.1 $
|
|
6
|
+
|
|
7
|
+
% data
|
|
8
|
+
subplot(1,2,1)
|
|
9
|
+
plot(data)
|
|
10
|
+
title('Data')
|
|
11
|
+
|
|
12
|
+
% reconstruction
|
|
13
|
+
subplot(1,2,2)
|
|
14
|
+
plot(rec, '.', 'MarkerSize', 10)
|
|
15
|
+
|
|
16
|
+
% legend
|
|
17
|
+
if ~exist('method', 'var')
|
|
18
|
+
leg = {'Reconstruction'};
|
|
19
|
+
else
|
|
20
|
+
leg = {method};
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
% add groundTruth
|
|
24
|
+
if exist('groundTruth', 'var')
|
|
25
|
+
hold on
|
|
26
|
+
stem(groundTruth, 'r')
|
|
27
|
+
hold off
|
|
28
|
+
leg = [leg, {'Ground truth'}];
|
|
29
|
+
title(['PSNR: ' num2str(plpsnr(groundTruth, rec))] );
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
legend(leg);
|
|
33
|
+
|
|
34
|
+
end
|