Conversion to binary : Matlab - matlab

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.

Related

How does MATLAB calculate immse?

How does Matlab calculate immse? I want to find the mse between two images. According to how to measure he similarity between two 2D complex fields in matlab?, immse is the same as MSE=mean((abs(Y(:))-abs(Y1(:))).^2) for reference image Y1 and comparison image Y. Likewise, I could calculate MSE as the summed square errors divided by the number of row*cols. When I run on one of the demo images, these different approaches don't give the same answer as immse.
Here are two MSE approaches in the sample code below. The image is from the Matlab immse demo and immse gives around an MSE=340. The other two codes give around an MSE=2.5.
Note: The code is example code, I did not use the same function name twice in the same script. And I understand if you want to complain about using size(image) but that is a detail. I am more worried about the basic flaw in my understanding that is giving me orders of magnitude differences. Thank you so much.
n01 = imread('pout.tif');
n02 = imnoise(n01,'salt & pepper', 0.02);
mse = mymse(n02,n01);
mlmse = immse(n02,n01);
function this = mymse(icomp, ibase)
[X Y nchan] = size(ibase);
diff = (icomp - ibase);
this = sum(sum(diff.*diff))/(X*Y*nchan);
end
function this = mymse(icomp, ibase)
this = mean ((abs(ibase(:)) - abs(icomp(:))).^2);
end
You can check the underlying code to many matlab functions by simply doing
open <func>
in the Matlab command window.
In this case you can see that immse is doing the norm of the differences, scaled by number of points.
function this = mymse(icomp, ibase)
this = sum((ibase(:) - icomp(:)).^2) / numel(ibase);
end

comparing generated data to measured data

we have measured data that we managed to determine the distribution type that it follows (Gamma) and its parameters (A,B)
And we generated n samples (10000) from the same distribution with the same parameters and in the same range (between 18.5 and 59) using for loop
for i=1:1:10000
tot=makedist('Gamma','A',11.8919,'B',2.9927);
tot= truncate(tot,18.5,59);
W(i,:) =random(tot,1,1);
end
Then we tried to fit the generated data using:
h1=histfit(W);
After this we tried to plot the Gamma curve to compare the two curves on the same figure uing:
hold on
h2=histfit(W,[],'Gamma');
h2(1).Visible='off';
The problem s the two curves are shifted as in the following figure "Figure 1 is the generated data from the previous code and Figure 2 is without truncating the generated data"
enter image description here
Any one knows why??
Thanks in advance
By default histfit fits a normal probability density function (PDF) on the histogram. I'm not sure what you were actually trying to do, but what you did is:
% fit a normal PDF
h1=histfit(W); % this is equal to h1 = histfit(W,[],'normal');
% fit a gamma PDF
h2=histfit(W,[],'Gamma');
Obviously that will result in different fits because a normal PDF != a gamma PDF. The only thing you see is that for the gamma PDF fits the curve better because you sampled the data from that distribution.
If you want to check whether the data follows a certain distribution you can also use a KS-test. In your case
% check if the data follows the distribution speccified in tot
[h p] = kstest(W,'CDF',tot)
If the data follows a gamma dist. then h = 0 and p > 0.05, else h = 1 and p < 0.05.
Now some general comments on your code:
Please look up preallocation of memory, it will speed up loops greatly. E.g.
W = zeros(10000,1);
for i=1:1:10000
tot=makedist('Gamma','A',11.8919,'B',2.9927);
tot= truncate(tot,18.5,59);
W(i,:) =random(tot,1,1);
end
Also,
tot=makedist('Gamma','A',11.8919,'B',2.9927);
tot= truncate(tot,18.5,59);
is not depending in the loop index and can therefore be moved in front of the loop to speed things up further. It is also good practice to avoid using i as loop variable.
But you can actually skip the whole loop because random() allows to return multiple samples at once:
tot=makedist('Gamma','A',11.8919,'B',2.9927);
tot= truncate(tot,18.5,59);
W =random(tot,10000,1);

MATLAB: How can I avoid iamresize and VideoReader if they are taking too much time?

