Background:
I am programming SIFT in matlab. I have computed the Difference of Gaussians and have stored them in a 2D cell array. The images in column 2 are half the size of column 1 and so on.
Questions.
Now that I have all of the images stored in my 2D cell array I would like to print them all in one figure.
Im been browsing the web for quite a bit but I haven't seen anything that could help. If anyone could point me in the right direction or provide an example it would be greatly appriciated.
Cheers
If you want a really simple solution then just make a composite image and fill in the regions with the images in the gaussian pyramid. I've given an example code below the works for my case but needs to be adapted for yours.
Code:
% Get total width and height
width_total = 0;
height_total = 0;
for i = 0:3 % Cycle over scales - 4 total
width_total = width_total+size(obj.gaussianpyramid{i+1,1},2);
height_total = height_total+size(obj.gaussianpyramid{i+1,1},1);
end
% Form composite gaussian
compositegaussian = zeros(width_total,height_total);
ind_x = 0;
for i = 0:3 % Cycle over octaves - 4 total
for j = 0:4 % Cycle over scales - 5 total
ind_y = j*size(obj.gaussianpyramid{i+1,j+1},1);
compositegaussian(ind_y+1:ind_y+size(obj.gaussianpyramid{i+1,j+1},1),ind_x+1:ind_x+size(obj.gaussianpyramid{i+1,j+1},2)) = obj.gaussianpyramid{i+1,j+1};
end
ind_x = ind_x + size(obj.gaussianpyramid{i+1,1},2);
end
figure, imshow(compositegaussian,[]);
Output:
Lets generate random 5x2 cell array where the first columns contains 10x10 images and the second - 5x5 images:
c = cell(5,2);
for k=1:5
c{k,1} = uint8(255 * rand(10));
c{k,2} = uint8(255 * rand(5));
end
The following code illustrates them:
figure;
n = size(c, 1);
for k = 1 : n
subplot(n, 2, k * 2 - 1);
image(c{k,1});
subplot(n, 2, k * 2);
image(c{k,2});
end
If the images are upside down, use set(gca,'YDir','normal'); after each image() call.
Related
I am trying to write my own function for scaling up an input image by using the Nearest-neighbor interpolation algorithm. The bad part is I am able to see how it works but cannot find the algorithm itself. I will be grateful for any help.
Here's what I tried for scaling up the input image by a factor of 2:
function output = nearest(input)
[x,y]=size(input);
output = repmat(uint8(0),x*2,y*2);
[newwidth,newheight]=size(output);
for i=1:y
for j=1:x
xloc = round ((j * (newwidth+1)) / (x+1));
yloc = round ((i * (newheight+1)) / (y+1));
output(xloc,yloc) = input(j,i);
end
end
Here is the output after Mark's suggestion
This answer is more explanatory than trying to be concise and efficient. I think gnovice's solution is best in that regard. In case you are trying to understand how it works, keep reading...
Now the problem with your code is that you are mapping locations from the input image to the output image, which is why you are getting the spotty output. Consider an example where input image is all white and output initialized to black, we get the following:
What you should be doing is the opposite (from output to input). To illustrate, consider the following notation:
1 c 1 scaleC*c
+-----------+ 1 +----------------------+ 1
| | | | | |
|----o | <=== | | |
| (ii,jj) | |--------o |
+-----------+ r | (i,j) |
inputImage | |
| |
+----------------------+ scaleR*r
ouputImage
Note: I am using matrix notation (row/col), so:
i ranges on [1,scaleR*r] , and j on [1,scaleC*c]
and ii on [1,r], jj on [1,c]
The idea is that for each location (i,j) in the output image, we want to map it to the "nearest" location in the input image coordinates. Since this is a simple mapping we use the formula that maps a given x to y (given all the other params):
x-minX y-minY
--------- = ---------
maxX-minX maxY-minY
in our case, x is the i/j coordinate and y is the ii/jj coordinate. Therefore substituting for each gives us:
jj = (j-1)*(c-1)/(scaleC*c-1) + 1
ii = (i-1)*(r-1)/(scaleR*r-1) + 1
Putting pieces together, we get the following code:
% read a sample image
inputI = imread('coins.png');
[r,c] = size(inputI);
scale = [2 2]; % you could scale each dimension differently
outputI = zeros(scale(1)*r,scale(2)*c, class(inputI));
for i=1:scale(1)*r
for j=1:scale(2)*c
% map from output image location to input image location
ii = round( (i-1)*(r-1)/(scale(1)*r-1)+1 );
jj = round( (j-1)*(c-1)/(scale(2)*c-1)+1 );
% assign value
outputI(i,j) = inputI(ii,jj);
end
end
figure(1), imshow(inputI)
figure(2), imshow(outputI)
A while back I went through the code of the imresize function in the MATLAB Image Processing Toolbox to create a simplified version for just nearest neighbor interpolation of images. Here's how it would be applied to your problem:
%# Initializations:
scale = [2 2]; %# The resolution scale factors: [rows columns]
oldSize = size(inputImage); %# Get the size of your image
newSize = max(floor(scale.*oldSize(1:2)),1); %# Compute the new image size
%# Compute an upsampled set of indices:
rowIndex = min(round(((1:newSize(1))-0.5)./scale(1)+0.5),oldSize(1));
colIndex = min(round(((1:newSize(2))-0.5)./scale(2)+0.5),oldSize(2));
%# Index old image to get new image:
outputImage = inputImage(rowIndex,colIndex,:);
Another option would be to use the built-in interp2 function, although you mentioned not wanting to use built-in functions in one of your comments.
EDIT: EXPLANATION
In case anyone is interested, I thought I'd explain how the solution above works...
newSize = max(floor(scale.*oldSize(1:2)),1);
First, to get the new row and column sizes the old row and column sizes are multiplied by the scale factor. This result is rounded down to the nearest integer with floor. If the scale factor is less than 1 you could end up with a weird case of one of the size values being 0, which is why the call to max is there to replace anything less than 1 with 1.
rowIndex = min(round(((1:newSize(1))-0.5)./scale(1)+0.5),oldSize(1));
colIndex = min(round(((1:newSize(2))-0.5)./scale(2)+0.5),oldSize(2));
Next, a new set of indices is computed for both the rows and columns. First, a set of indices for the upsampled image is computed: 1:newSize(...). Each image pixel is considered as having a given width, such that pixel 1 spans from 0 to 1, pixel 2 spans from 1 to 2, etc.. The "coordinate" of the pixel is thus treated as the center, which is why 0.5 is subtracted from the indices. These coordinates are then divided by the scale factor to give a set of pixel-center coordinates for the original image, which then have 0.5 added to them and are rounded off to get a set of integer indices for the original image. The call to min ensures that none of these indices are larger than the original image size oldSize(...).
outputImage = inputImage(rowIndex,colIndex,:);
Finally, the new upsampled image is created by simply indexing into the original image.
MATLAB has already done it for you. Use imresize:
output = imresize(input,size(input)*2,'nearest');
or if you want to scale both x & y equally,
output = imresize(input,2,'nearest');
You just need a more generalized formula for calculating xloc and yloc.
xloc = (j * (newwidth+1)) / (x+1);
yloc = (i * (newheight+1)) / (y+1);
This assumes your variables have enough range for the multiplication results.
I am just learning matlab now. I faced a difficulty in creating an array of 3 elements in a row.
I wrote a code
Source = randi ([0,1],1,3);
which gave me output
[1,1,0].....
[0,1,1]....
but I was willing to get only one 1 and two zeros in the output instead of getting two 1 and one zero.
I know I am wrong because I am using randi function and gives random value of 0 & 1 and output I get can be [0,0,1] ... [1,0,0]... too.
My clear problem is to only get only one 1 if I repeat as many times. e.g. I should get only [0,0,1] or [0,1,0] or [1,0,0].
Hope I can get solution.
Thank you.
Ujwal
Here's a way using randperm:
n = 3; %// total number of elements
m = 1; %// number of ones
x = [ones(1,m) zeros(1,n-m)];
x = x(randperm(numel(x)));
Here is a couple of alternative solutions for your problem.
Create zero-filled matrix and set random element to one:
x = zeros(1, 3);
x(randi(3)) = 1;
Create 1x3 eye matrix and randomly circshift it:
x = circshift(eye(1,3), [0, randi(3)]);
I'm working on a Gaussian Pyramid code for matlab. Basically it loads an image, creates a cell array and fills it with different levels of the gaussian pyramid.
I want to show the content of my cell array filled with images in one single figure,
so you can see the gaussian pyramid effect. Meaning the original image is at full size and the rest are downsampled by 2 each. And all that in one figure.
I'm quite the amateur when it comes to Matlab so I don't really know how to do that.
I already tried it somewhat with subplots but failed.
Thanks in advance.
I used a loop to add zeros at the top of all images then merged them
Sample cell,
im = imread('peppers.png');
for i = 1 : 5
I{i} = im(1 : 2*i : end, 1 : 2*i : end,:);
end
The code, I being your cell,
m = size(I{1}, 1);
newI = I{1};
for i = 2 : numel(I)
[q,p,~] = size(I{i});
I{i} = cat(1,repmat(zeros(1, p, 3),[m - q , 1]),I{i});
newI = cat(2,newI,I{i});
end
imshow(newI)
For 2D images use : I{i} = cat(1,repmat(zeros(1 , p),[m - q , 1]),I{i});
How about:
subplot(numel(YourCell), 1, 1), imshow(YourCell{1});
for k=2:5
subplot(1,numel(YourCell),k), imshow(YourCell{k})
xlim([1 size(YourCell{1},1)]);
ylim([1 size(YourCell{1},2)]);
end
Result (with dummy data):
Edit:
You can play with the arrangement of your tiles by calculating the position of the next one. Here is a quick and dirty example, you can surely do a better job:
Side by side:
border=5;
MergedImage=ones(size(YourCell{1},1), 2.5*size(YourCell{1},2));
MergedImage(1:size(YourCell{1},1), 1:size(YourCell{1},2))=YourCell{1};
Pos=[1, size(YourCell{1},1)+border];
for k=1:(numel(YourCell)-1)
MergedImage(Pos(1):Pos(1)+size(YourCell{k+1}, 1)-1, Pos(2):Pos(2)+size(YourCell{k+1}, 2)-1)=YourCell{k+1};
Pos=[Pos(1), Pos(2)+size(YourCell{k+1}, 2)+border];
end
imshow(MergedImage);
Or a tighter arrangement:
border=5;
MergedImage=ones(size(YourCell{1},1), 2*size(YourCell{1},2));
MergedImage(1:size(YourCell{1},1), 1:size(YourCell{1},2))=YourCell{1};
Pos=[1, size(YourCell{1},1)+border];
for k=1:(numel(YourCell)-1)
MergedImage(Pos(1):Pos(1)+size(YourCell{k+1}, 1)-1, Pos(2):Pos(2)+size(YourCell{k+1}, 2)-1)=YourCell{k+1};
if mod(k,2) == 0
Pos=[Pos(1)+size(YourCell{k+1}, 1)+border, Pos(2)];
else
Pos=[Pos(1), Pos(2)+size(YourCell{k+1}, 2)+border];
end
end
imshow(MergedImage);
Dear stackoverflow users,
Some years ago i used mathematica for several months. After not programming for a few years I now do a research project, as a student, in which I use Matlab. I have found a lot of good help here on stackoverflow but now i am stuck at the following problem:
I have a data set of connections between nodes on a rectangular grid, each node has a possible connection to its 8 neighbors. My measurements are in the form of a 3 by n matrix where the first two values designate a node and the third value designates whether or not they are connected, the size of the grid is predetermined. Typically there are about ten lines coming from two or three nodes which are neighboring at least one of each other. The goal of my research project is to calculate the area at distance r around this collection of lines.
So far I have been able to plot the lines with the code below, for which I used bits of code from right here on stackoverflow, which was extremely useful. However I cant get a contour line around it at a certain distance (with which I would hope to calculate the area inside this contour line). The gplot function returns two vectors with two coordinates per line which I find difficult to convert to something more useable. I tried defining a value Z at a distance from the lines, to decline with distance from the lines, so I get a slope coming from these lines. From this slope i could calculate contourlines. However, because the lines are just coordinates I dont know how to calculate the distance to that line, opposed to when they would have been functions.
I am really at a loss. I hope I have somewhat clearly posted my problem here. This is the second time I post this problem, I have now added comments to the code and pictures to explain myself better. Thanks for any advice given!
This I have so far, the xls file is the 3 by n matrix i mention above, I have also written its contents in matrix form in the code below so my problem is easier to understand:
%# here i set my data/constants
filename='random.xls'; file=xlsread(filename); y=width; x=length;
%# random.xls looks approximately like this, after xlsread(filename) you get
file=[21 22 1;
21 20 1;
15 16 1;
15 14 1;
15 23 1;
14 22 1;
14 21 1;
22 15 1;
23 14 1;
24 15 1;
6 15 1;
5 14 1;
7 14 1;
8 15 1];
%# predefined width and length, i usually get this from the file
width=8; length=4;
%# here i create my adjaceny matrix in a elegant way user amro posted on stackoverflow
%# however i immediately multiply it by 0, creating a y*x by y*x matrix with all zeroes
[X Y] = meshgrid(1:x,1:y); X = X(:); Y = Y(:);
adjacency = squareform( pdist([X Y], 'chebychev') == 1 ); adjacency=adjacency*0;
%# here i take the matrix "file" for which the first two values are node numbers and
%# the third value designates whether there is a connection between the two nodes to
%# fill in the connections in the adjacencymatrix
[nrows,ncols]=size(file);
for r = 1:nrows
if file(r,3)==1
adjacency(file(r,1),file(r,2))=1;
end
end
adjacency=(adjacency+adjacency.');
%# plots the adjacencymatrix
subplot(121), spy(adjacency)
%# plots the connections and designates the nodes, note that the numbers designating
%# the nodes do not match original data, this is a separate problem i have not solved
[xx yy] = gplot(adjacency, [X Y]);
subplot(122), plot(xx, yy, 'ks-', 'MarkerFaceColor','b')
%# these last lines of code for plotting the numbers of the grid i do not fully
%# understand, in here is the cause for the numbers not matching the original data
axis([0 x+1 0 y+1])
[X Y] = meshgrid(1:x,1:y);
X = reshape(X',[],1) + 0.1; Y = reshape(Y',[],1) + 0.1;
text(X, Y(end:-1:1), cellstr(num2str((1:x*y)')) )
xlabel('length')
ylabel('width')
title(filename)
to clarify my problem i added these two pictures:
current plot http://imgur.com/5uPd4
area i want to know http://imgur.com/WsIbg
Solution to finding surface area inside isoline or contourline at distance r from collection of lines in Matlab, approximation by graphical processing (dilating), not an exact or efficient awnser!
I have made an approximation, so this is not an exact awnser nor is it efficient coding. A friend of mine who studies machine vision suggested converting the lines to pixels and then dilating the image with a disk, after which the pixel count is a measure of surface area:
%# constants and variables
minx = min(xx);
miny = min(yy);
maxx = max(xx);
maxy = max(yy);
rangex = maxx - minx;
rangey = maxy - miny;
borderRelNum = sqrt(2);
electrodeToImageScaleFactor = 100;
imsizex = 2*(maxx+borderRelNum)*electrodeToImageScaleFactor+2;
imsizey = 2*(maxy+borderRelNum)*electrodeToImageScaleFactor+2;
im = zeros(imsizex, imsizey);
grayscalevalue = 255;
disksize = round(borderRelNum*electrodeToImageScaleFactor);
%# transformation matrices
centerElectrodeSpace = [1, 0, -(minx + maxx) / 2;
0, 1, -(miny + maxy) / 2;
0, 0, 1 ];
scaleElectrodeToImage = [electrodeToImageScaleFactor , 0, 0;
0, electrodeToImageScaleFactor , 0;
0, 0, 1 ];
centerImageSpace = [ 1, 0, imsizex / 2;
0, 1, imsizey / 2;
0, 0, 1 ];
electrodeToImage = centerImageSpace * scaleElectrodeToImage * centerElectrodeSpace;
%# transformation
for i = 0:(size(xx,1) / 3 - 1)
p1 = [xx(i*3 + 1); yy(i*3 + 1); 1];
p2 = [xx(i*3 + 2); yy(i*3 + 2); 1];
p1im = electrodeToImage * p1
p2im = electrodeToImage * p2
lx = linspace( min( p1im(1), p2im(1) ), max( p1im(1), p2im(1) ), borderRelNum*electrodeToImageScaleFactor )
ly = linspace( min( p1im(2), p2im(2) ), max( p1im(2), p2im(2) ), borderRelNum*electrodeToImageScaleFactor )
index = sub2ind(size(im),round(lx),round(ly));
im(index) = grayscalevalue;
end
%# Now dilate and count pixels
se = strel('disk', disksize, 0);
im = imdilate(im, se);
image(im)
colormap(gray)
sum(sum(im/grayscalevalue))*(1/electrodeToImageScaleFactor^2)
If someone is able to solve my problem more elegantly, efficiently or more precisely i would still very much appreciate it. But this will do for now.
-edit- ok this is VERY inefficient indeed, my pc has been crunching numbers for 30 minutes on my data set (10 xls files, not that much) now and is still at file 1 it seems if i look at workspace values
How can i Plot an array in a graph against its order in array in matlab ??
Example : x= [6,10,12,20] point 1 become 6:1 and point 3= 12:3 for example even after i remove some elemets from this array i want to preserve same order
example of what am trying to do here is to remove all values bellow mean while keep order cause it represent the time in sec's (this is from video processing code):
m=mean(amp);
for i=totalframes
if (amp(i) >= m)
time(i)=i/framerate;
end
end
amp(amp >= m) = [];
time(time > 0) = [];
figure, plot(time,amp) %% plot my curve
P.s: time and amp array was created by Zeros earlier in my code..
Thanks
If you want to remove all values below the mean m you should do:
inds=(amp<m) %% find where amp is lower than m
amp(inds) = []; %% remove corresponding amp
time(inds) = []; %% remove corresponding time
figure, plot(time,amp)
Change design of x from [6; 10; 12; 20] to [1 6; 2 10; 3 12; 4 20] and traverse this array deleting rows that you dont want then you will have result array with indexes.