You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
330 lines
12 KiB
C++
330 lines
12 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
|
|
#include <ImageProcessing_precompiled.h>
|
|
|
|
#include <math.h>
|
|
#include "FIR-Weights.h"
|
|
|
|
/* ####################################################################################################################
|
|
*/
|
|
|
|
namespace ImageProcessing
|
|
{
|
|
void calculateFilterRange(unsigned int srcFactor, int& srcFirst, int& srcLast,
|
|
unsigned int dstFactor, int dstFirst, int dstLast,
|
|
double blurFactor, class IWindowFunction<double>* windowFunction)
|
|
{
|
|
double s, t, u, scaleFactor; /* scale factors */
|
|
double srcRadius, srcCenter; /* window position and size */
|
|
|
|
#define s0 0
|
|
#define s1 srcFactor
|
|
#define d0 0
|
|
#define d1 dstFactor
|
|
|
|
/* the mapping from discrete destination coordinates to continuous source coordinates: */
|
|
#define MAP(b, scaleFactor, offset) ((b) + (offset)) / (scaleFactor)
|
|
|
|
/* relation of dstFactor to srcFactor */
|
|
s = (double)dstFactor / srcFactor;
|
|
t = d0 - s * (s0 - 0.5) - 0.5;
|
|
|
|
/* compute offsets for MAP */
|
|
u = d0 - s * (s0 - 0.5) - t;
|
|
|
|
/* find scale of filter
|
|
* when minifying, scaleFactor = 1/s, but when magnifying, scaleFactor = 1
|
|
*/
|
|
scaleFactor = (blurFactor == 0.0 ? 1.0 : (blurFactor > 0.0 ? (1.0 + blurFactor) : 1.0 / (1.0 - blurFactor))) * maximum(1., 1. / s);
|
|
|
|
/* find support radius of scaled filter
|
|
* if the window's length is <= 0.5 then we've got point sampling.
|
|
*/
|
|
srcRadius = maximum(0.5, scaleFactor * windowFunction->getLength());
|
|
|
|
/* sample the continuous filter, scaled by scaleFactor and
|
|
* positioned at continuous source coordinate srcCenter
|
|
*/
|
|
{
|
|
srcCenter = MAP(dstFirst + 0, s, u);
|
|
|
|
/* find the source coordinate range of this positioned filter window */
|
|
srcFirst = int(floor(srcCenter - srcRadius + 0.5));
|
|
}
|
|
|
|
{
|
|
srcCenter = MAP(dstLast - 1, s, u);
|
|
|
|
/* find the source coordinate range of this positioned filter window */
|
|
srcLast = int(floor(srcCenter + srcRadius + 0.5));
|
|
}
|
|
}
|
|
|
|
template<>
|
|
FilterWeights<signed short int>* calculateFilterWeights<signed short int>(unsigned int srcFactor, int srcFirst, int srcLast,
|
|
unsigned int dstFactor, int dstFirst, int dstLast, signed short int numRepetitions,
|
|
double blurFactor, class IWindowFunction<double>* windowFunction,
|
|
bool peaknorm, bool& plusminus)
|
|
|
|
{
|
|
#define WEIGHTBITS 15
|
|
#define WEIGHTONE (1 << WEIGHTBITS) /* filter weight of one */
|
|
|
|
double s, t, u, scaleFactor; /* scale factors */
|
|
double srcRadius, srcCenter; /* window position and size */
|
|
double sumfWeights, neg, pos, nrmWeights, fWeight; /* window position and size */
|
|
int i, i0, i1; /* window position and size */
|
|
int dstPosition;
|
|
signed short int n;
|
|
bool trimZeros = true, stillzero;
|
|
int lastnonzero, hWeight, highest;
|
|
signed int sumiWeights, iWeight;
|
|
signed short int* weightsPtr, *weightsMem;
|
|
FilterWeights<signed short int>* weightsObjs;
|
|
bool pm, pma = false;
|
|
|
|
/* pre-calculate filter window solutions for all rows
|
|
*/
|
|
weightsObjs = new FilterWeights<signed short int>[dstLast - dstFirst];
|
|
|
|
#define s0 0
|
|
#define s1 srcFactor
|
|
#define d0 0
|
|
#define d1 dstFactor
|
|
|
|
/* relation of dstFactor to srcFactor */
|
|
s = (double)dstFactor / srcFactor;
|
|
t = d0 - s * (s0 - 0.5) - 0.5;
|
|
|
|
/* compute offsets for MAP */
|
|
u = d0 - s * (s0 - 0.5) - t;
|
|
|
|
/* find scale of filter
|
|
* when minifying, scaleFactor = 1/s, but when magnifying, scaleFactor = 1
|
|
*/
|
|
scaleFactor = (blurFactor == 0.0 ? 1.0 : (blurFactor > 0.0 ? (1.0 + blurFactor) : 1.0 / (1.0 - blurFactor))) * maximum(1., 1. / s);
|
|
|
|
/* find support radius of scaled filter
|
|
* if the window's length is <= 0.5 then we've got point sampling.
|
|
*/
|
|
srcRadius = maximum(0.5, scaleFactor * windowFunction->getLength());
|
|
|
|
/* sample the continuous filter, scaled by ap->scaleFactor and
|
|
* positioned at continuous source coordinate srcCenter, for source coordinates in
|
|
* the range [0..len-1], writing the weights into wtab.
|
|
* Scale the weights so they sum up to WEIGHTONE, and trim leading and trailing
|
|
* zeros if trimZeros is true.
|
|
*/
|
|
#undef NORMALIZE_SUMMED_PEAK
|
|
#define NORMALIZE_MAXXED_PEAK
|
|
for (dstPosition = dstFirst, pm = false; dstPosition < dstLast; dstPosition++)
|
|
{
|
|
srcCenter = MAP(dstPosition, s, u);
|
|
|
|
/* find the source coordinate range of this positioned filter window */
|
|
i0 = int(floor(srcCenter - srcRadius + 0.5));
|
|
i1 = int(floor(srcCenter + srcRadius + 0.5));
|
|
|
|
/* clip against the source-range */
|
|
if (i0 < srcFirst)
|
|
{
|
|
i0 = srcFirst;
|
|
}
|
|
if (i1 > srcLast)
|
|
{
|
|
i1 = srcLast;
|
|
}
|
|
|
|
/* this is possible if we hit the final line */
|
|
if (i1 <= i0)
|
|
{
|
|
if (i1 >= srcLast)
|
|
{
|
|
i0 = i1 - 1;
|
|
}
|
|
else
|
|
{
|
|
i1 = i0 + 1;
|
|
}
|
|
}
|
|
|
|
AZ_Assert(i0 >= srcFirst, "%s: Invalid source coordinate range!", __FUNCTION__);
|
|
AZ_Assert(i1 <= srcLast, "%s: Invalid source coordinate range!", __FUNCTION__);
|
|
AZ_Assert(i0 < i1, "%s: Invalid source coordinate range!", __FUNCTION__);
|
|
|
|
/* find maximum peak to normalize the filter */
|
|
for (sumfWeights = 0, pos = 0, neg = 0, i = i0; i < i1; i++)
|
|
{
|
|
/* evaluate the filter function: */
|
|
fWeight = (*windowFunction)((i + 0.5 - srcCenter) / scaleFactor);
|
|
|
|
#if defined(NORMALIZE_SUMMED_PEAK)
|
|
/* get positive and negative summed peaks */
|
|
if (fWeight >= 0)
|
|
{
|
|
pos += fWeight;
|
|
}
|
|
else
|
|
{
|
|
neg += fWeight;
|
|
}
|
|
#elif defined(NORMALIZE_MAXXED_PEAK)
|
|
/* get positive and negative maximum peaks */
|
|
minmax(fWeight, neg, pos);
|
|
#endif
|
|
|
|
sumfWeights += fWeight;
|
|
}
|
|
|
|
/* the range of source samples to buffer: */
|
|
weightsMem = new signed short int[(i1 - i0) * abs(numRepetitions)];
|
|
|
|
/* set nrmWeights so that sumWeights of windowFunction() is approximately WEIGHTONE
|
|
* this needs to be adjusted because the maximum weight-coefficient
|
|
* is NOT allowed to leave [-32768,32767]
|
|
* a case like {+1.25,-0.25} does produce a sumWeights of 1.0 BUT
|
|
* produced a weight much too high (-40000)
|
|
*/
|
|
#if defined(NORMALIZE_SUMMED_PEAK)
|
|
sumfWeights = maximum(-neg, pos);
|
|
#elif defined(NORMALIZE_MAXXED_PEAK)
|
|
sumfWeights = maximum(sumfWeights, maximum(-neg, pos));
|
|
#endif
|
|
|
|
if (!peaknorm)
|
|
{
|
|
nrmWeights = (sumfWeights == 0. ? WEIGHTONE : (-neg > pos ? WEIGHTONE - 1 : WEIGHTONE) / sumfWeights);
|
|
}
|
|
else
|
|
{
|
|
nrmWeights = (sumfWeights == 0. ? WEIGHTONE : (-neg > pos ? WEIGHTONE - 1 : WEIGHTONE) / maximum(-neg, pos));
|
|
}
|
|
|
|
/* compute the discrete, sampled filter coefficients */
|
|
stillzero = trimZeros;
|
|
for (sumiWeights = 0, hWeight = -WEIGHTONE, weightsPtr = weightsMem, i = i0; i < i1; i++)
|
|
{
|
|
/* evaluate the filter function: */
|
|
fWeight = (*windowFunction)((i + 0.5 - srcCenter) / scaleFactor);
|
|
|
|
/* normalize against the peak sumWeights, because the sums are not allowed to leave -32768/32767 */
|
|
fWeight = fWeight * nrmWeights;
|
|
iWeight = int(round(fWeight));
|
|
|
|
/* find first nonzero */
|
|
if (stillzero && (iWeight == 0))
|
|
{
|
|
i0++;
|
|
}
|
|
else
|
|
{
|
|
AZ_Assert((-fWeight >= -32768.5) && (-fWeight <= 32767.5), "%s:The weight exceeded the maximum weight-coefficient.", __FUNCTION__);
|
|
|
|
if (!peaknorm)
|
|
{
|
|
sumiWeights += iWeight;
|
|
}
|
|
else
|
|
{
|
|
sumiWeights = maximum(sumiWeights, iWeight);
|
|
}
|
|
|
|
#define sgnextend(n, iWeight) (n & 1 ? (iWeight < 0 ? -1 : 0) : iWeight)
|
|
if (numRepetitions < 0)
|
|
{
|
|
/* add weight to table, interleaved sign */
|
|
for (n = 0; n < -numRepetitions; n++)
|
|
{
|
|
*weightsPtr++ = sgnextend(n, -iWeight);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* add weight to table */
|
|
for (n = 0; n < numRepetitions; n++)
|
|
{
|
|
*weightsPtr++ = -iWeight;
|
|
}
|
|
}
|
|
|
|
stillzero = false;
|
|
|
|
/* find last nonzero */
|
|
if (iWeight != 0)
|
|
{
|
|
lastnonzero = i;
|
|
}
|
|
|
|
/* check for negative values */
|
|
if (iWeight < 0)
|
|
{
|
|
pm = pma = true;
|
|
}
|
|
|
|
/* find most influential value */
|
|
if (iWeight >= hWeight)
|
|
{
|
|
highest = i;
|
|
hWeight = iWeight;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sumiWeights == 0)
|
|
{
|
|
i0 = (i0 + i1) >> 1;
|
|
i1 = (i0 + 1);
|
|
|
|
for (n = 0, weightsPtr = weightsMem; n < numRepetitions; n++)
|
|
{
|
|
*weightsPtr++ = -WEIGHTONE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* skip leading and trailing zeros */
|
|
if (trimZeros)
|
|
{
|
|
/* set i0 and i1 to the nonzero support of the filter */
|
|
i0 = i0;
|
|
i1 = i1 = lastnonzero + 1;
|
|
}
|
|
|
|
if (sumiWeights != WEIGHTONE)
|
|
{
|
|
/* Fudge with the highest value */
|
|
i = highest;
|
|
|
|
/* fudge srcCenter sample */
|
|
iWeight = WEIGHTONE - sumiWeights;
|
|
|
|
for (n = 0, weightsPtr = weightsMem + (i - i0) * numRepetitions; n < numRepetitions; n++)
|
|
{
|
|
*weightsPtr++ -= iWeight;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* the new adjusted range of source samples to buffer: */
|
|
weightsObjs[dstPosition].first = i0;
|
|
weightsObjs[dstPosition].last = i1;
|
|
weightsObjs[dstPosition].hasNegativeWeights = pm;
|
|
weightsObjs[dstPosition].weights = weightsMem;
|
|
}
|
|
|
|
plusminus = pma;
|
|
return weightsObjs;
|
|
}
|
|
}
|