matlab實現手繪風格(簡筆畫風格、漫畫風格)的曲線繪圖

matlab實現手繪風格(簡筆畫風格、漫畫風格)的曲線繪圖

問題的起源是在國外網站的一些論壇上,爲了繪出xkcd漫畫風格的曲線,嘗試用不同的繪圖軟件進行嘗試。

下圖爲xkcd漫畫中的一幅曲線插圖。
xkcd漫畫

比如在Create xkcd style diagram in TeX中,用TeX繪製這種曲線
https://tex.stackexchange.com/questions/74878/create-xkcd-style-diagram-in-tex
比如用python繪製曲線
https://stackoverflow.com/questions/29061729/gnuplot-how-to-mimic-sketch-graphs
在這裏插入圖片描述
還有利用matlab進行嘗試的
https://stackoverflow.com/questions/12701841/xkcd-style-graphs-in-matlab
在這裏插入圖片描述
接下來對上面matlab網站的代碼進行實現,並自己進行一些改進

1 網站上的實現方法

如果上外網比較慢,也可以在CSDN上也可以看到該方法的代碼
https://blog.csdn.net/meatball1982/article/details/80536909
下面我對代碼進行了分析和優化:
算法的思路如下:

1 繪製座標軸,加粗
2 進行曲線繪製,加粗
3 對新疊加的曲線進行加白邊的處理
4 添加手繪效果的字體
5 對整體圖片進行隨機扭動處理

優化的代碼如下:

%定義曲線
x = 1:0.1:10;
y1 = sin(x).*exp(-x/3) + 3;
y2 = 3*exp(-(x-7).^2/2) + 1;

%繪製曲線
fh = figure('color','w');
hold on
plot(x,y1,'b','lineWidth',3);
plot(x,y2,'w','lineWidth',7);
plot(x,y2,'r','lineWidth',3);
%設置座標軸範圍
xlim([0.95 10])
ylim([0 5])
%更改座標軸字體
set(gca,'fontName','Comic Sans MS','fontSize',18,'lineWidth',3,'box','off')
%設置輸出圖片大小
set(fh,'Units','pixels','Position',[100 100 360 270])
%添加文字 
 annotation(fh,'textarrow',[0.3 0.45],[0.55 0.40],...
     'string',sprintf('text%shere',char(10)),'headStyle','none','lineWidth',2,...
     'fontName','Comic Sans MS','fontSize',14,'verticalAlignment','middle','horizontalAlignment','left')

%保存原圖並輸入矩陣
saveas(gcf,'test.bmp');
close all
im=imread('test.bmp');


%增加一點白邊防止後面黑邊
im = padarray(im,[15 15 0],255);

%做隨機扭動特效
sfc = size(im);
[yy,xx]=ndgrid(1:7:sfc(1),1:7:sfc(2));
pts = [xx(:),yy(:)];
tf = fitgeotrans(pts+2*randn(size(pts)),pts,'lwm',12);
w = warning;
warning off images:inv_lwm:cannotEvaluateTransfAtSomeOutputLocations
imt = imwarp(im,tf);
warning(w)

%去除之前白邊
imt = imt(16:end-15,16:end-15,:);
%繪圖
figure('color','w')
imshow(imt)

這是輸出未進行隨機扭曲的圖像
在這裏插入圖片描述
之後對原圖像進行隨機扭曲,得到下圖類似水波紋的效果:
在這裏插入圖片描述

2 自己的實現方法

在之前方法的基礎上加入了perlin噪聲,使得曲線有更大尺度的震盪
原函數繪製如下:
在這裏插入圖片描述
去掉座標軸,加入自己繪製的座標軸,並加入較大尺度的柏林噪聲,得到:
在這裏插入圖片描述
之後將圖像整體進行扭曲
在這裏插入圖片描述
matlab的代碼如下

%自己嘗試的
%定義函數
x = 1:0.1:10;
y1 = sin(x).*exp(-x/3) + 3;
y2 = 3*exp(-(x-7).^2/2) + 1;
xlimtmat=[0.95 10];
ylimtmat=[0 5];

%變化參數
D=0.03;%perlin噪聲振幅
N=3;%perlin噪聲密度
S=1.2;%波動特效
axislabel_x=2:2:8;
axislabel_y=0:2:5;

%第一個圖
fh1 = figure('color','w');
hold on
plot(x,y1,'b','lineWidth',3);
plot(x,y2,'r','lineWidth',3);
hold off
set(fh1,'Units','pixels','Position',[100 100 360 270])
saveas(gcf,'test1.bmp');
close all