I am doing mean shift color based image segmentation on video frames.
Here is my code:
while hasFrame(v)
if k == 1
s(k).cdata = readFrame(v);
a = s(k).cdata;
I = imresize(a,[50,50]);
[means, Ims, Nms] = Ms(I,bw); %Mean Shift on first frame
Ims = im2uint8(Ims);
s(k).cdata = Ims;
else
s(k).cdata = readFrame(v);
a = s(k).cdata;
I = imresize(a,[50,50]);
[Ims,data2cluster]= MeanShiftCluster2(I,means); % simple segmentation based on norm using means of first frame
Ims = im2uint8(Ims);
Ims = imresize(Ims,[500,720]);
s(k).cdata = Ims;
end
k=k+1;
end
I am sending first frame for mean shift implementation and then using same resulting means for all other frames to calculate their respective clusters on basis of euclidean distance (My frames have minor changes).
Problems:
Profiler tells that iamresize and VideoReader functions are taking too long to execute. Are there any substitute that I can use?
imresize may be the slowest step of your processing.
But here are several idea to fasten the process.
imresize do what is called interpolation. This is can be a slow process, but the speed depends on the quality you want for the output. The default in matlab is bicubic. You can try bilinear or nearest. e.g :
[...] = imresize(...,'nearest');
In my personnal experimentation, I have also found that imresize as equivalent functions have some overhead. You could probably go "much" faster by calling the function only once for all your video frames. You will need to have enough memory to do this. Suppose that you you have all your frames in a 3d matrix dataMovie. When constructing this matrix, preallocation (by getting the number of frame) will help gaining some speed !
k = 0.5; % scaling parameter
tform = affine2d([k 0 0;0 k 0;0 0 1]);
dataTform = imwarp(dataMovie,tform,'nearest');
And then, apply your processing to the resize movie frame by frame. You can also provide the type of interpolation nearset, linear or bicubic.
If you are working on a color movie, you need to stack the 3 color layers of all the frame together, and get them back using the proper indexing.

Optimize matlab for loop for big data

I want to calculate the Euclidean distance between two images using the Hyperbolic Tangent (Sigmoid) kernel. Please follow this link where I have discussed the same problem using Gaussian Kernel in detail.
If x=(i,j) & y=(i1,j1) are any two pixels in our image then for hyperbolic tangent kernel, my H(x,y) will be defined as:
H(i,j) = tanh(alpha*(x'*y) + c)
where alpha and c are parameters and x' is the transpose of x. Parameter alpha can be taken as 1/N where N is my image dimension(8192 x 200 in my case) and c can take any value according to the problem. More detailed description about Hyperbolic Tangent kernel can be found here.
To achieve my goal & keeping the running time under consideration, I have written the below MATLAB script.
gray1=zeros(8192,200);
gray2=zeros(8192,200);
s1 = 8192;
s2 = 200;
alpha = s1*s2;
perms = combvec(1:s2,1:s1);
perms = [perms(2,:);perms(1,:)]';
perms1 = perms;
gray1(4096,100) = 10;
gray2(10,100) = 10;
img_diff = gray1 - gray2;
display('Calculation of Sigmoid Kernel started');
for i = 1:length(perms1)
kernel = sum(bsxfun(#times,perms,perms1(i,:))');
kernel1 = tanh((1/alpha)*kernel + 1)';
g_temp(i) = img_diff(:)'*kernel1;
end
temp = g_temp*img_diff(:);
ans = sqrt(temp);
In spite of my all efforts I couldn't vectorize it further so as to decrease its running cost. Currently, it is taking around 29 hours to complete which is too much for me as I want to run it for various different images. I want to give it a completely vectorized form using intrinsic MATLAB functions as it was done by #dan-man in the case of Gaussian Kernel. With his help the Gaussian Version was taking 1-2 secs to complete. I tried my best to use the same conv2fft function in this case also but it seems difficult to find a way to achieve that.
Can someone please help me to remove that one extra for loop so as to get the running cost of algorithm in the same proportion as that of the Gaussian version of same problem.
Thanks in advance.
Get rid of the nasty loop with matrix-multiplication -
g_temp = img_diff(:).'*tanh((1/alpha)*(perms*perms.')+1)
With my times in my PC for just 50 iterations, the code takes 2.07s
Just changing the bsxfun line to
kernel = sum(bsxfun(#times,perms,perms1(i,:)),2)';
as the warning suggests you can get it to 1.65s
If you use the Neural Network toolbox and substitute tanh by tansig , the time goes to 1.44s
If you write your own tanhas
kernel1= (2./(1+exp(-2.*((1/alpha)*kernel + 1)))-1)';
the time goes to 1.28s
Just these changes would mean improvement from 29h to 18h
And remember to preallocate!
g_temp=zeros(length(perms1),1);

eigenfaces are not showing correctly and are very dark

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.