Break a given MATLAB string into array of sections - matlab

Suppose I have the following string:
%%
a = 2
%%
a =3
%%
t = 0:.1:pi*4;
y = sin(t);
for k = 3:2:9
%%
y = y + sin(k*t)/k;
if ~mod(k,3)
%%
display(sprintf('When k = %.1f',k));
plot(t,y)
end
end
If you notice the third section has nested sections.
I want the output to be
[ 'a = 2', 'a=3' , 't = 0:.1:pi*4; y = sin(t); for k = 3:2:9 %% y = y + sin(k*t)/k; if ~mod(k,3) %% display(sprintf('When k = %.1f',k)); plot(t,y) end end']
How can achieve this using string manipulation?
The problem is using normal regex with '%%' will break the 3rd section into 3 sections.

Assuming the logic behind this is that you want to keep any loops or conditional statements (for, while, and if) together, then you can check for '%%' but also track the number of loops/conditionals you enter and exit.
If you are going through this line by line, then the code would look like this (where the variable tline is the line of text):
% initialize counters
str_count = 0;
in_loop = 0;
% iterate through text lines
while (tline ~= -1)
% check for the %% marker but only increment string counter if not in a loop
if ~isempty(strfind(tline,'%%')) && (in_loop == 0);
str_count = str_count + 1;
else
% if no %% or in a loop, add the current line to the current string
str_set{str_count} = [str_set{str_count} tline];
% check for "for", "if", or "while" and increment the loop counter if found
if ~isempty(strfind(tline,'for ')) || ~isempty(strfind(tline,'if ')) || ~isempty(strfind(tline,'while '))
in_loop = in_loop + 1;
end
% check for "end" and decrement the loop counter if found
if ~isempty(strfind(tline,'end'));
in_loop = in_loop - 1;
end
end
end
Keep in mind that this uses strfind to look for the for, while, if, and end commands (with spaces after the first three). However, it would also pick up words that had those strings at the end (for example, the line xfor = 1; would be picked up). So you either have to add some extra checks or be careful about how you name the variables -- perhaps a better way of looking for those strings is the best. You should see spaces before the words unless they are the first words, and could add conditions to that effect.

Related

Looping through to find max value without using max()

I'm trying to iterate in MATLAB (not allowed to use in built functions) to find the maximum value of each row in a certain matrix. I've been able to find the max value of the whole matrix but am unsure about isolating the row and finding the max value (once again without using max()).
My loop currently looks like this:
for i = 1:size(A, 1)
for j = 1:size(A, 2)
if A(i, j) > matrix_max
matrix_max = A(i, j);
row = i;
column = j;
end
end
end
You need a vector of results, not a single value. Note you could initialise this to zero. Don't initialise to zero unless you know you only have positive values. Instead, initialise to -inf using -inf*ones(...), as all values are greater than negative infinity. Or (see the bottom code block) initialise to the first column of A.
% Set up results vector, same number of rows as A, start at negative infinity
rows_max = -inf*ones(size(A,1),1);
% Set up similar to track column number. No need to track row number as doing each row!
col_nums = zeros(size(A,1),1);
% Loop through. i and j = sqrt(-1) by default in MATLAB, use ii and jj instead
for ii = 1:size(A,1)
for jj = 1:size(A,2)
if A(ii,jj) > rows_max(ii)
rows_max(ii) = A(ii,jj);
col_nums(ii) = jj;
end
end
end
Note that if vectorisation doesn't violate your "no built-ins" rule (it should be fine, it's making the most of the MATLAB language), then you can remove the outer (row) loop
rows_max = -inf*ones(size(A,1),1);
col_nums = zeros(size(A,1),1);
for jj = 1:size(A,2)
% Get rows where current column is larger than current max stored in row_max
idx = A(:,jj) > rows_max;
% Store new max values
rows_max(idx) = A(idx,jj);
% Store new column indices
col_nums(idx) = jj;
end
Even better, you can cut your loop short by 1, and initialise to the first column of A.
rows_max = A(:,1); % Set current max to the first column
col_nums = ones(size(A,1),1); % ditto
% Loop from 2nd column now that we've already used the first column
for jj = 2:size(A,2)
idx = A(:,jj) > rows_max;
rows_max(idx) = A(idx,jj);
col_nums(idx) = jj;
end
You can modified it likes the following to get each max for each row:
% initialize
matrix_max = zeros(size(A,1),1);
columns = zeros(size(A,1),1);
% find max
for i = 1:size(A, 1)
matrix_max(i) = A(i,1);
columns(i) = 1;
for j = 2:size(A, 2)
if A(i, j) > matrix_max(i)
matrix_max(i) = A(i, j);
columns(i) = j;
end
end
end

