I am currently working on a stenography assignment on how to embed secret image to a cover image using Wang's algorithm. Basically i just want to change for eg:
3d matrix
A(:,:,1) = [5 7 8; 0 1 9; 4 3 6];
A(:,:,2) = [1 0 4; 3 5 6; 9 8 7];
A(:,:,3) = [7 9 3; 4 5 9; 1 9 9];
To
Str = '578019436104356987793459199'
and also vice-versa if anybody can help out.
Another way is to just use sprintf. You first need to transpose each slice independently, so the call to permute as per Ander's answer will get to that point. After you can just supply a single format string of %d (integer) and the actual permuted matrix and it will unroll all elements column-wise and concatenate all of the numbers together. The additional advantage is that you no longer need to assume that only one digit occupies each matrix element:
str = sprintf('%d', permute(A, [2 1 3]));
Example
>> str = sprintf('%d', permute(A, [2 1 3]))
str =
578019436104356987793459199
>> class(str)
ans =
char
However, to reconstruct the matrix, you will have to assume that there's one element per matrix. In this case, you could use the undocumented sprintfc function that can output one cell per character, then convert the characters to numbers with str2double. Finally, reshape your matrix and undo the transpose:
A2 = permute(reshape(str2double(sprintfc('%c', str)), size(A)), [2 1 3]);
Example
>> A2 = permute(reshape(str2double(sprintfc('%c', str)), size(A)), [2 1 3])
A2(:,:,1) =
5 7 8
0 1 9
4 3 6
A2(:,:,2) =
1 0 4
3 5 6
9 8 7
A2(:,:,3) =
7 9 3
4 5 9
1 9 9
Because of the order of the unrolling of MATLAB matrices, your problem is slightly less straightforward than it may seem. You need to use reshape and permute to make it work.
str=arrayfun(#num2str,reshape(permute(A,[2 1 3]),[],1,1)).';
A2=permute(reshape(arrayfun(#str2double,str),[size(A)]),[2 1 3]);
isequal(A2,A)
This of course assumes what #Sardar comments in your question: all numbers have single digits (i.e. are integers range 0-9)
Related
I have a Matrix of size M by N in which each row has some zero entries. I want to create M row vectors such that each of the vector contains the non zero elements of each row. For example if I have the following Matrix
A=[0 0 0 5;0 0 4 6;0 1 2 3;9 10 2 3]
I want four different row vectors of the following form
[5]
[4 6]
[1 2 3]
[9 10 2 3]
This can be done with accumarray using an anonymous function as fourth input argument. To make sure that the results are in the same order as in A, the grouping values used as first input should be sorted. This requires using (a linearized version of) A transposed as second input.
ind = repmat((1:size(A,2)).',1,size(A,2)).';
B = A.';
result = accumarray(ind(:), B(:), [], #(x){nonzeros(x).'});
With A = [0 0 0 5; 0 0 4 6; 0 1 2 3; 9 10 2 3]; this gives
result{1} =
5
result{2} =
4 6
result{3} =
1 2 3
result{4} =
9 10 2 3
Since Matlab doesn't support non-rectangular double arrays, you'll want to settle on a cell array. One quick way to get the desired output is to combine arrayfun with logical indexing:
nonZeroVectors = arrayfun(#(k) A(k,A(k,:)~=0),1:size(A,1),'UniformOutput',false);
I used the ('UniformOutput',false) name-value pair for the reasons indicated in the documentation (I'll note that the pair ('uni',0) also works, but I prefer verbosity). This input produces a cell array with the entries
>> nonZerosVectors{:}
ans =
5
ans =
4 6
ans =
1 2 3
ans =
9 10 2 3
I have got a problem with splitting a vector by zeros.
I have a vector for example
v=[1 3 2 6 4 0 0 2 4 6 0 0 0 3 1]
I need to get vectors like
v1=[1 3 2 6 4]
v2=[2 4 6]
v3=[3 1]
Is there any way to do this by using MATLAB functions?
Of course I don't know of how many subvectors are included in main vector v and how many zeros delimits vectors.
I'm not a programmer and also I'm not a pro in MATLAB.
I know a procedural way to do this but want do it by MATLAB somehow.
I found a function A = strsplit(str,delimiter) but I don't have string I have a vector.
So I searched for conversion function. I found S = char(V) but when I executed it it crashed.
It's better to have the output as a cell array, not as separate variables. That way the output will be easier to handle.
Try this:
v = [1 3 2 6 4 0 0 2 4 6 0 0 0 3 1]; %// data
w = [false v~=0 false]; %// "close" v with zeros, and transform to logical
starts = find(w(2:end) & ~w(1:end-1)); %// find starts of runs of non-zeros
ends = find(~w(2:end) & w(1:end-1))-1; %// find ends of runs of non-zeros
result = arrayfun(#(s,e) v(s:e), starts, ends, 'uniformout', false); %// build result
Result (for your example):
>> result{:}
ans =
1 3 2 6 4
ans =
2 4 6
ans =
3 1
The strsplit() solution for a vector of whole numbers smaller than 9 (so a very specific solution, for a general solution see Luis Mendo's). Split and convert back to number:
res = strsplit(char(v), char(0));
res = cellfun(#(x) x - 0,res,'un',0);
celldisp(res)
res{1} =
1 3 2 6 4
res{2} =
2 4 6
res{3} =
3 1
I got a 4-by-n matrix, like
A =
1 5 9
3 0 6
2 3 10
7 8 4
What I want to do with A is getting each half column of A as
Line1Point1 = [1 3]
Line1Point2 = [2 7]
Line2Point1 = [5 0]
Line2Point2 = [3 8]
Line3Point1 = [9 6]
Line3Point2 = [10 4]
How could I do that? I’m pretty new to matlab coding.. Any help is really appreciated..
Cheers
Use reshape function, for example:
>> A = [1 5 9;
3 0 6;
2 3 10;
7 8 4];
>> reshape(A,2,6)
ans =
1 2 5 3 9 10
3 7 0 8 6 4
Storing such information as many variables is generally a bad idea
Some options for storing and accessing are
Cell array
Line=mat2cell(A,[2,2],ones(1,size(A,2))).'
access with
Line{2,1}
ans =
5
0
Indexing
as other answers
Anonymous Function
Line=#(l,p)A(2*p-1:2*p,l)
access with
Line(2,1)
ans =
5
0
Structure
Not really a useful solution, more for interests sake
for ii=1:size(A,2);for jj=1:2;Line(ii).Point(jj).Value=A(2*jj-1:2*jj,ii);end;end
access with
Line(2).Point(1).Value
ans =
5
0
A(1:2,1) will give you first half of the first column.
A(3:4,1) will give you second half of the first column.
A(1:2,2) will give you first half of the second column.
A(3:4,2) will give you second half of the second column.
A(1:2,3) will give you first half of the third column.
A(3:4,3) will give you second half of the third column.
You can create the variables with the eval function, which executes the input string. Using eval is commonly regarded as bad practice since it is horrible to debug.
Nevertheless, here's the code:
A = [1 5 9; 3 0 6; 2 3 10; 7 8 4];
for ii = 1:length(A(1,:))
eval(['Line' num2str(ii) 'Point1 = A(1:2, ii)' ]);
eval(['Line' num2str(ii) 'Point2 = A(3:4, ii)' ]);
end
% Now all variables are created - for example: Line2Point1
A more elegant solution could be to store the vectors in a cell array. You can acces the first vectors for example by typing: c{1,1}
c = cell(length(A(1,:)),2)
for ii = 1:length(A(1,:))
c{ii,1} = A(1:2, ii);
c{ii,2} = A(3:4, ii);
end
I would suggest using 3D arrays to store and then access those values.
Code
N = size(A,1)/2;
LinePoint = permute(reshape(A,N,size(A,1)/N,[]),[1 3 2])
Here,
2nd dimension indices (columns) would represent Line IDs
3rd dimension indices would represent Point IDs.
Thus, the representative 3D array would be - LinePoint(:,LineID,PointID).
Example run
For your given A, we would have LinePoint as -
LinePoint(:,:,1) =
1 5 9
3 0 6
LinePoint(:,:,2) =
2 3 10
7 8 4
Thus,
Line1Point1 would be denoted by LinePoint(:,1,1)
Line1Point2 would be denoted by LinePoint(:,1,2)
Line2Point1 would be denoted by LinePoint(:,2,1)
Line2Point2 would be denoted by LinePoint(:,2,2)
Line3Point1 would be denoted by LinePoint(:,3,1)
Line3Point2 would be denoted by LinePoint(:,3,2)
Lets say I have matrix such that A(:,:,1)=[1,2,3;2,3,4], A(:,:,2)=[3,4,5;4,5,6].
How is the easiest way of accessing and plotting the vectors (1,2,3),(2,3,4),(3,4,5),(4,5,6). I tried creating B=[A(:,:,1);A(:,:,2)], but i need a procedure to arbitrary number of A's.
Hope this isn't trivial and I've formulated myself satisfactory.
You should think 'vertically'. This will allow you to use colon indexing:
>> A(:,:,1) = [1,2,3;2,3,4].'; %'// NOTE: transpose of your original
>> A(:,:,2) = [3,4,5;4,5,6].'; %'// NOTE: transpose of your original
>> A(:,:)
ans =
1 2 3 4
2 3 4 5
3 4 5 6
The colon indexing with two colons works for any dimension A:
>> A(:,:,:,:,1,1) = [1 2 3; 2 3 4].'; %'
>> A(:,:,:,:,2,1) = [3 4 5; 4 5 6].'; %'
>> A(:,:,:,:,1,2) = [5 6 7; 6 7 8].'; %'
>> A(:,:,:,:,2,2) = [7 8 9; 8 9 0].'; %'
>> A(:,:)
ans =
1 2 3 4 5 6 7 8
2 3 4 5 6 7 8 9
3 4 5 6 7 8 9 0
Colon indexing in MATLAB is quite interesting and really powerful once you master it. For example, if you use fewer colons than there are dimensions in the array (like above), MATLAB will automatically concatenate the remainder of the data along the dimension equal to the colon count.
So, if A has 48 dimensions, but you index with just 2 colons: you'll get a 2D array, that is the concatenation of the remaining 46 dimensions along the 2nd dimension.
In general: if A has N dimensions, but you index with just M ≤ N colons: you'll get an M-D array, that is the concatenation of the remaining N-M dimensions along the Mth dimension.
So as long as you are free to define your A to contain vectors on the columns rather than the rows (you should advise everyone to do this, as virtually everything in MATLAB is a bit faster that way), I think this is the fastest and most elegant way to do what you want.
If not, well, then just reshape like Dan :)
Assuming the order does not matter, here is how you can do it for vectors of length 3:
B = reshape(shiftdim(A,2), [], 3)
plot(B')
For vectors of arbitrary dimensions, replace 3 by size(A,2)
Is there any easy way to concatenate matrices with unequal dimensions using zero padding?
short = [1 2 3]';
long = [4 5 6 7]';
desiredResult = horzcat(short, long);
I would like something like:
desiredResult =
1 4
2 5
3 6
0 7
Matrices in MATLAB are automatically grown and padded with zeroes when you assign to indices outside the current bounds of the matrix. For example:
>> short = [1 2 3]';
>> long = [4 5 6 7]';
>> desiredResult(1:numel(short),1) = short; %# Add short to column 1
>> desiredResult(1:numel(long),2) = long; %# Add long to column 2
>> desiredResult
desiredResult =
1 4
2 5
3 6
0 7
EDIT:
I have edited my earlier solution so that you won't have to supply a maxLength parameter to the function. The function calculates it before doing the padding.
function out=joinUnevenVectors(varargin)
%#Horizontally catenate multiple column vectors by appending zeros
%#at the ends of the shorter vectors
%#
%#SYNTAX: out = joinUnevenVectors(vec1, vec2, ... , vecN)
maxLength=max(cellfun(#numel,varargin));
out=cell2mat(cellfun(#(x)cat(1,x,zeros(maxLength-length(x),1)),varargin,'UniformOutput',false));
The convenience of having it as a function is that you can easily join multiple uneven vectors in a single line as joinUnevenVectors(vec1,vec2,vec3,vec4) and so on, without having to manually enter it in each line.
EXAMPLE:
short = [1 2 3]';
long = [4 5 6 7]';
joinUnevenVectors(short,long)
ans =
1 4
2 5
3 6
0 7
Matlab automatically does padding when writing to a non-existent element of a matrix.
Therefore, another very simple way of doing this is the following:
short=[1;2;3];
long=[4;5;6;7];
short(1:length(long),2)=long;