Extracting a 3x3 matrix from an image [duplicate] - matlab

This question already has an answer here:
How to divide a matrix into equals parts?
(1 answer)
Closed 9 years ago.
I need to extract a 3x3 matrix from an image and store it separately, and it should continue like this till the end of image. For example, my image is the following matrix:
p = [ 1 2 3 4 5 6 7 8 9; ...
1 2 3 4 5 6 7 8 9; ...
1 2 3 4 5 6 7 8 9; ...
1 2 3 4 5 6 7 8 9; ...
1 2 3 4 5 6 7 8 9; ...
1 2 3 4 5 6 7 8 9 ]
The output should be like this:
p1 = [1 2 3; 1 2 3; 1 2 3]
p2 = [4 5 6; 4 5 6; 4 5 6]
p3 = [7 8 9; 7 8 9; 7 8 9]
and so on....
Can you please suggest me code or a built-in function for this?

Simplest way to extract submatrices:
p1 = img(1:3, 1:3);
p2 = img(4:6, 4:6);
p3 = img(7:9, 7:9);
Function for doing slicing.
function imgsl = img_slice( img, ry, rx )
[ Y X ] = meshgrid(ry, rx);
imgsl = reshape(img(sub2ind(size(img),Y(:),X(:))),[length(rx) length(ry)]).';
Use it as follows:
p1 = img_slice( p, 1:3, 1:3 );
p2 = img_slice( p, 4:6, 4:6 );
p3 = img_slice( p, 7:9, 7:9 );

The image processing toolbox has a im2col function (link).
B = im2col(p, [3 3], 'distinct');
Then each column of B is a 3x3 block made into a vector, and you can use reshape(B(:, i), 3, 3) to recover the i-th 3x3 block. Note there are zeros padded to p.

Related

Find which matrix row has values specified from array

