Subtraction by tracking x y coordinates - matlab

I have set of arrays:
x1=[1 2 3 4 5 6 7 8 9];
y1=[1 2 3 4 5 6 7 8 9];
z1=[2 2 2 2 2 9 6 2 2];
and
x2=[6 7];
y2=[6 7];
z2=[2 2];
by tracking x y coordinates, the z arrays have to be subtracted so that output will be
x=[1 2 3 4 5 6 7 8 9];
y=[1 2 3 4 5 6 7 8 9];
z=[2 2 2 2 2 7 4 2 2];

You can get the indicies of your elements in z using the ismember function:
a1=[x1.',y1.'];
a2=[x2.',y2.'];
[~,ix]=ismember(a2,a1,'rows')
z1(ix)=z1(ix)-z2
To use the ismember two matrices a1 and a2 are created witch contain the coordinates in rows. Then ismember with 'rows' option is used to get the indices.
When a point exists in x2/y2 which does not exist in x1/y1 the above code will fail.

Related

Determining how many elements in a matrix are equal or bigger compared to another matrix element-wise

Let's say:
a = 1 2 3
4 5 6
7 8 9
b = 3 2 1
6 5 4
9 8 7
So in MATLAB: a = [1 2 3; 4 5 6; 7 8 9]; b = [3 2 1; 6 5 4; 9 8 7];. I want to know how many elements in a are equal or bigger than the element in the same place in b. So in this example, the result will be 6.
Let
a = [1 2 3
4 5 6
7 8 9];
b = [3 2 1
6 5 4
9 8 7];
then the expression
c = a>=b;
gives you the positions of the elements where a is larger than b.
sum(c(:));
Gives you the number of such elements.

Reshape MATLAB matrix with repeated indicies

I apologize if this is a repeated question.
Suppose I have a matrix A
0 1 2 3 4 5 6 7
8 9 1 2 3 4 5 6
and a vector b [1,2,3,4,1,2,3,4]. Thus, matrix A contains multiple ordered measurements based on vector b.
How can I reshape the matrix to have dimension [2 2 4], such that A(:,:,1) = [0,4;8,3]?
I understand I need to reshape. I tried using permute, however it does not handle repeated indices.
Thanks!
You are close, you just need to sort the columns before reshaping them
A=[0 1 2 3 4 5 6 7; 8 9 1 2 3 4 5 6]
%A =
% 0 1 2 3 4 5 6 7
% 8 9 1 2 3 4 5 6
b=[1,2,3,4,1,2,3,4]
%b =
% 1 2 3 4 1 2 3 4
[~,idx]=sort(b)
%idx =
% 1 5 2 6 3 7 4 8
A=A(:,idx)
%A =
% 0 4 1 5 2 6 3 7
% 8 3 9 4 1 5 2 6
A=reshape(A,[2,2,4])
%A(:,:,1) =
% 0 4
% 8 3
%A(:,:,2) =
% 1 5
% 9 4
%A(:,:,3) =
% 2 6
% 1 5
%A(:,:,4) =
% 3 7
% 2 6
Be careful, this will only work if you can assure that each number in b is repeated same number of times.
Assuming your b is always some repeated 1:n pattern like it is in your question, you can use:
p=4 % number of indices
permute(reshape(A,size(A,1),p,[]),[1,3,2])

How to randomly permute some matrix into a bigger matrix in Matlab?

This is the main matrix:
a =
1 2 3 3 4 5 2 5 7
3 4 5 5 6 8 6 4 9
This main matrix contain 3 small matrix. The first one is:
[1 2 3;3 4 5]
The second one is:
[3 4 5;5 6 8]
The third one is:
[2 5 7;6 4 9]
I want to randomly permute these 3 matrix into the main matrix like this:
a =
2 5 7 3 4 5 1 2 3
6 4 9 5 6 8 3 4 5
How I can do that?
If you connect three 2D matrices, it is better to use a 3D matrix:
%get a 3d matrix
b=reshape(a,size(a,1),3,[]);
%randomly permute third dimension
c=b(:,:,randperm(size(b,3)));
%return to 2d representation
d=reshape(c,size(a));

How to duplicate elements of a matrix without using the repmat function

