def test_PSNR(self): k = len(self.flat_array) x_zero = np.zeros(k) x_flat = np.arange(k) x_1d = np.arange(k).reshape(*self.d1_array.shape) x_2d = np.arange(k).reshape(*self.d2_array.shape) p = 1.42 psnr_const = 10 * np.log10(p**2 / np.mean(self.flat_const_offset ** 2)) psnr_noise = 10 * np.log10(p**2 / np.mean(self.flat_noise ** 2)) # Integrity check of test setup self.assertGreater(psnr_const, 1e-3) self.assertGreater(psnr_noise, 1e-3) self.assertNotAlmostEqual(psnr_const, psnr_noise) # Identical arrays self.assertEqual(calculate_psnr(x_zero, x_zero, p), np.inf) self.assertEqual(calculate_psnr(x_2d, x_2d, p), np.inf) # Additve offset self.assertAlmostEqual( calculate_psnr(x_flat, x_flat + self.flat_const_offset, p), psnr_const) self.assertAlmostEqual( calculate_psnr(x_1d, x_1d - self.d1_const_offset, p), psnr_const) self.assertAlmostEqual( calculate_psnr(x_2d, x_2d + self.d2_const_offset, p), psnr_const) # Additive noise self.assertAlmostEqual( calculate_psnr(x_flat, x_flat - self.flat_noise, p), psnr_noise) self.assertAlmostEqual( calculate_psnr(x_1d, x_1d + self.d1_noise, p), psnr_noise) self.assertAlmostEqual( calculate_psnr(x_2d, x_2d - self.d2_noise, p), psnr_noise) # Fails self.assertNotAlmostEqual( calculate_psnr(x_flat, x_flat + self.flat_noise, p), psnr_const) self.assertNotAlmostEqual( calculate_psnr(x_flat, x_flat - self.flat_const_offset, p), psnr_noise) self.assertNotAlmostEqual( calculate_psnr(x_flat, x_flat + self.flat_noise, 25), psnr_noise) self.assertNotAlmostEqual( calculate_psnr(x_flat, x_flat + self.flat_noise, p*1.01), psnr_noise)
def analyse(x, Phi, Psi, **kwargs): """ Sample an image, reconstruct it, and analyse the reconstructed image. Parameters ---------- x : numpy.ndarray The original image vector. Phi : magni.utils.matrices.Matrix or numpy.matrix The measurement matrix. Psi : magni.utils.matrices.Matrix or numpy.matrix The dictionary. Returns ------- x : numpy.ndarray The reconstructed image vector. See Also -------- magni.afm.config : Configuration options. magni.imaging.evaluation : Image reconstruction quality evaluation. Notes ----- Additional \*\*kwargs are passed on to the reconstruction algorithm. Examples -------- Prior to the actual example, data is loaded and a measurement matrix and a dictionary are defined. First, the example MI file provided with the package is loaded: >>> import os, numpy as np, magni >>> from magni.afm.reconstruction import analyse >>> path = magni.utils.split_path(magni.__path__[0])[0] >>> path = path + 'examples' + os.sep + 'example.mi' >>> if os.path.isfile(path): ... mi_file = magni.afm.io.read_mi_file(path) ... mi_buffer = mi_file.get_buffer('Topography')[0] ... mi_data = mi_buffer.data ... x = magni.imaging.mat2vec(mi_data) Next, a measurement matrix is defined. This matrix is equal to the matrix generated by running `np.eye(len(x))[::2, :]` but for speed, the matrix is instead defined with fast operations: >>> def Phi_A(x): ... y = x[::2] ... return y >>> def Phi_T(y): ... x = np.zeros((2 * len(y), 1)) ... x[::2] = y ... return x >>> if os.path.isfile(path): ... Phi = magni.utils.matrices.Matrix(Phi_A, Phi_T, (), ... (int(len(x) / 2), len(x))) Next, a dictionary is defined. This dictionary is the DCT basis likewise defined with fast operations: >>> if os.path.isfile(path): ... Psi = magni.imaging.dictionaries.get_DCT(mi_data.shape) Finally, the actual example: >>> if os.path.isfile(path): ... print('MSE: {:.2f}, PSNR: {:.2f}'.format(*analyse(x, Phi, Psi))) ... else: ... print('MSE: 0.24, PSNR: 6.22') MSE: 0.24, PSNR: 6.22 """ @_decorate_validation def validate_input(): _numeric('x', ('integer', 'floating', 'complex'), shape=(-1, 1)) _numeric('Phi', ('integer', 'floating', 'complex'), shape=(-1, x.shape[0])) _numeric('Psi', ('integer', 'floating', 'complex'), shape=(x.shape[0], -1)) validate_input() y = Phi.dot(x) x_hat = reconstruct(y, Phi, Psi, **kwargs) x_scaled = _visualisation.stretch_image(x, 1.0) x_hat_scaled = _visualisation.stretch_image(x_hat, 1.0) mse = _eval.calculate_mse(x_scaled, x_hat_scaled) psnr = _eval.calculate_psnr(x_scaled, x_hat_scaled, 1.0) return (mse, psnr)
def analyse(x, Phi, Psi): """ Sample an image, reconstruct it, and analyse the reconstructed image. Parameters ---------- x : numpy.ndarray The original image vector. Phi : magni.utils.matrices.Matrix or numpy.matrix The measurement matrix. Psi : magni.utils.matrices.Matrix or numpy.matrix The dictionary. Returns ------- x : numpy.ndarray The reconstructed image vector. See Also -------- magni.afm.config : Configuration options. magni.imaging.evaluation : Image reconstruction quality evaluation. Examples -------- Prior to the actual example, data is loaded and a measurement matrix and a dictionary are defined. First, the example MI file provided with the package is loaded: >>> import os, numpy as np, magni >>> from magni.afm.reconstruction import analyse >>> path = magni.utils.split_path(magni.__path__[0])[0] >>> path = path + 'examples' + os.sep + 'example.mi' >>> if os.path.isfile(path): ... mi_file = magni.afm.io.read_mi_file(path) ... mi_buffer = mi_file.get_buffer('Topography')[0] ... mi_data = mi_buffer.get_data() ... x = magni.imaging.mat2vec(mi_data) Next, a measurement matrix is defined. This matrix is equal to the matrix generated by running `np.eye(len(x))[::2, :]` but for speed, the matrix is instead defined with fast operations: >>> def Phi_A(x): ... y = x[::2] ... return y >>> def Phi_T(y): ... x = np.zeros((2 * len(y), 1)) ... x[::2] = y ... return x >>> if os.path.isfile(path): ... Phi = magni.utils.matrices.Matrix(Phi_A, Phi_T, (), ... (int(len(x) / 2), len(x))) Next, a dictionary is defined. This dictionary is the DCT basis likewise defined with fast operations: >>> if os.path.isfile(path): ... Psi = magni.imaging.dictionaries.get_DCT(mi_data.shape) Finally, the actual example: >>> if os.path.isfile(path): ... print('MSE: {:.2f}, PSNR: {:.2f}'.format(*analyse(x, Phi, Psi))) ... else: ... print('MSE: 0.24, PSNR: 6.22') MSE: 0.24, PSNR: 6.22 """ @_decorate_validation def validate_input(): _numeric('x', ('integer', 'floating', 'complex'), shape=(-1, 1)) _numeric('Phi', ('integer', 'floating', 'complex'), shape=(-1, x.shape[0])) _numeric('Psi', ('integer', 'floating', 'complex'), shape=(x.shape[0], -1)) validate_input() y = Phi.dot(x) x_hat = reconstruct(y, Phi, Psi) x_scaled = _visualisation.stretch_image(x, 1.0) x_hat_scaled = _visualisation.stretch_image(x_hat, 1.0) mse = _eval.calculate_mse(x_scaled, x_hat_scaled) psnr = _eval.calculate_psnr(x_scaled, x_hat_scaled, 1.0) return (mse, psnr)
def analyse(x, Phi, Psi): """ Sample an image, reconstruct it, and analyse the reconstructed image. Parameters ---------- x : numpy.ndarray The original image vector. Phi : magni.utils.matrices.Matrix or numpy.matrix The measurement matrix. Psi : magni.utils.matrices.Matrix or numpy.matrix The dictionary. Returns ------- x : numpy.ndarray The reconstructed image vector. See Also -------- magni.afm.config : Configuration options. magni.imaging.evaluation : Image reconstruction quality evaluation. Examples -------- Prior to the actual example, data is loaded and a measurement matrix and a dictionary are defined. First, the example MI file provided with the package is loaded: >>> from magni.afm.reconstruction import analyse >>> path = magni.utils.split_path(magni.__path__[0])[0] >>> path = path + 'examples' + os.sep + 'example.mi' >>> mi_file = magni.afm.io.read_mi_file(path) >>> mi_buffer = mi_file.get_buffer('Topography')[0] >>> mi_data = mi_buffer.get_data() >>> x = magni.imaging.mat2vec(mi_data) Next, a measurement matrix is defined. This matrix is equal to the matrix generated by running `np.eye(len(x))[::2, :]` but for speed, the matrix is instead defined with fast operations: >>> def Phi_A(x): ... y = x[::2] ... return y >>> def Phi_T(y): ... x = np.zeros((2 * len(y), 1)) ... x[::2] = y ... return x >>> Phi = magni.utils.matrices.Matrix(Phi_A, Phi_T, (), ... (int(len(x) / 2), len(x))) Next, a dictionary is defined. This dictionary is the DCT basis likewise defined with fast operations: >>> Psi = magni.imaging.dictionaries.get_DCT(mi_data.shape) Finally, the actual example: >>> print('MSE: {:.2f}, PSNR: {:.2f}'.format(*analyse(x, Phi, Psi))) MSE: 0.23, PSNR: 5.92 """ _validate_analyse(x, Phi, Psi) y = Phi.dot(x) x_hat = reconstruct(y, Phi, Psi) mse = _eval.calculate_mse(x, x_hat) psnr = _eval.calculate_psnr(x, x_hat, float(np.abs(x).max())) return (mse, psnr)
def show_psnr_energy_rolloff(img, reconstructions, fractions, return_vals=False, output_path=None, fig_ext='pdf'): """ Show the PSNR and energy rolloff for the reconstructions. A plot of the Peak Signal to Noise Ratio (PSNR) and retained energy in the `recontructions` versus the `fractions` of coefficients used in the reconstructions is shown. If return_vals is True, the data used in the plot is returned. If `output_path` is not None, the resulting figure and data used in the figure are saved. Parameters ---------- img : ndarray The image which the reconstructions are based on. reconstructions : list or tuple The reconstructions (each an ndarray) to show rolloff for. fractions : list or tuple The fractions of coefficents used in the reconstructions. return_vals : bool The flag indicating wheter or not to return the PSNR and energy values (the default is False, which indicate that the values are not returned). output_path : str The output path (see notes below) to save the figure and data to (the default is None, which implies that the figure and data are not saved). fig_ext : str The figure extension determining the format of the saved figure (the default is 'pdf' which implies that the figure is saved as a PDF). Returns ------- psnrs : ndarray The PSNR values shown in the figure (only returned if return_vals=True). energy : ndarray The retained energy values shown in the figure (only returned if return_vals=True). Notes ----- The `output_path` is specified as a path to a folder + an optional prefix to the file name. The remaining file name is fixed. If e.g, the fixed part of the file name was 'plot', then: * output_path = '/home/user/' would save the figure under /home/user/ with the name plot.pdf. * output_path = '/home/user/best' would save the figure under /home/user with the name best_plot.pdf. In addition to the saved figures, an annotated and chased HDF database with the data used to create the figures are also saved. The name of the HDF database is the same as for the figure with the exception that the file extension is '.hdf5'. Examples -------- Save a PSNR and energy rolloff plot for reconstructions bases on the DCT: >>> import os, numpy as np >>> from magni.imaging.dictionaries import analysis as _a >>> img = np.arange(64).astype(np.float).reshape(8, 8) >>> transform = 'DCT' >>> fractions = (0.2, 0.4) >>> coefs, recons = _a.get_reconstructions(img, transform, fractions) >>> o_p = './rolloff_test' >>> _a.show_psnr_energy_rolloff(img, recons, fractions, output_path=o_p) >>> current_dir = os.listdir('./') >>> for file in sorted(current_dir): ... if 'rolloff_test' in file: ... print(file) rolloff_test_psnr_energy_rolloff.hdf5 rolloff_test_psnr_energy_rolloff.pdf """ @_decorate_validation def validate_input(): _numeric('img', ('integer', 'floating', 'complex'), shape=(-1, -1)) _levels('reconstructions', (_generic(None, 'explicit collection'), _numeric(None, ('integer', 'floating', 'complex'), shape=img.shape))) _levels('fractions', (_generic(None, 'explicit collection'), _numeric(None, 'floating', range_='[0;1]'))) _numeric('return_vals', 'boolean') _generic('output_path', 'string', ignore_none=True) _generic('fig_ext', 'string') validate_input() psnrs = np.zeros_like(fractions) energy = np.zeros_like(fractions) for k, reconstruction in enumerate(reconstructions): psnrs[k] = _evaluation.calculate_psnr(img, reconstruction, float(img.max())) energy[k] = _evaluation.calculate_retained_energy(img, reconstruction) fig, axes = plt.subplots(1, 2) axes[0].plot(fractions, psnrs) axes[0].set_xlabel('Fraction of coefficients') axes[0].set_ylabel('PSNR [dB]') axes[1].plot(fractions, energy) axes[1].set_xlabel('Fraction of coefficients') axes[1].set_ylabel('Retained energy [%]') fig.suptitle(('PSNR/Energy vs. fraction of coefficients used in ' + 'reconstruction'), fontsize=14) plt.tight_layout(rect=(0, 0, 1, 0.95)) # Save figures and data if output_path is not None: datasets = { 'psnrs': { 'fractions': fractions, 'values': psnrs }, 'energy': { 'fractions': fractions, 'values': energy } } _save_output(output_path, 'psnr_energy_rolloff', fig, fig_ext, datasets) # Return values if return_vals: return psnrs, energy