resize matrix in matlab - matlab

i was using the function "resizem" to expand the size of my matrix, without erasing the data. recently, after using the function, it sends me an error that the function cannot use integers of type double. i have tried to use abs().^2 on my matrix but it didn't work.
is there any other function that can do the same?
note: i need the data to not change, so if i have an matrix
A = [-1 0 2; 4 1 2] i want it to become a 5x5 matrix like so:
A = [-1 -0.5 0 1 2; 4 2.5 1 1.5 2]
Also, I have tried the function 'imresize', and gives me the same problem as the resizem. (I own both the tool box, and my matrix is in type double)

If A = [-1 0 2; 4 1 2] you could do something like A = [A, [1, 2; 1.5 2]] to get A = [-1 -0.5 0 1 2; 4 2.5 1 1.5 2].

I would try to go for imresize (which is part of the Image Processing Toolbox). I never used those functions, but looking at the error you are receiving, which is related to variable types, the new option should provide more flexibility. In fact, while resizem returns double precision output, imresize returns an output of the same type as the input.
A = [-1 0 2; 4 1 2];
imresize(A,[2 5]);
The example shows how to use it. I also tested both outcomes:
A = [-1 0 2; 4 1 2];
A_imr = imresize(A,[2 5]);
A_rem = resizem(A,[2 5]);
This is the result for imresize:
A_imr:
-1,08000000000000 -0,720000000000000 -1,77635683940025e-15 1,29600000000000 2,16000000000000
4,24000000000000 2,82400000000000 1,00000000000000 1,48000000000000 2,08000000000000
This is the result for resizem:
A_rem :
-1 -1 0 2 2
4 4 1 2 2
For further tinkering, try to play with scale and method arguments. In imresize, for example, you need to specify the appropriate interpolation kernel to achive averaging.

Related

matlab how to get the derivative of a pchip interpolation function based on some discrete points

