summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--TODO1
-rw-r--r--src/interpolation.py86
-rwxr-xr-xtest/monotone_cubic_interpolation6
3 files changed, 89 insertions, 4 deletions
diff --git a/TODO b/TODO
index d5508ed..05d7151 100644
--- a/TODO
+++ b/TODO
@@ -12,7 +12,6 @@ Medium priority:
Low priority:
Add support for temporarily closing DRM connection so that multiple users can run in DRM
Add ramp interpolators:
- test/monotone_cubic_interpolation
https://en.wikipedia.org/wiki/Spline_interpolation
https://en.wikipedia.org/wiki/Lanczos_resampling
https://en.wikipedia.org/wiki/Kochanek–Bartels_spline
diff --git a/src/interpolation.py b/src/interpolation.py
index e6bb896..6c2bce1 100644
--- a/src/interpolation.py
+++ b/src/interpolation.py
@@ -101,6 +101,92 @@ def cubicly_interpolate_ramp(r, g, b, tension = 0):
return (R, G, B)
+def monotonic_cubicly_interpolate_ramp(r, g, b, tension = 0):
+ '''
+ Interpolate ramps to the size of the output axes using
+ monotone cubic Hermite spline and the Fritsch–Carlson method
+
+ Does not overshoot, but regular cubic interpolation with uses
+ linear replacement for overshot areas is better
+
+ @param r:list<float> The red colour curves
+ @param g:list<float> The green colour curves
+ @param b:list<float> The blue colour curves
+ @param tension:float A [0, 1] value of the tension
+ @return :(r:list<float>, g:list<float>, b:list<float>) The input parameters extended to sizes of `o_size`,
+ or their original size, whatever is larger.
+ '''
+ C = lambda c : c[:] if len(c) >= o_size else ([None] * o_size)
+ R, G, B = C(r), C(g), C(b)
+ # Basis functions
+ #h00 = lambda t : (1 + 2 * t) * (1 - t) ** 2
+ h10 = lambda t : t * (1 - t) ** 2
+ h01 = lambda t : t ** 2 * (3 - 2 * t)
+ h11 = lambda t : t ** 2 * (t - 1)
+ def tangent(values, index, last):
+ '''
+ Calculate the tangent at a point
+
+ @param values:list<float> Mapping from points to values
+ @param index:int The point
+ @param last:int The last point
+ @return :float The tangent at the point `index`
+ '''
+ if last == 0: return 0
+ if index == 0: return values[1] - values[0]
+ if index == last: return values[last] - values[last - 1]
+ return (values[index + 1] - values[index - 1]) / 2
+ # Tension coefficent
+ c_ = 1 - tension
+ ## Interpolant selection
+ # Compute the slopes of the secant
+ # lines between successive points
+ ds = [small[i + 1] - small[i] for i in range(small_)]
+ # Initialize the tangents at every
+ # data point as the average of the secants
+ ms = [ds[0]] + [(ds[i - 1] + ds[i]) / 2 for i in range(1, small_)] + [ds[small_ - 1]]
+ βlast = 0
+ for i in range(small_):
+ if ds[i] == 0:
+ # Two successive values are equal, ms[i],
+ # must be zero to preserve monotonicity,
+ # no idea to do further work on them.
+ ms[i], βlast = 0, -1
+ continue
+ # Look for local extremums
+ α, β = ms[i] / ds[i], ms[i + 1] / ds[i]
+ if (α < 0) or (βlast < 0):
+ # Local extremum found,
+ # ensure piecewise monotonicity
+ ms[i], β = 0, -1
+ elif α ** 2 + β ** 2 > 9:
+ # Otherwise, prevent overshoot and ensure
+ # monotonicity by restricting the (α, β)
+ # vector to a circle of radius 3.
+ τ = 3 / (α ** 2 + β ** 2) ** 0.5
+ ms[i], ms[i + 1] = τ * α * ds[i], τ * β * ds[i]
+ βlast = β
+ ## Interpolate each curve
+ for small, large in ((r, R), (g, G), (b, B)):
+ small_, large_ = len(small) - 1, len(large) - 1
+ # Only interpolate if scaling up
+ if large_ > small_:
+ for i in range(len(large)):
+ # Scaling
+ j = i * small_ / large_
+ # Floor, weight, ceiling
+ j, w, k = int(j), j % 1, min(int(j) + 1, small_)
+ # Points
+ pj, pk = small[j], small[k]
+ # Tangents
+ mj, mk = c_ * ms[j], c_ * ms[k]
+ # Interpolation
+ large[i] = pj + h10(w) * mj + h01(w) * (pk - pj) + h11(w) * mk
+ ## Check local monotonicity
+ eliminate_halos(r, g, b, R, G, B)
+ return (R, G, B)
+
+
def polynomially_interpolate_ramp(r, g, b): # TODO Speedup, demo and document this
'''
Polynomially interpolate ramps to the size of the output axes.
diff --git a/test/monotone_cubic_interpolation b/test/monotone_cubic_interpolation
index 4ade1dc..a659dcd 100755
--- a/test/monotone_cubic_interpolation
+++ b/test/monotone_cubic_interpolation
@@ -21,7 +21,7 @@
# using the Fritsch–Carlson method.
# Does not overshoot, but regular
# cubic interpolation with linear
-# replace for overshots is better.
+# replacement for overshots is better.
# Load matplotlib.pyplot,
@@ -87,7 +87,7 @@ def interpolate(small, tension = 0):
large = [None] * len(small) ** 2
small_, large_ = len(small) - 1, len(large) - 1
# Basis functions
- h00 = lambda t : (1 + 2 * t) * (1 - t) ** 2
+ #h00 = lambda t : (1 + 2 * t) * (1 - t) ** 2
h10 = lambda t : t * (1 - t) ** 2
h01 = lambda t : t ** 2 * (3 - 2 * t)
h11 = lambda t : t ** 2 * (t - 1)
@@ -132,7 +132,7 @@ def interpolate(small, tension = 0):
# Tangents
mj, mk = c_ * ms[j], c_ * ms[k]
# Interpolation
- large[i] = h00(w) * pj + h10(w) * mj + h01(w) * pk + h11(w) * mk
+ large[i] = pj + h10(w) * mj + h01(w) * (pk - pj) + h11(w) * mk
return large
# Plot interpolation