calculate number of matches between two images using MATLAB vl_sift - image-manipulation

I’m new to MATLAB. I’m using VL_Feat library. I’m trying to construct a code that can calculate number of matching points between two images. Up to now I know how to match two images. What I want to get is number of matching points.
As an example
“X key points found in image 1”
“Y key points found in image 2”
“z matches”
Can anyone help me?
im1Path = fullfile(vl_root, 'data', 'roofs1.jpg') ;
im2Path = fullfile(vl_root, 'data', 'roofs2.jpg') ;
im1 = imread(im1Path) ;
im2 = imread(im2Path) ;
[f1,d1] = vl_sift(im2single(rgb2gray(im1))) ;
[f2,d2] = vl_sift(im2single(rgb2gray(im2))) ;
[matches, scores] = vl_ubcmatch(d1,d2) ;
fprintf(' %d a counts.\n', vl_ubcmatch(d1,d2));

As I understand you want to find the no of keypoints of the two images separately.the given statements below will not produce the exact output you want but I hope this will help you to some extent. this also show some important info regarding the keypoints. If the two images are I & J,then after reading the two images you can add these lines-
I = single(rgb2gray(I));
vl_covdet(I, 'verbose');
J = single(rgb2gray(J));
vl_covdet(J, 'verbose');
and then rest of the codes.

Related

Finding peaks in matlab in flat regions