I have some data like
interesting_data =
-0.5665 -0.5329 -0.2251 0.2251 0.5329 0.5689
It is obvious there is a zero cross between index 3 and 4. I found I can use this function to get the zero cross point of pchip interpolation.
fzero(#(xi)interp1(1:1:length(interesting_data),interesting_data,xi,'pchip'),3)
So I believe matlab have a behind function for the pchip interpolation between [3,4]. Suppose the pchip module will generate the equation as y = ax^2+bx+C, x is within [3,4[, or something like that. I hope to know the fomular, then I can calculate the derivation at the zero-crossing position, in this case, x=3.5.
Is there any way to do that? Or any function to tell the derivation directly from the hidden equation?
Why not just see when the sign flips. Here is your array and signs:
array =[ -0.5665 -0.5329 -0.2251 0.2251 0.5329 0.5689];
sign(array)
ans =
-1 -1 -1 1 1 1
When the sign changes, it will return 2 or -2
diff(sign(array))
ans =
0 0 2 0 0
So just find the nonzeros
find(abs(diff(sign(array))))
ans =
3
Lets try it for another array
array=randn(1,10)
array =
1.42837429557213 1.40677399588789 0.257616732589725 -0.93068654061524 0.391997711945428 1.53494945223268 -1.03683690895487 0.126547794228052 -0.394102426308772 -0.562889126426436
diff(sign(array))
ans =
0 0 -2 2 0 -2 2 -2 0
find(diff(sign(array)))
ans =
3 4 6 7 8

Comparing Vectors of Different Length

I am trying to compare two vectors of different size. For instance when I run the code below:
A = [1 4 3 7 9];
B = [1 2 3 4 5 6 7 8 9];
myPadded = [A zeros(1,4)];
C = ismember(myPadded,B)
I get the following output:
C = 1 1 1 1 1 0 0 0 0
However, I want an output that will reflect the positions of the compared values, hence, I would like an output that is displayed as follows:
C = 1 0 1 1 0 0 1 0 1
Please, I need some help :)
There are 2 points. First, you are writing the inputs of ismember in the wrong order. Additionally, you do not need to grow your matrix. Simply try ismember(B, A) and you will get what you expect.
The function ismember(myPadded, B) returns a vector the same size of myPadded, indicating if the i-th element of myPadded is present in B.
To get what you want, just invert parameter order: ismember(B, myPadded).
A quick way of doing this is to use logical indexing. This will only work if the last digit of B is included in A.
A = [1 4 3 7 9];
c(A) = 1; % or true.
An assumption here is that you want to subindex a vector 1:N, so that B always is B = 1:N. In case the last digit is not one this is easy to fix. Just remember to return all to its previous state after you are done. It will be 2 rows extra though.
This solution is meant as a special case working on a very common problem.

How to generate random numbers from fixed set

I've got fixed numbers: -3, -1, 1, 3. How do I randomly generate a matrix like the following?
1 -1 -3 -1
3 -3 -3 3
3 3 1 -1
3 -3 3 -1
Use randi to create random index values into your vector of possible values:
x = [-3 -1 1 3]
y = randi(length(x),[5 5]);
y = x(y);
Although #nkjt's answer is probably the way to go, if you have the Statistics Toolbox you can simplify a little using randsample (with replacement):
result = NaN(3,6); %// define required size
result(:) = randsample([-3 -1 1 3], numel(result), true);
Or, if the original numbers are equally spaced as in your example, you can solve it in one line:
result = 2*randi(4,[3 6])-5; %// "2" and "5" as per your original values
You can use
randperm Random permutation

neighbor analysis in MATLAB

I have an m-by-n matrix named A, with values 1s and 0s. I want to convert all 0s values to 1s if at least 5 out of 8 neighbor pixels are 1s. What I tried is to use the nlfilter function, but I'm not getting how the arg fun should be used, and I would need a help.
I created a function as handle for nlfilter as following:
function b = gap_fill(A)
b=A;
index= A([1 2 3 4 6 7 8 9]);
if sum(index)>=5
b(5)= 1
end
end
Then I tried to do this:
B= nlfilter(A,[3 3],#gap_fill)
But it gave this error:
??? Subscripted assignment dimension mismatch.
Error in ==> nlfilter at 75
b(i,j) = feval(fun,x,params{:});
Any suggestion? The main problem is I'm not used to handle functions.
= UPDATING =
I finally came up with a good result. I changed my function to output a scalar and when I use it as fun arg in nlfilter it work the way I want. This is my code, thanks for helping and I hope it could be useful for anybody:
function b = gap_fill(A)
index= A([1 2 3 4 6 7 8 9]);
if sum(index)>=5
A(5)= 1;
end
b=A(5);
end
In MATLAB:
b= nlfilter (A,[3 3],'gap_fill')
You can do it in one line with blockproc:
B = blockproc(A,[1 1],#(x)sum(x.data(:)),'BorderSize',[1 1],'TrimBorder',0)-A>=5;
For example,
A =
1 0 1 1 0
0 0 0 1 1
1 1 1 1 1
0 1 0 1 1
gives the result
B =
0 0 0 0 0
0 1 1 1 0
0 0 1 1 1
0 0 1 0 0
Note that border pixels of the image are handled correctly, thanks to using the 'BorderSize' option of blockproc.
To keep the original ones in A, apply a final "or" operation:
B = B|A;
I think it is because the documentation for nlfilter says that the user function must return a scalar and you are trying to return a matrix.
B = nlfilter(A, [m n], fun) applies the function fun to each m-by-n sliding block
of the grayscale image A. fun is a function that accepts an m-by-n matrix as input
and returns a scalar (!!!) result.
For a solution that's slightly faster than blockproc, you can use a 2D convolution:
mask = ones(3);
mask(5) = 0;
B = conv2(A,mask,'same') >= 5;
To make this even faster (you'll only notice this if the arrays become larger), you can make use of the fact that an average filter is separable:
B = conv2(conv2(A,ones(1,3),'same'),ones(3,1),'same') - A >= 5;
The fun function must return an scalar in your case it returns a matrix. from matlab
B = nlfilter(A, [m n], fun) applies the function fun to each m-by-n sliding block of the grayscale image A. fun is a function that accepts an m-by-n matrix as input and returns a scalar result.
c = fun(x)
so your code shoud be There are better ways to code it,specially with amtrix but following your sample:
function b = gap_fill(A)
index= A([1 2 3 4 6 7 8 9]);
if A(5)sum(index)>=5
b = 1;
else
b = A(5);
end
end
Sorry for the error I change b = 0 to b= A(5)

MATLAB - Efficient methods for populating matrices using information in other (sparse) matrices?

Apologies for the awkward title, here is a more specific description of the problem. I have a large (e.g. 10^6 x 10^6) sparse symmetric matrix which defines bonds between nodes.
e.g. The matrix A = [0 1 0 0 0; 1 0 0 2 3; 0 0 0 4 0; 0 2 4 0 5; 0 3 0 5 0] would describe a 5-node system, such that nodes 1 and 2 are connected by bond number A(1,2) = 1, nodes 3 and 4 are connected by bond number A(3,4) = 4, etc.
I want to form two new matrices. The first, B, would list the nodes connected to each node (i.e. each row i of B has elements given by find(A(i,:)), and padded with zeros at the end if necessary) and the second, C, would list the bonds connected to that node (i.e. each row i of C has elements given by nonzeros(A(i,:)), again padded if necessary).
e.g. for the matrix A above, I would want to form B = [2 0 0; 1 4 5; 4 0 0; 2 3 5; 2 4 0] and C = [1 0 0; 1 2 3; 4 0 0; 2 4 5; 3 5 0]
The current code is:
B=zeros(length(A), max(sum(spones(A))))
C=zeros(length(A), max(sum(spones(A))))
for i=1:length(A)
B(i,1:length(find(A(i,:)))) = find(A(i,:));
C(i,1:length(nonzeros(A(i,:)))) = nonzeros(A(i,:));
end
which works, but is slow for large length(A). I have tried other formulations, but they all include for loops and don't give much improvement.
How do I do this without looping through the rows?
Hmm. Not sure how to vectorize (find returns linear indices when given a matrix, which is not what you want), but have you tried this:
B=zeros(length(A), 0);
C=zeros(length(A), 0);
for i=1:length(A)
Bi = find(A(i,:));
B(i,1:length(Bi)) = Bi;
Ci = nonzeros(A(i,:));
C(i,1:length(Ci)) = Ci;
end
I made two changes:
removed call to spones (seems unnecessary; the performance hit needed to expand the # of columns in B and C is probably minimal)
cached result of find() and nonzeros() so they're not called twice
I know it's hard to read, but that code is a vectorized version of your code:
[ i j k ] = find(A);
A2=(A~=0);
j2=nonzeros(cumsum(A2,2).*A2);
C2=accumarray([i,j2],k)
k2=nonzeros(bsxfun(#times,1:size(A,2),A2));
B2=accumarray([i,j2],k2);
Try it and tell me if it works for you.