%第二個圖
fh2 = figure('color','w');
hold on

%座標軸繪製
xaxis_x=linspace(xlimtmat(1),xlimtmat(end),101);
xaxis_y=linspace(ylimtmat(1), ylimtmat(1) ,101);
yaxis_x=linspace(xlimtmat(1), xlimtmat(1) ,101);
yaxis_y=linspace(ylimtmat(1),ylimtmat(end),101);
plot(xaxis_x,xaxis_y+randfun2(xaxis_x,N)*D*diff(ylimtmat),'k','lineWidth',3)%x軸
plot(yaxis_x+randfun2(yaxis_y,N)*D*diff(xlimtmat),yaxis_y,'k','lineWidth',3)%y軸

%曲線繪製
yrand=randfun2(x,N)*D*diff(ylimtmat);
plot(x,y1+randfun2(x,N)*D*diff(ylimtmat),'b','lineWidth',3);
plot(x,y2+yrand,'w','lineWidth',7);
plot(x,y2+yrand,'r','lineWidth',3);
xlim([xlimtmat(1)-0.8*D*diff(xlimtmat),xlimtmat(end)])
ylim([ylimtmat(1)-0.8*D*diff(ylimtmat),ylimtmat(end)])
axis off



%文字
annotation(fh2,'textarrow',[0.3 0.45],[0.55 0.40],...
     'string',sprintf('text%shere',char(10)),'headStyle','none','lineWidth',2,...
     'fontName','Comic Sans MS','fontSize',14,'verticalAlignment','middle','horizontalAlignment','left')
%座標文字
stringcell_x=num2cell(axislabel_x);
stringcell_y=num2cell(axislabel_y);
text(axislabel_x,0*axislabel_x-diff(xlimtmat)*0.03,stringcell_x,'FontSize',14,'fontName','Comic Sans MS')
text(0*axislabel_y-diff(ylimtmat)*0,axislabel_y,stringcell_y,'FontSize',14,'fontName','Comic Sans MS')%,'HorizontalAlignment','right')

hold off
set(fh2,'Units','pixels','Position',[100 100 360 270])

%保存
saveas(gcf,'test2.bmp');
close all
%讀取爲矩陣
im=imread('test2.bmp');
%增加一點邊防止後面黑邊
im = padarray(im,[15 15 0],255);

%做隨機扭動特效
sfc = size(im);
[yy,xx]=ndgrid(1:7:sfc(1),1:7:sfc(2));
pts = [xx(:),yy(:)];
tf = fitgeotrans(pts+S*randn(size(pts)),pts,'lwm',12);
w = warning;
warning off images:inv_lwm:cannotEvaluateTransfAtSomeOutputLocations
imt = imwarp(im,tf);
warning(w)

%去除之前白邊
imt = imt(16:end-15,16:end-15,:);
%第三個圖
fh3=figure('color','w');
imshow(imt)
set(fh3,'Units','pixels','Position',[100 100 360 270])
saveas(gcf,'test3.bmp');


%生成隨機曲線
function yr=randfun1(x,N)
%利用樣條函數隨機噪聲,效果不好
yR=rand(1,N+2);
xR=x(1)+rand(1,N)*(x(end)-x(1));
xR=[x(1),xR,x(end)];
yr=interp1(xR,yR,x,'spline');
end

function yr=randfun2(x,N)
%利用perlin噪聲
%分配插值點
xP=(x-x(1))/(x(end)-x(1))*N;
%爲插值點分配隨機梯度
uxmat=rand(1,N+2)*2-1;
%設立空矩陣
zmat=0*xP;
for j=1:length(xP)
    %計算每個角點的點積
    %n0
    ddx=xP(j)-floor(xP(j));
    ux=uxmat(1,floor(xP(j))-0+1);
    n0=(ux*ddx);
    %n1
    ddx=xP(j)-floor(xP(j))-1;
%     if floor(xP(j))-0+2==12
%         xP
%     end
    ux=uxmat(1,floor(xP(j))-0+2);
    n1=(ux*ddx);
    %6加權
    zmat(j)=lerp(n0,n1,xP(j)-floor(xP(j)));
end
yr=zmat/N*(x(end)-x(1))+x(1);
end

function u=lerp(a,b,t)%權重相加
    tw=6*t.^5-15*t.^4+10*t.^3;%6*t.^5-15*t.^4+10*t.^3;%3*t.^2-2*t.^3;%
    u=(1-tw)*a + tw*b;
end
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章