2

I'm looking through the Python Imaging Library docs for a way to take 2 similar images and "subtract one from the other". Here is a visual aid:

enter image description here

enter image description here

We've all seen these nifty "turning a word into its meaning" things, right? I want to basically take the second image and subtract the first image, so I want to return only the lines added to the word "cat" to make the actual cat. What functions will help me along with doing this?

Update: I've been working on this continuously while waiting. This is what I've tried.

import numpy as np
from PIL import Image
from PIL import ImageChops
import math,operator, matplotlib.cm as cm

img1 = Image.open("cat1.PNG")
img2 = Image.open("cat2.PNG")


img1array = (list(img1.getdata()))
img1new = Image.fromarray(np.uint8(cm.gist_earth(img1array)*255))

img2array = (list(img2.getdata()))
img2new = Image.fromarray(np.uint8(cm.gist_earth(img2array)*255))

dif = np.fabs(np.subtract(img2array[:], img1array[:]))

difimg = Image.fromarray(np.uint8(cm.gist_earth(dif)*255))

difimg.save("out1.PNG")

However, this outputs a file that Windows 10 can't even open. My idea was to convert both images to an array, subtract them, and then recreate the difference as an image. This does indeed save a file called out1.PNG, but Windows gives an error when trying to open it: We can't open this file. Note - I resized the 2nd image using an online resizer, PIL was giving me problems about size differences...

enter image description here

whatwhatwhat
  • 1,991
  • 4
  • 31
  • 50
  • Does it necessarily need to be done with a PIL function? What you are trying to do is an arrays subtraction, and thus an array oriented library is very well suited for this purpose e.g. NumPy – Jalo Dec 23 '16 at 09:09
  • @Jalo it does not need to be PIL, seeing as how this is just a fun creative project of mine – whatwhatwhat Dec 23 '16 at 11:27

1 Answers1

0

I think what you are looking for is called image registration. You want to know by how much you have to shift one image to get the other. Then you can do a simple subtraction. There are different methods to do this. The simplest one is use brute force (see the code below). I am thresholding the images in order to reduce problems due to variations in illumination intensity.

Other alternative is to use are more sophisticated alignment method. There are some implemented in opencv 1, 2, or you can use a method based on FFT.

import numpy as np
import matplotlib.pylab as plt


th = 170 #arbitrary threshold, you can use automatic methods like otsu or even better some adaptative thresholding.
Ibth = (Ibig < th).astype(np.int)
Isth = (Ismall < th).astype(np.int)

dxt = (Ibth.shape[1] - Isth.shape[1])-1
dyt = (Ibth.shape[0] - Isth.shape[0])-1

xdiff = np.zeros((dyt, dxt))

S = Isth.shape
for dx in range(dxt):
    for dy in range(dyt):

        dpix = Isth-Ibth[dy:(S[0]+dy), dx:(S[1]+dx)]

        #I am only considering pixels that get overlaped in the bigger image.
        #The non-uniform illumination spoils minimization if I use np.abs.
        #This could be corrected using opencv adaptativeThreshold
        xdiff[dy,dx] = np.sum(dpix>0)

#find the global minima
im_shift = np.unravel_index(xdiff.argmin(), xdiff.shape)

#show the result
im_diff = np.copy(Ibth).astype(np.int)
im_diff[im_shift[0]:(S[0]+im_shift[0]), im_shift[1]:(S[1]+im_shift[1])] -= Isth


plt.figure()

plt.subplot(2,2,1)
plt.imshow(Ib,  cmap='gray', interpolation='none')

plt.subplot(2,2,3)
plt.imshow(Is,  cmap='gray', interpolation='none')

plt.subplot(1,2,2)
plt.imshow(im_diff,  cmap='gray', interpolation='none')
Community
  • 1
  • 1
ver228
  • 109
  • 2
  • What do I use for `Ibig` and `Ismall`? I tried `Ismall = Image.open("cat1.PNG")` and `Ibig = Image.open("cat2.PNG")` but this gave me an unorderable types error. – whatwhatwhat Dec 25 '16 at 02:26
  • Please note that the end goal is not to simply align the 2 images. I want to know what lines need to be added to the 1st image in order to create the 2nd image. – whatwhatwhat Dec 25 '16 at 23:42