I am looking for functions to perform segmentation of noisy medical images (grayscale) with GMM (Gaussian Mixture Models).
I have found in MATLAB:
gm = gmdistribution(mu,sigma)
idx = cluster(gm,X)
given X, my grayscale image.
How would you define mu and sigma? What size should they be? And how would you initialize them?
I have tried the following (given an image of size (576x720)):
mu = rand(5,size(X,2));
sigma = ones(720,720);
gm = gmdistribution(mu,sigma);
idx = cluster(gm,X);
but I get an error:
Error using wdensity (line 29)
Ill-conditioned covariance created.
Error in gmdistribution/cluster (line 59)
log_lh=wdensity(X,obj.mu, obj.Sigma, obj.PComponents, obj.SharedCov, CovType);
I have a basic idea of how GMM works, i.e. soft clustering, but I 'd like help of a more advanced person to understand what I'm doing here.
Wrong function. You are looking for fitgmdist(X,k), where you input your estimate of number of objects to be segmented as k. Then the program will attempt to calculate mu and sigma by using the EM-algorithm.
That ill conditioned covariance created -warning is typical, you are going to see that a lot if your data is noisy. I suggest regularization, by tweaking the 'RegularizationValue' -parameter, possibly setting constraints on the covariance-structures and/or filtering the noisy image. I've always had good results when using the BM3D (for 2D images) and BM4D -filters (for 3D images).
I'm happy to help if you have any specific questions but you are also going to have to do your homework on this. Image processing is hard, bunch of moving parts you need to handle before even the basic stuff starts to work reliably.
Related
I posted this question on the CV SO a few days ago but it has gone basically unobserved by the forum. I'm trying to implement NBNN in MATLAB to do image classification on the CIFAR-10 image dataset. The algorithm is pretty simple, and I'm confident in it's correctness, however, I'm receiving terrible accuracy rates with 22-28%. I'm unsure why and I'm hoping someone who has experience with image classification or the algorithm could point me in the right direction. The algorithm learns off of SIFT image descriptors, which could be one of the reasons why it's under-performing. Matlab only has a SURF feature detector. From what I've read, SURF/SIFT are basically equivalent. I've been using features, (nDescriptros x 64) obtained from the function below to train my model.
points = detectSURFFeatures(rgb2gray(image));
[features,valid_points] = extractFeatures(image,points);
Another possible issue with the CIFAR dataset and this approach is the small size of the images. Each image is 32 x 32 images which, I beleive, makes feature detection very difficult. I've played around with the different octave settings in the detectSURFFeatures() but nothing has brought my accuracy above 28%.
The annotated code for the approach is below. It's difficult to understand but still might be helpful.
Hopefully someone can help me out.
for i = 3001:4000 %Train on the first 3000 instances and test on the remaining 1000.
closeness = [];
for j = 1:10 %loop over the 10 catergories
class = train(trainLabel==j,:); % Pull out all descriptors that belong to class j
descriptor = test(test_id==i,:); % Pull out all descriptors for image i
[idx,dist] = knnsearch(class,descriptor,'K',1); % Find the distance between the descriptors and the closest labeled descriptor in class j.
total = sum(dist); % sum up distances
closeness = [closeness,sum(total)]; % append a vector of the image-to-class distances.
end
[val,cat] = min(closeness); % Find choose the class that resulted in the lowest, summed distance.
predLabel = [predLabel;cat]; % Append to a vector of labels.
i
end
If your images are 32x32 pixels, then trying to detect interest points is not a good idea. As you have observed, you would get very few features, if any. Upsampling the images is one option. Another option is to use a global descriptor like HOG (extractHOGFeatures).
My objective is to handle illumination and expression variations on an image. So I tried to implement a MATLAB code in order to work with only the important information within the image. In other words, to work with only the "USEFUL" information on an image. To do that, it is necessary to delete all unimportant information from the image.
Reference: this paper
Lets see my steps:
1) Apply the Histogram Equalization in order to get an histo_equalized_image=histeq(MyGrayImage). so that large intensity variations
can be handled to some extent.
2) Apply svd approximations on the histo_equalized_image. But before to do that, I applied the svd decomposition ([L D R]=svd(histo_equalized_image)), then these singular values are used to make the derived image J=L*power(D, i)*R where i varies between 1 and 2.
3) Finally, the derived image is combined with the original image to: C=(MyGrayImage+(a*J))/1+a. Where a varies from 0 to 1.
4) But all the steps above are not able to perform well under varying conditions. So finally, wavelet transform should be used to handle those variations(we use only the LL image bloc). Low frequency component contains the useful information, also, unimportant
information gets lost in this component. The (LL) component is ineffective with illumination changes and expression variations.
I wrote a matlab code for that, and I would like to know if my code is correct or no (if no, so how to correct it). Furthermore, I am interested to know if I can optimize these steps. Can we improve this method? if yes, so how? Please I need help.
Lets see now my Matlab code:
%Read the RGB image
image=imread('img.jpg');
%convert it to grayscale
image_gray=rgb2gray(image);
%convert it to double
image_double=im2double(image_gray);
%Apply histogram equalization
histo_equalized_image=histeq(image_double);
%Apply the svd decomposition
[U S V] = svd(histo_equalized_image);
%calculate the derived image
P=U * power(S, 5/4) * V';
%Linearly combine both images
J=(single(histo_equalized_image) + (0.25 * P)) / (1 + 0.25);
%Apply DWT
[c,s]=wavedec2(J,2,'haar');
a1=appcoef2(c,s,'haar',1); % I need only the LL bloc.
You need to define, what do you mean by "USEFUL" or "important" information. And only then do some steps.
Histogram equalization is global transformation, which gives different results on different images. You can make an experiment - do histeq on image, that benefits from it. Then make two copies of the original image and draw in one black square (30% of image area) and white square on second. Then apply histeq and compare results.
Low frequency component contains the useful information, also,
unimportant information gets lost in this component.
Really? Edges and shapes - which are (at least for me) quite important are in high frequencies. Again we need definition of "useful" information.
I cannot see theoretical background why and how your approach would work. Could you a little bit explain, why do you choose this method?
P.S. I`m not sure if this papers are relevant to you, but recommend "Which Edges Matter?" by Bansal et al. and "Multi-Scale Image Contrast Enhancement" by V. Vonikakis and I. Andreadis.
If I estimate the entropy of a vector of standard normal random variables using the Matlab entropy() function, I get an answer somewhere in the region of 4, whereas the actual entropy should be 0.5 * log(2*pi*e*sigma^2) which is approximately equal to 1.4.
Does anyone know where the discrepancy is coming from?
Note: To save time here is the Matlab code
for i = 1:1000
X(i) = randn();
end
'The entropy of X is'
entropy(X)
Please read the help (help entropy) or documentation for entropy. You'll see that it's designed for images and uses a histogram technique rather than calculating the it analytically. You'll need to create your own function if you want the formula from Wikipedia, but as the formula is so simple, that should be no problem.
I believe that the reason that you're getting such divergent answers is that entropy scales the bins of the histogram by the number of elements. If you want to uses such an estimation technique you'll want to use hist and scale the bins by area. See this StackOverflow question.
Question
I have an images sequence representing depth information which I'd like to clean.
There are some outliers (values with intensity below 25, for a 0-255 range) which I would like to be filled with an acceptable alternative (an average value localised to that specific area could be a good guess).
Can someone see a simple way to do this? I've tried to use a median filter (filter size of 10) substituting the undesired values with NaN, but it did worsen the situation, which improves instead by substituting them with a general average value.
P.S. Someone has already suggested me to use a fast wavelet reconstruction, but I would not really know where to start...
Implemented solution (so far)
The solution I implemented (before reading about inpaint_nans suggested by tmpearce) is:
duplicate the original image;
filling the invalid pixels with a general average value;
use a circular disk of ray 10 for blurring it;
replacing the invalid values in the original image with what I got from point 3.
run a median filter of size 10.
img2 = img;
img2(img < .005) = mean(img(:));
H = fspecial('disk',10);
img3 = imfilter(img2,H,'symmetric');
img4 = img;
img4(img < .3) = img3(img < .3);
filterSize = 10;
padopt = {'zeros','indexed','symmetric'};
IMG = medfilt2(img4, [1 1]*filterSize, padopt{p});
I recommend the inpaint_nans contribution from the MATLAB File Exchange - start as you've already done by replacing outliers with NaN and use the link to go from there.
From the description of the function:
Interpolate NaN elements in a 2-d array using non-NaN elements. Can
also extrapolate, as it does not use a triangulation of the data.
Inpaint_nans offers several different approaches to the interpolation,
which give tradeoffs in accuracy versus speed and memory required. All
the methods currently found in inpaint_nans are based on sparse linear
algebra and PDE discretizations. In essence, a PDE is solved to be
consistent with the information supplied.
Hooray for reusable code!
Use a function called roifill. You need to mess with it a little bit. I had to use imdilate because it interpolates from the boundary.
Code:
testimage = imread('BAPz5.png');
testimage = double(rgb2gray(testimage));
testimage_filt = roifill(testimage,imdilate(testimage<100,true(4)));
figure(1);
subplot(1,2,1);
imshow(testimage,[]);
subplot(1,2,2);
imshow(testimage_filt,[]);
Output:
The post is answered but just for the record, in [1], the author based on a basic principle of natural shapes, i.e., the objects follow a second order smoothness, he suggests an in-painting method that minimize curvature in a
least-squares sense. He also offers code. Good luck.
[1] Α Categoty-Level 3-D Object Database: Putting the kineckto Work (ICCV)
I have a Binary classification problem that I need to do in MATLAB. There are two classes and the training data and testing data problems are from two classes and they are 2d coordinates drawn from Gaussian distributions.
The samples are 2D points and they are something like these (1000 samples for class A and 1000 samples for class B):
I am just posting some of them here:
5.867766 3.843014
5.019520 2.874257
1.787476 4.483156
4.494783 3.551501
1.212243 5.949315
2.216728 4.126151
2.864502 3.139245
1.532942 6.669650
6.569531 5.032038
2.552391 5.753817
2.610070 4.251235
1.943493 4.326230
1.617939 4.948345
If a new test data comes in, how should I classify the test sample?
P(Class/TestPoint) is proportional to P(TestPoint/Class) * (ProbabilityOfClass).
I am not sure of how we compute the P(Sample/Class) variable for the 2D coordinates given. Right now, I am using the formula
P(Coordinates/Class) = (Coordinates- mean for that class) / standard deviation of points in that class).
However, I am not getting very good test results with this. Am I doing anything wrong?
That is the good method, however the formula is not correct, look at the multivariate gaussian distribution article on wikipedia:
P(TestPoint|Class)=
,
where is the determinant of A.
Sigma = classPoint*classPoint';
mu = mean(classPoint,2);
proba = 1/((2*pi)^(2/2)*det(Sigma)^(1/2))*...
exp(-1/2*(testPoint-mu)*inv(Sigma)*(testPoint-mu)');
In your case, since they are as many points in both class, P(class)=1/2
Assuming your formula is correctly applied, another issue could be the derivation of features from your data points. Your problem might not be suited for a linear classifier.