Added Image Quality Assessment.

This commit is contained in:
Branimir Karadžić 2016-04-07 20:05:20 -07:00
parent 931c6ed0f6
commit f3b9fed29a
16 changed files with 1645 additions and 0 deletions

32
3rdparty/iqa/LICENSE vendored Normal file
View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2011, Tom Distler (http://tdistler.com)
* All rights reserved.
*
* The BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the tdistler.com nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

36
3rdparty/iqa/README.txt vendored Normal file
View File

@ -0,0 +1,36 @@
Doxygen documentation can be found at: http://tdistler.com/iqa
BUILD:
All build artifacts end up in build/<configuration>, where <configuration> is
'debug' or 'release'.
Windows:
- Open iqa.sln, select 'Debug' or 'Release', and build. The output is a
static library 'iqa.lib'.
- To run the tests under the debugger, first right-click the 'test' project,
select Properties -> Configuration Properties -> Debugging and set
'Working Directory' to '$(OutDir)'. Then start the application.
Linux:
- Change directories into the root of the IQA branch you want to build.
- Type `make` for a debug build, or `make RELEASE=1` for a release build.
The output is a static library 'libiqa.a'.
- Type `make test` (or `make test RELEASE=1`) to build the unit tests.
- Type `make clean` (or `make clean RELEASE=1`) to delete all build
artifacts.
- To run the tests, `cd` to the build/<configuration> directory and type
`./test`.
USE:
- Include 'iqa.h' in your source file.
- Call iqa_* methods.
- Link against the IQA library.
HELP & SUPPORT:
Further help can be found at: https://sourceforge.net/projects/iqa/support

111
3rdparty/iqa/include/convolve.h vendored Normal file
View File

@ -0,0 +1,111 @@
/*
* Copyright (c) 2011, Tom Distler (http://tdistler.com)
* All rights reserved.
*
* The BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the tdistler.com nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _CONVOLVE_H_
#define _CONVOLVE_H_
typedef float (*_iqa_get_pixel)(const float *img, int w, int h, int x, int y, float bnd_const);
/** Out-of-bounds array values are a mirrored reflection of the border values*/
float KBND_SYMMETRIC(const float *img, int w, int h, int x, int y, float bnd_const);
/** Out-of-bounds array values are set to the nearest border value */
float KBND_REPLICATE(const float *img, int w, int h, int x, int y, float bnd_const);
/** Out-of-bounds array values are set to 'bnd_const' */
float KBND_CONSTANT(const float *img, int w, int h, int x, int y, float bnd_const);
/** Defines a convolution kernel */
struct _kernel {
float *kernel; /**< Pointer to the kernel values */
int w; /**< The kernel width */
int h; /**< The kernel height */
int normalized; /**< 1 if the kernel values add up to 1. 0 otherwise */
_iqa_get_pixel bnd_opt; /**< Defines how out-of-bounds image values are handled */
float bnd_const; /**< If 'bnd_opt' is KBND_CONSTANT, this specifies the out-of-bounds value */
};
/**
* @brief Applies the specified kernel to the image.
* The kernel will be applied to all areas where it fits completely within
* the image. The resulting image will be smaller by half the kernel width
* and height (w - kw/2 and h - kh/2).
*
* @param img Image to modify
* @param w Image width
* @param h Image height
* @param k The kernel to apply
* @param result Buffer to hold the resulting image ((w-kw)*(h-kh), where kw
* and kh are the kernel width and height). If 0, the result
* will be written to the original image buffer.
* @param rw Optional. The width of the resulting image will be stored here.
* @param rh Optional. The height of the resulting image will be stored here.
*/
void _iqa_convolve(float *img, int w, int h, const struct _kernel *k, float *result, int *rw, int *rh);
/**
* The same as _iqa_convolve() except the kernel is applied to the entire image.
* In other words, the kernel is applied to all areas where the top-left corner
* of the kernel is in the image. Out-of-bound pixel value (off the right and
* bottom edges) are chosen based on the 'bnd_opt' and 'bnd_const' members of
* the kernel structure. The resulting array is the same size as the input
* image.
*
* @param img Image to modify
* @param w Image width
* @param h Image height
* @param k The kernel to apply
* @param result Buffer to hold the resulting image ((w-kw)*(h-kh), where kw
* and kh are the kernel width and height). If 0, the result
* will be written to the original image buffer.
* @return 0 if successful. Non-zero otherwise.
*/
int _iqa_img_filter(float *img, int w, int h, const struct _kernel *k, float *result);
/**
* Returns the filtered version of the specified pixel. If no kernel is given,
* the raw pixel value is returned.
*
* @param img Source image
* @param w Image width
* @param h Image height
* @param x The x location of the pixel to filter
* @param y The y location of the pixel to filter
* @param k Optional. The convolution kernel to apply to the pixel.
* @param kscale The scale of the kernel (for normalization). 1 for normalized
* kernels. Required if 'k' is not null.
* @return The filtered pixel value.
*/
float _iqa_filter_pixel(const float *img, int w, int h, int x, int y, const struct _kernel *k, const float kscale);
#endif /*_CONVOLVE_H_*/

55
3rdparty/iqa/include/decimate.h vendored Normal file
View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2011, Tom Distler (http://tdistler.com)
* All rights reserved.
*
* The BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the tdistler.com nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _DECIMATE_H_
#define _DECIMATE_H_
#include "convolve.h"
/**
* @brief Downsamples (decimates) an image.
*
* @param img Image to modify
* @param w Image width
* @param h Image height
* @param factor Decimation factor
* @param k The kernel to apply (e.g. low-pass filter). Can be 0.
* @param result Buffer to hold the resulting image (w/factor*h/factor). If 0,
* the result will be written to the original image buffer.
* @param rw Optional. The width of the resulting image will be stored here.
* @param rh Optional. The height of the resulting image will be stored here.
* @return 0 on success.
*/
int _iqa_decimate(float *img, int w, int h, int factor, const struct _kernel *k, float *result, int *rw, int *rh);
#endif /*_DECIMATE_H_*/

134
3rdparty/iqa/include/iqa.h vendored Normal file
View File

@ -0,0 +1,134 @@
/*
* Copyright (c) 2011, Tom Distler (http://tdistler.com)
* All rights reserved.
*
* The BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the tdistler.com nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _IQA_H_
#define _IQA_H_
#include "iqa_os.h"
/**
* Allows fine-grain control of the SSIM algorithm.
*/
struct iqa_ssim_args {
float alpha; /**< luminance exponent */
float beta; /**< contrast exponent */
float gamma; /**< structure exponent */
int L; /**< dynamic range (2^8 - 1)*/
float K1; /**< stabilization constant 1 */
float K2; /**< stabilization constant 2 */
int f; /**< scale factor. 0=default scaling, 1=no scaling */
};
/**
* Allows fine-grain control of the MS-SSIM algorithm.
*/
struct iqa_ms_ssim_args {
int wang; /**< 1=original algorithm by Wang, et al. 0=MS-SSIM* by Rouse/Hemami (default). */
int gaussian; /**< 1=11x11 Gaussian window (default). 0=8x8 linear window. */
int scales; /**< Number of scaled images to use. Default is 5. */
const float *alphas; /**< Pointer to array of alpha values for each scale. Required if 'scales' isn't 5. */
const float *betas; /**< Pointer to array of beta values for each scale. Required if 'scales' isn't 5. */
const float *gammas; /**< Pointer to array of gamma values for each scale. Required if 'scales' isn't 5. */
};
/**
* Calculates the Mean Squared Error between 2 equal-sized 8-bit images.
* @note The images must have the same width, height, and stride.
* @param ref Original reference image
* @param cmp Distorted image
* @param w Width of the images
* @param h Height of the images
* @param stride The length (in bytes) of each horizontal line in the image.
* This may be different from the image width.
* @return The MSE.
*/
float iqa_mse(const unsigned char *ref, const unsigned char *cmp, int w, int h, int stride);
/**
* Calculates the Peak Signal-to-Noise-Ratio between 2 equal-sized 8-bit
* images.
* @note The images must have the same width, height, and stride.
* @param ref Original reference image
* @param cmp Distorted image
* @param w Width of the images
* @param h Height of the images
* @param stride The length (in bytes) of each horizontal line in the image.
* This may be different from the image width.
* @return The PSNR.
*/
float iqa_psnr(const unsigned char *ref, const unsigned char *cmp, int w, int h, int stride);
/**
* Calculates the Structural SIMilarity between 2 equal-sized 8-bit images.
*
* See https://ece.uwaterloo.ca/~z70wang/publications/ssim.html
* @note The images must have the same width, height, and stride.
* @param ref Original reference image
* @param cmp Distorted image
* @param w Width of the images
* @param h Height of the images
* @param stride The length (in bytes) of each horizontal line in the image.
* This may be different from the image width.
* @param gaussian 0 = 8x8 square window, 1 = 11x11 circular-symmetric Gaussian
* weighting.
* @param args Optional SSIM arguments for fine control of the algorithm. 0 for
* defaults. Defaults are a=b=g=1.0, L=255, K1=0.01, K2=0.03
* @return The mean SSIM over the entire image (MSSIM), or INFINITY if error.
*/
float iqa_ssim(const unsigned char *ref, const unsigned char *cmp, int w, int h, int stride,
int gaussian, const struct iqa_ssim_args *args);
/**
* Calculates the Multi-Scale Structural SIMilarity between 2 equal-sized 8-bit
* images. The default algorithm is MS-SSIM* proposed by Rouse/Hemami 2008.
*
* See https://ece.uwaterloo.ca/~z70wang/publications/msssim.pdf and
* http://foulard.ece.cornell.edu/publications/dmr_hvei2008_paper.pdf
*
* @note 1. The images must have the same width, height, and stride.
* @note 2. The minimum image width or height is 2^(scales-1) * filter, where 'filter' is 11
* if a Gaussian window is being used, or 9 otherwise.
* @param ref Original reference image
* @param cmp Distorted image
* @param w Width of the images.
* @param h Height of the images.
* @param stride The length (in bytes) of each horizontal line in the image.
* This may be different from the image width.
* @param args Optional MS-SSIM arguments for fine control of the algorithm. 0
* for defaults. Defaults are wang=0, scales=5, gaussian=1.
* @return The mean MS-SSIM over the entire image, or INFINITY if error.
*/
float iqa_ms_ssim(const unsigned char *ref, const unsigned char *cmp, int w, int h, int stride,
const struct iqa_ms_ssim_args *args);
#endif /*_IQA_H_*/

66
3rdparty/iqa/include/iqa_os.h vendored Normal file
View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2011, Tom Distler (http://tdistler.com)
* All rights reserved.
*
* The BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the tdistler.com nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _OS_H_
#define _OS_H_
/* Microsoft tends to implement features early, but they have a high legacy
* cost because they won't break existing implementations. As such, certain
* features we take for granted on other platforms (like C99) aren't fully
* implemented. This file is meant to rectify that.
*/
#ifdef WIN32
#include <windows.h>
#define IQA_INLINE __inline
#ifndef INFINITY
#define INFINITY (float)HUGE_VAL /**< Defined in C99 (Windows is C89) */
#endif /*INFINITY*/
#ifndef NAN
static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff};
#define NAN (*(const float *) __nan) /**< Defined in C99 (Windows is C99) */
#endif
#define IQA_EXPORT __declspec(dllexport)
#else /* !Windows */
#define IQA_INLINE inline
#define IQA_EXPORT
#endif
#endif /* _OS_H_ */

64
3rdparty/iqa/include/math_utils.h vendored Normal file
View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2011, Tom Distler (http://tdistler.com)
* All rights reserved.
*
* The BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the tdistler.com nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _MATH_UTILS_H_
#define _MATH_UTILS_H_
#include "iqa_os.h"
#include <math.h>
/**
* Rounds a float to the nearest integer.
*/
IQA_EXPORT IQA_INLINE int _round(float a);
IQA_EXPORT IQA_INLINE int _max(int x, int y);
IQA_EXPORT IQA_INLINE int _min(int x, int y);
/**
* Compares 2 floats to the specified digit of precision.
* @return 0 if equal, 1 otherwise.
*/
IQA_EXPORT IQA_INLINE int _cmp_float(float a, float b, int digits);
/**
* Compares 2 matrices with the specified precision. 'b' is assumed to be the
* same size as 'a' or smaller.
* @return 0 if equal, 1 otherwise
*/
IQA_EXPORT IQA_INLINE int _matrix_cmp(const float *a, const float *b, int w, int h, int digits);
#endif /*_MATH_UTILS_H_*/

117
3rdparty/iqa/include/ssim.h vendored Normal file
View File

@ -0,0 +1,117 @@
/*
* Copyright (c) 2011, Tom Distler (http://tdistler.com)
* All rights reserved.
*
* The BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the tdistler.com nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SSIM_H_
#define _SSIM_H_
#include "convolve.h"
/*
* Circular-symmetric Gaussian weighting.
* h(x,y) = hg(x,y)/SUM(SUM(hg)) , for normalization to 1.0
* hg(x,y) = e^( -0.5*( (x^2+y^2)/sigma^2 ) ) , where sigma was 1.5
*/
#define GAUSSIAN_LEN 11
static const float g_gaussian_window[GAUSSIAN_LEN][GAUSSIAN_LEN] = {
{0.000001f, 0.000008f, 0.000037f, 0.000112f, 0.000219f, 0.000274f, 0.000219f, 0.000112f, 0.000037f, 0.000008f, 0.000001f},
{0.000008f, 0.000058f, 0.000274f, 0.000831f, 0.001619f, 0.002021f, 0.001619f, 0.000831f, 0.000274f, 0.000058f, 0.000008f},
{0.000037f, 0.000274f, 0.001296f, 0.003937f, 0.007668f, 0.009577f, 0.007668f, 0.003937f, 0.001296f, 0.000274f, 0.000037f},
{0.000112f, 0.000831f, 0.003937f, 0.011960f, 0.023294f, 0.029091f, 0.023294f, 0.011960f, 0.003937f, 0.000831f, 0.000112f},
{0.000219f, 0.001619f, 0.007668f, 0.023294f, 0.045371f, 0.056662f, 0.045371f, 0.023294f, 0.007668f, 0.001619f, 0.000219f},
{0.000274f, 0.002021f, 0.009577f, 0.029091f, 0.056662f, 0.070762f, 0.056662f, 0.029091f, 0.009577f, 0.002021f, 0.000274f},
{0.000219f, 0.001619f, 0.007668f, 0.023294f, 0.045371f, 0.056662f, 0.045371f, 0.023294f, 0.007668f, 0.001619f, 0.000219f},
{0.000112f, 0.000831f, 0.003937f, 0.011960f, 0.023294f, 0.029091f, 0.023294f, 0.011960f, 0.003937f, 0.000831f, 0.000112f},
{0.000037f, 0.000274f, 0.001296f, 0.003937f, 0.007668f, 0.009577f, 0.007668f, 0.003937f, 0.001296f, 0.000274f, 0.000037f},
{0.000008f, 0.000058f, 0.000274f, 0.000831f, 0.001619f, 0.002021f, 0.001619f, 0.000831f, 0.000274f, 0.000058f, 0.000008f},
{0.000001f, 0.000008f, 0.000037f, 0.000112f, 0.000219f, 0.000274f, 0.000219f, 0.000112f, 0.000037f, 0.000008f, 0.000001f},
};
/*
* Equal weight square window.
* Each pixel is equally weighted (1/64) so that SUM(x) = 1.0
*/
#define SQUARE_LEN 8
static const float g_square_window[SQUARE_LEN][SQUARE_LEN] = {
{0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f},
{0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f},
{0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f},
{0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f},
{0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f},
{0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f},
{0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f},
{0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f, 0.015625f},
};
/* Holds intermediate SSIM values for map-reduce operation. */
struct _ssim_int {
double l;
double c;
double s;
};
/* Defines the pointers to the map-reduce functions. */
typedef int (*_map)(const struct _ssim_int *, void *);
typedef float (*_reduce)(int, int, void *);
/* Arguments for map-reduce. The 'context' is user-defined. */
struct _map_reduce {
_map map;
_reduce reduce;
void *context;
};
/**
* Private method that calculates the SSIM value on a pre-processed image.
*
* The input images must have stride==width. This method does not scale.
*
* @note Image buffers are modified.
*
* Map-reduce is used for doing the final SSIM calculation. The map function is
* called for every pixel, and the reduce is called at the end. The context is
* caller-defined and *not* modified by this method.
*
* @param ref Original reference image
* @param cmp Distorted image
* @param w Width of the images
* @param h Height of the images
* @param k The kernel used as the window function
* @param mr Optional map-reduce functions to use to calculate SSIM. Required
* if 'args' is not null. Ignored if 'args' is null.
* @param args Optional SSIM arguments for fine control of the algorithm. 0 for defaults.
* Defaults are a=b=g=1.0, L=255, K1=0.01, K2=0.03
* @return The mean SSIM over the entire image (MSSIM), or INFINITY if error.
*/
float _iqa_ssim(float *ref, float *cmp, int w, int h, const struct _kernel *k, const struct _map_reduce *mr, const struct iqa_ssim_args *args);
#endif /* _SSIM_H_ */

195
3rdparty/iqa/source/convolve.c vendored Normal file
View File

@ -0,0 +1,195 @@
/*
* Copyright (c) 2011, Tom Distler (http://tdistler.com)
* All rights reserved.
*
* The BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the tdistler.com nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "convolve.h"
#include <stdlib.h>
float KBND_SYMMETRIC(const float *img, int w, int h, int x, int y, float bnd_const)
{
(void)bnd_const;
if (x<0) x=-1-x;
else if (x>=w) x=(w-(x-w))-1;
if (y<0) y=-1-y;
else if (y>=h) y=(h-(y-h))-1;
return img[y*w + x];
}
float KBND_REPLICATE(const float *img, int w, int h, int x, int y, float bnd_const)
{
(void)bnd_const;
if (x<0) x=0;
if (x>=w) x=w-1;
if (y<0) y=0;
if (y>=h) y=h-1;
return img[y*w + x];
}
float KBND_CONSTANT(const float *img, int w, int h, int x, int y, float bnd_const)
{
if (x<0) x=0;
if (y<0) y=0;
if (x>=w || y>=h)
return bnd_const;
return img[y*w + x];
}
static float _calc_scale(const struct _kernel *k)
{
int ii,k_len;
double sum=0.0;
if (k->normalized)
return 1.0f;
else {
k_len = k->w * k->h;
for (ii=0; ii<k_len; ++ii)
sum += k->kernel[ii];
if (sum != 0.0)
return (float)(1.0 / sum);
return 1.0f;
}
}
void _iqa_convolve(float *img, int w, int h, const struct _kernel *k, float *result, int *rw, int *rh)
{
int x,y,kx,ky,u,v;
int uc = k->w/2;
int vc = k->h/2;
int kw_even = (k->w&1)?0:1;
int kh_even = (k->h&1)?0:1;
int dst_w = w - k->w + 1;
int dst_h = h - k->h + 1;
int img_offset,k_offset;
double sum;
float scale, *dst=result;
if (!dst)
dst = img; /* Convolve in-place */
/* Kernel is applied to all positions where the kernel is fully contained
* in the image */
scale = _calc_scale(k);
for (y=0; y < dst_h; ++y) {
for (x=0; x < dst_w; ++x) {
sum = 0.0;
k_offset = 0;
ky = y+vc;
kx = x+uc;
for (v=-vc; v <= vc-kh_even; ++v) {
img_offset = (ky+v)*w + kx;
for (u=-uc; u <= uc-kw_even; ++u, ++k_offset) {
sum += img[img_offset+u] * k->kernel[k_offset];
}
}
dst[y*dst_w + x] = (float)(sum * scale);
}
}
if (rw) *rw = dst_w;
if (rh) *rh = dst_h;
}
int _iqa_img_filter(float *img, int w, int h, const struct _kernel *k, float *result)
{
int x,y;
int img_offset;
float scale, *dst=result;
if (!k || !k->bnd_opt)
return 1;
if (!dst) {
dst = (float*)malloc(w*h*sizeof(float));
if (!dst)
return 2;
}
scale = _calc_scale(k);
/* Kernel is applied to all positions where top-left corner is in the image */
for (y=0; y < h; ++y) {
for (x=0; x < w; ++x) {
dst[y*w + x] = _iqa_filter_pixel(img, w, h, x, y, k, scale);
}
}
/* If no result buffer given, copy results to image buffer */
if (!result) {
for (y=0; y<h; ++y) {
img_offset = y*w;
for (x=0; x<w; ++x, ++img_offset) {
img[img_offset] = dst[img_offset];
}
}
free(dst);
}
return 0;
}
float _iqa_filter_pixel(const float *img, int w, int h, int x, int y, const struct _kernel *k, const float kscale)
{
int u,v,uc,vc;
int kw_even,kh_even;
int x_edge_left,x_edge_right,y_edge_top,y_edge_bottom;
int edge,img_offset,k_offset;
double sum;
if (!k)
return img[y*w + x];
uc = k->w/2;
vc = k->h/2;
kw_even = (k->w&1)?0:1;
kh_even = (k->h&1)?0:1;
x_edge_left = uc;
x_edge_right = w-uc;
y_edge_top = vc;
y_edge_bottom = h-vc;
edge = 0;
if (x < x_edge_left || y < y_edge_top || x >= x_edge_right || y >= y_edge_bottom)
edge = 1;
sum = 0.0;
k_offset = 0;
for (v=-vc; v <= vc-kh_even; ++v) {
img_offset = (y+v)*w + x;
for (u=-uc; u <= uc-kw_even; ++u, ++k_offset) {
if (!edge)
sum += img[img_offset+u] * k->kernel[k_offset];
else
sum += k->bnd_opt(img, w, h, x+u, y+v, k->bnd_const) * k->kernel[k_offset];
}
}
return (float)(sum * kscale);
}

59
3rdparty/iqa/source/decimate.c vendored Normal file
View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2011, Tom Distler (http://tdistler.com)
* All rights reserved.
*
* The BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the tdistler.com nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "decimate.h"
#include <stdlib.h>
int _iqa_decimate(float *img, int w, int h, int factor, const struct _kernel *k, float *result, int *rw, int *rh)
{
int x,y;
int sw = w/factor + (w&1);
int sh = h/factor + (h&1);
int dst_offset;
float *dst=img;
if (result)
dst = result;
/* Downsample */
for (y=0; y<sh; ++y) {
dst_offset = y*sw;
for (x=0; x<sw; ++x,++dst_offset) {
dst[dst_offset] = _iqa_filter_pixel(img, w, h, x*factor, y*factor, k, 1.0f);
}
}
if (rw) *rw = sw;
if (rh) *rh = sh;
return 0;
}

82
3rdparty/iqa/source/math_utils.c vendored Normal file
View File

@ -0,0 +1,82 @@
/*
* Copyright (c) 2011, Tom Distler (http://tdistler.com)
* All rights reserved.
*
* The BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the tdistler.com nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "math_utils.h"
#include <math.h>
int _round(float a)
{
int sign_a = a > 0.0f ? 1 : -1;
return a-(int)a >= 0.5 ? (int)a + sign_a : (int)a;
}
int _max(int x, int y)
{
return x >= y ? x : y;
}
int _min(int x, int y)
{
return x <= y ? x : y;
}
int _cmp_float(float a, float b, int digits)
{
/* Round */
int sign_a = a > 0.0f ? 1 : -1;
int sign_b = b > 0.0f ? 1 : -1;
double scale = pow(10.0, (double)digits);
double ax = a * scale;
double bx = b * scale;
int ai = ax-(int)ax >= 0.5 ? (int)ax + sign_a : (int)ax;
int bi = bx-(int)bx >= 0.5 ? (int)bx + sign_b : (int)bx;
/* Compare */
return ai == bi ? 0 : 1;
}
int _matrix_cmp(const float *a, const float *b, int w, int h, int digits)
{
int offset;
int result=0;
int len=w*h;
for (offset=0; offset<len; ++offset) {
if (_cmp_float(a[offset], b[offset], digits)) {
result = 1;
break;
}
}
return result;
}

277
3rdparty/iqa/source/ms_ssim.c vendored Normal file
View File

@ -0,0 +1,277 @@
/*
* Copyright (c) 2011, Tom Distler (http://tdistler.com)
* All rights reserved.
*
* The BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the tdistler.com nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "iqa.h"
#include "ssim.h"
#include "decimate.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>
/* Default number of scales */
#define SCALES 5
/* Low-pass filter for down-sampling (9/7 biorthogonal wavelet filter) */
#define LPF_LEN 9
static const float g_lpf[LPF_LEN][LPF_LEN] = {
{ 0.000714f,-0.000450f,-0.002090f, 0.007132f, 0.016114f, 0.007132f,-0.002090f,-0.000450f, 0.000714f},
{-0.000450f, 0.000283f, 0.001316f,-0.004490f,-0.010146f,-0.004490f, 0.001316f, 0.000283f,-0.000450f},
{-0.002090f, 0.001316f, 0.006115f,-0.020867f,-0.047149f,-0.020867f, 0.006115f, 0.001316f,-0.002090f},
{ 0.007132f,-0.004490f,-0.020867f, 0.071207f, 0.160885f, 0.071207f,-0.020867f,-0.004490f, 0.007132f},
{ 0.016114f,-0.010146f,-0.047149f, 0.160885f, 0.363505f, 0.160885f,-0.047149f,-0.010146f, 0.016114f},
{ 0.007132f,-0.004490f,-0.020867f, 0.071207f, 0.160885f, 0.071207f,-0.020867f,-0.004490f, 0.007132f},
{-0.002090f, 0.001316f, 0.006115f,-0.020867f,-0.047149f,-0.020867f, 0.006115f, 0.001316f,-0.002090f},
{-0.000450f, 0.000283f, 0.001316f,-0.004490f,-0.010146f,-0.004490f, 0.001316f, 0.000283f,-0.000450f},
{ 0.000714f,-0.000450f,-0.002090f, 0.007132f, 0.016114f, 0.007132f,-0.002090f,-0.000450f, 0.000714f},
};
/* Alpha, beta, and gamma values for each scale */
static float g_alphas[] = { 0.0000f, 0.0000f, 0.0000f, 0.0000f, 0.1333f };
static float g_betas[] = { 0.0448f, 0.2856f, 0.3001f, 0.2363f, 0.1333f };
static float g_gammas[] = { 0.0448f, 0.2856f, 0.3001f, 0.2363f, 0.1333f };
struct _context {
double l; /* Luminance */
double c; /* Contrast */
double s; /* Structure */
float alpha;
float beta;
float gamma;
};
/* Called for each pixel */
int _ms_ssim_map(const struct _ssim_int *si, void *ctx)
{
struct _context *ms_ctx = (struct _context*)ctx;
ms_ctx->l += si->l;
ms_ctx->c += si->c;
ms_ctx->s += si->s;
return 0;
}
/* Called to calculate the final result */
float _ms_ssim_reduce(int w, int h, void *ctx)
{
double size = (double)(w*h);
struct _context *ms_ctx = (struct _context*)ctx;
ms_ctx->l = pow(ms_ctx->l / size, (double)ms_ctx->alpha);
ms_ctx->c = pow(ms_ctx->c / size, (double)ms_ctx->beta);
ms_ctx->s = pow(fabs(ms_ctx->s / size), (double)ms_ctx->gamma);
return (float)(ms_ctx->l * ms_ctx->c * ms_ctx->s);
}
/* Releases the scaled buffers */
void _free_buffers(float **buf, int scales)
{
int idx;
for (idx=0; idx<scales; ++idx)
free(buf[idx]);
}
/* Allocates the scaled buffers. If error, all buffers are free'd */
int _alloc_buffers(float **buf, int w, int h, int scales)
{
int idx;
int cur_w = w;
int cur_h = h;
for (idx=0; idx<scales; ++idx) {
buf[idx] = (float*)malloc(cur_w*cur_h*sizeof(float));
if (!buf[idx]) {
_free_buffers(buf, idx);
return 1;
}
cur_w = cur_w/2 + (cur_w&1);
cur_h = cur_h/2 + (cur_h&1);
}
return 0;
}
/*
* MS_SSIM(X,Y) = Lm(x,y)^aM * MULT[j=1->M]( Cj(x,y)^bj * Sj(x,y)^gj )
* where,
* L = mean
* C = variance
* S = cross-correlation
*
* b1=g1=0.0448, b2=g2=0.2856, b3=g3=0.3001, b4=g4=0.2363, a5=b5=g5=0.1333
*/
float iqa_ms_ssim(const unsigned char *ref, const unsigned char *cmp, int w, int h,
int stride, const struct iqa_ms_ssim_args *args)
{
int wang=0;
int scales=SCALES;
int gauss=1;
const float *alphas=g_alphas, *betas=g_betas, *gammas=g_gammas;
int idx,x,y,cur_w,cur_h;
int offset,src_offset;
float **ref_imgs, **cmp_imgs; /* Array of pointers to scaled images */
float msssim;
struct _kernel lpf, window;
struct iqa_ssim_args s_args;
struct _map_reduce mr;
struct _context ms_ctx;
if (args) {
wang = args->wang;
gauss = args->gaussian;
scales = args->scales;
if (args->alphas)
alphas = args->alphas;
if (args->betas)
betas = args->betas;
if (args->gammas)
gammas = args->gammas;
}
/* Make sure we won't scale below 1x1 */
cur_w = w;
cur_h = h;
for (idx=0; idx<scales; ++idx) {
if ( gauss ? cur_w<GAUSSIAN_LEN || cur_h<GAUSSIAN_LEN : cur_w<LPF_LEN || cur_h<LPF_LEN )
return INFINITY;
cur_w /= 2;
cur_h /= 2;
}
window.kernel = (float*)g_square_window;
window.w = window.h = SQUARE_LEN;
window.normalized = 1;
window.bnd_opt = KBND_SYMMETRIC;
if (gauss) {
window.kernel = (float*)g_gaussian_window;
window.w = window.h = GAUSSIAN_LEN;
}
mr.map = _ms_ssim_map;
mr.reduce = _ms_ssim_reduce;
/* Allocate the scaled image buffers */
ref_imgs = (float**)malloc(scales*sizeof(float*));
cmp_imgs = (float**)malloc(scales*sizeof(float*));
if (!ref_imgs || !cmp_imgs) {
if (ref_imgs) free(ref_imgs);
if (cmp_imgs) free(cmp_imgs);
return INFINITY;
}
if (_alloc_buffers(ref_imgs, w, h, scales)) {
free(ref_imgs);
free(cmp_imgs);
return INFINITY;
}
if (_alloc_buffers(cmp_imgs, w, h, scales)) {
_free_buffers(ref_imgs, scales);
free(ref_imgs);
free(cmp_imgs);
return INFINITY;
}
/* Copy original images into first scale buffer, forcing stride = width. */
for (y=0; y<h; ++y) {
src_offset = y*stride;
offset = y*w;
for (x=0; x<w; ++x, ++offset, ++src_offset) {
ref_imgs[0][offset] = (float)ref[src_offset];
cmp_imgs[0][offset] = (float)cmp[src_offset];
}
}
/* Create scaled versions of the images */
cur_w=w;
cur_h=h;
lpf.kernel = (float*)g_lpf;
lpf.w = lpf.h = LPF_LEN;
lpf.normalized = 1;
lpf.bnd_opt = KBND_SYMMETRIC;
for (idx=1; idx<scales; ++idx) {
if (_iqa_decimate(ref_imgs[idx-1], cur_w, cur_h, 2, &lpf, ref_imgs[idx], 0, 0) ||
_iqa_decimate(cmp_imgs[idx-1], cur_w, cur_h, 2, &lpf, cmp_imgs[idx], &cur_w, &cur_h))
{
_free_buffers(ref_imgs, scales);
_free_buffers(cmp_imgs, scales);
free(ref_imgs);
free(cmp_imgs);
return INFINITY;
}
}
cur_w=w;
cur_h=h;
msssim = 1.0;
for (idx=0; idx<scales; ++idx) {
ms_ctx.l = 0;
ms_ctx.c = 0;
ms_ctx.s = 0;
ms_ctx.alpha = alphas[idx];
ms_ctx.beta = betas[idx];
ms_ctx.gamma = gammas[idx];
if (!wang) {
/* MS-SSIM* (Rouse/Hemami) */
s_args.alpha = 1.0f;
s_args.beta = 1.0f;
s_args.gamma = 1.0f;
s_args.K1 = 0.0f; /* Force stabilization constants to 0 */
s_args.K2 = 0.0f;
s_args.L = 255;
s_args.f = 1; /* Don't resize */
mr.context = &ms_ctx;
msssim *= _iqa_ssim(ref_imgs[idx], cmp_imgs[idx], cur_w, cur_h, &window, &mr, &s_args);
}
else {
/* MS-SSIM (Wang) */
s_args.alpha = 1.0f;
s_args.beta = 1.0f;
s_args.gamma = 1.0f;
s_args.K1 = 0.01f;
s_args.K2 = 0.03f;
s_args.L = 255;
s_args.f = 1; /* Don't resize */
mr.context = &ms_ctx;
msssim *= _iqa_ssim(ref_imgs[idx], cmp_imgs[idx], cur_w, cur_h, &window, &mr, &s_args);
}
if (msssim == INFINITY)
break;
cur_w = cur_w/2 + (cur_w&1);
cur_h = cur_h/2 + (cur_h&1);
}
_free_buffers(ref_imgs, scales);
_free_buffers(cmp_imgs, scales);
free(ref_imgs);
free(cmp_imgs);
return msssim;
}

50
3rdparty/iqa/source/mse.c vendored Normal file
View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2011, Tom Distler (http://tdistler.com)
* All rights reserved.
*
* The BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the tdistler.com nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "iqa.h"
/* MSE(a,b) = 1/N * SUM((a-b)^2) */
float iqa_mse(const unsigned char *ref, const unsigned char *cmp, int w, int h, int stride)
{
int error, offset;
unsigned long long sum=0;
int ww,hh;
for (hh=0; hh<h; ++hh) {
offset = hh*stride;
for (ww=0; ww<w; ++ww, ++offset) {
error = ref[offset] - cmp[offset];
sum += error * error;
}
}
return (float)( (double)sum / (double)(w*h) );
}

42
3rdparty/iqa/source/psnr.c vendored Normal file
View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2011, Tom Distler (http://tdistler.com)
* All rights reserved.
*
* The BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the tdistler.com nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "iqa.h"
#include <math.h>
/* PSNR(a,b) = 10*log10(L^2 / MSE(a,b)), where L=2^b - 1 (8bit = 255) */
float iqa_psnr(const unsigned char *ref, const unsigned char *cmp, int w, int h, int stride)
{
const int L_sqd = 255 * 255;
return (float)( 10.0 * log10( L_sqd / iqa_mse(ref,cmp,w,h,stride) ) );
}

322
3rdparty/iqa/source/ssim.c vendored Normal file
View File

@ -0,0 +1,322 @@
/*
* Copyright (c) 2011, Tom Distler (http://tdistler.com)
* All rights reserved.
*
* The BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the tdistler.com nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "iqa.h"
#include "convolve.h"
#include "decimate.h"
#include "math_utils.h"
#include "ssim.h"
#include <stdlib.h>
#include <math.h>
/* Forward declarations. */
IQA_INLINE static double _calc_luminance(float, float, float, float);
IQA_INLINE static double _calc_contrast(double, float, float, float, float);
IQA_INLINE static double _calc_structure(float, double, float, float, float, float);
static int _ssim_map(const struct _ssim_int *, void *);
static float _ssim_reduce(int, int, void *);
/*
* SSIM(x,y)=(2*ux*uy + C1)*(2sxy + C2) / (ux^2 + uy^2 + C1)*(sx^2 + sy^2 + C2)
* where,
* ux = SUM(w*x)
* sx = (SUM(w*(x-ux)^2)^0.5
* sxy = SUM(w*(x-ux)*(y-uy))
*
* Returns mean SSIM. MSSIM(X,Y) = 1/M * SUM(SSIM(x,y))
*/
float iqa_ssim(const unsigned char *ref, const unsigned char *cmp, int w, int h, int stride,
int gaussian, const struct iqa_ssim_args *args)
{
int scale;
int x,y,src_offset,offset;
float *ref_f,*cmp_f;
struct _kernel low_pass;
struct _kernel window;
float result;
double ssim_sum=0.0;
struct _map_reduce mr;
/* Initialize algorithm parameters */
scale = _max( 1, _round( (float)_min(w,h) / 256.0f ) );
if (args) {
if(args->f)
scale = args->f;
mr.map = _ssim_map;
mr.reduce = _ssim_reduce;
mr.context = (void*)&ssim_sum;
}
window.kernel = (float*)g_square_window;
window.w = window.h = SQUARE_LEN;
window.normalized = 1;
window.bnd_opt = KBND_SYMMETRIC;
if (gaussian) {
window.kernel = (float*)g_gaussian_window;
window.w = window.h = GAUSSIAN_LEN;
}
/* Convert image values to floats. Forcing stride = width. */
ref_f = (float*)malloc(w*h*sizeof(float));
cmp_f = (float*)malloc(w*h*sizeof(float));
if (!ref_f || !cmp_f) {
if (ref_f) free(ref_f);
if (cmp_f) free(cmp_f);
return INFINITY;
}
for (y=0; y<h; ++y) {
src_offset = y*stride;
offset = y*w;
for (x=0; x<w; ++x, ++offset, ++src_offset) {
ref_f[offset] = (float)ref[src_offset];
cmp_f[offset] = (float)cmp[src_offset];
}
}
/* Scale the images down if required */
if (scale > 1) {
/* Generate simple low-pass filter */
low_pass.kernel = (float*)malloc(scale*scale*sizeof(float));
if (!low_pass.kernel) {
free(ref_f);
free(cmp_f);
return INFINITY;
}
low_pass.w = low_pass.h = scale;
low_pass.normalized = 0;
low_pass.bnd_opt = KBND_SYMMETRIC;
for (offset=0; offset<scale*scale; ++offset)
low_pass.kernel[offset] = 1.0f/(scale*scale);
/* Resample */
if (_iqa_decimate(ref_f, w, h, scale, &low_pass, 0, 0, 0) ||
_iqa_decimate(cmp_f, w, h, scale, &low_pass, 0, &w, &h)) { /* Update w/h */
free(ref_f);
free(cmp_f);
free(low_pass.kernel);
return INFINITY;
}
free(low_pass.kernel);
}
result = _iqa_ssim(ref_f, cmp_f, w, h, &window, &mr, args);
free(ref_f);
free(cmp_f);
return result;
}
/* _iqa_ssim */
float _iqa_ssim(float *ref, float *cmp, int w, int h, const struct _kernel *k, const struct _map_reduce *mr, const struct iqa_ssim_args *args)
{
float alpha=1.0f, beta=1.0f, gamma=1.0f;
int L=255;
float K1=0.01f, K2=0.03f;
float C1,C2,C3;
int x,y,offset;
float *ref_mu,*cmp_mu,*ref_sigma_sqd,*cmp_sigma_sqd,*sigma_both;
double ssim_sum, numerator, denominator;
double luminance_comp, contrast_comp, structure_comp, sigma_root;
struct _ssim_int sint;
/* Initialize algorithm parameters */
if (args) {
if (!mr)
return INFINITY;
alpha = args->alpha;
beta = args->beta;
gamma = args->gamma;
L = args->L;
K1 = args->K1;
K2 = args->K2;
}
C1 = (K1*L)*(K1*L);
C2 = (K2*L)*(K2*L);
C3 = C2 / 2.0f;
ref_mu = (float*)malloc(w*h*sizeof(float));
cmp_mu = (float*)malloc(w*h*sizeof(float));
ref_sigma_sqd = (float*)malloc(w*h*sizeof(float));
cmp_sigma_sqd = (float*)malloc(w*h*sizeof(float));
sigma_both = (float*)malloc(w*h*sizeof(float));
if (!ref_mu || !cmp_mu || !ref_sigma_sqd || !cmp_sigma_sqd || !sigma_both) {
if (ref_mu) free(ref_mu);
if (cmp_mu) free(cmp_mu);
if (ref_sigma_sqd) free(ref_sigma_sqd);
if (cmp_sigma_sqd) free(cmp_sigma_sqd);
if (sigma_both) free(sigma_both);
return INFINITY;
}
/* Calculate mean */
_iqa_convolve(ref, w, h, k, ref_mu, 0, 0);
_iqa_convolve(cmp, w, h, k, cmp_mu, 0, 0);
for (y=0; y<h; ++y) {
offset = y*w;
for (x=0; x<w; ++x, ++offset) {
ref_sigma_sqd[offset] = ref[offset] * ref[offset];
cmp_sigma_sqd[offset] = cmp[offset] * cmp[offset];
sigma_both[offset] = ref[offset] * cmp[offset];
}
}
/* Calculate sigma */
_iqa_convolve(ref_sigma_sqd, w, h, k, 0, 0, 0);
_iqa_convolve(cmp_sigma_sqd, w, h, k, 0, 0, 0);
_iqa_convolve(sigma_both, w, h, k, 0, &w, &h); /* Update the width and height */
/* The convolution results are smaller by the kernel width and height */
for (y=0; y<h; ++y) {
offset = y*w;
for (x=0; x<w; ++x, ++offset) {
ref_sigma_sqd[offset] -= ref_mu[offset] * ref_mu[offset];
cmp_sigma_sqd[offset] -= cmp_mu[offset] * cmp_mu[offset];
sigma_both[offset] -= ref_mu[offset] * cmp_mu[offset];
}
}
ssim_sum = 0.0;
for (y=0; y<h; ++y) {
offset = y*w;
for (x=0; x<w; ++x, ++offset) {
if (!args) {
/* The default case */
numerator = (2.0 * ref_mu[offset] * cmp_mu[offset] + C1) * (2.0 * sigma_both[offset] + C2);
denominator = (ref_mu[offset]*ref_mu[offset] + cmp_mu[offset]*cmp_mu[offset] + C1) *
(ref_sigma_sqd[offset] + cmp_sigma_sqd[offset] + C2);
ssim_sum += numerator / denominator;
}
else {
/* User tweaked alpha, beta, or gamma */
/* passing a negative number to sqrt() cause a domain error */
if (ref_sigma_sqd[offset] < 0.0f)
ref_sigma_sqd[offset] = 0.0f;
if (cmp_sigma_sqd[offset] < 0.0f)
cmp_sigma_sqd[offset] = 0.0f;
sigma_root = sqrt(ref_sigma_sqd[offset] * cmp_sigma_sqd[offset]);
luminance_comp = _calc_luminance(ref_mu[offset], cmp_mu[offset], C1, alpha);
contrast_comp = _calc_contrast(sigma_root, ref_sigma_sqd[offset], cmp_sigma_sqd[offset], C2, beta);
structure_comp = _calc_structure(sigma_both[offset], sigma_root, ref_sigma_sqd[offset], cmp_sigma_sqd[offset], C3, gamma);
sint.l = luminance_comp;
sint.c = contrast_comp;
sint.s = structure_comp;
if (mr->map(&sint, mr->context))
return INFINITY;
}
}
}
free(ref_mu);
free(cmp_mu);
free(ref_sigma_sqd);
free(cmp_sigma_sqd);
free(sigma_both);
if (!args)
return (float)(ssim_sum / (double)(w*h));
return mr->reduce(w, h, mr->context);
}
/* _ssim_map */
int _ssim_map(const struct _ssim_int *si, void *ctx)
{
double *ssim_sum = (double*)ctx;
*ssim_sum += si->l * si->c * si->s;
return 0;
}
/* _ssim_reduce */
float _ssim_reduce(int w, int h, void *ctx)
{
double *ssim_sum = (double*)ctx;
return (float)(*ssim_sum / (double)(w*h));
}
/* _calc_luminance */
IQA_INLINE static double _calc_luminance(float mu1, float mu2, float C1, float alpha)
{
double result;
float sign;
/* For MS-SSIM* */
if (C1 == 0 && mu1*mu1 == 0 && mu2*mu2 == 0)
return 1.0;
result = (2.0 * mu1 * mu2 + C1) / (mu1*mu1 + mu2*mu2 + C1);
if (alpha == 1.0f)
return result;
sign = result < 0.0 ? -1.0f : 1.0f;
return sign * pow(fabs(result),(double)alpha);
}
/* _calc_contrast */
IQA_INLINE static double _calc_contrast(double sigma_comb_12, float sigma1_sqd, float sigma2_sqd, float C2, float beta)
{
double result;
float sign;
/* For MS-SSIM* */
if (C2 == 0 && sigma1_sqd + sigma2_sqd == 0)
return 1.0;
result = (2.0 * sigma_comb_12 + C2) / (sigma1_sqd + sigma2_sqd + C2);
if (beta == 1.0f)
return result;
sign = result < 0.0 ? -1.0f : 1.0f;
return sign * pow(fabs(result),(double)beta);
}
/* _calc_structure */
IQA_INLINE static double _calc_structure(float sigma_12, double sigma_comb_12, float sigma1, float sigma2, float C3, float gamma)
{
double result;
float sign;
/* For MS-SSIM* */
if (C3 == 0 && sigma_comb_12 == 0) {
if (sigma1 == 0 && sigma2 == 0)
return 1.0;
else if (sigma1 == 0 || sigma2 == 0)
return 0.0;
}
result = (sigma_12 + C3) / (sigma_comb_12 + C3);
if (gamma == 1.0f)
return result;
sign = result < 0.0 ? -1.0f : 1.0f;
return sign * pow(fabs(result),(double)gamma);
}

View File

@ -13,6 +13,7 @@ project "texturec"
path.join(BGFX_DIR, "src"),
path.join(BGFX_DIR, "3rdparty"),
path.join(BGFX_DIR, "3rdparty/nvtt"),
path.join(BGFX_DIR, "3rdparty/iqa/include"),
}
files {
@ -31,6 +32,8 @@ project "texturec"
path.join(BGFX_DIR, "3rdparty/pvrtc/**.h"),
path.join(BGFX_DIR, "3rdparty/tinyexr/**.cc"),
path.join(BGFX_DIR, "3rdparty/tinyexr/**.h"),
path.join(BGFX_DIR, "3rdparty/iqa/include/**.h"),
path.join(BGFX_DIR, "3rdparty/iqa/source/**.c"),
path.join(BGFX_DIR, "tools/texturec/**.cpp"),
path.join(BGFX_DIR, "tools/texturec/**.h"),
}