Better Nohalo comments

This commit is contained in:
Nicolas Robidoux 2010-05-18 20:30:14 +00:00
parent 4f9e33aaf4
commit 4112bcc70a

View File

@ -1,7 +1,7 @@
/* Nohalo subdivision followed by LBB (Locally Bounded Bicubic) /* Nohalo subdivision followed by LBB (Locally Bounded Bicubic)
* interpolation * interpolation
* *
* N. Robidoux and C. Racette 11/5--17/5/2009 * N. Robidoux, C. Racette and J. Cupitt 11/5--18/5/2009
* *
* N. Robidoux 1/4-29/5/2009 * N. Robidoux 1/4-29/5/2009
* *
@ -68,7 +68,7 @@
* *
* "Nohalo" is a resampler with a mission: smoothly straightening * "Nohalo" is a resampler with a mission: smoothly straightening
* oblique lines without undesirable side-effects. In particular, * oblique lines without undesirable side-effects. In particular,
* without much blurring and with absolutely no added haloing. * without much blurring and with no added haloing.
* *
* In this code, one Nohalo subdivision is performed. The * In this code, one Nohalo subdivision is performed. The
* interpolation is finished with LBB (Locally Bounded Bicubic). * interpolation is finished with LBB (Locally Bounded Bicubic).
@ -79,28 +79,35 @@
* Nohalo is interpolatory * Nohalo is interpolatory
* ======================= * =======================
* *
* That is, nohalo preserves point values: If asked for the value at * That is, Nohalo preserves point values: If asked for the value at
* the center of an input pixel, the sampler returns the corresponding * the center of an input pixel, the sampler returns the corresponding
* value, unchanged. In addition, because nohalo is continuous, if * value, unchanged. In addition, because Nohalo is continuous, if
* asked for a value at a location "very close" to the center of an * asked for a value at a location "very close" to the center of an
* input pixel, then the sampler returns a value "very close" to * input pixel, then the sampler returns a value "very close" to
* it. (Nohalo is not smoothing like, say, B-Spline * it. (Nohalo is not smoothing like, say, B-Spline
* pseudo-interpolation.) * pseudo-interpolation.)
* *
* ======================================================== * ====================================================================
* Nohalo is co-monotone (this is why it's called "nohalo") * Nohalo subdivision is co-monotone (this is why it's called "no-halo")
* ======================================================== * ====================================================================
* *
* What monotonicity more or less means here is that the resampled * One consequence of monotonicity is that additional subdivided
* value is in the range of the four closest input values. This * values are in the range of the four closest input values, which is
* property is why there is no added haloing. It also implies that * a form of local boundedness. (Note: plain vanilla bilinear and
* clamping is unnecessary (provided abyss values are within the range * nearest neighbour are also co-monotone.) LBB is also locally
* of acceptable values, which is always the case). (Note: plain * bounded. Consequently, Nohalo subdivision followed by LBB is
* vanilla bilinear is also co-monotone.) * locally bounded. When used as a finishing scheme for Nohalo, the
* standard LBB bounds imply that the final interpolated value is in
* the range of the nine closest input values. This property is why
* there is very little added haloing, even when a finishing scheme
* which is not strictly monotone. Another consequence of local
* boundedness is that clamping is unnecessary (provided abyss values
* are within the range of acceptable values, which is "always" the
* case).
* *
* Note: If the abyss policy is an extrapolating one---for example, * Note: If the abyss policy is an extrapolating one---for example,
* linear or bilinear extrapolation---clamping is still unnecessary * linear or bilinear extrapolation---clamping is still unnecessary
* unless one attempts to resample outside of the convex hull of the * UNLESS one attempts to resample outside of the convex hull of the
* input pixel positions. Consequence: the "corner" image size * input pixel positions. Consequence: the "corner" image size
* convention does not require clamping when using linear * convention does not require clamping when using linear
* extrapolation abyss policy when performing image resizing, but the * extrapolation abyss policy when performing image resizing, but the
@ -115,6 +122,10 @@
* Nohalo is a local method * Nohalo is a local method
* ======================== * ========================
* *
* The interpolated pixel value when using Nohalo subdivision followed
* by LBB only depends on the 21 (5x5 minus the four corners) closest
* input values.
*
* =============================== * ===============================
* Nohalo is second order accurate * Nohalo is second order accurate
* =============================== * ===============================
@ -122,15 +133,15 @@
* (Except possibly near the boundary: it is easy to make this * (Except possibly near the boundary: it is easy to make this
* property carry over everywhere but this requires a tuned abyss * property carry over everywhere but this requires a tuned abyss
* policy---linear extrapolation, say---or building the boundary * policy---linear extrapolation, say---or building the boundary
* conditions inside the sampler.) Nohalo is exact on linear * conditions inside the sampler.) Nohalo+LBB is exact on linear
* intensity profiles, meaning that if the input pixel values (in the * intensity profiles, meaning that if the input pixel values (in the
* stencil) are obtained from a function of the form f(x,y) = a + b*x * stencil) are obtained from a function of the form f(x,y) = a + b*x
* + c*y (a, b, c constants), then the computed pixel value is exactly * + c*y (a, b, c constants), then the computed pixel value is exactly
* the value of f(x,y) at the asked-for sampling location. The * the value of f(x,y) at the asked-for sampling location. The
* boundary condition which is emulated by VIPS throught the "extend" * boundary condition which is emulated by VIPS through the "extend"
* extension of the input image---this corresponds to the nearest * extension of the input image---this corresponds to the nearest
* neighbour abyss policy---does NOT make this resampler exact on * neighbour abyss policy---does NOT make this resampler exact on
* linears at the boundary. It does, however, guarantee that no * linears near the boundary. It does, however, guarantee that no
* clamping is required even when resampled values are computed at * clamping is required even when resampled values are computed at
* positions outside of the extent of the input image (when * positions outside of the extent of the input image (when
* extrapolation is required). * extrapolation is required).
@ -139,23 +150,23 @@
* Nohalo is nonlinear * Nohalo is nonlinear
* =================== * ===================
* *
* In particular, resampling a sum of images may not be the same as * Both Nohalo and LBB are nonlinear, consequently their composition
* summing the resamples. (This occurs even without taking into account * is nonlinear. In particular, resampling a sum of images may not be
* over and underflow issues: images can only take values within a * the same as summing the resamples. (This occurs even without taking
* banded range, and consequently no sampler is truly linear.) * into account over and underflow issues: images can only take values
* within a banded range, and consequently no sampler is truly
* linear.)
* *
* ==================== * ====================
* Weaknesses of nohalo * Weaknesses of Nohalo
* ==================== * ====================
* *
* In some cases, the initial subdivision computation is wasted: * In some cases, the initial subdivision computation is wasted:
* *
* If a region is bichromatic, the nonlinear component of the level 1 * If a region is bi-chromatic, the nonlinear component of Nohalo
* nohalo is zero in the interior of the region, and consequently * subdivision is zero in the interior of the region, and consequently
* nohalo boils down to bilinear. For such images, either stick to * Nohalo subdivision boils down to bilinear. For such images, LBB is
* bilinear, or use a higher level (quality) setting. (There is no * probably a better choice.
* real harm in using nohalo when it boils down to bilinear if one
* does not mind wasting cycles.)
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
@ -741,9 +752,25 @@ lbbicubic( const double c00,
/* /*
* Computation of the four min and four max over 3x3 input data * Computation of the four min and four max over 3x3 input data
* sub-blocks of the 4x4 input stencil. (Because there is * sub-blocks of the 4x4 input stencil.
* redundancy, only 17 minima and 17 maxima are needed; if done with *
* conditional moves, only 28 different flags are involved.) * Surprisingly, we have not succeeded in using the fact that the
* data comes from the (co-monotone) method Nohalo so that it is
* known ahead of time that
*
* dos_thr is between dos_two and dos_fou
*
* tre_two is between dos_two and qua_two
*
* tre_fou is between dos_fou and qua_fou
*
* qua_thr is between qua_two and qua_fou
*
* tre_thr is in the convex hull of dos_two, dos_fou, qua_two and qua_fou
*
* to minimize the number of flags and conditional moves.
*
* Suggestions welcome!
*/ */
const double m1 = (dos_two <= dos_thr) ? dos_two : dos_thr ; const double m1 = (dos_two <= dos_thr) ? dos_two : dos_thr ;
const double M1 = (dos_two <= dos_thr) ? dos_thr : dos_two ; const double M1 = (dos_two <= dos_thr) ? dos_thr : dos_two ;
@ -1033,15 +1060,15 @@ lbbicubic( const double c00,
} }
/* /*
* Call Nohalo with an interpolator as a parameter. * Call Nohalo+LBB with a careful type conversion as a parameter.
* *
* It would be nice to do this with templates somehow---for one thing * It would be nice to do this with templates somehow---for one thing
* this would allow code comments!---but we can't figure a clean way * this would allow code comments!---but we can't figure a clean way
* to do it. * to do it.
*/ */
#define NOHALO_INTER( inter ) \ #define NOHALO_CONVERSION( conversion ) \
template <typename T> static void inline \ template <typename T> static void inline \
nohalo_ ## inter( PEL* restrict pout, \ nohalo_ ## conversion( PEL* restrict pout, \
const PEL* restrict pin, \ const PEL* restrict pin, \
const int bands, \ const int bands, \
const int lskip, \ const int lskip, \
@ -1262,7 +1289,7 @@ lbbicubic( const double c00,
qua_fou ); \ qua_fou ); \
\ \
{ \ { \
const T result = to_ ## inter<T>( double_result ); \ const T result = to_ ## conversion<T>( double_result ); \
in++; \ in++; \
*out++ = result; \ *out++ = result; \
} \ } \
@ -1271,13 +1298,13 @@ lbbicubic( const double c00,
} }
NOHALO_INTER( fptypes ) NOHALO_CONVERSION( fptypes )
NOHALO_INTER( withsign ) NOHALO_CONVERSION( withsign )
NOHALO_INTER( nosign ) NOHALO_CONVERSION( nosign )
#define CALL( T, inter ) \ #define CALL( T, conversion ) \
nohalo_ ## inter<T>( out, \ nohalo_ ## conversion<T>( out, \
p, \ p, \
bands, \ bands, \
lskip, \ lskip, \