Principal component analysis (PCA) compute mean using python - python

I am a beginner to python and I am implementing Principal component analysis (PCA) using python, but I am having a problem computing the mean.
Here is my code:
import Image
import os
from PIL import Image
from numpy import *
import numpy as np
#import images
dirname = "C:\\Users\\Karim\\Downloads\\att_faces\\New folder"
X = [np.asarray(Image.open(os.path.join(dirname, fn))) for fn in os.listdir(dirname)]
#get number of images and dimentions
path, dirs, files = os.walk(dirname).next()
num_images = len(files)
image_file = "C:\\Users\\Karim\\Downloads\\att_faces\\New folder\\2.pgm"
img = Image.open(image_file)
width, height = img.size
print width
print height
print num_images
M = (X-mean(X.T,axis=1)).T # subtract the mean (along columns)
I get the error:
AttributeError: 'list' object has no attribute 'T'

The problem is X.T in your last line because X is a python list, not a numpy.ndarray. It isn't clear what you're trying to do here but if you wanted to combine all the image arrays into a single numpy array, you could convert X = np.array(X) before the last line.
Also, unless you specifically want to roll your own PCA implementation, you can do this much more easily with numpy by using np.cov (for covariance calculation) and np.linalg.eig (to compute the eigenvalues and eigenvectors of the covariance matrix).

images -= np.mean(images, axis=0)

Related

Undo np.fft.fft2 to get the original image

I've just started to learn about images frecuency domain.
I have this function:
def fourier_transform(img):
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
magnitude_spectrum = 20*np.log(np.abs(fshift))
return magnitude_spectrum
And I want to implement this function:
def inverse_fourier_transform(magnitude_spectrum):
return img
But I don't know how.
My idea is to use magnitude_spectrum to get the original img.
How can I do it?
You are loosing phases here: np.abs(fshift).
np.abs takes only real part of your data. You could separate the amplitudes and phases by:
abs = fshift.real
ph = fshift.imag
In theory, you could work on abs and join them later together with phases and reverse FFT by np.fft.ifft2.
EDIT:
You could try this approach:
import numpy as np
import matplotlib.pyplot as plt
# single chanel image
img = np.random.random((100, 100))
img = plt.imread(r'path/to/color/img.jpg')[:,:,0]
# should be only width and height
print(img.shape)
# do the 2D fourier transform
fft_img = np.fft.fft2(img)
# shift FFT to the center
fft_img_shift = np.fft.fftshift(fft_img)
# extract real and phases
real = fft_img_shift.real
phases = fft_img_shift.imag
# modify real part, put your modification here
real_mod = real/3
# create an empty complex array with the shape of the input image
fft_img_shift_mod = np.empty(real.shape, dtype=complex)
# insert real and phases to the new file
fft_img_shift_mod.real = real_mod
fft_img_shift_mod.imag = phases
# reverse shift
fft_img_mod = np.fft.ifftshift(fft_img_shift_mod)
# reverse the 2D fourier transform
img_mod = np.fft.ifft2(fft_img_mod)
# using np.abs gives the scalar value of the complex number
# with img_mod.real gives only real part. Not sure which is proper
img_mod = np.abs(img_mod)
# show differences
plt.subplot(121)
plt.imshow(img, cmap='gray')
plt.subplot(122)
plt.imshow(img_mod, cmap='gray')
plt.show()
You cannot recover the exact original image without the phase information, so you cannot only use the magnitude of the fft2.
To use the fft2 to recover the image, you just need to call numpy.fft.ifft2. See the code below:
import numpy as np
from numpy.fft import fft2, ifft2, fftshift, ifftshift
#do the 2D fourier transform
fft_img = fftshift(fft2(img))
# reverse the 2D fourier transform
freq_filt_img = ifft2(ifftshift(fft_img))
freq_filt_img = np.abs(freq_filt_img)
freq_filt_img = freq_filt_img.astype(np.uint8)
Note that calling fftshift and ifftshift is not necessary if you just want to recover the original image directly, but I added them in case there is some plotting to be done in the middle or some other operation that requires the centering of the zero frequency.
The result of calling numpy.abs() or freq_filt_img.real (assuming positive values for each pixel) to recover the image should be the same because the imaginary part of the ifft2 should be really small. Of course, the complexity of numpy.abs() is O(n) while freq_filt_img.real is O(1)

Why does scipy.signal.correlate2d fail to work in this example?