I have data in an array in matlab. I want to find peaks, but faced the following problem shown in the picture below.
To generate peaks and plot them I used the following code:
gyryMF = medfilt1(gyry, 3);
[pks, gyryPeaks] = findpeaks(gyryMF);
%%
plot(gyryMF);
text(gyryPeaks+.02,pks,num2str((1:numel(pks))'));
As you see from picture, some peaks not found, because there is a flat region. I wonder if somehow I can find and include them as well?
How about writing your own peaks function with your own criteria?
peak_no = []
ind_peak_no = []
if Data(x) < Data(x+1) && Data(x+1) > Data(x+2) && Data(x+1)> Peak_min
peak_no = [peak_no;Data(x+1)];
ind_peak_no = [ind_peak_no; x+1];
end

Display second longest line in MATLAB? [duplicate]

This question already has answers here:
Get the indices of the n largest elements in a matrix
(4 answers)
Closed 6 years ago.
When using a binary image with several lines I know that this code displays the longest line:
lineStats = regionprops(imsk, {'Area','PixelIdxList'});
[length, index] = max([lineStats.Area]);
longestLine = zeros(size(imsk));
longestLine(lineStats(index).PixelIdxList)=1;
figure
imshow(longestLine)
Is there a way to display the second longest line? I need to display a line that is a little shorter than the longest line in order to connect them.
EDIT: Is there a way to display both lines on the binary image figure?
Thank you.
I would set the longest line to zero and use max again, after I copy the original vector.
lineStats = regionprops(imsk, {'Area','PixelIdxList'});
[length, index] = max([lineStats.Area]);
lineAreas = [lineStats.Area]; %copy all lineStats.Area values into a new vector
lineAreas(index) = NaN; %remove the longest line by setting it to not-a-number
[length2, index2] = max(lineAreas);
EDIT: Response to new question
sort may be a more straight forward approach for multiples, but you can still use max.
lineAreas = [lineStats.Area]; %copy all lineStats.Area values into a new vector
% add a for loop that iteratively stores the desired indices
nLines = 3;
index = zeros(1,nLines);
for iLines = 1:nLines
[length, index(iLines)] = max(lineAreas);
lineAreas(index) = NaN; %remove the longest line by setting it to not-a-number
end
longestLine = zeros(size(imsk));
% I cannot be certain this will work since your example is not reproducible
longestLine([lineStats(index).PixelIdxList]) = 1;
figure
imshow(longestLine)
Instead of using max use sort in descending order and take the second element. Like max, sort also provides the indexes of the returned values, so the two functions are pretty compatible.
eStats = regionprops(imsk, {'Area','PixelIdxList'});
[length, index] = sort([lineStats.Area], 'descend');
longestLine = zeros(size(imsk));
longestLine(lineStats(index(2)).PixelIdxList)=1; % here take the second largest
figure
imshow(longestLine)
As an alternative with focus on performance and ease of use, here's one approach using bwlabel instead of regionprops -
[L, num] = bwlabel(imsk, 8);
count_pixels_per_obj = sum(bsxfun(#eq,L(:),1:num));
[~,sidx] = sort(count_pixels_per_obj,'descend');
N = 3; % Shows N biggest objects/lines
figure,imshow(ismember(L,sidx(1:N))),title([num2str(N) ' biggest blobs'])
On the performance aspect, here's one post that does some benchmarking on snowflakes and coins images from MATLAB's image gallery.
Sample run -
imsk = im2bw(imread('coins.png')); %%// Coins photo from MATLAB Library
N = 2:
N = 3:

Sorting dicom images in Matlab

I am working with lung data sets in matlab, but I need to sort the slices correctly and show them.
I knew that can be done using the "instance number" parameter in Dicom header, but I did not manage to run the correct code.
How can I do that?
Here is my piece of code:
Dicom_directory = uigetdir();
sdir = strcat(Dicom_directory,'\*.dcm');
files = dir(sdir);
I = strcat(Dicom_directory, '\',files(i).name);
x = repmat(double(0), [512 512 1 ]);
x(:,:,1) = double(dicomread(I));
axes(handles.axes1);
imshow(x,[]);
First of all, to get the DICOM header, you need to use dicominfo which will return a struct containing each of the fields. If you want to use the InstanceNumber field to sort by, then you can do this in such a way.
%// Get all of the files
directory = uigetdir();
files = dir(fullfile(directory, '*.dcm'));
filenames = cellfun(#(x)fullfile(directory, x), {files.name}, 'uni', 0);
%// Ensure that they are actually DICOM files and remove the ones that aren't
notdicom = ~cellfun(#isdicom, filenames);
files(notdicom) = [];
%// Now load all the DICOM headers into an array of structs
infos = cellfun(#dicominfo, filenames);
%// Now sort these by the instance number
[~, inds] = sort([infos.InstanceNumber]);
infos = infos(inds);
%// Now you can loop through and display them
dcm = dicomread(infos(1));
him = imshow(dcm, []);
for k = 1:numel(infos)
set(him, 'CData', dicomread(infos(k)));
pause(0.1)
end
That being said, you have to be careful sorting DICOMs using the InstanceNumber. This is not a robust way of doing it because the "InstanceNumber" can refer to the same image acquired over time or different slices throughout a 3D volume. If you want one or the other, I would choose something more specific.
If you want to sort physical slices, I would recommend sorting by the SliceLocation field (if available). If sorting by time, you could use TriggerTime (if available).
Also you will need to consider that there could also potentially be multiple series in your folder so maybe consider using the SeriesNumber to differentiate these.

Matlab get vector of specific pixels

I am pretty new to Matlab and encountered a problem when working with images.
I want to get a pixel that is in a specific colour (blue) in the following image:
image
My current code looks something like this:
function p = mark(image)
%// display image I in figure
imshow(image);
%// first detect all blue values higher 60
high_blue = find(image(:,:,3)>60);
%cross elements is needed as an array later on, have to initialize it with 0
cross_elements = 0;
%// in this iteration the marked values are reduced to the ones
%where the statement R+G < B+70 applies
for i = 1:length(high_blue)
%// my image has the size 1024*768, so to access the red/green/blue values
%// i have to call the i-th, i+1024*768-th or i+1024*768*2-th position of the "array"
if ((image(high_blue(i))+image(high_blue(i)+768*1024))<...
image(high_blue(i)+2*768*1024)+70)
%add it to the array
cross_elements(end+1) = high_blue(i);
end
end
%// delete the zero element, it was only needed as a filler
cross_elements = cross_elements(cross_elements~=0);
high_vector = zeros(length(cross_elements),2);
for i = 1:length(cross_elements)
high_vector(i,1) = ceil(cross_elements(i)/768);
high_vector(i,2) = mod(cross_elements(i), 768);
end
black = zeros(768 ,1024);
for i = 1:length(high_vector)
black(high_vector(i,2), high_vector(i,1)) = 1;
end
cc = bwconncomp(black);
a = regionprops(cc, 'Centroid');
p = cat(1, a.Centroid);
%// considering the detection of the crosses:
%// RGB with B>100, R+G < 100 for B<150
%// consider detection in HSV?
%// close the figure
%// find(I(:,:,3)>150)
close;
end
but it is not optimized for Matlab, obviously.
So i was wondering if there was a way to search for pixels with specific values,
where the blue value is larger than 60 (not hard with the find command,
but at the same time the values in the red and green area not too high.
Is there a command I am missing?
Since English isn't my native language, it might even help if you gave me some suitable keywords for googling ;)
Thanks in advance
Based on your question at the end of the code, you could get what you want in a single line:
NewImage = OldImage(:,:,1) < SomeValue & OldImage(:,:,2) < SomeValue & OldImage(:,:,3) > 60;
imshow(NewImage);
for example, where as you see you provide a restriction for each channel using logical operators, that you can customize of course (eg. using | as logical OR). Is this what you are looking for? According to your code you seem to be looking for specific regions in the image like crosses or coins is that the case? Please provide more details if the code I gave you is completely off the track :)
Simple example:
A = imread('peppers.png');
B = A(:,:,3)>60 & A(:,:,2)<150 & A(:,:,1) < 100;
figure;
subplot(1,2,1);
imshow(A);
subplot(1,2,2)
imshow(B);
Giving this:

How to write this in an elegant way (cell arrays and structs in MATLAB)

I would like to plot connected points in MATLAB.
My connected points come from connecting objects of "stats", where each "stat" comes from a BW regionprops struct.
The code I have written works, but it suffers from a lot of "ugliness", which I couldnt fix even after trying various ways.
function plot_line( line )
a = cell2mat(line);
b = {a.Centroid};
matx = {};
maty = {};
for i = 1:size(b,2)
matx{end+1} = b{i}(1);
maty{end+1} = b{i}(2);
end
plot ( cell2mat(matx), cell2mat(maty) );
end
Can you help me make this code nicer? It's not critical, as my code works fine and as the lines are short (<100 points) the performance is not an issue.
It is just that it would be really nice to know how this tiny function should be written in the proper way, without for loops and 3 calls of cell2mat.
In my example:
line is a <1xn cell>,
line{1} has a property 'Centroid' and
line{i}.Centroid(1) are the x coordinates and
line{i}.Centroid(2) are the y coordinates.
Actually, all I need is plotting line{i}.Centroid(1), line{i}.Centroid(2) for i = 1:size(line,2), but I don't know how.
Instead of creating a cell array b, you can create a numerical array directly, by catenating using CAT:
tmp = cat(1,line{:});
coordinates = cat(1,tmp.Centroid);
plot(coordinates(:,1),coordinates(:,2))
EDIT
If you want to keep it really short (i.e. even shorter than #Amro's solution you can use CELLFUN like this in order get a one-liner:
plot(cellfun(#(x)x.Centroid(1),line),cellfun(#(x)x.Centroid(2),line))
Example:
line = repmat({struct('Centroid',[1 2])},1,5); %# similar to the data you have
%# extract x/y coordinates
x = cellfun(#(s)s.Centroid(1),line)
y = cellfun(#(s)s.Centroid(2),line)
%# plot
plot(x,y)
You could also do it as:
xy = cell2mat(cellfun(#(s)s.Centroid, line, 'UniformOutput',false)');
plot(xy(:,1),xy(:,2))