How can I find which row in a matrix has a specified set values that I entered in an array?
So for example;
A = [4 5 6 7;
8 4 5 6;
4 5 6 8;
8 4 8 9;
1 2 2 4;
5 3 4 6];
and I want to find which row has the vector of [4 5 6 8]
You can use a combination of all and find...
With implicit expansion (R2016b or newer)
find( all( A == [4 5 6 8], 2 ) )
Equivalently you can use bsxfun (compatible with all MATLAB versions)
find( all( bsxfun( #eq, A, [4 5 6 8] ), 2 ) )
The output in both cases is 3 from your example A.
I would go for #Wolfie's approach, assuming order matters.
Another possibility is to use ismember. This can be used both when order matters and when it doesn't. Let
A = [4 5 6 7; 8 4 5 6; 4 5 6 8; 8 4 8 9; 1 2 2 4; 5 3 4 6];
v = [4 5 6 8];
If order matters:
result = find(ismember(A, v, 'rows'));
If order doesn't matter:
result = find(all(ismember(A, v), 2));

How to combine matrix of different size in a cell array into a matrix in MATLAB

Similarly to How to combine vectors of different length in a cell array into matrix in MATLAB I would like to combine matrix having different dimension, stored in a cell array, into a matrix having zeros instead of the empty spaces. Specifically, I have a cell array {1,3} having 3 matrix of size (3,3) (4,3) (4,3):
A={[1 2 3; 4 5 6; 7 8 9] [1 2 3; 4 5 6; 7 8 9; 9 9 9] [1 2 3; 4 5 6; 7 8 9; 4 4 4]}
and I would like to obtain something like:
B =
1 2 3 1 2 3 1 2 3
4 5 6 4 5 6 4 5 6
7 8 9 7 8 9 7 8 9
0 0 0 9 9 9 4 4 4
I tried using cellfun and cell2mat but I do not figure out how to do this. Thanks.
Even if other answers are good, I'd like to submit mine, using cellfun.
l = max(cellfun(#(x) length(x),A))
B = cell2mat(cellfun(#(x) [x;zeros(l-length(x),3)], A, 'UniformOutput', 0));
Using bsxfun's masking capability -
%// Convert A to 1D array
A1d = cellfun(#(x) x(:).',A,'Uni',0) %//'
%// Get dimensions of A cells
nrows = cellfun('size', A, 1)
ncols = cellfun('size', A, 2)
%// Create a mask of valid positions in output numeric array, where each of
%// those numeric values from A would be put
max_nrows = max(nrows)
mask = bsxfun(#le,[1:max_nrows]',repelem(nrows,ncols)) %//'
%// Setup output array and put A values into its masked positions
B = zeros(max_nrows,sum(ncols))
B(mask) = [A1d{:}]
Sample run
Input -
A={[1 2 3 5 6; 7 8 9 3 8] [1 2 3; 4 5 6; 7 8 9; 9 9 9] [1 2 3; 4 5 6; 7 8 9; 4 4 4]}
Output -
B =
1 2 3 5 6 1 2 3 1 2 3
7 8 9 3 8 4 5 6 4 5 6
0 0 0 0 0 7 8 9 7 8 9
0 0 0 0 0 9 9 9 4 4 4
I would be surprised if this is possible in one or a few lines. You will probably have to do some looping yourself. The following achieves what you want in the specific case of incompatible first dimension lengths:
A={[1 2 3; 4 5 6; 7 8 9] [1 2 3; 4 5 6; 7 8 9; 9 9 9] [1 2 3; 4 5 6; 7 8 9; 4 4 4]}
maxsize = max(cellfun(#(x) size(x, 1), A));
B = A;
for k = 1:numel(B)
if size(B{k}, 1) < maxsize
tmp = B{k};
B{k} = zeros(maxsize, size(tmp,1));
B{k}(1:size(tmp,1),1:size(tmp,2)) = tmp;
end
end
B = cat(2, B{:});
Now B is:
B =
1 2 3 1 2 3 1 2 3
4 5 6 4 5 6 4 5 6
7 8 9 7 8 9 7 8 9
0 0 0 9 9 9 4 4 4
I would do it using a good-old for loop, which is quite intuitive I think.
Here is the commented code:
clc;clear var
A={[1 2 3; 4 5 6; 7 8 9] [1 2 3; 4 5 6; 7 8 9; 9 9 9] [1 2 3; 4 5 6; 7 8 9; 4 4 4]};
%// Find the maximum rows and column # to initialize the output array.
MaxRow = max(cell2mat(cellfun(#(x) size(x,1),A,'Uni',0)));
SumCol = sum(cell2mat(cellfun(#(x) size(x,2),A,'Uni',0)));
B = zeros(MaxRow,SumCol);
%// Create a counter to keep track of the current columns to fill
ColumnCounter = 1;
for k = 1:numel(A)
%// Get the # of rows and columns for each cell from A
NumRows = size(A{k},1);
NumCols = size(A{k},2);
%// Fill the array
B(1:NumRows,ColumnCounter:ColumnCounter+NumCols-1) = A{k};
%// Update the counter
ColumnCounter = ColumnCounter+NumCols;
end
disp(B)
Output:
B =
1 2 3 1 2 3 1 2 3
4 5 6 4 5 6 4 5 6
7 8 9 7 8 9 7 8 9
0 0 0 9 9 9 4 4 4
[max_row , max_col] = max( size(A{1}) , size(A{2}) , size(A{3}) );
A{1}(end:max_row , end:max_col)=0;
A{2}(end:max_row , end:max_col)=0;
A{3}(end:max_row , end:max_col)=0;
B=[A{1} A{2} A{3}];
for this specific problem, simply this will do:
B=cat(1,A{:});
or what I often just give a try for 2D cells, and works for your example as well:
B=cell2mat(A');
if you literally don't give a f* what dimension it will be cut in (and you're exceedingly lazy): put the same into a try-catch-block and loop over some dims as below.
function A=cat_any(A)
for dims=1:10% who needs more than 10 dims? ... otherwise replace 10 with: max(cellfun(#ndims,in),[],'all')
try, A=cat(dims,A{:}); end
if ~iscell(A), return A; end
end
disp('Couldn''t cat!') %if we can't cat, tell the user
end
Beware, this might lead to unexpected results ... but in most cases simply just worked for me.

Repeat each row of a matrix

I have variable A of size m by n. I want to generate B of size m by m*n, such as below example.
Example:
A = [1 2 3;
4 5 6;
7 8 9]
Should result with
B = [1 2 3 4 5 6 7 8 9;
1 2 3 4 5 6 7 8 9;
1 2 3 4 5 6 7 8 9]
Is there any way to do that without using loop? m and n is variable.
You should use the repmat Matlab funtion:
B = repmat(A,M,N) creates a large matrix B consisting of an M-by-N
tiling of copies of A. The size of B is [size(A,1)*M, size(A,2)*N].
The statement repmat(A,N) creates an N-by-N tiling.
For your specific case one solution may be:
A=A';
B=repmat(A(:)',3,1);
And for the general case one solution may be:
A_aux=reshape(A',1,size(A,1)*size(A,2));
B=repmat(A_aux,size(A,1),1);
Repmat is indeed the way to go here, as mentioned by #Nerea. This solution should give the same answer as his, but personally I consider it to be a bit more elegant:
B=repmat(reshape(A',1,[]),size(A,1),1);
To include a quite fast bsxfun solution:
A = [1 2 3 4;
5 6 7 8;
9 10 11 12]
A = A.' %'
B = bsxfun(#plus,zeros(size(A,2),1),A(:).')
or use kron, but its surely slower:
A = A.'
B = kron(A(:),ones(1,size(A,2))).'
B =
1 2 3 4 5 6 7 8 9 10 11 12
1 2 3 4 5 6 7 8 9 10 11 12
1 2 3 4 5 6 7 8 9 10 11 12
No repmats
[m n] = size(A);
B = ones(m,1) * reshape( A.', 1, [] );
One approach
with repmat, reshape and permute combo!
out = repmat(reshape(permute(A,[3 2 1]),1,[]),size(A,1),1,1);
or Another approach without reshape but becomes a 2 liner
out1 = permute(A,[3 2 1]);
out = repmat(out1(:).',size(A,1),1,1);

Markertype of scatter points in Matlab based on condition

Suppose I have the following data:
xData = [4 7 2 1 2 8 7 1 1 3];
yData = [1 2 3 4 5 6 7 8 9 10];
P = [5 10 4 2 7 3 8 1 9 3];
I want to use a different markertype based on P. If the corresponding element in P<5 then 'o' and if P>5 then '^'. I know how to do this based on colour (although I don't actually know how to specify what colours to use?) but can this be done with markertype?
scatter(xData,yData,70,P>5)
Any ideas? Thanks!
You will need to do 2 scatter plots with less and more:
xData = [4 7 2 1 2 8 7 1 1 3];
yData = [1 2 3 4 5 6 7 8 9 10];
P = [5 10 4 2 7 3 8 1 9 3];
x_less = xData(P < 5);
x_more = xData(P >= 5);
y_less = yData(P < 5);
y_more = yData(P >= 5);
figure;
scatter(x_less, y_less, 20, 'r', 'o')
hold on
scatter(x_more, y_more, 20, 'b', '^')
This will give you an example like this:
Hope this helps.

Matlab.Copying the rows n times in order [duplicate]

This question already has answers here:
A similar function to R's rep in Matlab [duplicate]
(4 answers)
Closed 9 years ago.
Hey I would like to do something like the following
A = [...
1 2 3
4 5 6
7 8 9]
to
B = [...
1 2 3
1 2 3
1 2 3
4 5 6
4 5 6
4 5 6
7 8 9
7 8 9
7 8 9]
But please do not advice manual things. I am writing an algorithm with inputs and matrix dimensions may change.
There's a few ways. The simplest I think would be to use the Kronecker product:
B = kron(A, ones(3,1))
the faster but less readable solution is replication by multiplication and reshaping:
B = reshape((A(:) * ones(1,3))', 3*size(A,1),size(A,2))
or the same solution, but then using repmat:
B = reshape(repmat(A(:).',3,1), 3*size(A,1),size(A,2))
You can also try something based on the following:
a = [1 2 3]
b = [4 5 6]
c = [7 8 9]
d = [ a; a; b; b; c; c]
e = [ repmat([a], [2, 1]) ;
repmat([b], [2, 1]) ;
repmat([c], [2, 1]) ]
d and e both result in the matrix below:
=
1 2 3
1 2 3
4 5 6
4 5 6
7 8 9
7 8 9
To append more rows you can also use this for loop and see what the result is:
e = []
for i = 1:2
e = [ e;
repmat([a], [2, 1]) ;
repmat([b], [2, 1]) ;
repmat([c], [2, 1]) ]
end