MATLAB displaying a table [duplicate]

I want to use MATLAB's printmat do display a matrix with labels. But this doesn't work for complex numbers:
N = 5;
x = rand(N,1);
y = rand(N,1);
z = x + 1i*y;
printmat([x,y,z],'fftdemo','N=1 2 3 4 5','x y x+iy');
Output:
fftdemo =
x y x+iy
N=1 0.84072 0.34998 0.84072
2 0.25428 0.19660 0.25428
3 0.81428 0.25108 0.81428
4 0.24352 0.61604 0.24352
5 0.92926 0.47329 0.92926
As you can see the imaginary part of z isn't printed.
Is there a way to get Matlab to display complex numbers or another way to achieve this?
Any print function in matlab will only print real value of imaginary number. TO get both the parts you must call them explicitly.So correct usage would be
printmat([x,y,real(z),imag(z)],'fftdemo','N=1 2 3 4 5','x y x iy');
But this wont be of any use now since both are parts are getting printed twice.
Here is a slightly altered version of printmat that will print complex numbers. Feel free to fiddle around a bit more with it for better looks :)
function [] = printmat2(a,name,rlab,clab)
%PRINTMAT Print matrix with labels.
% PRINTMAT(A,NAME,RLAB,CLAB) prints the matrix A with the row labels
% RLAB and column labels CLAB. NAME is a string used to name the
% matrix. RLAB and CLAB are string variables that contain the row
% and column labels delimited by spaces. For example, the string
%
% RLAB = 'alpha beta gamma';
%
% defines 'alpha' as the label for the first row, 'beta' for the
% second row and 'gamma' for the third row. RLAB and CLAB must
% contain the same number of space delimited labels as there are
% rows and columns respectively.
%
% PRINTMAT(A,NAME) prints the matrix A with numerical row and column
% labels. PRINTMAT(A) prints the matrix A without a name.
%
% See also: PRINTSYS.
% Clay M. Thompson 9-24-90
% Copyright 1986-2002 The MathWorks, Inc.
% $Revision: 1.10 $ $Date: 2002/04/10 06:32:35 $
error(nargchk(1,4,nargin));
space = ' ';
[nrows,ncols] = size(a);
if nargin<2, name = []; end
if nargin==3, error('Wrong number of input arguments.'); end
if nargin<4,
rlab = []; clab = [];
for i=1:nrows, rlab = [rlab, sprintf('--%d--> ',i)]; end
for i=1:ncols, clab = [clab, sprintf('--%d--> ',i)]; end
rlab=rlab(1:length(rlab)-1);
clab=clab(1:length(clab)-1);
end
col_per_scrn=5;
len=12;
if (nrows==0)|(ncols==0),
if ~isempty(name), disp(' '), disp(sprintf('%s = ',name)), end
disp(' ')
disp(' []')
disp(' ')
return
end
% Remove extra spaces (delimiters)
ndx1 = find(clab==' ');
ndx2 = find([ndx1,0]==[-1,ndx1+1]);
if ~isempty(clab), clab(ndx1(ndx2))=[]; end
ndx1 = find(rlab==' ');
ndx2 = find([ndx1,0]==[-1,ndx1+1]);
if ~isempty(rlab), rlab(ndx1(ndx2))=[]; end
% Determine position of delimiters
cpos = find(clab==' ');
if length(cpos)<ncols-1, error('Not enough column labels.'); end
cpos = [0,cpos,length(clab)+1];
rpos = find(rlab==' ');
if length(rpos)<nrows-1, error('Not enough row labels.'); end
rpos = [0,rpos,length(rlab)+1];
col=1;
n = min(col_per_scrn-1,ncols-1);
disp(' ')
if ~isempty(name), disp(sprintf('%s = ',name)), end % Print name
while col<=ncols
% Print labels
s = space(ones(1,len+1));
for j=0:n,
lab = clab(cpos(col+j)+1:cpos(col+j+1)-1);
if length(lab)>len,
lab=lab(1:len);
else
lab=[space(ones(1,len-length(lab))),lab]; end
s= [s,' ',lab];
end
disp(setstr(s))
for i=1:nrows,
s = rlab(rpos(i)+1:rpos(i+1)-1);
if length(s)>len, s=s(1:len); else s=[space(ones(1,len-length(s))),s]; end
s = [' ',s];
for j=0:n,
element = a(i,col+j);
if imag(element) ~= 0
s=[s,sprintf('%12.5f + %12.5fi',[real(element) imag(element)])];
else
if element==0,
s=[s,' 0'];
elseif (element>=1.e6)|(element<=-1.e5)|(abs(element)<.0001)
s=[s,sprintf(' %12.5e',element)];
else
s=[s,sprintf(' %12.5f',element)];
end
end
end
disp(s)
end % for
col = col+col_per_scrn;
disp(' ')
if (ncols-col<n), n=ncols-col; end
end % while
% end printmat

