/**********************************************************************
* 
* finalpreview.h
*
* This file is part of MitoGen
* 
* Copyright (C) 2013-2016 -- Centre for Biomedical Image Analysis (CBIA)
* http://cbia.fi.muni.cz/
* 
* MitoGen is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* 
* MitoGen is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with MitoGen. If not, see <http://www.gnu.org/licenses/>.
* 
* Author: David Svoboda and Vladimir Ulman
* 
* Description: 
* A collection of functions simulating the aberrations and imperfections
* caused by an optical system (microscope), and sampling and noise generation
* cause by an acquisition device (CCD camera).
*
***********************************************************************/

#ifndef MITOGEN_TOOLBOX_FINALPREVIEW_H
#define MITOGEN_TOOLBOX_FINALPREVIEW_H

#include <i3d/image3d.h>
#include <ini/iniparser.h>

/**
 * Just computes preview of final image, which is to simulate
 * transmission of the phantom image \e phantom through optical system
 * and its acquisition in the sensor device.
 *
 * The level of noise is a bit different in the region of \e mask
 * in order to outline cell shape. The texture stored in the
 * phantom image \e phantom often does not spread over the whole \e mask
 * giving false impression of what is the real size of the cell.
 *
 * If the GTGEN_WITH_ANISOTROPIC_GT is defined, both \e phantom and
 * \e mask images are resampled to meet the resolution supplied in the
 * \e configIni file. The \e final image always meets this resolution
 * regardless of the GTGEN_WITH_ANISOTROPIC_GT state. If the macro is 
 * not defined, both \e phantom and \e mask images not resampled.
 *
 * If the GTGEN_WITH_CHRCENTRESINPHANTHOMS is defined, the chromocentres
 * are removed from the phantom image (before it is turned into a final
 * image, ofcourse). So the \e phantom image is changed in this particular case.
 *
 * \param[in,out] phantom	phantom image
 * \param[in,out] mask		cell mask
 * \param[out] final			finale preview image
 * \param[in] configIni		configuration of the simulation
 *
 * The \e phantom and \e mask images must be of the same size and resolution.
 * It is expected that both of them be isotropic, but it is not required.
 *
 * The \e configIni is a reference to parameters for the Stage II and III
 * simulation routines.
 */
template <class MV, class PV>
void PrepareFinalPreviewImage(i3d::Image3d<PV> &phantom,
										i3d::Image3d<MV> &mask,
										i3d::Image3d<PV> &final,
										const IniHandler &configIni);

/**
 * Computes the true final image, which is to conduct a proper simulation
 * of transmission of the phantom image \e phantom through optical system
 * and its acquisition in the sensor device. In other words, it processes
 * the Stage II and Stage III of the simulator.
 *
 * The \e phantom image is always stretched (pixel-wise multiplied) with
 * the stretch factor \e scale.
 *
 * If the GTGEN_WITH_ANISOTROPIC_GT is defined, both \e phantom and
 * \e mask images are resampled to meet the resolution supplied in the
 * \e configIni file. The \e final image always meets this resolution
 * regardless of the GTGEN_WITH_ANISOTROPIC_GT state. If the macro is 
 * not defined, both \e phantom and \e mask images not resampled.
 *
 * If the GTGEN_WITH_CHRCENTRESINPHANTHOMS is defined, the chromocentres
 * are removed from the phantom image (before it is turned into a final
 * image, ofcourse).
 *
 * \param[in,out] phantom	phantom image
 * \param[in,out] mask		cell mask
 * \param[out] final			finale preview image
 * \param[in] configIni		configuration of the simulation
 * \param[in] scale			stretch factor to adjust the phantom
 *
 * The \e phantom and \e mask images must be of the same size and resolution.
 * It is expected that both of them be isotropic, but it is not required.
 *
 * The \e configIni is a reference to parameters for the Stage II and III
 * simulation routines.
 */
template <class MV, class PV>
void PrepareFinalImage(i3d::Image3d<PV> &phantom, 
							  i3d::Image3d<MV> &mask,
							  i3d::Image3d<PV> &final,
							  const IniHandler &configIni,
							  const float scale = 1.0f);

