Skip to content Skip to sidebar Skip to footer

Interpolate Between Two Images

I'm trying to interpolate between two images in Python. Images are of shapes (188, 188) I wish to interpolate the image 'in-between' these two images. Say Image_1 is at location

Solution 1:

I figured this out. Or at least a method that produces desirable results.

Based on: Interpolating Between Two Planes in 3d space

defsigned_bwdist(im):
    '''
    Find perim and return masked image (signed/reversed)
    '''    
    im = -bwdist(bwperim(im))*np.logical_not(im) + bwdist(bwperim(im))*im
    return im

defbwdist(im):
    '''
    Find distance map of image
    '''
    dist_im = distance_transform_edt(1-im)
    return dist_im

definterp_shape(top, bottom, precision):
    '''
    Interpolate between two contours

    Input: top 
            [X,Y] - Image of top contour (mask)
           bottom
            [X,Y] - Image of bottom contour (mask)
           precision
             float  - % between the images to interpolate 
                Ex: num=0.5 - Interpolate the middle image between top and bottom image
    Output: out
            [X,Y] - Interpolated image at num (%) between top and bottom

    '''if precision>2:
        print("Error: Precision must be between 0 and 1 (float)")

    top = signed_bwdist(top)
    bottom = signed_bwdist(bottom)

    # row,cols definition
    r, c = top.shape

    # Reverse % indexing
    precision = 1+precision

    # rejoin top, bottom into a single array of shape (2, r, c)
    top_and_bottom = np.stack((top, bottom))

    # create ndgrids 
    points = (np.r_[0, 2], np.arange(r), np.arange(c))
    xi = np.rollaxis(np.mgrid[:r, :c], 0, 3).reshape((r**2, 2))
    xi = np.c_[np.full((r**2),precision), xi]

    # Interpolate for new plane
    out = interpn(points, top_and_bottom, xi)
    out = out.reshape((r, c))

    # Threshold distmap to values above 0
    out = out > 0return out


# Run interpolation
out = interp_shape(image_1,image_2, 0.5)

Example output: Example Output

Solution 2:

I don't know the solution to your problem, but I don't think it's possible to do this with interpn.

I corrected the code that you tried, and used the following input images:

img1img2

But the result is:

result

Here's the corrected code:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from scipy import interpolate

n = 8
img1 = np.zeros((n, n))
img2 = np.zeros((n, n))

img1[2:4, 2:4] = 1img2[4:6, 4:6] = 1

plt.figure()
plt.imshow(img1, cmap=cm.Greys)

plt.figure()
plt.imshow(img2, cmap=cm.Greys)

points = (np.r_[0, 2], np.arange(n), np.arange(n))
values = np.stack((img1, img2))
xi = np.rollaxis(np.mgrid[:n, :n], 0, 3).reshape((n**2, 2))
xi = np.c_[np.ones(n**2), xi]

values_x = interpolate.interpn(points, values, xi, method='linear')
values_x = values_x.reshape((n, n))
print(values_x)

plt.figure()
plt.imshow(values_x, cmap=cm.Greys)
plt.clim((0, 1))

plt.show()

I think the main difference between your code and mine is in the specification of xi. interpn tends to be somewhat confusing to use, and I've explained it in greater detail in an older answer. If you're curious about the mechanics of how I've specified xi, see this answer of mine explaining what I've done.

This result is not entirely surprising, because interpn just linearly interpolated between the two images: so the parts which had 1 in one image and 0 in the other simply became 0.5.

Over here, since one image is the translation of the other, it's clear that we want an image that's translated "in-between". But how would interpn interpolate two general images? If you had one small circle and one big circle, is it in any way clear that there should be a circle of intermediate size "between" them? What about interpolating between a dog and a cat? Or a dog and a building?

I think you are essentially trying to "draw lines" connecting the edges of the two images and then trying to figure out the image in between. This is similar to sampling a moving video at a half-frame. You might want to check out something like optical flow, which connects adjacent frames using vectors. I'm not aware if and what python packages/implementations are available though.

Solution 3:

I came across a similar problem where I needed to interpolate the shift between frames where the change did not merely constitute a translation but also changes to the shape itself . I solved this problem by :

  • Using center_of_mass from scipy.ndimage.measurements to calculate the center of the object we want to move in each frame
  • Defining a continuous parameter t where t=0 first and t=1 last frame
  • Interpolate the motion between two nearest frames (with regard to a specific t value) by shifting the image back/forward via shift from scipy.ndimage.interpolation and overlaying them.

Here is the code:

def inter(images,t):
#input: 
# images: list of arrays/frames ordered according to motion
# t: parameter ranging from 0 to 1 corresponding to first and last frame 
#returns: interpolated image

#direction of movement, assumed to be approx. linear 
a=np.array(center_of_mass(images[0]))
b=np.array(center_of_mass(images[-1]))

#find index of two nearest frames 
arr=np.array([center_of_mass(images[i]) for i in range(len(images))])
v=a+t*(b-a) #convert t into vector 
idx1 = (np.linalg.norm((arr - v),axis=1)).argmin()
arr[idx1]=np.array([0,0]) #this is sloppy, should be changed if relevant values are near [0,0]
idx2 = (np.linalg.norm((arr - v),axis=1)).argmin()

if idx1>idx2:
    b=np.array(center_of_mass(images[idx1])) #center of mass of nearest contour
    a=np.array(center_of_mass(images[idx2])) #center of mass of second nearest contour
    tstar=np.linalg.norm(v-a)/np.linalg.norm(b-a) #define parameter ranging from 0 to 1 for interpolation between two nearest frames
    im1_shift=shift(images[idx2],(b-a)*tstar) #shift frame 1
    im2_shift=shift(images[idx1],-(b-a)*(1-tstar)) #shift frame 2
    return im1_shift+im2_shift #return average

if idx1<idx2:
    b=np.array(center_of_mass(images[idx2]))
    a=np.array(center_of_mass(images[idx1]))
    tstar=np.linalg.norm(v-a)/np.linalg.norm(b-a)
    im1_shift=shift(images[idx2],-(b-a)*(1-tstar))
    im2_shift=shift(images[idx1],(b-a)*(tstar))
    return im1_shift+im2_shift

Result example

Post a Comment for "Interpolate Between Two Images"