[python-dtcwt] 125/497: add some verification against MATLAB output

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Tue Jul 21 18:05:56 UTC 2015


This is an automated email from the git hooks/post-receive script.

ghisvail-guest pushed a commit to branch debian/sid
in repository python-dtcwt.

commit 79376c206dc64755a1ff56afc2f07f388167af94
Author: Rich Wareham <rjw57 at cam.ac.uk>
Date:   Wed Nov 6 12:12:41 2013 +0000

    add some verification against MATLAB output
    
    Add a new test which checks that the output from the Python code matches
    that of MATLAB to within machine precision.
    
    We also need a nasty workaround for Python 2/3 incompatibility with npz.
    The npz format uses pickle to store objects. The pickle format is
    incompatible between PYthon 2 and 3 due to Unicode encoding issues. We
    work around this by ensuring that we only store plain ol'arrays in the
    npz file. It's mucky, but compatible.
---
 matlab/.gitignore          |   1 +
 matlab/README.md           |  18 +++++++++++
 matlab/gen_verif.m         |  30 ++++++++++++++++++
 matlab/lena.mat            | Bin 0 -> 261700 bytes
 matlab/verif_m_to_npz.py   |  33 +++++++++++++++++++
 tests/testagainstmatlab.py |  77 +++++++++++++++++++++++++++++++++++++++++++++
 tests/util.py              |  28 +++++++++++++++++
 tests/verification.npz     | Bin 0 -> 128072 bytes
 8 files changed, 187 insertions(+)