/**
 * Computes the Signal-to-Noise Ratio (SNR) of the input image \e img
 * given that signal voxels are those within the mask \e mask.
 * Voxels outside the mask are considered as background.
 *
 * The SNR is computed as:
 * \verbatim
 * (avg(fg region) - avg(bg region)) / std_dev(fg region)
 * \endverbatim
 *
 * \param[in] img		image of which SNR is to be computed
 * \param[in] mask	corresponding mask image
 *
 * \return Returns the computed SNR.
 */
template <class MV, class PV>
float ComputeSNR_Naive(i3d::Image3d<PV> const &img,
							  i3d::Image3d<MV> const &mask);

/**
 * Computes the Signal-to-Noise Ratio (SNR) of the input image \e img
 * given that signal voxels are those within the mask \e mask.
 * Voxels outside the mask are considered as background.
 *
 * The SNR is computed as:
 * \verbatim
 * (avg(fg region) - avg(bg region)) / std_dev(fg region)
 * \endverbatim
 *
 * This function, however, uses two-pass algorithms for 'compensated'
 * computations of both the mean and variance. It should be more accurate.
 *
 * For the mean, Kahan summation alg. is used [1].
 * \verbatim
 * mean=0
 * compensation=0	//a running compensation for lost low-order bits
 *
 * for d in data_to_be_summed
 *   d_compensated=d-compensation
 *   sum=mean+d_compensated							//this potentially loses low-order bits
 *   compensation=(sum-mean) - d_compensated		//recovers what's been lost and adds it in the next round,
 *   															//algebraically, 'compensation' should be zero
 *   mean=sum
 * endfor
 * \endverbatim
 *
 * For the variance (square of the standard deviation) the eq. (1.4) [2],\
 * the prof. Bjorek's alg., is used.
 * \verbatim
 * d is data_to_be_summed, mean is mean of this data:
 * variance=[ sum(d-mean)^2 - (sum(d-mean))^2/N ] / N
 * \endverbatim
 * The Kahan summation is applied for both summations as well.
 *
 * Literature:
 *
 * [1] Kahan, William (January 1965), "Further remarks on reducing truncation errors",
 * Communications of the ACM 8 (1): 40, doi:10.1145/363707.363723.
 * http://en.wikipedia.org/wiki/Kahan_summation_algorithm
 *
 * [2] Chan, Tony F.; Golub, Gene H.; LeVeque, Randall J. (1979),
 * "Updating Formulae and a Pairwise Algorithm for Computing Sample Variances.",
 * Technical Report STAN-CS-79-773, Department of Computer Science, Stanford University.
 * ftp://reports.stanford.edu/pub/cstr/reports/cs/tr/79/773/CS-TR-79-773.pdf
 *
 * \param[in] img		image of which SNR is to be computed
 * \param[in] mask	corresponding mask image
 *
 * \return Returns the computed SNR.
 */
template <class MV, class PV>
float ComputeSNR(i3d::Image3d<PV> const &img,
					  i3d::Image3d<MV> const &mask);

/**
 * Computes the Signal-to-Noise Ratio (SNR) of the input image \e img,
 * just like the function ComputeSNR_Naive(), but with modified mask image \e mask.
 *
 * Say, A is integer division of the NoStepWidth by 2, i.e. A = floor(NoStepWidth/2).
 * The foreground region is determined by the \e mask eroded with i3d::ErosionO(...,A).
 * A is the last parameter of the i3d::ErosionO(), the radius_size parameter.
 * The background region is determined by inversion of the \e mask after it is
 * dilated with i3d::DilationO() with radius_size being NoStepWidth-A. In the end,
 * the should be a NoStepWidth wide stripe between the foreground and background regions,
 * a no-step zone not used for the SNR computation.
 * 
 * \param[in] img				image of which SNR is to be computed
 * \param[in] mask			corresponding mask image
 * \param[in] NoStepWidth	the width of the no-step zone, default value is 5
 *
 * \return Returns the computed SNR.
 */
template <class MV, class PV>
float ComputeSNR_Naive_NoStepZone(i3d::Image3d<PV> const &img,
											 i3d::Image3d<MV> const &mask,
											 const int NoStepWidth=5);

#endif