Given the matrix I = [1,2;3,4], I would like to duplicate the elements to create a matrix I2 such that:
I2 = [1 1 1 2 2 2
1 1 1 2 2 2
1 1 1 2 2 2
3 3 3 4 4 4
3 3 3 4 4 4
3 3 3 4 4 4]
Other than using repmat, what other methods or functions are available?
Use kron:
>> N = 3 %// Number of times to replicate a number in each dimension
>> I = [1,2;3,4];
>> kron(I, ones(N))
ans =
1 1 1 2 2 2
1 1 1 2 2 2
1 1 1 2 2 2
3 3 3 4 4 4
3 3 3 4 4 4
3 3 3 4 4 4
This probably deserves some explanation in case you're not aware of what kron does. kron stands for the Kronecker Tensor Product. kron between two matrices A of size m x n and B of size p x q creates an output matrix of size mp x nq such that:
Therefore, for each coefficient in A, we take this value, multiply it with every value in the matrix B and we position these matrices in the same order as we see in A. As such, if we let A = I, and B be the 3 x 3 matrix full of ones, you thus get the above result.
Using indexing:
I = [1, 2; 3, 4]; %// original matrix
n = 3; %// repetition factor
I2 = I(ceil(1/n:1/n:size(I,1)), ceil(1/n:1/n:size(I,2))); %// result
One-liner with bsxfun -
R = 3; %// Number of replications
I2 = reshape(bsxfun(#plus,permute(I,[3 1 4 2]),zeros(R,1,R)),R*size(I,1),[])
Sample run -
I =
3 2 5
9 8 9
I2 =
3 3 3 2 2 2 5 5 5
3 3 3 2 2 2 5 5 5
3 3 3 2 2 2 5 5 5
9 9 9 8 8 8 9 9 9
9 9 9 8 8 8 9 9 9
9 9 9 8 8 8 9 9 9

Rearranging matrix using col2im in Matlab

My matrix is this:
0 3 0
0 1 2
4 4 1
I use im2col on it like this:
im2col(A, [2 2], 'sliding')
which correctly yields this:
0 0 3 1
0 4 1 4
3 1 0 2
1 4 2 1
I call this matrix K. Now I use col2im to go back to my original matrix. From the Matlab documentation I use this:
col2im(K, [2 2], [5 5],'sliding')
But this doesn't gives me my original matrix A. Reason being [5 5] should be [4 4] to get a 3*3 matrix for starters. But when I do that I get
??? Error using ==> reshape
To RESHAPE the number of elements must not change.
Why is that? And how can I get my original matrix back?
Fromthe docs:
A = col2im(B,[m n],[mm nn],'sliding') rearranges the row vector B into
a matrix of size (mm-m+1)-by-(nn-n+1). B must be a vector of size
1-by-(mm-m+1)*(nn-n+1). B is usually the result of processing the
output of im2col(...,'sliding') using a column compression function
(such as sum).
So that says to me you should be trying something like:
col2im(sum(K), [2 2], [4 4],'sliding')
however that would require K to have 9 columns. I don't have the image processing toolbox handy to test this right now
Your col2im doesn't work because it uses reshape and for that the number of elements of the matrix you wish to reshape (K) and the new one, need to be the same. This is not the case anymore, as through your transformation of A with im2col you obviously changed that. A has 9 and K 16 elements.
So you basically need to get back to a 3*3 matrix again by getting rid of the redundand doubled elements (due to the overlapping 2*2 blocks used in im2col) in K.
For that you could just make a new matrix (C) with the elements that you need:
C = [K([1,3,11;2,4,12;6,8,16])]
As long as you first went from a 3*3 to a 4*4 matrix using the same order of blocks this should work.
Maybe you could tell us more about what you really want to achieve, because I don't see any reason for this in the first place. It may also be possible that you might be better off using other functions instead, but I can only see that if I know what the reasoning behind your question is.
clear
clc
img = double(imread('tire.tif'));
[r c] = size(img);
w = 8;
imgBlock = im2col(img,[w w],'sliding'); imgBlock = imgBlock(:);
[x y] = meshgrid(1:c,1:r);
xx = im2col(x,[w w], 'sliding'); xx = xx(:);
yy = im2col(y,[w w], 'sliding'); yy = yy(:);
img2 = accumarray([yy xx], imgBlock, [], #mean);
figure,imshow(img, []);
figure,imshow(img2,[]);
% random matrix as image
img = randi(10,4)
img =
6 2 2 7
5 8 7 8
1 4 3 5
4 6 7 1
% matrix size
[r c] = size(img)
% patch size
w = 2;
% image to patch
imgBlock = im2col(img,[w w],'sliding')
% image patchs matrix to a vector
imgBlock = imgBlock(:);
r =
4
c =
4
imgBlock =
6 5 1 2 8 4 2 7 3
5 1 4 8 4 6 7 3 7
2 8 4 2 7 3 7 8 5
8 4 6 7 3 7 8 5 1
% index matrix size equal image size
[x y] = meshgrid(1:c,1:r)
% index matric to patchs;to vector
xx = im2col(x,[w w], 'sliding'); xx = xx(:);
yy = im2col(y,[w w], 'sliding'); yy = yy(:);
x =
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
y =
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
% yy :row index xx: column index
% applies the function mean to each subset of elements in imgBlock that have identical subscripts in [yy xx].
img2 = accumarray([yy xx], imgBlock, [], #mean);
img
img2
img =
6 2 2 7
5 8 7 8
1 4 3 5
4 6 7 1
img2 =
6 2 2 7
5 8 7 8
1 4 3 5
4 6 7 1
% [col,row,value]
a = [xx,yy,imgBlock]
a =
1 1 6
1 2 5
2 1 2
2 2 8
1 2 5
1 3 1
2 2 8
2 3 4
1 3 1
1 4 4
2 3 4
2 4 6
2 1 2
2 2 8
3 1 2
3 2 7
2 2 8
2 3 4
3 2 7
3 3 3
2 3 4
2 4 6
3 3 3
3 4 7
3 1 2
3 2 7
4 1 7
4 2 8
3 2 7
3 3 3
4 2 8
4 3 5
3 3 3
3 4 7
4 3 5
4 4 1
% The number of times that img(2,2) occurs in the matrix img
a(xx == 2 & yy == 2,:)
ans =
2 2 8
2 2 8
2 2 8
2 2 8