How to reduce the time consumed by the for loop? - matlab
I am trying to implement a simple pixel level center-surround image enhancement. Center-surround technique makes use of statistics between the center pixel of the window and the surrounding neighborhood as a means to decide what enhancement needs to be done. In the code given below I have compared the center pixel with average of the surrounding information and based on that I switch between two cases to enhance the contrast. The code that I have written is as follows:
im = normalize8(im,1); %to set the range of pixel from 0-255
s1 = floor(K1/2); %K1 is the size of the window for surround
M = 1000; %is a constant value
out1 = padarray(im,[s1,s1],'symmetric');
out1 = CE(out1,s1,M);
out = (out1(s1+1:end-s1,s1+1:end-s1));
out = normalize8(out,0); %to set the range of pixel from 0-1
function [out] = CE(out,s,M)
B = 255;
out1 = out;
for i = s+1 : size(out,1) - s
for j = s+1 : size(out,2) - s
temp = out(i-s:i+s,j-s:j+s);
Yij = out1(i,j);
Sij = (1/(2*s+1)^2)*sum(sum(temp));
if (Yij>=Sij)
Aij = A(Yij-Sij,M);
out1(i,j) = ((B + Aij)*Yij)/(Aij+Yij);
else
Aij = A(Sij-Yij,M);
out1(i,j) = (Aij*Yij)/(Aij+B-Yij);
end
end
end
out = out1;
function [Ax] = A(x,M)
if x == 0
Ax = M;
else
Ax = M/x;
end
The code does the following things:
1) Normalize the image to 0-255 range and pad it with additional elements to perform windowing operation.
2) Calls the function CE.
3) In the function CE obtain the windowed image(temp).
4) Find the average of the window (Sij).
5) Compare the center of the window (Yij) with the average value (Sij).
6) Based on the result of comparison perform one of the two enhancement operation.
7) Finally set the range back to 0-1.
I have to run this for multiple window size (K1,K2,K3, etc.) and the images are of size 1728*2034. When the window size is selected as 100, the time consumed is very high.
Can I use vectorization at some stage to reduce the time for loops?
The profiler result (for window size 21) is as follows:
The profiler result (for window size 100) is as follows:
I have changed the code of my function and have written it without the sub-function. The code is as follows:
function [out] = CE(out,s,M)
B = 255;
Aij = zeros(1,2);
out1 = out;
n_factor = (1/(2*s+1)^2);
for i = s+1 : size(out,1) - s
for j = s+1 : size(out,2) - s
temp = out(i-s:i+s,j-s:j+s);
Yij = out1(i,j);
Sij = n_factor*sum(sum(temp));
if Yij-Sij == 0
Aij(1) = M;
Aij(2) = M;
else
Aij(1) = M/(Yij-Sij);
Aij(2) = M/(Sij-Yij);
end
if (Yij>=Sij)
out1(i,j) = ((B + Aij(1))*Yij)/(Aij(1)+Yij);
else
out1(i,j) = (Aij(2)*Yij)/(Aij(2)+B-Yij);
end
end
end
out = out1;
There is a slight improvement in the speed from 93 sec to 88 sec. Suggestions for any other improvements to my code are welcomed.
I have tried to incorporate the suggestions given to replace sliding window with convolution and then vectorize the rest of it. The code below is my implementation and I'm not getting the result expected.
function [out_im] = CE_conv(im,s,M)
B = 255;
temp = ones(2*s,2*s);
temp = temp ./ numel(temp);
out1 = conv2(im,temp,'same');
out_im = im;
Aij = im-out1; %same as Yij-Sij
Aij1 = out1-im; %same as Sij-Yij
Mij = Aij;
Mij(Aij>0) = M./Aij(Aij>0); % if Yij>Sij Mij = M/Yij-Sij;
Mij(Aij<0) = M./Aij1(Aij<0); % if Yij<Sij Mij = M/Sij-Yij;
Mij(Aij==0) = M; % if Yij-Sij == 0 Mij = M;
out_im(Aij>=0) = ((B + Mij(Aij>=0)).*im(Aij>=0))./(Mij(Aij>=0)+im(Aij>=0));
out_im(Aij<0) = (Mij(Aij<0).*im(Aij<0))./ (Mij(Aij<0)+B-im(Aij<0));
I am not able to figure out where I'm going wrong.
A detailed explanation of what I'm trying to implement is given in the following paper:
Vonikakis, Vassilios, and Ioannis Andreadis. "Multi-scale image contrast enhancement." In Control, Automation, Robotics and Vision, 2008. ICARCV 2008. 10th International Conference on, pp. 856-861. IEEE, 2008.
I've tried to see if I could get those times down by processing with colfiltand nlfilter, since both are usually much faster than for-loops for sliding window image processing.
Both worked fine for relatively small windows. For an image of 2048x2048 pixels and a window of 10x10, the solution with colfilt takes about 5 seconds (on my personal computer). With a window of 21x21 the time jumped to 27 seconds, but that is still a relative improvement on the times displayed on the question. Unfortunately I don't have enough memory to colfilt using windows of 100x100, but the solution with nlfilter works, though taking about 120 seconds.
Here the code
Solution with colfilt:
function outval = enhancematrix(inputmatrix,M,B)
%Inputmatrix is a 2D matrix or column vector, outval is a 1D row vector.
% If inputmatrix is made of integers...
inputmatrix = double(inputmatrix);
%1. Compute S and Y
normFactor = 1 / (size(inputmatrix,1) + 1).^2; %Size of column.
S = normFactor*sum(inputmatrix,1); % Sum over the columns.
Y = inputmatrix(ceil(size(inputmatrix,1)/2),:); % Center row.
% So far we have all S and Y, one value per column.
%2. Compute A(abs(Y-S))
A = Afunc(abs(S-Y),M);
% And all A: one value per column.
%3. The tricky part. If Y(i)-S(i) > 0 do something.
doPositive = (Y > S);
doNegative = ~doPositive;
outval = zeros(1,size(inputmatrix,2));
outval(doPositive) = (B + A(doPositive) .* Y(doPositive)) ./ (A(doPositive) + Y(doPositive));
outval(doNegative) = (A(doNegative) .* Y(doNegative)) ./ (A(doNegative) + B - Y(doNegative));
end
function out = Afunc(x,M)
% Input x is a row vector. Output is another row vector.
out = x;
out(x == 0) = M;
out(x ~= 0) = M./x(x ~= 0);
end
And to call it, simply do:
M = 1000; B = 255; enhancenow = #(x) enhancematrix(x,M,B);
w = 21 % windowsize
result = colfilt(inputImage,[w w],'sliding',enhancenow);
Solution with nlfilter:
function outval = enhanceimagecontrast(neighbourhood,M,B)
%1. Compute S and Y
normFactor = 1 / (length(neighbourhood) + 1).^2;
S = normFactor*sum(neighbourhood(:));
Y = neighbourhood(ceil(size(neighbourhood,1)/2),ceil(size(neighbourhood,2)/2));
%2. Compute A(abs(Y-S))
test = (Y>=S);
A = Afunc(abs(Y-S),M);
%3. Return outval
if test
outval = ((B + A) * Y) / (A + Y);
else
outval = (A * Y) / (A + B - Y);
end
function aval = Afunc(x,M)
if (x == 0)
aval = M;
else
aval = M/x;
end
And to call it, simply do:
M = 1000; B = 255; enhancenow = #(x) enhanceimagecontrast(x,M,B);
w = 21 % windowsize
result = nlfilter(inputImage,[w w], enhancenow);
I didn't spend much time checking that everything is 100% correct, but I did see some nice contrast enhancement (hair looks particularly nice).
This answer is the implementation that was suggested by Peter. I debugged the implementation and presenting the final working version of the fast implementation.
function [out_im] = CE_conv(im,s,M)
B = 255;
im = ( im - min(im(:)) ) ./ ( max(im(:)) - min(im(:)) )*255;
h = ones(s,s)./(s*s);
out1 = imfilter(im,h,'conv');
out_im = im;
Aij = im-out1; %same as Yij-Sij
Aij1 = out1-im; %same as Sij-Yij
Mij = Aij;
Mij(Aij>0) = M./Aij(Aij>0); % if Yij>Sij Mij = M/(Yij-Sij);
Mij(Aij<0) = M./Aij1(Aij<0); % if Yij<Sij Mij = M/(Sij-Yij);
Mij(Aij==0) = M; % if Yij-Sij == 0 Mij = M;
out_im(Aij>=0) = ((B + Mij(Aij>=0)).*im(Aij>=0))./(Mij(Aij>=0)+im(Aij>=0));
out_im(Aij<0) = (Mij(Aij<0).*im(Aij<0))./ (Mij(Aij<0)+B-im(Aij<0));
out_im = ( out_im - min(out_im(:)) ) ./ ( max(out_im(:)) - min(out_im(:)) );
To call this use the following code
I = imread('pout.tif');
w_size = 51;
M = 4000;
output = CE_conv(I(:,:,1),w_size,M);
The output for the 'pout.tif' image is given below
The execution time for Bigger image and with 100*100 block size is around 5 secs with this implementation.
Related
How can I measure length of signal in simulink?
I have model with "matlab function block" in which I have recursive least square method. Recursive algorithm needs to know length of incoming signal in order to work correctly. But when I use command N=length(y) it returns me length N= 1. But I think it should give me higher length. Simulink model Matlab function block code "rls_iden6" function [P,N] = fcn(u,y) %% N = length(y); sigma=1; C = sigma*eye(2); %p P = ones(2,1); z= [y; u]; lamda=1; for n=1:N sample_out = y(n); C = (C - ( (C*z*z'*C)/( lamda+(z'*C*z) ) ))/lamda; P = P + (C*z* (sample_out - (z'*P))); end My final code should look like it's shown below, because it works in matlab workspace. Simulink should give me 5 parameters instead of just 2. load data_cela.mat u=U; %input y=Y; %output %% input = 3; output = 2; system = input + output; N = length(y); %initial conditions sigma = 1; C = sigma*eye(system); P = ones(system,1); lamda = 1; %forgetting factor for n=3:N for i=1:2 W(i) = y(n-i); %output end for i=1:3 V(i) = u(n-i+1); %input end z = [V';W']; sample_out = y(n); pom(n)= z' * P; error(n) = y(n) - pom(n); C = (C - ( (C*z*z'*C)/( lamda+(z'*C*z) ) ))/lamda; P = P + (C*z* (sample_out - (z'*P) ) ); change(1:system,n) = P; end f_param = [P(1:3);-P(4:5)]; num = [P(1:3,1)]; den = [1;-P(4:5,1)]; num1 = num(3,1); trasferfunction = tf(num1,den',1) Result: 0.002879 ---------------------- z^2 - 1.883 z + 0.8873
You will need to add a buffer before signal to convert the scalar to matrix. Then after the buffer has been added set the buffer size to the amount of data you want, i.e. by setting it to 2 will make 2 rows and 1 column. This will help you to get the data however, for setting delay properly you will require to set buffer overlap to 1. Hope this helps.
Speed up calculation of maximum of normxcorr2
I need to calculate the maximum of normalized cross correlation of million of particles. The size of the two parameters of normxcorr2 is 56*56. I can't parallelize the calculations. Is there any suggestion to speed up the code especially that I don't need all the results but only the maximum value of each cross correlation (to know the displacement)? Example of the algorithm %The choice of 170 particles is because in each time %the code detects 170 particles, so over 10000 images it's 1 700 000 particles particle_1=rand(54,54,170); particle_2=rand(56,56,170); for i=1:170 C=normxcorr2(particle_1(:,:,i),particle_2(:,:,i)); L(i)=max(C(:)); end
I don't have MATLAB so I ran the following code on this site: https://www.tutorialspoint.com/execute_matlab_online.php which is actually octave. So I implemented "naive" normalized cross correlation and indeed for these small images sizes the naive performs better: Elapsed time is 2.62645 seconds - for normxcorr2 Elapsed time is 0.199034 seconds - for my naive_normxcorr2 The code is based on the article http://scribblethink.org/Work/nvisionInterface/nip.pdf which describes how to calculate the standard deviation needed for the normalization in an efficient way using integral image, this is the box_corr function. Also, MATLAB's normxcorr2 returns a padded image so I took the max on the unpadded part. pkg load image function [N] = naive_corr(pat,img) [n,m] = size(img); [np,mp] = size(pat); N = zeros(n-np+1,m-mp+1); for i = 1:n-np+1 for j = 1:m-mp+1 N(i,j) = sum(dot(pat,img(i:i+np-1,j:j+mp-1))); end end end %w_arr the array of coefficients for the boxes %box_arr of size [k,4] where k is the number boxes, each box represented by %4 something ... function [C] = box_corr2(img,box_arr,w_arr,n_p,m_p) % construct integral image + zeros pad (for boundary problems) I = cumsum(cumsum(img,2),1); I = [zeros(1,size(I,2)+2); [zeros(size(I,1),1) I zeros(size(I,1),1)]; zeros(1,size(I,2)+2)]; % initialize result matrix [n,m] = size(img); C = zeros(n-n_p+1,m-m_p+1); %C = zeros(n,m); jump_x = 1; jump_y = 1; x_start = ceil(n_p/2); x_end = n-x_start+mod(n_p,2); x_span = x_start:jump_x:x_end; y_start = ceil(m_p/2); y_end = m-y_start+mod(m_p,2); y_span = y_start:jump_y:y_end; arr_a = box_arr(:,1) - x_start; arr_b = box_arr(:,2) - x_start+1; arr_c = box_arr(:,3) - y_start; arr_d = box_arr(:,4) - y_start+1; % cumulate box responses k = size(box_arr,1); % == numel(w_arr) for i = 1:k a = arr_a(i); b = arr_b(i); c = arr_c(i); d = arr_d(i); C = C ... + w_arr(i) * ( I(x_span+b,y_span+d) ... - I(x_span+b,y_span+c) ... - I(x_span+a,y_span+d) ... + I(x_span+a,y_span+c) ); end end function [NCC] = naive_normxcorr2(temp,img) [n_p,m_p]=size(temp); M = n_p*m_p; % compute template mean & std temp_mean = mean(temp(:)); temp = temp - temp_mean; temp_std = sqrt(sum(temp(:).^2)/M); % compute windows' mean & std wins_mean = box_corr2(img,[1,n_p,1,m_p],1/M, n_p,m_p); wins_mean2 = box_corr2(img.^2,[1,n_p,1,m_p],1/M,n_p,m_p); wins_std = real(sqrt(wins_mean2 - wins_mean.^2)); NCC_naive = naive_corr(temp,img); NCC = NCC_naive ./ (M .* temp_std .* wins_std); end n = 170; particle_1=rand(54,54,n); particle_2=rand(56,56,n); [n_p1,m_p1,c_p1]=size(particle_1); [n_p2,m_p2,c_p2]=size(particle_2); L1 = zeros(n,1); L2 = zeros (n,1); tic for i=1:n C1=normxcorr2(particle_1(:,:,i),particle_2(:,:,i)); C1_unpadded = C1(n_p1:n_p2 , m_p1:m_p2); L1(i)=max(C1_unpadded(:)); end toc tic for i=1:n C2=naive_normxcorr2(particle_1(:,:,i),particle_2(:,:,i)); L2(i)=max(C2(:)); end toc
Index exceeds matrix dimensions error in Runge-Kutta method: Matlab
I'm trying to make a time stepping code using the 4th order Runge-Kutta method but am running into issues indexing one of my values properly. My code is: clc; clear all; L = 32; M = 32; N = 32; % No. of elements Lx = 2; Ly = 2; Lz = 2; % Size of each element dx = Lx/L; dy = Ly/M; dz = Lz/N; % Step size Tt = 1; t0 = 0; % Initial condition T = 50; % Final time dt = (Tt-t0)/T; % Determining time step interval % Wave characteristics H = 2; % Wave height a = H/2; % Amplitude Te = 6; % Period omega = 2*pi/Te; % Wave rotational frequency d = 25; % Water depth x = 0; % Location of cylinder axis u0(1:L,1:M,1:N,1) = 0; % Setting up solution space matrix (u values) v0(1:L,1:M,1:N,1) = 0; % Setting up solution space matrix (v values) w0(1:L,1:M,1:N,1) = 0; % Setting up solution space matrix (w values) [k,L] = disp(d,omega); % Solving for k and wavelength using Newton-Raphson function %u = zeros(1,50); %v = zeros(1,50); %w = zeros(1,50); time = 1:1:50; for t = 1:T for i = 1:L for j = 1:M for k = 1:N eta(i,j,k,t) = a*cos(omega*time(1,t); u(i,j,k,1) = u0(i,j,k,1); v(i,j,k,1) = v0(i,j,k,1); w(i,j,k,1) = w0(i,j,k,1); umag(i,j,k,t) = a*omega*(cosh(k*(d+eta(i,j,k,t))))/sinh(k*d); vmag(i,j,k,t) = 0; wmag(i,j,k,t) = -a*omega*(sinh(k*(d+eta(i,j,k,t))))/sinh(k*d); uRHS(i,j,k,t) = umag(i,j,k,t)*cos(k*x-omega*t); vRHS(i,j,k,t) = vmag(i,j,k,t)*sin(k*x-omega*t); wRHS(i,j,k,t) = wmag(i,j,k,t)*sin(k*x-omega*t); k1x(i,j,k,t) = dt*uRHS(i,j,k,t); k2x(i,j,k,t) = dt*(0.5*k1x(i,j,k,t) + dt*uRHS(i,j,k,t)); k3x(i,j,k,t) = dt*(0.5*k2x(i,j,k,t) + dt*uRHS(i,j,k,t)); k4x(i,j,k,t) = dt*(k3x(i,j,k,t) + dt*uRHS(i,j,k,t)); u(i,j,k,t+1) = u(i,j,k,t) + (1/6)*(k1x(i,j,k,t) + 2*k2x(i,j,k,t) + 2*k3x(i,j,k,t) + k4x(i,j,k,t)); k1y(i,j,k,t) = dt*vRHS(i,j,k,t); k2y(i,j,k,t) = dt*(0.5*k1y(i,j,k,t) + dt*vRHS(i,j,k,t)); k3y(i,j,k,t) = dt*(0.5*k2y(i,j,k,t) + dt*vRHS(i,j,k,t)); k4y(i,j,k,t) = dt*(k3y(i,j,k,t) + dt*vRHS(i,j,k,t)); v(i,j,k,t+1) = v(i,j,k,t) + (1/6)*(k1y(i,j,k,t) + 2*k2y(i,j,k,t) + 2*k3y(i,j,k,t) + k4y(i,j,k,t)); k1z(i,j,k,t) = dt*wRHS(i,j,k,t); k2z(i,j,k,t) = dt*(0.5*k1z(i,j,k,t) + dt*wRHS(i,j,k,t)); k3z(i,j,k,t) = dt*(0.5*k2z(i,j,k,t) + dt*wRHS(i,j,k,t)); k4z(i,j,k,t) = dt*(k3z(i,j,k,t) + dt*wRHS(i,j,k,t)); w(i,j,k,t+1) = w(i,j,k,t) + (1/6)*(k1z(i,j,k,t) + 2*k2z(i,j,k,t) + 2*k3z(i,j,k,t) + k4z(i,j,k,t)); a(i,j,k,t+1) = ((u(i,j,k,t+1))^2 + (v(i,j,k,t+1))^2 + (w(i,j,k,t+1))^2)^0.5; end end end end At the moment, the values seem to be fine for the first iteration but then I have the error Index exceeds matrix dimension in the line calculating eta. I understand that I am not correctly indexing the eta value but am not sure how to correct this. My goal is to update the value of eta for each loop of t and then use that new eta value for the rest of the calculations. I'm still quite new to programming and am trying to understand indexing, especially in 3 or 4 dimensional matrices and would really appreciate any advice in correctly calculating this value. Thanks in advance for any advice!
You declare time = 1:1:50; which is just a row vector but access it here eta(i,j,k,t) = a*cos(omega*time(i,j,k,t)); as if it were an array with 4 dimensions. To correctly access element x of time you need to use syntax time(1,x); (as it is a 1 x 50 array)
How to stop MATLAB from rounding extremely small values to 0?
I have a code in MATLAB which works with very small numbers, for example, I have values that are on the order of 10^{-25}, however when MATLAB does the calculations, the values themselves are rounded to 0. Note, I am not referring to format to display these extra decimals, but rather the number itself is changed to 0. I think the reason is because MATLAB, by default, uses up to 15 digits after the decimal point for its calculations. How can I change this so that numbers that are very very small are retained as they are in the calculations? EDIT: My code is the following: clc; clear; format long; % Import data P = xlsread('Data.xlsx', 'P'); d = xlsread('Data.xlsx', 'd'); CM = xlsread('Data.xlsx', 'Cov'); Original_PD = P; %Store original PD LM_rows = size(P,1)+1; %Expected LM rows LM_columns = size(P,2); %Expected LM columns LM_FINAL = zeros(LM_rows,LM_columns); %Dimensions of LM_FINAL for ii = 1:size(P,2) P = Original_PD(:,ii); % c1, c2, ..., cn, c0, f interval = cell(size(P,1)+2,1); for i = 1:size(P,1) interval{i,1} = NaN(size(P,1),2); interval{i,1}(:,1) = -Inf; interval{i,1}(:,2) = d; interval{i,1}(i,1) = d(i,1); interval{i,1}(i,2) = Inf; end interval{i+1,1} = [-Inf*ones(size(P,1),1) d]; interval{i+2,1} = [d Inf*ones(size(P,1),1)]; c = NaN(size(interval,1),1); for i = 1:size(c,1) c(i,1) = mvncdf(interval{i,1}(:,1),interval{i,1}(:,2),0,CM); end c0 = c(size(P,1)+1,1); f = c(size(P,1)+2,1); c = c(1:size(P,1),:); b0 = exp(1); b = exp(1)*P; syms x; eqn = f*x; for i = 1:size(P,1) eqn = eqn*(c0/c(i,1)*x + (b(i,1)-b0)/c(i,1)); end eqn = c0*x^(size(P,1)+1) + eqn - b0*x^size(P,1); x0 = solve(eqn); x0 = double(x0); for i = 1:size(x0) id(i,1) = isreal(x0(i,1)); end x0 = x0(id,:); x0 = x0(x0 > 0,:); clear x; for i = 1:size(P,1) x(i,:) = (b(i,1) - b0)./(c(i,1)*x0) + c0/c(i,1); end % x = [x0 x1 ... xn] x = [x0'; x]; x = x(:,sum(x <= 0,1) == 0); % lamda lamda = -log(x); LM_FINAL(:,ii) = lamda; end The problem is in this step: for i = 1:size(P,1) x(i,:) = (b(i,1) - b0)./(c(i,1)*x0) + c0/c(i,1); end where the "difference" gets very close to 0. How can I stop this rounding from occurring at this step? For example, when i = 10, I have the following values: b_10 = 0.006639735483297 b_0 = 2.71828182845904 c_10 = 0.000190641848119641 c_0 = 0.356210110252579 x_0 = 7.61247930625269 After doing the calculations we get: -1868.47805854794 + 1868.47805854794 which yields a difference of -2.27373675443232E-12, that gets rounded to 0 by MATLAB. EDIT 2: Here is my data file which is used for the code. After you run the code (should take about a minute and half to finish running), row 11 in the variable x shows 0 (even after double clicking to check it's real value), when it shouldn't.
The problem you're having is because the IEEE standard for floating points can't distinguish your numbers from zero because they don't utilize sufficient bits. Have a look at John D'Errico's Big Decimal Class and Variable Precision Integer Arithmetic. Another option would be to use the Big Integer Class from Java but that might be more challenging if you are unfamiliar with using Java and othe rexternal libraries in MATLAB. Can you give an example of the calculations in which you are using 1e-25 and getting zero? Here's what I get for a floating point called small_num and one of John's high-precision-floats called small_hpf when assigning them and multiplying by pi. >> small_num = 1e-25 small_num = 1.0000e-25 >> small_hpf = hpf(1e-25) small_hpf = 1.000000000000000038494869749191839081371989361591338301396127644e-25 >> small_num * pi ans = 3.1416e-25 >> small_hpf * pi ans = 3.141592653589793236933163473501228686498684350685747717239459106e-25
Why do I get so many eigenvalues of zero in my Matlab eigenfaces implementation?
I'm trying to implement a very basic eigenface calculation in Matlab. It kind of works but I get only two meaningful eigenvalues - the rest are zero. The corresponding eigenvectors seem to be right since most of them will show an eigenface when converting to an image. So why are most of my eigenvalues zero? I need them to be different from zero in order to sort the eigenfaces by their significance (greatest magnitude eigenvalues). I am reading 400 images, each size h/w = 112/92 px They can be found here: http://www.cl.cam.ac.uk/Research/DTG/attarchive/pub/data/att_faces.zip The code: clear all; files = dir('eigenfaces2/training/*.pgm'); [numFaces, discard] = size(files); h = 112; w = 92; s = h * w; %calculate average face avgFace = zeros(s, 1); faces = []; for i=1:numFaces file = strcat('eigenfaces2/training/', files(i).name); im = double(imread(file)); im = reshape(im, s, 1); avgFace = avgFace + im; faces(:,i) = im; end avgFace = avgFace ./ numFaces; A = []; for i=1:numFaces diff = avgFace - faces(i); A(:,i) = diff; end numEigs = 20; L = (A' * A) / numFaces; [tmpEigs, discard] = eigs(L, numEigs); eigenfaces = []; for i=1:numEigs v = tmpEigs(:,i); eigenfaces(:,i) = A * v; end %visualize largest eigenfaces figure; for i=1:numEigs eigface = eigenfaces(:,i); mmax = max(eigface); mmin = min(eigface); eigface = 255 .* (eigface-mmin) ./ (mmax-mmin); eigface = reshape(eigface, h, w); subplot(4,5,i); imshow(uint8(eigface)); end
I've don't have much experience with computer vision/image recognition, but I think you might want diff = avgFace - faces(:,i); in your second for loop. Otherwise it's just subtracting a constant from avgFace each time, and so A (and hence L) only gets a rank of 2.