I am trying to cross-correlate two images, and thus locate the template image on the first image, by finding the maximum correlation value.
I drew an image with some random shapes (first image), and cut out one of these shapes (template). Now, when I use scipy's correlate2d, and locate point in the correlation with maximum values, several point appear. From my knowledge, shouldn't there only be one point where the overlap is at max?
The idea behind this exercise is to take some part of an image, and then correlate that to some previous images from a database. Then I should be able to locate this part on the older images based on the maximum value of correlation.
My code looks something like this:
from matplotlib import pyplot as plt
from PIL import Image
import scipy.signal as sp
img = Image.open('test.png').convert('L')
img = np.asarray(img)
temp = Image.open('test_temp.png').convert('L')
temp = np.asarray(temp)
corr = sp.correlate2d(img, temp, boundary='symm', mode='full')
plt.imshow(corr, cmap='hot')
plt.colorbar()
coordin = np.where(corr == np.max(corr)) #Finds all coordinates where there is a maximum correlation
listOfCoordinates= list(zip(coordin[1], coordin[0]))
for i in range(len(listOfCoordinates)): #Plotting all those coordinates
plt.plot(listOfCoordinates[i][0], listOfCoordinates[i][1],'c*', markersize=5)
This yields the figure:
Cyan stars are points with max correlation value (255).
I expect there to be only one point in "corr" to have the max value of correlation, but several appear. I have tried to use different modes of correlating, but to no avail.
This is the test image I use when correlating.
This is the template, cut from the original image.
Can anyone give some insight to what I might be doing wrong here?
You are probably overflowing the numpy type uint8.
Try using:
img = np.asarray(img,dtype=np.float32)
temp = np.asarray(temp,dtype=np.float32)
Untested.
Applying
img = img - img.mean()
temp = temp - temp.mean()
before computing the 2D cross-correlation corr should give you the expected result.
Cleaning up the code, for a full example:
from imageio import imread
from matplotlib import pyplot as plt
import scipy.signal as sp
import numpy as np
img = imread('https://i.stack.imgur.com/JL2LW.png', pilmode='L')
temp = imread('https://i.stack.imgur.com/UIUzJ.png', pilmode='L')
corr = sp.correlate2d(img - img.mean(),
temp - temp.mean(),
boundary='symm',
mode='full')
# coordinates where there is a maximum correlation
max_coords = np.where(corr == np.max(corr))
plt.plot(max_coords[1], max_coords[0],'c*', markersize=5)
plt.imshow(corr, cmap='hot')

Median Filter with Python and OpenCV

I try make python program for do median filter. I got this article http://www.programming-techniques.com/2013/02/median-filter-using-c-and-opencv-image.html , so I try to translate that code to python code.
this the code in python
from cv2 import * #Import functions from OpenCV
import cv2
if __name__ == '__main__':
source = cv2.imread("Medianfilterp.png", CV_LOAD_IMAGE_GRAYSCALE)
final = source[:]
for y in range(len(source)):
for x in range(y):
final[y,x]=source[y,x]
members=[source[0,0]]*9
for y in range(1,len(source)-1):
for x in range(1,y-1):
members[0] = source[y-1,x-1]
members[1] = source[y,x-1]
members[2] = source[y+1,x-1]
members[3] = source[y-1,x]
members[4] = source[y,x]
members[5] = source[y+1,x]
members[6] = source[y-1,x+1]
members[7] = source[y,x+1]
members[8] = source[y+1,x+1]
members.sort()
final[y,x]=members[4]
cv.NamedWindow('Source_Picture', cv.CV_WINDOW_AUTOSIZE)
cv.NamedWindow('Final_Picture', cv.CV_WINDOW_AUTOSIZE)
cv2.imshow('Source_Picture', source) #Show the image
cv2.imshow('Final_Picture', final) #Show the image
cv2.waitKey()
This is a picture before the median filter:
but I got strange results, the results of the program :
First, I recommend that you not re-invent the wheel. OpenCV already contains a method to perform median filtering:
final = cv2.medianBlur(source, 3)
That said, the problem with your implementation lies in your iteration bounds. Your y range is correct. However, for x in range(1,y-1): only iterates up to the current y value, and not the entire x range of the image. This explains why the filter is only applied to a triangular region in the lower-left of the image. You can use the shape field of the image (which is really just a numpy array) to get the image dimensions, which can then be iterated over:
for y in range(1,source.shape[0]-1):
for x in range(1,source.shape[1]-1):
This will apply the filter to the entire image:

class PCA matplotlib for face recognition

