Added Image Quality Assessment.
This commit is contained in:
parent
931c6ed0f6
commit
f3b9fed29a
32
3rdparty/iqa/LICENSE
vendored
Normal file
32
3rdparty/iqa/LICENSE
vendored
Normal 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
36
3rdparty/iqa/README.txt
vendored
Normal 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
111
3rdparty/iqa/include/convolve.h
vendored
Normal 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
55
3rdparty/iqa/include/decimate.h
vendored
Normal 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
134
3rdparty/iqa/include/iqa.h
vendored
Normal 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
66
3rdparty/iqa/include/iqa_os.h
vendored
Normal 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
64
3rdparty/iqa/include/math_utils.h
vendored
Normal 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
117
3rdparty/iqa/include/ssim.h
vendored
Normal 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
195
3rdparty/iqa/source/convolve.c
vendored
Normal 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
59
3rdparty/iqa/source/decimate.c
vendored
Normal 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
82
3rdparty/iqa/source/math_utils.c
vendored
Normal 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
277
3rdparty/iqa/source/ms_ssim.c
vendored
Normal 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
50
3rdparty/iqa/source/mse.c
vendored
Normal 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
42
3rdparty/iqa/source/psnr.c
vendored
Normal 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
322
3rdparty/iqa/source/ssim.c
vendored
Normal 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);
|
||||
}
|
@ -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"),
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user