diff --git a/matlab/.gitignore b/matlab/.gitignore
new file mode 100644
index 0000000..2d92f62
--- /dev/null
+++ b/matlab/.gitignore
@@ -0,0 +1 @@
+verification.mat
diff --git a/matlab/README.md b/matlab/README.md
new file mode 100644
index 0000000..7e38978
--- /dev/null
+++ b/matlab/README.md
@@ -0,0 +1,18 @@
+# MATLAB support scripts
+
+This directory contains the MATLAB files required to recreate the verification
+data. Obviously you must have MATLAB installed but you also require the DT-CWT
+toolbox available on [Nick Kingsbury's](http://www-sigproc.eng.cam.ac.uk/~ngk/)
+home page.
+
+The ``gen_verif.m`` script is not sophisticated; they simply exercise a number
+of the DT-CWT toolbox routines and saves the result to ``verification.mat``.
+Run it with a command like the following:
+
+```console
+$ MATLABPATH=/path/to/dtcwt_toolbox4_3 /path/to/matlab -nosplash -nodesktop -r "run /path/to/gen_verif; quit"
+```
+
+The ``verif_m_to_npz.py`` script uses SciPy to load the MATLAB output and
+convert it into NumPy's native ``.npz`` format. This file is used by the test
+suite and is located at ``tests/verification.npz``.
diff --git a/matlab/gen_verif.m b/matlab/gen_verif.m
new file mode 100644
index 0000000..df161c4
--- /dev/null
+++ b/matlab/gen_verif.m
@@ -0,0 +1,30 @@
+%% Generate verification arrays to compare known good DT-CWT inputs and outputs.
+%%
+%% This script assumes that Nick Kingsbury's DT-CWT toolbox has been installed.
+%%
+%% Run with something like:
+%%
+%% $ MATLABPATH=/path/to/dtcwt_toolbox4_3 /path/to/matlab -nosplash -nodesktop -r "run /path/to/gen_verif; quit"
+
+%% Load Lena image
+inputs = load('lena.mat');
+lena = inputs.lena;
+
+near_sym_b = load('near_sym_b');
+qshift_d = load('qshift_d');
+
+h1a = qshift_d.h1a;
+h1b = flipud(h1a);
+
+lena_coldfilt = coldfilt(lena, h1b, h1a);
+
+g0a = qshift_d.g0a;
+g0b = flipud(g0a);
+
+lena_colifilt = colifilt(lena, g0b, g0a);
+
+[lena_Yl, lena_Yh, lena_Yscale] = dtwavexfm2(lena, 4, 'near_sym_a', 'qshift_a');
+
+save('verification.mat', 'lena_coldfilt', 'lena_colifilt', 'lena_Yl', 'lena_Yh', 'lena_Yscale');
+
+%% 
diff --git a/matlab/lena.mat b/matlab/lena.mat
new file mode 100644
index 0000000..b84ade3
Binary files /dev/null and b/matlab/lena.mat differ
diff --git a/matlab/verif_m_to_npz.py b/matlab/verif_m_to_npz.py
new file mode 100755
index 0000000..c291584
--- /dev/null
+++ b/matlab/verif_m_to_npz.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+import numpy as np
+from scipy.io import loadmat
+from numpy import savez
+
+def summarise_mat(M, apron=8):
+    """HACK to provide a 'summary' matrix consisting of the corners of the
+    matrix and summed versions of the sub matrices."""
+
+    centre = M[apron:-apron,apron:-apron,...]
+    centre_sum = np.mean(np.mean(centre, axis=0, keepdims=True), axis=1, keepdims=True)
+
+    return np.vstack((
+        np.hstack((M[:apron,:apron,...], np.mean(M[:apron,apron:-apron,...], axis=1, keepdims=True), M[:apron,-apron:,...])),
+        np.hstack((np.mean(M[apron:-apron,:apron,...], axis=0, keepdims=True), centre_sum, np.mean(M[apron:-apron,-apron:,...], axis=0, keepdims=True))),
+        np.hstack((M[-apron:,:apron,...], np.mean(M[-apron:,apron:-apron,...], axis=1, keepdims=True), M[-apron:,-apron:,...])),
+    ))
+
+verif = loadmat('verification.mat')
+verif = dict((k,v) for k, v in verif.iteritems() if not k.startswith('_'))
+
+for idx, v in enumerate(verif['lena_Yh']):
+    verif['lena_Yh_{0}'.format(idx)] = v[0]
+del verif['lena_Yh']
+
+for idx, v in enumerate(verif['lena_Yscale']):
+    verif['lena_Yscale_{0}'.format(idx)] = v[0]
+del verif['lena_Yscale']
+
+summaries = dict((k, summarise_mat(v)) for k, v in verif.iteritems())
+
+savez('../tests/verification.npz', **summaries)
diff --git a/tests/testagainstmatlab.py b/tests/testagainstmatlab.py
new file mode 100644
index 0000000..0170195
--- /dev/null
+++ b/tests/testagainstmatlab.py
@@ -0,0 +1,77 @@
+import os
+from nose.tools import raises
+from nose.plugins.attrib import attr
+
+import numpy as np
+from dtcwt import dtwavexfm2, dtwaveifm2, biort, qshift
+from dtcwt.lowlevel import coldfilt, colifilt
+
+from .util import assert_almost_equal, summarise_mat
+
+## IMPORTANT NOTE ##
+
+# These tests match only a 'summary' matrix from MATLAB which is formed by
+# dividing a matrix into 9 parts thusly:
+#
+#  A | B | C
+# ---+---+---
+#  D | E | F
+# ---+---+---
+#  G | H | I
+#
+# Where A, C, G and I are NxN and N is some agreed 'apron' size. E is replaced
+# my it's element-wise mean and thus becomes 1x1. The remaining matrices are
+# replaced by the element-wise mean along the apropriate axis to result in a
+# (2N+1) x (2N+1) matrix. These matrices are compared.
+#
+# The rationale for this summary is that the corner matrices preserve
+# interesting edge-effects and some actual values whereas the interior matrices
+# preserve at least some information on their contents. Storing such a summary
+# matrix greatly reduces the amount of storage required.
+
+# Summary matching requires greater tolerance
+TOLERANCE = 1e-5
+
+def assert_almost_equal_to_summary(a, summary, *args, **kwargs):
+    assert_almost_equal(summarise_mat(a), summary, *args, **kwargs)
+
+def setup():
+    global lena
+    lena = np.load(os.path.join(os.path.dirname(__file__), 'lena.npz'))['lena']
+
+    global verif
+    verif = np.load(os.path.join(os.path.dirname(__file__), 'verification.npz'))
+
+def test_lena_loaded():
+    assert lena.shape == (512, 512)
+    assert lena.min() >= 0
+    assert lena.max() <= 1
+    assert lena.dtype == np.float32
+
+def test_lena_loaded():
+    assert verif is not None
+    assert 'lena_coldfilt' in verif
+
+def test_coldfilt():
+    h0o, g0o, h1o, g1o = biort('near_sym_b')
+    h0a, h0b, g0a, g0b, h1a, h1b, g1a, g1b = qshift('qshift_d')
+    A = coldfilt(lena, h1b, h1a)
+    assert_almost_equal_to_summary(A, verif['lena_coldfilt'], tolerance=TOLERANCE)
+
+def test_coldfilt():
+    h0o, g0o, h1o, g1o = biort('near_sym_b')
+    h0a, h0b, g0a, g0b, h1a, h1b, g1a, g1b = qshift('qshift_d')
+    A = colifilt(lena, g0b, g0a)
+    assert_almost_equal_to_summary(A, verif['lena_colifilt'], tolerance=TOLERANCE)
+
+def test_dtwavexfm2():
+    Yl, Yh, Yscale = dtwavexfm2(lena, 4, 'near_sym_a', 'qshift_a', include_scale=True)
+    assert_almost_equal_to_summary(Yl, verif['lena_Yl'], tolerance=TOLERANCE)
+
+    for idx, a in enumerate(Yh):
+        assert_almost_equal_to_summary(a, verif['lena_Yh_{0}'.format(idx)], tolerance=TOLERANCE)
+
+    for idx, a in enumerate(Yscale):
+        assert_almost_equal_to_summary(a, verif['lena_Yscale_{0}'.format(idx)], tolerance=TOLERANCE)
+
+# vim:sw=4:sts=4:et
diff --git a/tests/util.py b/tests/util.py
new file mode 100644
index 0000000..6452e2e
--- /dev/null
+++ b/tests/util.py
@@ -0,0 +1,28 @@
+import numpy as np
+
+TOLERANCE = 1e-12
+
+def assert_almost_equal(a, b, tolerance=TOLERANCE):
+    md = np.abs(a-b).max()
+    if md <= tolerance:
+        return
+
+    raise AssertionError(
+            'Arrays differ by a maximum of {0} which is greater than the tolerance of {1}'.
+            format(md, tolerance))
+
+def summarise_mat(M, apron=8):
+    """HACK to provide a 'summary' matrix consisting of the corners of the
+    matrix and summed versions of the sub matrices.
+    
+    N.B. Keep this in sync with matlab/verif_m_to_npz.py.
+
+    """
+    centre = M[apron:-apron,apron:-apron,...]
+    centre_sum = np.mean(np.mean(centre, axis=0, keepdims=True), axis=1, keepdims=True)
+
+    return np.vstack((
+        np.hstack((M[:apron,:apron,...], np.mean(M[:apron,apron:-apron,...], axis=1, keepdims=True), M[:apron,-apron:,...])),
+        np.hstack((np.mean(M[apron:-apron,:apron,...], axis=0, keepdims=True), centre_sum, np.mean(M[apron:-apron,-apron:,...], axis=0, keepdims=True))),
+        np.hstack((M[-apron:,:apron,...], np.mean(M[-apron:,apron:-apron,...], axis=1, keepdims=True), M[-apron:,-apron:,...])),
+    ))
diff --git a/tests/verification.npz b/tests/verification.npz
new file mode 100644
index 0000000..664902d
Binary files /dev/null and b/tests/verification.npz differ

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/python-dtcwt.git



More information about the debian-science-commits mailing list