How to convert an Image matrix into a vector in Matlab - matlab

I cant seem to figure this out:
I need to reshape a matrix into a vector and so far I have this:
img = imread('image.png');
grayImage = rgb2gray(img);
imageArray = reshape(grayImage, r, c);
Which outputs something like:
imgVector=[1 2 3 4 5 6 7 8 9 0]
My problem is I need it to do something like this:
imgArray=[1 2 3
4 5 6
7 8 9]
Reshaped into:
imgVector=[1 2 3 6 5 4 7 8 9]
I hope that make sense. Basically I need it to be unzipped so it goes from left to right and then right to left after the next row. Any help would be appreciated. Thank you in advance.

Fundamentally what you're trying to do is flip each row left-to-right, so the built-in function fliplr will do the trick.
To do it in a single step, just select every other row in your indexing operation:
>> imgArray=[1 2 3; 4 5 6; 7 8 9]
imgArray =
1 2 3
4 5 6
7 8 9
>> imgArray(2:2:end,:)=fliplr(imgArray(2:2:end,:))
imgArray =
1 2 3
6 5 4
7 8 9
Then you can turn it into a vector by reshaping.
imgVector=reshape(imgArray',1,[]);
#%transpose the array----^
Since reshaping is done column-wise, transpose the array first to get it in the format you want.

You can use the fliplr function, which inverts the order of a vector.
Here is a simple example:
A = [1 2 3;4 5 6;7 8 9];
A =
1 2 3
4 5 6
7 8 9
A(2,:) = fliplr(A(2,:));
A =
1 2 3
6 5 4
7 8 9
So could use a loop an flip every other row for your entire image. Hope that helps!

Related

Is there any command to find mean of first 5 values then next 5 values for a total of 1000 values in a vector in MATLAB

Is there any command to find mean of first 5 values then next 5 values from a total of 25 values present in a vector in MATLAB. If the dataset is X.
If anyone can help me to provide a code where I can get mean at every 5th value.
X=[4 5 6 7 2 5 7 4 2 6 7 3 2 1 5 7 8 3 4 6 8 4 2 6 8];
You can for instance reshape the vector in an array with reshape and then apply the mean function:
M = mean(reshape(X, [5, numel(X)/5]),1);
or simply
M = mean(reshape(X, 5, []),1);
But there as stated in the comments there are many other ways.
Here is one simple way to do it. Rearrange the vector into a matrix loop over the columns and take the mean of all values in each column. Store the results in a new vector.
X=[4 5 6 7 2 5 7 4 2 6 7 3 2 1 5 7 8 3 4 6 8 4 2 6 8];
Xr = reshape(X,5,5)
cols = size(Xr)(2)
avgs=zeros(1,cols)
for i= 1:cols
avgs(i) = mean(Xr(:,i))
end

Rotating a matrix to create a spiral order of values

How do I rotate a matrix to create a spiral order of values?
For example,
12 4 2
8 3 11
6 7 2
I am supposed to to display 12 4 2 11 2 7 6 8 3 but I don't know how to terminate at the 1st row and rotate the function 90 degrees. Thanks in advance for the help.
Hint:
Check the spiral function:
spiral(n) is an n-by-n matrix with elements ranging
from 1 to n^2 in a rectangular spiral pattern.
Use its output to build an index into the original values. You may also need sort, as well as fliplr to reverse the order of values.
See the code after you've given it a try.
x = [12 4 2; 8 3 11; 6 7 2];
t = fliplr(spiral(sqrt(numel(x))));
[~, ind] = sort(t(:));
result = fliplr(x(ind).');
A =[12 4 2;...
8 3 11;...
6 7 2];
B=[];
for ii=1:5
B = [B A(1,:)];
A(1,:)=[];
A=rot90(A);
end
B
B =
12 4 2 11 2 7 6 8 3

Extend the borders of a matrix and replicate the border elements in MATLAB

I am given the following matrix B:
B =
1 4 7
2 5 8
3 6 9
I would like to pad this matrix so that there is a 1 element border that surrounds it with the border elements replicated. Essentially, I would like this result:
B =
1 1 4 7 7
1 1 4 7 7
2 2 5 8 8
3 3 6 9 9
3 3 6 9 9
How can I do this in MATLAB?
If you have the Image Processing Toolbox, use padarray, specifically the replicate flag. If you don't have it, there's an implementation that someone made here on Github: https://github.com/gpeyre/matlab-toolboxes/blob/master/toolbox_nlmeans/toolbox/ordfilt2/padarray.m . You can download it and use the function for your own use.
padarray creates a larger matrix with the source matrix centred within this larger matrix. You have several options on what you can do with the extra border elements. The default behaviour is to set these equal to 0. However, we can specify the replicate flag, which copies values along the original border of the matrix and places them along the extra border elements with this new matrix. Because you want to go from 3 x 3 to 5 x 5, you just need a 1 element border along both dimensions. You specify this with the second parameter to padarray. The replicate flag is the third parameter:
>> B = reshape(1:9, 3, 3);
>> B2 = padarray(B, [1 1], 'replicate')
B2 =
1 1 4 7 7
1 1 4 7 7
2 2 5 8 8
3 3 6 9 9
3 3 6 9 9
Edit
If you don't want to use padarray, you can use the scatteredInterpolant class instead, with nearest as the interpolation flag. You would build a 3 x 3 2D spatial grid of coordinates that map to each value in B, then we'd specify a 5 x 5 spatial grid of coordinates where the border elements are outside of the range of the original 3 x 3 grid. Something like this:
>> [X,Y] = meshgrid(1:3,1:3);
>> [X2,Y2] = meshgrid(0:4,0:4);
>> F = scatteredInterpolant(X(:),Y(:),B(:),'nearest');
>> B2 = F(X2, Y2)
B2 =
1 1 4 7 7
1 1 4 7 7
2 2 5 8 8
3 3 6 9 9
3 3 6 9 9
The question was explicitly to add a single element as border, so try this (no toolbox needed):
B = [1 4 7; 2 5 8; 3 6 9] % or use B=rand(3,4), etc. to try something else.
B2 = B([1 1:end end],[1 1:end end])
This is the result (as desired):
B =
1 4 7
2 5 8
3 6 9
B2 =
1 1 4 7 7
1 1 4 7 7
2 2 5 8 8
3 3 6 9 9
3 3 6 9 9

matlab: dividing vector into overlapping chunks of fixed size

I've a vector that I would like to split into overlapping subvectors of size cs in shifts of sh. Imagine the input vector is:
v=[1 2 3 4 5 6 7 8 9 10 11 12 13]; % A=[1:13]
given a chunksize of 4 (cs=4) and shift of 2 (sh=2), the result should look like:
[1 2 3 4]
[3 4 5 6]
[5 6 7 8]
[7 8 9 10]
[9 10 11 12]
note that the input vector is not necessarily divisible by the chunksize and therefore some subvectors are discarded. Is there any fast way to compute that, without the need of using e.g. a for loop?
In a related post I found how to do that but when considering non-overlapping subvectors.
You can use the function bsxfun in the following manner:
v=[1 2 3 4 5 6 7 8 9 10 11 12 13]; % A=[1:13]
cs=4;
sh=2;
A = v(bsxfun(#plus,(1:cs),(0:sh:length(v)-cs)'));
Here is how it works. bsxfun applies some basic functions on 2 arrays and performs some repmat-like if the sizes of inputs do not fit. In this case, I generate the indexes of the first chunk, and add the offset of each chunck. As one input is a row-vector and the other is a column-vector, the result is a matrix. Finally, when indexing a vector with a matrix, the result is a matrix, that is precisely what you expect.
And it is a one-liner, (almost) always fun :).
Do you have the signal processing toolbox? Then the command is buffer. First look at the bare output:
buffer(v, 4, 2)
ans =
0 1 3 5 7 9 11
0 2 4 6 8 10 12
1 3 5 7 9 11 13
2 4 6 8 10 12 0
That's clearly the right idea, with only a little tuning necessary to give you exactly the output you want:
[y z] = buffer(v, 4, 2, 'nodelay');
y.'
ans =
1 2 3 4
3 4 5 6
5 6 7 8
7 8 9 10
9 10 11 12
That said, consider leaving the vectors columnwise, as that better matches most use cases. For example, the mean of each window is just mean of the matrix, as columnwise is the default.
I suppose the simplest way is actually with a loop.
A vectorizes solution can be faster, but if the result is properly preallocated the loop should perform decently as well.
v = 1:13
cs = 4;
sh = 2;
myMat = NaN(floor((numel(v) - cs) / sh) + 1,cs);
count = 0;
for t = cs:sh:numel(v)
count = count+1;
myMat(count,:) = v(t-cs+1:t);
end
You can accomplish this with ndgrid:
>> v=1:13; cs=4; sh=2;
>> [Y,X]=ndgrid(1:(cs-sh):(numel(v)-cs+1),0:cs-1)
>> chunks = X+Y
chunks =
1 2 3 4
3 4 5 6
5 6 7 8
7 8 9 10
9 10 11 12
The nice thing about the second syntax of the colon operator (j:i:k) is that you don't have to calculate k exactly (e.g. 1:2:6 gives [1 3 5]) if you plan to discard the extra entries, as in this problem. It automatically goes to j+m*i, where m = fix((k-j)/i);
Different test:
>> v=1:14; cs=5; sh=2; % or v=1:15 or v=1:16
>> [Y,X]=ndgrid(1:(cs-sh):(numel(v)-cs+1),0:cs-1); chunks = X+Y
chunks =
1 2 3 4 5
4 5 6 7 8
7 8 9 10 11
10 11 12 13 14
And a new row will form with v=1:17. Does this handle all cases as needed?
What about this? First I generate the starting-indices based on cs and sh for slicing the single vectors out of the full-length vector, then I delete all indices for which idx+cs would exceed the vector length and then I'm slicing out the single sub-vectors via arrayfun and afterwards converting them into a matrix:
v=[1 2 3 4 5 6 7 8 9 10 11 12 13]; % A=[1:13]
cs=4;
sh=2;
idx = 1:(cs-sh):length(v);
idx = idx(idx+cs-1 <= length(v))
A = arrayfun(#(i) v(i:(i+cs-1)), idx, 'UniformOutput', false);
cell2mat(A')
E.g. for cs=5; sh=3; this would give:
idx =
1 3 5 7
ans =
1 2 3 4 5
3 4 5 6 7
5 6 7 8 9
7 8 9 10 11
Depending on where the values cs; sh come from, you'd probably want to introduce a simple error-check so that cs > 0; as well as sh < cs. sh < 0 would be possible theoretically if you'd want to leave some values out in between.
EDIT: Fixed a very small bug, should be running for different combinations of sh and cs now.

To subtract a vector of values in matlab

Please is there a matlab code to subtract two vector values where one value is always the larger?
Eg;
A=[10 9 8 7 6 5 4 3 2 1]; B=[5 4 3 2 1 10 9 8 7 6];
I want to subtract these two vectors where the minuend is always the larger so that the answer will be:
[5 5 5 5 5 5 5 5 5 5]
How can I do this?
Use the following code: abs(A-B)