I am trying to make face recognition by Principal Component Analysis (PCA) using python. I am using class pca found in matplotlib. Here is it's documentation:
class matplotlib.mlab.PCA(a)
compute the SVD of a and store data for PCA. Use project to project the data onto a reduced set of dimensions
Inputs:
a: a numobservations x numdims array
Attrs:
a a centered unit sigma version of input a
numrows, numcols: the dimensions of a
mu : a numdims array of means of a
sigma : a numdims array of atandard deviation of a
fracs : the proportion of variance of each of the principal components
Wt : the weight vector for projecting a numdims point or array into PCA space
Y : a projected into PCA space
The factor loadings are in the Wt factor, ie the factor loadings for the 1st principal component are given by Wt[0]
And here is my code:
import os
from PIL import Image
import numpy as np
import glob
import numpy.linalg as linalg
from matplotlib.mlab import PCA
#Step 1: put database images into a 2D array
filenames = glob.glob('C:\\Users\\Karim\\Downloads\\att_faces\\New folder/*.pgm')
filenames.sort()
img = [Image.open(fn).convert('L').resize((90, 90)) for fn in filenames]
images = np.asarray([np.array(im).flatten() for im in img])
#Step 2: database PCA
results = PCA(images.T)
w = results.Wt
#Step 3: input image
input_image = Image.open('C:\\Users\\Karim\\Downloads\\att_faces\\1.pgm').convert('L')
input_image = np.asarray(input_image)
#Step 4: input image PCA
results_in = PCA(input_image)
w_in = results_in.Wt
#Step 5: Euclidean distance
d = np.sqrt(np.sum(np.asarray(w - w_in)**2, axis=1))
But I am getting an error:
Traceback (most recent call last):
File "C:/Users/Karim/Desktop/Bachelor 2/New folder/matplotlib_pca.py", line 32, in <module>
d = np.sqrt(np.sum(np.asarray(w - w_in)**2, axis=1))
ValueError: operands could not be broadcast together with shapes (30,30) (92,92)
Can anyone help me to correct the error?
Is that the correct way for face recognition?
The error is telling you that the two arrays (w and w_in) are not the same size and numpy can not figure out how to broadcast the values to take the difference.
I am not familiar with this function, but I would guess that the source of the issue is your input images are different sizes.

Numpy manipulating array of True values dependent on x/y index

