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

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

Related

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])

Enlarge matrix repeating its values [duplicate]

This question already has answers here:
Replicate matrix one row at a time [duplicate]
(2 answers)
Closed 6 years ago.
I need to enlarge a matrix A to a matrix B with size n times the size of A. The values must be repeated, eg:
A size 2x3, n = 3, leads to B size 6x9:
Sample values:
A =
1 2 3
4 5 6
Results with:
B =
1 1 1 2 2 2 3 3 3
1 1 1 2 2 2 3 3 3
1 1 1 2 2 2 3 3 3
4 4 4 5 5 5 6 6 6
4 4 4 5 5 5 6 6 6
4 4 4 5 5 5 6 6 6
What is the fastest way to achieve that in Matlab?
There is also the Kronecker Tensor Product (kron) function:
n = 3;
B = kron(A,ones(n));
B =
1 1 1 2 2 2 3 3 3
1 1 1 2 2 2 3 3 3
1 1 1 2 2 2 3 3 3
4 4 4 5 5 5 6 6 6
4 4 4 5 5 5 6 6 6
4 4 4 5 5 5 6 6 6
If you have the Image Processing Toolbox you can easily do this using imresize with nearest neighbor interpolation.
A = [1 2 3; 4 5 6];
% Repeat each element 3 times in each direction
B = imresize(A, 3, 'nearest');
% 1 1 1 2 2 2 3 3 3
% 1 1 1 2 2 2 3 3 3
% 1 1 1 2 2 2 3 3 3
% 4 4 4 5 5 5 6 6 6
% 4 4 4 5 5 5 6 6 6
% 4 4 4 5 5 5 6 6 6
If you don't have the Image Processing Toolbox, you can use interp2 with nearest neighbor interpolation to do something similar.
scaleFactor = 3;
[xx,yy] = meshgrid(linspace(1, size(A, 2), size(A, 2) * scaleFactor), ...
linspace(1, size(A, 1), size(A, 1) * scaleFactor));
B = interp2(A, xx, yy, 'nearest');

Given a number, Generate a series of 'L' shaped matrix with MATLAB

Given any number. Lets say for example 5, I need to generate a matrix similar to this:
1 2 3 4 5
2 2 3 4 5
3 3 3 4 5
4 4 4 4 5
5 5 5 5 5
How to generate a matrix similar to this using Matlab?
I'd use bsxfun:
n = 5;
matrix = bsxfun(#max, 1:n, (1:n).');
An alternative (probably slower) is to use ndgrid:
n = 5;
[ii, jj] = ndgrid(1:n);
matrix = max(ii, jj);
Nothing will ever beat bsxfun as used by Luis Mendo., but for the sake of reminding people of the existence of Matlab's gallery function, here another approach:
n = 5;
A = gallery('minij',n)
B = n + 1 - A(end:-1:1,end:-1:1)
A =
1 1 1 1 1
1 2 2 2 2
1 2 3 3 3
1 2 3 4 4
1 2 3 4 5
B =
1 2 3 4 5
2 2 3 4 5
3 3 3 4 5
4 4 4 4 5
5 5 5 5 5

how to split a matrix of size 88x88 in 4 parts in matlab

so far i have done
Declare a random Matrix M of size 88 x 88
Type of M should be uint8 (all values should be between 0 to 255).
Spilt the Matrix into 4 parts: p1, p2, p3, p4
Transpose all parts
Concatenate all these four parts into new matrix N
Approach #1
If you have the Image Processing Toolbox, you can use blockproc for a pretty straight-forward solution to this -
fun = #(block_struct) transpose(block_struct.data);
N = blockproc(M, [size(M,1)/2 size(M,2)/2], fun)
Approach #2
Let's suppose you have an input matrix of size m x n and you would like to partition it into dim1p parts along the rows and dim2p parts along the columns, so that each block is of size m/dim1p x n/dim2p and you would like transpose them and finally concatenate them back to form a 2D array. This could be thought of as a general case of what you had proposed in the question.
To solve such a case with performance in mind, you can use this -
[m,n] = size(M); %// Get size
dim1p = 2; %// number of parts to be partitioned along dimension-1 (rows)
dim2p = 2; %// number of parts to be partitioned along dimension-2 (columns)
%// Split and transpose, resulting in a 3D array
A = reshape(permute(reshape(M, m, n/dim2p, []), [2 1 3]), n/dim2p, m/dim1p, []);
%// Join the 3D slices back into a 2D array for the desired output
nrows = n*dim1p/dim2p;
N = reshape(permute(reshape(permute(A,[1 3 2]),nrows,dim2p,[]),[1 3 2]),nrows,[])
Sample run (assuming M as 9 x 8 sized and partitioning it into 3 and 4 parts along the rows and columns respectively so that each block is of size 3 x 2) -
M =
5 6 2 6 4 2 1 3
2 8 8 1 3 8 3 7
5 1 6 8 4 1 6 8
6 5 7 3 3 6 7 1
4 3 9 3 2 2 5 3
4 9 5 7 6 2 2 1
7 6 2 5 9 3 5 6
8 9 5 6 9 6 7 1
1 1 3 3 4 9 1 3
dim1p =
3
dim2p =
4
N =
5 2 5 2 8 6 4 3 4 1 3 6
6 8 1 6 1 8 2 8 1 3 7 8
6 4 4 7 9 5 3 2 6 7 5 2
5 3 9 3 3 7 6 2 2 1 3 1
7 8 1 2 5 3 9 9 4 5 7 1
6 9 1 5 6 3 3 6 9 6 1 3
You are not much clear in the question, Maybe this helps,
M = uint8(randi([0 255],[88 88]));
p1 = M(1:end/2 ,1:end/2 );
p2 = M(1:end/2 ,end/2+1:end);
p3 = M(end/2+1:end,1:end/2 );
p4 = M(end/2+1:end,end/2+1:end);
N = [p1' p2';p3' p4'];
Another approach would be to use mat2cell to split up the matrix into a 2 x 2 grid of cells, transpose each of the cell's contents using cellfun, then piece them all together using cell2mat. Therefore:
[rows, cols] = size(M);
C = mat2cell(M, [rows/2, rows/2], [cols/2, cols/2]);
D = cellfun(#transpose, C, 'uni', 0);
out = cell2mat(D);
Minor note: This only works when the rows and columns are both even.

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