Transposing matrix / Trouble understanding how bsxfun works - image

This could be a weird question because Many would be wondering why to use such a complicated function like bsxfun for transposing while you have the .' operator.
But, transposing isn't a problem for me. I frame my own questions and try to solve using specific functions so that i learn how the function actually works. I tried solving some examples using bsxfun and have succeeded in getting desired results. But my thought, that i have understood how this function works, changed when i tried this example.
The example image i've taken is a square 2D image, so that i'm not trying to access an index which is unavailable.
Here is my code:
im = imread('cameraman.tif');
imshow(im);
[rows,cols] = size(im);
imout = bsxfun(#(r,c) im(c,r),(1:rows).',1:cols);
Error i got:
Error using bsxfun
Invalid output dimensions.
Error in test (line 9)
imout = bsxfun(#(r,c) im(c,r),(1:rows).',1:cols);
PS: I tried interchanging r and c inside im( , ) (like this: bsxfun(#(r,c) im(r,c),(1:rows).',1:cols)) which didn't pose any error and i got the same exact image as the input.
I also tried this using loops and simple transpose using .' operator which works perfectly.
Here is my loopy code:
imout(size(im)) = 0;
for i = 1:rows
for j = 1:cols
imout(i,j) = im(j,i);
end
end
Answer i'm expecting is, what is wrong with my code, what does the error signify and how could the code be modified to make it work.

You can use the anonymous function with bsxfun like so -
%// Create the tranposed indices with BSXFUN
idx = bsxfun(#(r,c) (c-1)*size(im,1)+r,1:rows,(1:cols).') %//'
%// Index into input array with those indices for the final transposed output
imout = im(idx)

The problem here is that your function doesn't return an output the same shape as the input it is given. Although the requirement for bsxfun is that the function operates element-wise, it is not called with scalar elements. So, you need to do this:
x = randi(5, 4, 5)
[m, n] = size(x);
bsxfun(#(r, c) transpose(x(c, r)), (1:n)', 1:m)

I wanted to know how bsxfun works so i created a function like this:
bsxfun test function:
function out = bsxfuntest(r,c)
disp([size(r) , size(c)]);
out = r + c; // just normal addition so that it works fine.
end
My script:
im = magic(5);
[rows,cols] = size(im);
bsxfun(#bsxfuntest ,(1:rows).',1:cols);
Output: (not the value of output of the function. These are those which are printed within bsxfuntest.m function using disp)
5 1 1 1
5 1 1 1
5 1 1 1
5 1 1 1
5 1 1 1
Conclusion:
bsxfun passes each column into the function instead of each element.
If either one of the input is a scalar, then the function is called only one time i.e the matrix whether it is 2D or 3D or nD, is passed in one go.
Try this:
bsxfun(#bsxfuntest , repmat(5,[5 5 5]) ,1);
Also if both the inputs are of same dimensions, then also the function is called only one time.
Try this:
bsxfun(#bsxfuntest , repmat(5,[5 5 2]) , repmat(2,[5 5 2]))
If none of them is a scalar, and both the inputs are of different dimensions, then The inputs are passed as column vectors.
Try this:
bsxfun(#bsxfuntest , repmat(5,[5 5 1]) ,permute(1:3,[1 3 2]));
and this:
bsxfun(#bsxfuntest , repmat(5,[5 5 2]) ,permute(1:2,[1 3 2]));
Coming to the problem
>> im
im =
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
Taking the code in the question:
imout = bsxfun(#(r,c) im(c,r),(1:rows).',1:cols);
When i try im(c,r) i.e im(1,(1:5).')
>> im(1,(1:5).')
ans =
17 24 1 8 15
Here, bsxfun expects a column vector while the output is a row vector. I guess that is the reason why MatLab produces an error stating
Invalid output dimensions.
This was also the reason why i didn't get any error when i replaced r and c in the above code like this bsxfun(#(r,c) im(r,c),(1:rows).',1:cols). Because here, the output was a column vector itself.
So i tried to transpose the results to obtain the column vector like this:
>> imout = bsxfun(#(r,c) (im(c,r)).',(1:rows).',1:cols)
imout =
17 23 4 10 11
24 5 6 12 18
1 7 13 19 25
8 14 20 21 2
15 16 22 3 9
The code is exactly the same as Edrics's solution and it gives the expected results.

Related

How to plot on the same graph with for cycles with Gnuplot?

I want to fit multiple data set and plot the result on the same graph, what I' am doing is:
do for [i=2:500]{
fit f(x) "myData" using 1:i via a,b
plot f(x)
}
The fit works fine, the big problem is that this code produce a different plot at each iteration. I would like to have all the fitted functions in a single graph. Is there any way ?
I guess you cannot fit and plot in the same loop. Well, there would be the multiplot environment (check help multiplot), but I guess this is not your idea.
So, you can fit in a do for loop and store the fitted parameters in an array for later use during plotting.
You didn't specify any function, so I assumed something. Check the following minimized example:
Code:
### fitting in a loop
reset session
$Data <<EOD
1 1 6 4
2 4 10 1
3 9 15 0
4 16 22 1
5 25 31 4
6 36 42 9
7 49 55 16
EOD
f(x,a,b,c) = a*(x-b)**2 + c
colMin = 2
colMax = 4
set fit quiet nolog
array A[colMax]
array B[colMax]
array C[colMax]
do for [col=colMin:colMax] {
a=1; b=1; c=1 # some initial values, sometimes 0 or NaN is not a good start
fit f(x,a,b,c) $Data u 1:col via a,b,c
A[col] = a; B[col] = b; C[col] = c
}
set key top left
plot for [col=colMin:colMax] $Data u 1:col w p pt 7 title sprintf("Column %d",col), \
for [col=colMin:colMax] f(x,A[col],B[col],C[col]) w l \
title sprintf("a=%.2f, b=%.2f, c=%.2f",A[col],B[col],C[col])
### end of code
Result:

Matlab best match of a sequence within a matrix

I want to find the best match of a sequence of integers within a NxN matrix. The problem is that I don't know how to extract the position of this best match. The following code that I have should calculate the edit distance but I would like to know where in my grid that edit distance is shortest!
function res = searchWordDistance(word,grid)
% wordsize = length(word); % extract the actual size
% [x ,y] = find(word(1) == grid);
D(1,1,1)=0;
for i=2:length(word)+1
D(i,1,1) = D(i-1,1,1)+1;
end
for j=2:length(grid)
D(1,1,j) = D(1,1,j-1)+1;
D(1,j,1) = D(1,j-1,1)+1;
end
% inspect the grid for best match
for i=2:length(word)
for j=2:length(grid)
for z=2:length(grid)
if(word(i-1)==grid(j-1,z-1))
d = 0;
else
d=1;
end
c1=D(i-1,j-1,z-1)+d;
c2=D(i-1,j,z)+1;
c3=D(i,j-1,z-1)+1;
D(i,j,z) = min([c1 c2 c3]);
end
end
end
I have used this code (in one less dimension) to compare two strings.
EDIT Using a 5x5 matrix as example
15 17 19 20 22
14 8 1 15 24
11 4 17 3 2
14 2 1 14 8
19 23 5 1 22
now If I have a sequence [4,1,1] and [15,14,12,14] they should be found using the algorithm. The first one is a perfect match(diagonal starts at (3,2)). The second one is on the first column and is the closest match for that sequence since only one number is wrong.

effective way of transformation from 2D to 1D vector

i want to create 1D vector in matlab from given matrix,for this i have implemented following algorithm ,which use trivial way
% create one dimensional vector from 2D matrix
function [x]=one_dimensional(b,m,n)
k=1;
for i=1:m
for t=1:n
x(k)=b(i,t);
k=k+1;
end
end
x;
end
when i run it using following example,it seems to do it's task fine
b=[2 1 3;4 2 3;1 5 4]
b =
2 1 3
4 2 3
1 5 4
>> one_dimensional(b,3,3)
ans =
2 1 3 4 2 3 1 5 4
but generally i know that,arrays are not good way to use in matlab,because it's performance,so what should be effective way for transformation matrix into row/column vector?i am just care about performance.thanks very much
You can use the (:) operator...But it works on columns not rows so you need to transpose using the 'operator before , for example:
b=b.';
b(:)'
ans=
2 1 3 4 2 3 1 5 4
and I transposed again to get a row output (otherwise it'll the same vector only in column form)
or also, this is an option (probably a slower one):
reshape(b.',1,[])

fourier and zero padding

I'm filtering an image using a mask and the Discret Fourier Trasform, till now i have this
A=double(imread('C:\Users\samsung\Documents\Lab Imagenes\CHE.jpg','jpg'));
B=[1 4 6 4 1; 4 16 24 16 4; 6 24 36 24 6; 4 16 24 16 4; 1 4 6 4 1];
F=(1/256).*(B);
DFT_A=fftshift(fft2(A));
imshow(DFT_A);
DFT_A_F=DFT_A.*F;
figure
imshow(DFT_A_F)
but when i want to see partial results I got this error
??? Error using ==> times
Matrix dimensions must agree.
Error in ==> fourier1 at 10
DFT_A_F=DFT_A.*F;
I know that i need to do zero padding to the mask, but i don't know how to do it, please I need help
Thanks!
what you want is called 'padarray' , just after you define DFT_A:
padsize= [round(0.5*size(DFT_A,1)-0.5*size(F,1)) round(0.5*size(DFT_A,2)-0.5*size(F,2))];
F = padarray(F, padsize);
DFT_A_F=DFT_A.*F;
...
But why won't you just (given that A is a 2D matrix, so rgb2gray it if needed):
DFT_A_F = conv2(A,B,'same');
It is faster, because you don't need to multiply all these zeros, and should get you the same result.

matlab for loop: fastest and most efficient method to reproduce large matrix

My data is a 2096x252 matrix of double values. I need a for loop or an equivalent which performs the following:
Each time the matrix is reproduced the first array is deleted and the second becomes the first. When the loop runs again, the remaining matrix is reproduced and the first array is deleted and the next becomes the first and so on.
I've tried using repmat but it is too slow and tedious when dealing with large matrices (2096x252).
Example input:
1 2 3 4
3 4 5 6
3 5 7 5
9 6 3 2
Desired output:
1 2 3 4
3 4 5 6
3 5 7 5
9 6 3 2
3 4 5 6
3 5 7 5
9 6 3 2
3 5 7 5
9 6 3 2
9 6 3 2
Generally with Matlab it is much faster to pre-allocate a large array than to build it incrementally. When you know in advance the final size of the large array there's no reason not to follow this general advice.
Something like the following should do what you want. Suppose you have an array in(nrows, ncols); then
indices = [0 nrows:-1:1];
out = zeros(sum(indices),ncols);
for ix = 1:nrows
out(1+sum(indices(1:ix)):sum(indices(1:ix+1)),:) = in(ix:end,:);
end
This worked on your small test input. I expect you can figure out what is going on.
Whether it is the fastest of all possible approaches I don't know, but I expect it to be much faster than building a large matrix incrementally.
Disclaimer:
You'll probably have memory issues with large matrices, but that is not the question.
Now, to the business:
For a given matrix A, the straightforward approach with the for loop would be:
[N, M] = size(A);
B = zeros(sum(1:N), M);
offset = 1;
for i = 1:N
B(offset:offset + N - i, :) = A(i:end, :);
offset = offset + size(A(i:end, :), 1);
end
B is the desired output matrix.
However, this solution is expected to be slow as well, because of the for loop.
Edit: preallocated B instead of dynamically changing size (this optimization should achieve a slight speedup).

Resources