I need to show 1st 10 eigenfaces using PCA for a image feature vector matrix.
I am using following matlab code to create 1st eigenface but I am getting very dark and not so correct eigenfaces.
eFea is a matrix of 240x4096 where each row represents an image of 64x64
newData = eFea';
data = newData;
[M,N] = size(data);
mn = mean(data,2);
data = double(data) - repmat(mn,1,N);
% construct the matrix Y
Y = data' / sqrt(N-1);
% SVD
[u,S,PC] = svd(Y,0);
imshow(reshape(PC(1,:),64,64))
any hints regarding the error in code will be helpful.
IMSHOW does not automatically scale the image. Thus, if you only have values from, say, 0 to 0.3 in the eigenface, everything will be really dark. Try imshow(reshape(PC(1,:),64,64),[]) instead.
This is a really old topic but I want to answer something anyway.
Honestly, I think the error is somewhere else, although what Jonas said might give good-looking results.
You need to add the mean of the data again in the end. I just had the same problem with the dark principal components, that's why I found this question. But then I realized, that when you do PCA, you substract the mean first. That means that in the end, you need to add it again.
Related
I am currently running improfile on MATLAB with a line going through the center of the picture below:
After doing so, I'm plotting the resultant using the code below:
xi = [1 size(d_Img,2) size(d_Img,2) 1];
yi = [ceil(size(d_Img,1)/2), ceil(size(d_Img,1)/2), ceil(size(d_Img,1)/2 ),ceil(size(d_Img,1)/2)];
c_d = improfile(d_Img,xi,yi);
c_c = improfile(c_Img,xi,yi);
c_d = c_d';
c_c = c_c';
size_c = size(c_d);
n = 1:size_c(2);
plot(n,c_d);
And here is the plot:
Why are the curves mirroring each other? I am asking to gain a better understanding of what exactly improfile seems to be achieving in MATLAB.
improfile computes something like a "path integral", it gives you the image intensity values around a user specified path. For example, if you use:
improfile(img,[1 1],[1 size(img,2)]);
It gives the same as img(:,1). This is because the path you are using in improfile is from (1,1) to (1,size(img,2)) , meaning the first row. However you could definitely add more complicated paths.
In your case you are going trow a path defined by 4 points. The points are, if I substitute your equation by the resultant numbers:
(1,79)->(134,79)->(134,79)->(1,79). Thus, looking at this, it is obvious that your result should be mirrored, because you are integrating over a line the way there, and back!
Sidenote:
you can do plot(c_d); and forget about that n
I am trying to extract veins using thinning algorithm. So far i did this much of code for image enhancement and its pretty much working. But when i computed binary thresholding i am not able to identify the veins from the back ground.Due to a vague output i am not able to do further processing for thinning. Can any one tell me whats wrong in this code? or is it because the threshold has to be done in some other way.
a=imread('vein.jpg');
cform = makecform('srgb2lab');
for ii = 1:3
a(:,:,ii) = medfilt2(a(:,:,ii),[5 5]);
end
lab = applycform(a,cform);
b=lab(:,:,1);
c=im2bw(b,0.2);
neg=1-c;
color=a;
r=color(:,:,1);
r(~c)= 0;
g = color(:,:,2);
g(~c)= 0;
b = color(:,:,3);
b(~c)= 0;
color = cat(3,r,g,b);
gray=rgb2gray(color);
i1=imresize(gray,[256 256],'bilinear');
i2=histeq(i1,256);
e=medfilt2(i2,[5 5]);
figure(1),imshow(e);
f=medfilt2(e,[5 5]);
figure(2),imshow(f);
thresh_level = graythresh(g);
BW = im2bw(g, thresh_level);
figure(10),imshow(BW);
greythresh uses Otsu's method, which is a good general method that works on the distribution of intensities. However it's not ideal for every situation, particularly if you've applied lots of nonlinear processing to the image first (e.g. clipping the channels).
You could try to generate your own threshold - look at the intensity distribution or, since you have them, the distribution in the colour channels and see if there's a plausible place to separate them. You could try to model it as a mixture of Gaussians (2 seems like a good number to start with, look up gmdistribution.fit) or do some other type of clustering. Is there any information in the colour channels that you could use?
If you end up the other way - with veins that are much darker but are continuous - then you could use morphological operators on the binarised image to get it back to the expected range. Perhaps this is what the thinning algorithm does.
I find examples the best way to demonstrate my question. I generate some data, add some random noise, and fit it to get back my chosen "generator" value...
x = linspace(0.01,1,50);
value = 3.82;
y = exp(-value.*x);
y = awgn(y,30);
options = optimset('MaxFunEvals',1000,'MaxIter',1000,'TolFun',1e-10,'Display','off');
model = #(p,x) exp(-p(1).*x);
startingVals = [5];
lb = [1];
ub = [10];
[fittedValue] = lsqcurvefit(model,startingVals,x,y,lb,ub,options)
fittedGraph = exp(-fittedValue.*x);
plot(x,y,'o');
hold on
plot(x,fittedGraph,'r-');
In this new example, I have generated the same data but this time added much more noise to the first 15 points. Because it is random sometimes it works out okay, but after a few runs I get a good example that illustrates my problem. Same code, except for these lines added under value = 3.82
y = exp(-value.*x);
y(1:15) = awgn(y(1:15),5);
y(15:end) = awgn(y(15:end),30);
As you can see, it has clearly not given a good fit to where the data seems reliable, because it is fitting from points 1-50. What I want to do is say, okay MATLAB, I can see we have some noisy data but it seems decent over a range, only fit your exponential from points 15 to the end. I could go back to my code and update it to do this, but I will be batch fitting graphs like this where each one will have different ranges of 'good' data.
So what I am after is a GUI callback mechanisms that allows me to click on two circles from the data and have them change color or something, which indicates the lsqcurvefit will only fit over that range. Internally all it has to change is inside the lsqcurvefit call e.g.
x(16:end),y(16:end)
But the range should update depending on the starting and ending circles I have clicked.
I hope my question is clear. Thanks.
You could use ginput to select the two points for your min and max in the plot.
[x,y]=ginput(2);
%this returns you the x and y coordinates of two points clicked after each other
%the min point is assumed to be clicked first
min=[x(1) y(1)];
max=[x(2) y(2)];
then you could fit your curve with the coordinates for min and max I guess.
You could also switch between a rightclick for the min and a leftclick for the max etc.
Hope this helps you.
I'm attempting to run this simple diffusion case (I understand that it isn't ideal generally), and I'm doing fine with getting the inside of the solid, but need some help with the outer edges.
global M
size=100
M=zeros(size,size);
M(25,25)=50;
for diffusive_steps=1:500
oldM=M;
newM=zeros(size,size);
for i=2:size-1;
for j=2:size-1;
%we're considering the ij-th pixel
pixel_conc=oldM(i,j);
newM(i,j+1)=newM(i,j+1)+pixel_conc/4;
newM(i,j-1)=newM(i,j-1)+pixel_conc/4;
newM(i+1,j)=newM(i+1,j)+pixel_conc/4;
newM(i-1,j)=newM(i-1,j)+pixel_conc/4;
end
end
M=newM;
end
It's a pretty simple piece of code, and I know that. I'm not very good at using Octave yet (chemist by trade), so I'd appreciate any help!
If you have concerns about the border of your simulation you could pad your matrix with NaN values, and then remove the border after the simulation has completed. NaN stands for not a number and is often used to denote blank data. There are many MATLAB functions work in a useful way with these values.
e.g. finding the mean of an array which has blanks:
nanmean([0 nan 5 nan 10])
ans =
5
In your case, I would start by adding a border of NaNs to your M matrix. I'm using 'n' instead of 'size', since size is an important function in MATLAB, and using it as a variable can lead to confusing errors.
n=100;
blankM=zeros(n+2,n+2);
blankM([1,end],:) = nan;
blankM(:, [1,end]) = nan;
Now we can define 'M'. N.B that the first column and row will be NaNs so we need to add an offset (25+1):
M = blankM;
M(26,26)=50;
Run the simulation through,
m = size(blankM, 1);
n = size(blankM, 2);
for diffusive_steps=1:500
oldM = M;
newM = blankM;
for i=2:m-1;
for j=2:n-1;
pixel_conc=oldM(i,j);
newM(i,j+1)=newM(i,j+1)+pixel_conc/4;
newM(i,j-1)=newM(i,j-1)+pixel_conc/4;
newM(i+1,j)=newM(i+1,j)+pixel_conc/4;
newM(i-1,j)=newM(i-1,j)+pixel_conc/4;
end
end
M=newM;
end
and then extract the area of interest
finalResult = M(2:end-1, 2:end-1);
One simple change you might make is to add a boundary of ghost cells, or halo, around the domain of interest. Rather than mis-use the name size I've used a variable called sz. Replace:
M=zeros(sz,sz)
with
M=zeros(sz+2,sz+2)
and then compute your diffusion over the interior of this augmented matrix, ie over cells (2:sz+1,2:sz+1). When it comes to considering the results, discard or just ignore the halo.
Even simpler would be to simply take what you already have and ignore the cells in your existing matrix which are on the N,S,E,W edges.
This technique is widely used in problems such as, and similar to, yours and avoids the need to write code which deals with the computations on cells which don't have a full complement of neighbours. Setting the appropriate value for the contents of the halo cells is a problem-dependent matter, 0 isn't always the right value.
What is the difference between hist and imhist functions in Matlab? I have a matrix of color levels values loaded from image with imread and need to count entropy value of the image using histogram.
When using imhist the resulting matrix contains zeros in all places except the last one (lower-right) which contains some high value number (few thousands or so).
Because that output seems to be wrong, I have tried to use hist instead of imhist and the resulting values are much better, the matrix is fulfilled with correct-looking values instead of zeros.
However, according to the docs, imhist should be better in this case and hist should give weird results..
Unfortunately I am not good at Matlab, so I can not provide you with better problem description. I can add some other information in the future, though.
So I will try to better explain my problem..I have an image, for which I should count entropy and few other values (how much bytes it will take to save that image,..). I wrote this function and it works pretty well
function [entropy, bytes_image, bytes_coding] = entropy_single_pixels(im)
im = double(im);
histg = hist(im);
histg(histg==0) = [];
nzhist = histg ./ numel(im);
entropy = -sum(nzhist.*log2(nzhist));
bytes_image = (entropy*(numel(im))/8);
bytes_coding = 2*numel(unique(im));
fprintf('ENTROPY_VALUE:%s\n',num2str(entropy));
fprintf('BYTES_IMAGE:%s\n',num2str(bytes_image));
fprintf('BYTES_CODING:%s\n',num2str(bytes_coding));
end
Then I have to count the same, but I have to make "pairs" from pixels which are below each other. So I have only half the rows and the same count of columns. I need to express every unique pixel pair as a different number, so I multiplied the first one by 1000 and added the second one to it... Subsequently I need to actually apply the same function as in the first example, but that is the time, when I am getting weird numbers from the imhist function. When using hist, it seems to be OK, but I really don't think that behavior is correct, so that must be my error somewhere. I actually understand pretty good, to what I want to do, or at least I hope so, but unfortunately Matlab makes all that kind of hard for me :)
hist- compute histogram(count number of occurance of each pixel) in color image.........
imhist- compute histogram in two dimensional image.
Use im2double instead of double if you want to use imhist. The imhist function expects double or single-precision data to be in the [0,1] data range, which is why you see everything in the last bin of the histogram.