New Tutorial / Example File
I spent a little time working up a MATLAB tutorial file that does a little more explanation. It talks about open source code licensing and creative commons copyright. It shows some basic MATLAB drawing examples, it emulates a specific work, shows how to parameterize and randomize the code, then shows one way to re-create a single image from a set of parameters.
I tested it in Octave Online and most seems to work. Octave Online Link
Images for tutorial from / inspired by Claisse.
Tutorial file download: tutorial.m
% 2022 Ed Gatzke (1/20/2022) epg@sc.edu
%
% This tutorial is organized as follows:
% 1. Licensing. The source code is open source
% 2. MATLAB drawing basics
% 3. Emulating a type of art example
% 4. Making the code randomize the output
% 5. Parameterizing the code for reproducibilty
% 6. User-defined functions
%
% HOW TO USE THIS TUTORIAL
% Start MATLAB and type edit at the >> prompt then hit return/enter
% Open the file (tutorial.m) in the editor using the open button
% Read throught the file, hitting the Run button or F5 to execute code
% At some points there are lines with the command return to stop code
% You can delete the return funtion or comment out the return to run more
%
%
%% Code Licensing Section
%
% Code licensed under GPL v3.0
% https://www.gnu.org/licenses/gpl-3.0.en.html
%
% Simple explanation: Software code based on these works must remain free!
%
% The GPL grants open-source permissions for users including:
% The right to download and run the software freely
% The right to make changes to the software as desired
% The right to redistribute (or even sell!) copies of the software
% The right to modify and distribute copies of new versions of the software
%
% Open-source code requires that the source code remain available to users
% so that folks can improve and fix things. Imagine a company makes a
% product and sells it but then goes out of business. The software product
% could never be developed further! With open-source code, others can fix
% bugs and make improvements.
%
% One catch is that you are required to release changes in the code if you
% sell it. Some companies will take open-source code, make lots of
% modifications and improvements, but never sell a product so they never
% have to release the code back to the community. Their software product
% is just used internally, never sold so they never have to release code.
%
%
% This code can be used to make art. Art released from epg is released with
% a creative commons license but other users with derivative works can
% select any license they want. The creative commons license is very close
% being a "public domain" license but iit does require folks to give credit
%
% Art licensed under Creative Commons Attribution 3.0 Unported
% https://creativecommons.org/licenses/by/3.0/
% Simple explanation: This is not "public domain!" You are free to:
% Share — copy and redistribute the material in any medium or format
% Adapt — remix, transform, and build upon the material for any purpose,
% even selling the works commercially.
% The licensor cannot revoke freedoms as long as you follow the terms.
% Under the following terms:
% Attribution — You must give appropriate credit, provide a link to the
% license, and indicate if changes were made. You may do so in any
% reasonable manner, but not in any way that suggests the licensor endorses
% you or your use.
% No additional restrictions — You may not apply legal terms or
% technological measures that legally restrict others from doing anything
% the license permits.
%
%
% This work inspired by Genvive Classie
% https://en.wikipedia.org/wiki/Genevi%C3%A8ve_Claisse
%% 2. MATLAB Drawing Basics
% Matlab draws to a figure window. This turns off some menu stuff
close all % This closes all the open figures
figure('Name','Art','NumberTitle','off') % New fig with window title
set(gcf, 'MenuBar', 'none'); % Clear out some of the stuff in a figure
set(gcf, 'ToolBar', 'none'); % Remove the toolbar too!
% gcf is the current figure data object.
get(gcf) % You can see what data is available for an object
pos=get(gcf,'Position'); % You can get a specific set of data
pos(1)=1200; % Move the x value over to 1200
set(gcf,'Position',pos); % Change the vector that describes position
% MATLAB will erase the whole figure when you draw to it a second time. To
% avoid this, you have to turn on the hold feature
hold on
% We are going to draw to a grid, from 0 to xmax and 0 to ymax. (0,0) is
% in the bottom left corner, (xmax,ymax is top right)
xmax=10;
ymax=10;
% fill can be used to specify a shape by the corners of the shape for x & y
% The last argument is a vector for red, green, blue ranging 0 to 1
fa=fill([0 xmax xmax 0],[0 0 ymax ymax],[1 0 0]); % Big red box
fb=fill([1 2 1],[ 1 1 2],[0 1 0]); % Tiny green triangle
fc=fill([4 5 6 5 4 3],[ 4 4 5 6 6 5],[0 0 1]); % blue hexagon
fd=fill([4 5 6 5 4 3],[ 4 4 5 6 6 5]+3,[0 0 1]); % blue hexagon shifted up
% The output value of fill is the data object. Look in the command window
% to see all the various attributes that can be modified.
get(fd)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% return function stops the code at that point!!!
return % Add a comment symbol % before return to continue on!!!!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% You can use the object value to change attributes for an object
set(fd,'FaceAlpha',.4) % Reducing alpha makes the object more transparent
% The fill command objects all include a different edge color. The edge
% can be removed by change the attribute.
set(fa,'edgecolor','none')
set(fb,'edgecolor','none')
set(fc,'edgecolor','none')
set(fd,'edgecolor','none')
% There is a user-defined function to make nice circles. The following
% makes a circle centered at 7,3 with radius 2 that is white and alpha
% value of 0.8, so partially transparent. User-defined functions can be at
% the bottom of a .m script file or in their own .m file
circles(7,3,2,[1 1 1],.8);
% Another user-defined function (at bottom of the file) can easily make a
% rectangle. This makes a rectangle with the bottom left corner at (1,3)
% that is .5 wide, 4 high, black, and no transparency (alpha = 1)
rectangle(1,3,.5,4,[0 0 0],1);
% Another user-defined function at the bottom will rotate a list of points
% by a given number of degrees. Consider a triangle with vertices at the
% points (3,1) (4,1) & (3,2) that rotates CCW by 20 degrees:
[xx,yy]=rotate([3 4 3],[ 1 1 2],20);
fe=fill(xx,yy,[0 1 0],'edgecolor','none'); % Tiny green rotated triangle
% Now make a skinny rectangle and rotate it clockwise (CW) by 20
[xx,yy]=rotate([7 7.5 7.5 7],[ 6 6 9 9],-20); % Rotate clockwise 20
ff=fill(xx,yy,[1 1 1],'edgecolor','none'); % Rotated white rectangle
% How about a star?
x=[-1 -.1 0 .1 1 .1 0 -.1]+3; % Make points then shift over and up
y=[0 .1 1 .1 0 -.1 -1 -.1]+3;
[xx,yy]=rotate(x,y,-45); % Rotate clockwise 45
fg=fill(x,y,[1 1 0],'edgecolor','none'); % Yellow star
fh=fill(xx,yy,[1 1 0],'edgecolor','none'); % Yellow star rotated
% The following stuff cleans up the plot a bit. MATLAB likes to treat most
% figures as a numeric plot, not a drawing canvas.
axis([0 max([xmax ymax]) 0 max([xmax ymax])]); % make sure it is square
axis square;
set(gca,'XTickLabel',[],'YTickLabel',[]); % Get rid of figure stuff
set(gca,'XTick',[],'YTick',[]);
set(gcf,'color',[1 1 1]);
set(gca,'XColor',[1 1 1],'YColor',[1 1 1]);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
return % Code will stop here if not commented out with % symbol!!!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% The previous code was to give examples of drawing simple objects using
% MATLAB functions and some user-defined functions that may help make
% simple shapes.
%
%% 3. Emulating a type of art example
% Genevieve Claisse is a geometrical abstract painter.
% A simple image with yellow, black, white, and blue circles is here:
% https://alchetron.com/Genevi%C3%A8ve-Claisse
%
% Colors can be found using color picking web sites like:
% https://imagecolorpicker.com/
%
% The rectangle is rgba(249,193,24,255)
% White circle is rgba(230,224,210,255)
% Dark circle is rgba(17,18,13,255)
% Blue circle is rgba(44,53,108,255)
% Inner cirlce is rgba(232,161,11,255)
%
% Note these numbers run 0 to 255, not 0 to 1.
% Also note that the alpha value is given as well (all are high=1.0)
% Also realize the web site gives a nice color pallette for the image, a
% suite of related colors that should go nicely together based on the
% colors found in the image.
% Create a background box rectangle using the first color
% Remember, using a figure size of 10x10
alph=1;
cr=[249,193,24]/255; % Color for box converted to 0-1 range
f=fill([0 xmax xmax 0],[0 0 ymax ymax],cr);
set(f,'edgecolor','none','facealpha',alph);
% Now we need the circles. Let's extract all their colors now:
cac=[230,224,210]/255; % White big
cbc=[17,18,13]/255; % Dark big
ccc=[44,53,108]/255; % Blueish medium
cdc=[232,161,11]/255; % Inner yellow medium
% Now draw the circles. I played around with the centers and radii until
% they matched the original pretty well. I got one close then added
% another and another, I didn't try to do all at once. For this one, each
% pair shares a center.
circles(5,5,4.5,cac,alph);
circles(5,5,3.75,cbc,alph);
circles(4.4,4.4,2.85,ccc,alph);
circles(4.4,4.4,2.4,cdc,alph);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
return % Code will stop here if not commented out with % symbol!!!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 4. Making the code randomize the output
% This is nice to almost exactly copy, but instead we would like to make a
% new work inspired by the original. This type of artwork is often called
% a pastiche.
% This means the code will pick some values to randomize. At the same
% time, we will collect all the random values so we could "save" the
% requisite numbers needed to regenerate the art later on.
% Set up some local variables to make parameters for the art. Some of the
% parameter values will change each time the code is run.
% For this, we will just put randomly sized circles in random locations
ncirc=3; % How many circles?
p=[ncirc xmax ymax]; % make parameter vector p to reproduce image
% Some things will be random. Collecting all the values allows the image
% to be recreated given the parameter string
% MATLAB has multiple color maps with related colors. The names are
% specified below in the cmaps list for some of them
map=3; % Which colormap to use, 1<map<13
% What are the names of all the color maps?
cmaps={'parula' 'jet' 'hsv' 'hot' 'cool' 'spring' 'summer' 'autumn' ...
'winter' 'gray' 'bone' 'copper' 'pink'};
% Use the colormap function to get the color map
% The colormap name string length can change! That is why it is a {} list
% The number of related colors desired is nc
nc=10 % Number of colors to pull from colormap
% MATLAB can create an arbitrary function call then evaluate it internally
str=['cm=colormap(' cmaps{map} '(nc));']; % Make the MATLAB "command"
eval(str); % This evaluates a string like you typed it
cmi=randperm(nc); % Pick a random order for the colors using randperm
cm=cm(cmi,:); % Re-order the colors randomly, should be a matrix of nc
% rows and 3 columns since we wanted nc different related colors
whos cm
% Create a background box rectangle using the first random color
alph=1;
f=fill([0 xmax xmax 0],[0 0 ymax ymax],cm(1,:));
set(f,'edgecolor','none','facealpha',alph);
p=[p cm(1,:) alph]; % Add background fill color to parameter
%Make some circles of decreasing size
% rand() gives a uniform distribution ranging 0 to 1
for i=(ncirc+1):-1:2 % This increments down instead of up! For three
% circles, the counter i will be 4 then 3 then 2!
alph=1;
xc=3+rand()*4; % This ranges from -1 to 7
yc=3+rand()*4; % This ranges from -1 to 7
cr=(i/2)+(i/2)*rand(); % The radius probably is biggest first iteration
% So the first radius will range from 2-4, second 1.5-3, third is 1-2
circles(xc,yc,cr,cm(i,:),alph); % Draw the circle on top of others
% Save the numbers needed to created this random circle!
p=[p xc yc cr cm(i,:) alph]; % Add circle fill color to parameter list
end
% Clean up the figure nicely here:
axis([0 max([xmax ymax]) 0 max([xmax ymax])]); % make sure it is square
axis square;
set(gca,'XTickLabel',[],'YTickLabel',[]); % Get rid of figure stuff
set(gca,'XTick',[],'YTick',[]);
set(gcf,'color',[1 1 1]);
set(gca,'XColor',[1 1 1],'YColor',[1 1 1]);
% Instead of commenting out code to not run, you can use an IF statement.
% Using the variable named printimage, it can serve as a toggle. Setting
% the variable to 0 will turn off saving the image, setting it to a value
% of 1 will allow the IF statement to run so the image is saved to file
printimage=0 % Set this value to 1 to save a jpg/png image file! 0 to not
if printimage>0 % Start image printing code here!
% You can print the image to file. Two image options are jpeg and png
print testfile.jpg -djpeg
print testfile.png -dpng
% If you investigate these images, a png typically looks better than a
% jpg when you zoom in. However, they both are a bit "pixelated". One
% option in MATLAB to generate higher quality images is to expand the
% figure before you save it.
pos=get(gcf,'Position')
posnew=[pos(1) pos(2) 20*pos(3) 20*pos(4)];
set(gcf,'Position',posnew)
print testfileBIG.png -dpng
set(gcf,'Position',pos) % The original window size needs to be set
% back because the giant window puts controls where you can't move it
% JPG images use lossy image compression. Depending on the amount of
% compression, you can get blotchy colors near crisp color transitions.
% PNG images do not use compression so you get fewer issues.
end % End for image printing code here
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
return % Code will stop here if not commented out with % symbol!!!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 5. Parameterizing the code for reproducibilty
% After running the code a few times, I saw a nice looking random example
% so I kept the parameter vector that should have all the numbers we need
% to reproduce it. The parameters for the image I liked were:
p=[ 3.0000 10.0000 10.0000 0.8000 0 1.0000 1.0000 4.0486 3.1778 3.5099 ...
0.8000 1.0000 0 1.0000 3.9711 4.7696 2.5317 0.2000 1.0000 0 1.0000 ...
4.4369 5.9454 1.3947 0.2000 0 1.0000 1.0000]
% What are these numbers we defined from above? The were defined as:
% p=[ncirc xmax ymax]; % General parameters (3)
% p=[p cm(1,:) alph]; % Adds background fill color parameters (4)
% p=[p xc yc cr cm(i,:) alph]; % Adds circle fill info to parameter 3x(7)
%
% The 28 numbers in my p vector should be enough to reproduce my nice image
% Note this is generalized so that I could change the numer of circles
% above from 3 to something else and my code may still run.
ncirc=p(1); % How many circles?
xmax=p(2); % How big is my canvas in x direction?
ymax=p(3) % How big is my canvas in the y direction?
bc=p(4:6) % Get background color for canvas
bca=p(7); % Background canvas alpha
f=fill([0 xmax xmax 0],[0 0 ymax ymax],bc,'facealpha',bca);
% Now use the rest of the parameters to draw the circles for the nice image
% I liked.
for i=1:ncirc % FOR each circle
% Extract the seven parameters needed for the circle. This is tricky
% to index properly. There are seven values for the first circle. The
% first circle starts at element 8 and ends at 14, second is 15 to 21,
% third is 22 to 28. The index variable i counts up 1, 2, 3:
cdata=p(7+(i-1)*7+1:7+7*i); % grab all seven parameters for this circle
xc=cdata(1); % center for x
yc=cdata(2); % center for y
cr=cdata(3); % circle radius
cc=cdata(4:6); % circle color
alph=cdata(7); % circle alpha
circles(xc,yc,cr,cc,alph);
end
% Now, every time the code is run, the exact same image will be produced
% based on the parameters in my vector p. The vector p is basically the
% "fingerprint" for my image that should hold enough information to
% reproduce the original image. Now I can run the random code until I find
% another nice image, save the corressponding vector p so that I can remake
% the image (or make minor modifications) any time I want.
% Nice sets of data can be saved using the save command. The following
% will make a claisse_nice.mat data file with the vector p
% save claisse_nice p % This will save the vector in the mat file
% load claisse_nice % This loads the data file
% If you only have a single variable to save, you can save as an ASCII text
% file so that other applications could use the data. Sometimes email
% systems will not let you email a MATLAB data file with a .mat extension
% because some .mat files are "dangerous" to PC systems.
% save -ascii claisse_nice.txt p
%
% Howver, when you load the text file, the variable is jsut the file name
% load claisse_nice.txt % This will load the text file
% p=claisse_nice % This will make a copy of the data into variable p
%% 6. User-defined functions
%
% These functions are provided to help do simple things like draw a
% rectangle, draw a circle, or rotate a set of points
%
% These functions can be called from inside this file.
% You can modify the functions if you want.
function [f,X,Y]=rectangle(x,y,dx,dy,c,alph)
% This function draws a rectangle with lower left corner at the point (x,y)
% of dx width and dy height with color c and alpha alph
X=[x x+dx x+dx x];
Y=[y y y+dy y+dy];
f=fill(X,Y,c);
set(f,'edgecolor','none','facealpha',alph);
end
function [f,x,y]=circles(xc,yc,r,c,alph)
% This function draws a circle of radius r and color c and alpha alph
% centered at the point (xc,yc). f is the fill handle object, x and y are
% the sets of x,y points used.
a=[0:0.001:2*pi];
for i=1:length(a)
x(i,1)=r*cos(a(i));
y(i,1)=r*sin(a(i));
end
x=[x ; x(1)];
y=[y ; y(1)];
x=x+xc;
y=y+yc;
f=fill(x,y,c);
set(f,'edgecolor','none','facealpha',alph);
end
function [xx,yy]=rotate(x,y,theta)
% This function takes a list of x,y points, finds a center for them and
% rotates them by theta degrees around the center.
xc=min(x)+(max(x)-min(x))/2;
yc=min(y)+(max(y)-min(y))/2;
dx=x-xc;
dy=y-yc;
rad=theta*pi/180;
xx=cos(rad)*dx-sin(rad)*dy+xc;
yy=sin(rad)*dx+cos(rad)*dy+yc;
end
Comments
Post a Comment