So I have an array (it's large - 2048x2048), and I would like to do some element wise operations dependent on where they are. I'm very confused how to do this (I was told not to use for loops, and when I tried that my IDE froze and it was going really slow).
Onto the question:
h = aperatureimage
h[:,:] = 0
indices = np.where(aperatureimage>1)
for True in h:
h[index] = np.exp(1j*k*z)*np.exp(1j*k*(x**2+y**2)/(2*z))/(1j*wave*z)
So I have an index, which is (I'm assuming here) essentially a 'cropped' version of my larger aperatureimage array. *Note: Aperature image is a grayscale image converted to an array, it has a shape or text on it, and I would like to find all the 'white' regions of the aperature and perform my operation.
How can I access the individual x/y values of index which will allow me to perform my exponential operation? When I try index[:,None], leads to the program spitting out 'ValueError: broadcast dimensions too large'. I also get array is not broadcastable to correct shape. Any help would be appreciated!
One more clarification: x and y are the only values I would like to change (essentially the points in my array where there is white, z, k, and whatever else are defined previously).
EDIT:
I'm not sure the code I posted above is correct, it returns two empty arrays. When I do this though
index = (aperatureimage==1)
print len(index)
Actually, nothing I've done so far works correctly. I have a 2048x2048 image with a 128x128 white square in the middle of it. I would like to convert this image to an array, look through all the values and determine the index values (x,y) where the array is not black (I only have white/black, bilevel image didn't work for me). I would then like to take all the values (x,y) where the array is not 0, and multiply them by the h[index] value listed above.
I can post more information if necessary. If you can't tell, I'm stuck.
EDIT2: Here's some code that might help - I think I have the problem above solved (I can now access members of the array and perform operations on them). But - for some reason the Fx values in my for loop never increase, it loops Fy forever....
import sys, os
from scipy.signal import *
import numpy as np
import Image, ImageDraw, ImageFont, ImageOps, ImageEnhance, ImageColor
def createImage(aperature, type):
imsize = aperature*8
middle = imsize/2
im = Image.new("L", (imsize,imsize))
draw = ImageDraw.Draw(im)
box = ((middle-aperature/2, middle-aperature/2), (middle+aperature/2, middle+aperature/2))
import sys, os
from scipy.signal import *
import numpy as np
import Image, ImageDraw, ImageFont, ImageOps, ImageEnhance, ImageColor
def createImage(aperature, type):
imsize = aperature*8 #Add 0 padding to make it nice
middle = imsize/2 # The middle (physical 0) of our image will be the imagesize/2
im = Image.new("L", (imsize,imsize)) #Make a grayscale image with imsize*imsize pixels
draw = ImageDraw.Draw(im) #Create a new draw method
box = ((middle-aperature/2, middle-aperature/2), (middle+aperature/2, middle+aperature/2)) #Bounding box for aperature
if type == 'Rectangle':
draw.rectangle(box, fill = 'white') #Draw rectangle in the box and color it white
del draw
return im, middle
def Diffraction(aperaturediameter = 1, type = 'Rectangle', z = 2000000, wave = .001):
# Constants
deltaF = 1/8 # Image will be 8mm wide
z = 1/3.
wave = 0.001
k = 2*pi/wave
# Now let's get to work
aperature = aperaturediameter * 128 # Aperaturediameter (in mm) to some pixels
im, middle = createImage(aperature, type) #Create an image depending on type of aperature
aperaturearray = np.array(im) # Turn image into numpy array
# Fourier Transform of Aperature
Ta = np.fft.fftshift(np.fft.fft2(aperaturearray))/(len(aperaturearray))
# Transforming and calculating of Transfer Function Method
H = aperaturearray.copy() # Copy image so H (transfer function) has the same dimensions as aperaturearray
H[:,:] = 0 # Set H to 0
U = aperaturearray.copy()
U[:,:] = 0
index = np.nonzero(aperaturearray) # Find nonzero elements of aperaturearray
H[index[0],index[1]] = np.exp(1j*k*z)*np.exp(-1j*k*wave*z*((index[0]-middle)**2+(index[1]-middle)**2)) # Free space transfer for ap array
Utfm = abs(np.fft.fftshift(np.fft.ifft2(Ta*H))) # Compute intensity at distance z
# Fourier Integral Method
apindex = np.nonzero(aperaturearray)
U[index[0],index[1]] = aperaturearray[index[0],index[1]] * np.exp(1j*k*((index[0]-middle)**2+(index[1]-middle)**2)/(2*z))
Ufim = abs(np.fft.fftshift(np.fft.fft2(U))/len(U))
# Save image
fim = Image.fromarray(np.uint8(Ufim))
fim.save("PATH\Fim.jpg")
ftfm = Image.fromarray(np.uint8(Utfm))
ftfm.save("PATH\FTFM.jpg")
print "that may have worked..."
return
if __name__ == '__main__':
Diffraction()
You'll need numpy, scipy, and PIL to work with this code.
When I run this, it goes through the code, but there is no data in them (everything is black). Now I have a real problem here as I don't entirely understand the math I'm doing (this is for HW), and I don't have a firm grasp on Python.
U[index[0],index[1]] = aperaturearray[index[0],index[1]] * np.exp(1j*k*((index[0]-middle)**2+(index[1]-middle)**2)/(2*z))
Should that line work for performing elementwise calculations on my array?
Could you perhaps post a minimal, yet complete, example? One that we can copy/paste and run ourselves?
In the meantime, in the first two lines of your current example:
h = aperatureimage
h[:,:] = 0
you set both 'aperatureimage' and 'h' to 0. That's probably not what you intended. You might want to consider:
h = aperatureimage.copy()
This generates a copy of aperatureimage while your code simply points h to the same array as aperatureimage. So changing one changes the other.
Be aware, copying very large arrays might cost you more memory then you would prefer.
What I think you are trying to do is this:
import numpy as np
N = 2048
M = 64
a = np.zeros((N, N))
a[N/2-M:N/2+M,N/2-M:N/2+M]=1
x,y = np.meshgrid(np.linspace(0, 1, N), np.linspace(0, 1, N))
b = a.copy()
indices = np.where(a>0)
b[indices] = np.exp(x[indices]**2+y[indices]**2)
Or something similar. This, in any case, sets some values in 'b' based on the x/y coordinates where 'a' is bigger than 0. Try visualizing it with imshow. Good luck!
Concerning the edit
You should normalize your output so it fits in the 8 bit integer. Currently, one of your arrays has a maximum value much larger than 255 and one has a maximum much smaller. Try this instead:
fim = Image.fromarray(np.uint8(255*Ufim/np.amax(Ufim)))
fim.save("PATH\Fim.jpg")
ftfm = Image.fromarray(np.uint8(255*Utfm/np.amax(Utfm)))
ftfm.save("PATH\FTFM.jpg")
Also consider np.zeros_like() instead of copying and clearing H and U.
Finally, I personally very much like working with ipython when developing something like this. If you put the code in your Diffraction function in the top level of your script (in place of 'if __ name __ &c.'), then you can access the variables directly from ipython. A quick command like np.amax(Utfm) would show you that there are indeed values!=0. imshow() is always nice to look at matrices.

Categories