Interpolating elements of a color matrix on the basis of some given reference elements
<p>This is more or less a follow up question to <a href="http://stackoverflow.com/questions/39485178/two-dimensional-color-ramp-256x256-matrix-interpolated-from-4-corner-colors?noredirect=1#comment66289716_39485178">Two dimensional color ramp (256x256 matrix) interpolated from 4 corner colors</a> that was profoundly answered by jadsq today.</p>

<p>For linear gradients the previous answer works very well. However, if one wants to have better control of the stop colors of the gradient, this method seems not to be very practical. What might help in this situation is to have some reference color points in a matrix (lookup table) which are used to interpolate color values for the empty position in the look-up table. What I mean might be easier read out of the below image.</p>

<p><a href="http://i.stack.imgur.com/AwPYk.png" rel="nofollow"><img src="http://i.stack.imgur.com/AwPYk.png" alt="enter image description here"></a></p>

<p>The whole idea is taken from <a href="http://cartography.oregonstate.edu/pdf/2006_JennyHurni_SwissStyleShading.pdf" rel="nofollow">http://cartography.oregonstate.edu/pdf/2006_JennyHurni_SwissStyleShading.pdf</a> page 4 to 6. I've read through the paper, I understand theoretically what is going on but failing miserably because of my low experience with interpolation methods and to be honest, general math skills. What might also be of interest is, that they use a sigmoid Gaussian bell as interpolation method (page 6). They argue that Gaussian weighting yielded the visually best results and was simple to compute (equation 1, with k=0.0002 for a table of 256 per 256 cells).</p>

<hr>

<p>Edit (better illustrations):</p>

<p><a href="http://i.stack.imgur.com/cQVW1.png" rel="nofollow"><img src="http://i.stack.imgur.com/cQVW1.png" alt="Weighting functions for interpolating colours"></a></p>

<p><a href="http://i.stack.imgur.com/hGXfz.png" rel="nofollow"><img src="http://i.stack.imgur.com/hGXfz.png" alt="Equation 1"></a></p>

<hr>

<p>I have the other parts of their presented methods in place but filling the empty values in the matrix really is a key part and keeps me from continuing. Once again, thank you for your help!</p>

<p>What I have right now:</p>

<pre><code>#!/usr/bin/env python3
import numpy as np
import matplotlib.pyplot as plt 

# the matrix with the reference color elements
ref=np.full([7, 7, 3], [255,255,255], dtype=np.uint8)
ref[0][6] = (239,238,185)
ref[1][1] = (120,131,125)
ref[4][6] = (184,191,171)
ref[6][2] = (150,168,158)
ref[6][5] = (166,180,166)

# s = ref.shape
#
# from scipy.ndimage.interpolation import zoom
# zooming as in http://stackoverflow.com/a/39485650/1230358 doesn't seem to work here anymore, because we have no corner point as reference but randomly distributed points within the matrix. As far as I know ...
# zoomed=zoom(ref,(256/s[0],256/s[1],1),order=1)

plt.subplot(211)
plt.imshow(ref,interpolation='nearest')
# plt.subplot(212)
# plt.imshow(zoomed,interpolation='nearest')
plt.show()
</code></pre>

<p>I'm here again (a bit late,  sorry,I just found the question) with a fairly short solution using <code>griddata</code> from <code>scipy.interpolate</code>. That function is meant to do precisely what you want : interpolate values on a grid from just a few points. The issues being the following : with that you won't be able to use fancy weights only the predefined interpolation method, and the holes around the border can't be directly interpolated either, so here I completed them with nearest values.</p>

<p>Here's the demo code :</p>

<pre><code># the matrix with the reference color elements
ref=np.full([7, 7, 3], 0 , dtype=np.uint8)
#Note I fill with 0 instead of 255
ref[0][6] = (239,238,185)
ref[1][1] = (120,131,125)
ref[4][6] = (184,191,171)
ref[6][2] = (150,168,158)
ref[6][5] = (166,180,166)

from scipy.interpolate import griddata

#we format the data to feed in griddata
points=np.where(ref != 0)
values=ref[points]
grid_x,grid_y,grid_z=np.mgrid[0:7,0:7,0:3]

#we compute the inperpolation
filled_grid=griddata(points, values, (grid_x, grid_y, grid_z), method='linear')
filled_grid=np.array(filled_grid,dtype=np.uint8) #we convert the float64 to uint8

#filled_grid still has holes around the border
#here i'll complete the holes with the nearest value
points=np.where(filled_grid != 0)
values=filled_grid[points]
near_grid=griddata(points, values, (grid_x, grid_y, grid_z), method='nearest')
completed_grid=(near_grid*(filled_grid == 0))+filled_grid

plt.subplot(131)
plt.imshow(ref,interpolation='nearest')
plt.subplot(132)
plt.imshow(filled_grid,interpolation='nearest')
plt.subplot(133)
plt.imshow(completed_grid,interpolation='nearest')
plt.show()
</code></pre>

<p><strong>Output:</strong>
<a href="http://i.stack.imgur.com/ZTSrr.png" rel="nofollow"><img src="http://i.stack.imgur.com/ZTSrr.png" alt="output of the code"></a></p>

python numpy image-processing matrix scipy