How to extract Shape and Texture vertices from .wrl(VRML) file to .mat

I have 3D data. And there is a .wrl(VRML) file in it. I need to load that file and then extract only the shape and texture vertices (x,y,z)points. How to do that?
This is the code i have:
%/*********************************************************************************
% FUNCTION NAME : read_vrml
% AUTHOR : G. Akroyd
% PURPOSE : reads a VRML or Inventor file and stores data points and connectivity
% in arrays ready for drawing wireframe images.
%
% VARIABLES/PARAMETERS:
% i/p filename name of vrml file
% o/p nel number of geometry parts (elements) in file
% o/p w3d geometry structure ;-
% w3d.pts array of x y z values for each element
% w3d.knx array of connection nodes for each element
% w3d.color color of each element
% w3d.polynum number of polygons for each element
% w3d.trans transparency of each element
%
% Version / Date : 3.0 / 23-9-02
% removed triang optn & replaced face array Nan padding
% with 1st value padding to correct opengl display prob.
% Version / Date : 2.0 / 17-7-00
% changed output to a structure rather than separate arrays
% to use less memory.
% 1.0 / 21-6-99
% original version
%**********************************************************************************/
function [nel,w3d,infoline] = read_vrml(filename)
keynames=char('Coordinate3','point','coordIndex');
fp = fopen(filename,'r');
if fp == -1
fclose all;
str = sprintf('Cannot open file %s \n',filename);
errordlg(str);
error(str);
end
%* initialise arrays & counters */
fv = zeros(1,3);
foundkey=zeros(1,3); %* flags to determine if keywords found */
endpts=0; %/* flag set when end of co-ord pts reached for an element */
npt=0; %/* counter for num pts or conections */
npol=1; % counter for number of polygons in an element
nel=1; %/* counter for num of elements */
color(1,1:3) = [0.5 0.55 0.5]; % default color
maxnp = 0;
tempstr = ' ';
lastel = 1;
lnum = 1;
w3d(1).name = 'patch1';
infoline = '#';
trnsp(1) = 1; % transparency array - one val per element
%/* start of main loop for reading file line by line */
while ( tempstr ~= -1)
tempstr = fgets(fp); % -1 if eof
if tempstr(1) == '#' & lnum == 2,
infoline = tempstr;
end
lnum = lnum +1; % line counter
if ~isempty(findstr(tempstr,'DEF')) & ~endpts,
w3d(nel).name = sscanf(tempstr,'%*s %s %*s %*s');
end
if ~isempty(findstr(tempstr,'rgb')) | ~isempty(findstr(tempstr,'diffuseColor')) % get color data
sp = findstr(tempstr,'[');
if isempty(sp), sp = 12 + findstr(tempstr,'diffuseColor'); end
nc = 0;
if ~isempty(sp)
sp = sp +1;
[cvals,nc]=sscanf(tempstr(sp:length(tempstr)),'%f %f %f,');
end
if nc >= 3
if nel > lastel+1
for m = lastel+1:nel-1
color(m,1:3) = color(1,1:3); % if color not set then make equal to 1st
end
end
% if multi colors set then populate color matrix, this is an inventor feature
for s = 1:fix(nc/3)
color(s+nel-1,1:3) = cvals(3*s-2:3*s)';
lastel = s+nel-1;
end
end
end
if ~isempty(findstr(tempstr,'transparency')), % get transparency level
sp = findstr(tempstr,'trans');
[tvals,nc]=sscanf(tempstr(sp+12:length(tempstr)),'%f');
if nc > 0, trnsp(nel) = tvals(1); end
end
for i=1:3 %/* check for each keyword in line */
key = deblank(keynames(i,:));
if ~isempty(findstr(tempstr,key)) & isempty(findstr(tempstr,'#'))
%/* if key found again before all found there is a problem
% so reset flag for that key */
if ~foundkey(i), foundkey(i)=1;else foundkey(i)=0; end
if(i>1 & ~foundkey(i-1)) foundkey(i)=0; end %/* previous key must exist first ! */
end
end
if(foundkey(1) & foundkey(2)) %/* start of if A first 2 keys found */
if foundkey(3) %/* scan for connectivity data */
tempstr = [tempstr,' #']; %/* last word marker for end of line */
skip = '';
%/* loop puts integer values in a line into connection array */
word = ' ';
while(word(1) ~= '#')
format = sprintf('%s %%s#',skip);
[word,nw] = sscanf(tempstr,format);
skip = [skip,'%*s'];
[node,nred] = sscanf(word,'%d,');
if nred>0
for p = 1:nred
if node(p) ~= -1
npt = npt +1;
% increment node value as matlab counts from 1, vrml 0
w3d(nel).knx(npol,npt) = node(p)+1;
else
if npt > maxnp(nel), maxnp(nel) = npt; end
npt = 0;
npol = npol + 1;
end
end
end
end
if ~isempty(findstr(tempstr,']')) %/* End of data block marker */
polynum(nel)=npol-1; %/* store num of polygons in this element */
endpts=0; %/* reset flag ready for next element search */
npt=0;
npol=1;
foundkey = zeros(1,4); %/* reset keyword flags for next search */
nel = nel+1; %/* now looking for next element so increment counter
maxnp(nel) = 0;
w3d(nel).name = sprintf('patch%d',nel); % name next block
end
end %/* end of scan for connectivity */
%/* got 1st 2 keys but not 3rd and not end of co-ords data */
if(foundkey(2) & ~foundkey(3) & ~endpts) %/* scan for pts data */
sp = findstr(tempstr,'[');
if isempty(sp)
%/* points data in x y z columns */
[fv,nv]=sscanf(tempstr,'%f %f %f,');
else
%/* if block start marker [ in line - need to skip over it to data
% hence pointer to marker incremented */
sp = sp +1;
[fv,nv]=sscanf(tempstr(sp:length(tempstr)),'%f %f %f,');
end
if(nv>0)
if mod(nv,3) ~= 0
fclose(fp);
error('Error reading 3d wire co-ordinates: should be x y z, on each line');
end
nov = fix(nv/3);
for p = 1:nov
npt = npt+1;
w3d(nel).pts(npt,1:3)=fv(3*p-2:3*p);
end
end
if ~isempty(findstr(tempstr,']')) %/* end of pts data block */
endpts=1; %/* flag to stop entry to pts scan while reading connections */
npt=0;
end
end %/* end of scan for data pts */
end %/* end of if A */
end %/* end of main loop */
if nel == 0
fclose(fp);
error('Error reading 3d file: no data found');
end
nel = nel -1;
% if not same number of verticies in each polygon we need to fill
% out rest of row in array with 1st value
nc = size(color);
ts = size(trnsp);
for i = 1:nel
facs = w3d(i).knx;
ind1 = find(facs==0); [rown,coln] = ind2sub(size(facs),ind1);
facs(ind1) = facs(rown);
w3d(i).knx = facs;
if i > 1 & i > nc(1), color(i,1:3) = color(1,1:3); end % extend color array to cover all elements
w3d(i).color = color(i,1:3);
w3d(i).polynum = polynum(i);
if i > ts(2) | trnsp(i)==0,
trnsp(i) = 1;
end % extend transparency array to cover all elements
w3d(i).trans = trnsp(i);
end
fclose(fp);
% END OF FUNCTION read_vrml
%=====================================================================================
Here i have just replaced filename with sub1.wrl which is my vrml file.
It gives the following error
read_vrml
Error using read_vrml (line 31)
Not enough input arguments.
And if i edit ...function [nel,w3d,infoline] = read_vrml()
i.e to not enter anything only at the place of first occurrence of filename.
It gives error
read_vrml
Undefined variable "sub1" or class "sub1.wrl".
Error in read_vrml (line 31)
fp = fopen(sub1.wrl,'r');
I think you misunderstood the way functions are to be used.
Save the function into your matlab directory.
Then in your console/script call the function like this:
MySurf=read_vrml('sub1.wrl');
If you try to put your file name instead of the argument in the function definition, it will fail. Also, in Matlab, file names are arrays of characters (strings), you need to use quotation marks (') to identify a string.
SYNTAX-wise
fp = fopen( 'sub1.wrl', 'r' ); %% 'un-quoted' string was considered a variable
VRML-wise
The cleanest / the most straightforward would be to pre-process the .wrl file ( with a use of regex et al ) to retrieve the VRML-code decomposed [ x, y, z] data and to allow a pipe-line processing thereof

error with "The matrix MSG in ENCODE must have K columns"

im working on a video steganography using LSB technique..im using traffic.avi and xylophone.mpg as the cover medium and when im using the licence.txt file (in the attach file) to encode into the video it runs well however when im using a short messsage for the input text it shows an error which is
"The matrix MSG in ENCODE must have K columns." and sometimes when use short text it gives error "msg is too long to encode"
i have no idea what does this 2 set of coding means and how to edit the code to make it possible to encode a short msg...below this is some of the code that i guess relate to this problem
num2add = 80-length(msg); % Number of spaces to add to end of MSG.
if num2add < 0, error('This message is too long to encode.'), end
newmsg = [msg,repmat(' ',1,num2add)]; % 80 chars always encoded.
msgmat = dec2bin(newmsg)-48; % Each row is a bin. rep. of an ascii char.
and also this coding
if m_msg == 1
type_flag = 2; % binary vector
[msg, added] = vec2mat(msg, k);
elseif m_msg ~= k
error('comm:encode:InvalidMatrixColumnSize','The matrix MSG in ENCODE must have K columns.');
BELOW THIS IS THE FULL ENCODE CODING continue after the first part of the above coding!
B = pic1(:,:,1); [piclngth pichght] = size(B); % Choose the first page.
dim1 = piclngth-2; dim2 = pichght-3; keyb = key(end:-1:1);
rows = cumsum(double(key));
columns = cumsum(double(keyb)); % Coord pairs for KEY (rows,columns)
A = zeros(dim1,dim2); % This matrix will house the hiding points.
A = crtmtrx(A,rows,columns,dim1,dim2,key);
idx = find(A==1); % This same index will be used for pic matrix.
for vv = 1:80 % This is the encoder.
for uu = 1:8
if msgmat(vv,uu)==1;
if rem(B(idx(uu+8*(vv-1))),2)==0
if(frame==1)
disp('some pixel value of original frame');
B(idx(uu+8*(vv-1)))
end
B(idx(uu+8*(vv-1))) = B(idx(uu+8*(vv-1)))+1;
if(frame==1)
disp('some pixel value of stegno video frame');
B(idx(uu+8*(vv-1)))
end
end
elseif rem(B(idx(uu+8*(vv-1))),2)==1
if(frame==1)
disp('some pixel value of original frame');
B(idx(uu+8*(vv-1)))
end
B(idx(uu+8*(vv-1))) = B(idx(uu+8*(vv-1)))-1;
if(frame==1)
disp('some pixel value of stegno video frame');
B(idx(uu+8*(vv-1)))
end
end
end
end
global newpic;
newpic = pic1; newpic(:,:,1) = B;
f(frame) = im2frame(newpic);
end
frameRate = get(vidObj,'FrameRate');
movie2avi(f,'stegano_video.avi','compression','None', 'fps', 20);
success = 1;
function A = crtmtrx(A,rows,columns,dim1,dim2,key)
% Creates the matrix used to find the points to hide the message.
jj = 1; idx = 1;
while 640 > length(idx) % Need 560 points to hide 80 characters.
for ii = 1:length(rows)
if rows(ii) < dim1
rows(ii) = rem(dim1,rows(ii))+1;
else
rows(ii) = rem(rows(ii),dim1)+1;
end
if columns(ii) < dim2
columns(ii) = rem(dim2,columns(ii))+1;
else
columns(ii) = rem(columns(ii),dim2)+1;
end
A(rows(ii),columns(ii)) = 1;
end
rows = jj*cumsum(double(columns))+round(dim2/2); % Each pass is diff.
columns = jj*cumsum(double(rows))+round(dim1/2);
if jj > ceil(640/length(key))+2 % Estimate how many iters. needed.
idx = find(A==1);
end
jj = jj+1;
end
this is some of the input text and the right one is the encypted txt
The code that triggers the error is pretty clear:
num2add = 80-length(msg); % Number of spaces to add to end of MSG.
if num2add < 0, error('This message is too long to encode.'), end
So basically you will get the error as soon as there are more than 80 characters in msg. I am not sure whether the 80 is meaningfull, you can try to increase it but that may break something else.

Dynamic-variable sized arrays in matlab

This code is working but needs to be improved for efficient calculations
anisLoc=[];% Variable sized array
PiezoLoc=[]; % Variable sized array
for i=1:q % Looking in all q
if ~isempty(LayerProp{i}.c)% if c is not empty then
anisLoc=[anisLoc,i];
c{i}=LayerProp{i}.c;
end
if ~isempty(LayerProp{i}.e) % if e is not empty then
% if LayerProp{i}.e(3,3)
PiezoLoc=[i;PiezoLoc];
e{i}=LayerProp{i}.e;
% end
end
end
anisLoc and Piezoloc are variable sized arrays. I set them on their maximum values q
but they change size and could not empty them after so they produce same answer from initial code!!
anisLoc=zeros(q,1);% Variable sized array
PiezoLoc=zeros(1,q);% Variable sized array
% This loop checks for specific input in data in all
for i=1:q % Looking in all q
if ~isempty(LayerProp{i}.c)% if c is not empty
anisLoc=[i;anisLoc];
c{i}=LayerProp{i}.c;
end
if ~isempty(LayerProp{i}.e) % if e is not empty
% if LayerProp{i}.e(3,3)
PiezoLoc=[PiezoLoc,i];
e{i}=LayerProp{i}.e;
% end
end
end
I believe this should be quite a bit faster:
anisLoc=zeros(q,1);% Variable sized array
PiezoLoc=zeros(1,q);% Variable sized array
% This loop checks for specific input in data in all
k = 0;
m = 0;
for ii=1:q % Looking in all q
if ~isempty(LayerProp{ii}.c)% if c is not empty
k = k + 1;
anisLoc(k)=ii;
c{ii}=LayerProp{ii}.c;
end
if ~isempty(LayerProp{ii}.e) % if e is not empty
% if LayerProp{ii}.e(3,3)
m = m + 1;
PiezoLoc(m) = ii;
e{ii}=LayerProp{ii}.e;
% end
end
anisLoc(k+1:end) = [];
PiezoLoc(m+1:end) = [];
end