MATLAB | 二维波函数坍缩算法随机地图生成
Posted slandarer
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MATLAB | 二维波函数坍缩算法随机地图生成相关的知识,希望对你有一定的参考价值。
注
本文原理解释和很多图片结构来自和参考了知乎大佬大灰熊
的这篇:
https://zhuanlan.zhihu.com/p/542605872
算法解释
该算法叫做二维波函数坍缩算法,虽然名听着很玄乎但其实和数独区别也不大,都是一些图决定周围图能取哪些:
在网站
(http://cr31.co.uk/stagecast/wang/tiles_e.html)可以获取一系列的素材图:
这张图每32个像素就是一个图块,整张图能划分为4x4个图块
图像分割且编号
% 图片切分
imgListN*N=[];
pixNum=size(img,1)/N;
for i=1:N
for j=1:N
imgListsub2ind([N,N],i,j)=...
img(((i-1)*pixNum+1):(i*pixNum),...
((j-1)*pixNum+1):(j*pixNum),:);
end
end
各个方向的可行图
比如编号为10的图像右侧只有几张图可以与之相邻:
可以通过计算边界的均方根误差,若是误差小于一定值就认为可以相连(就有点像某年数学建模国赛碎纸片拼接第一问):
% 构建联通表
imgAdjList(N*N).r=[];
imgAdjList(N*N).l=[];
imgAdjList(N*N).u=[];
imgAdjList(N*N).d=[];
for i=1:N*N
imgC=imgListi;
imgAdjList(i).r=[];
imgAdjList(i).l=[];
imgAdjList(i).u=[];
imgAdjList(i).d=[];
for j=1:N*N
imgS=imgListj;
% 以下是均方根误差检测部分
% 检测是否右联通 -----------------------------------------------------------
rImgC=imgC(:,end,:);rImgC=rImgC(:);
rImgS=imgS(:,1,:);rImgS=rImgS(:);
rErr=sqrt(mean((rImgC-rImgS).^2));
if rErr<err
imgAdjList(i).r=[imgAdjList(i).r,j];
end
% 检测是否左联通 -----------------------------------------------------------
lImgC=imgC(:,1,:);lImgC=lImgC(:);
lImgS=imgS(:,end,:);lImgS=lImgS(:);
lErr=sqrt(mean((lImgC-lImgS).^2));
if lErr<err
imgAdjList(i).l=[imgAdjList(i).l,j];
end
% 检测是否上联通 -----------------------------------------------------------
uImgC=imgC(1,:,:);uImgC=uImgC(:);
uImgS=imgS(end,:,:);uImgS=uImgS(:);
uErr=sqrt(mean((uImgC-uImgS).^2));
if uErr<err
imgAdjList(i).u=[imgAdjList(i).u,j];
end
% 检测是否下联通 -----------------------------------------------------------
dImgC=imgC(end,:,:);dImgC=dImgC(:);
dImgS=imgS(1,:,:);dImgS=dImgS(:);
dErr=sqrt(mean((dImgC-dImgS).^2));
if dErr<err
imgAdjList(i).d=[imgAdjList(i).d,j];
end
end
end
这里err值设置为40,可根据需要调整,进行完上述步骤后获得联通表,举例一下编号为10的图可与之相邻的图:
imgAdjList(10)
ans =
包含以下字段的 struct:
r: [9 10 11 12 13 14 15 16]
l: [5 6 7 8 9 10 11 12]
u: [1 2 5 6 9 10 13 14]
d: [2 3 6 7 10 11 14 15]
编号填充
要生成新图片的编号矩阵,首先生成全0矩阵,之后就需要不断地随机产生随机数往0的位置填充,填充的随机数需要能与当前上下左右的图相邻:
每当有一部分图片被确定,就有一部分位置只能填入特殊的图片。
% 构建序号矩阵
% 不想进行太多次回退,回退五次直接重新生成
indMat=zeros(rows,cols);
while any(any(indMat==0))
try
indMat=zeros(rows,cols);
for j=1:cols
for i=1:rows
k=sub2ind([rows,cols],i,j);
for kk=1:5% 回退五次
[ti,tj]=ind2sub([rows,cols],k);
fullList=fillij(indMat,imgAdjList,N,ti,tj);
if ~isempty(fullList)
indMat(ti,tj)=fullList(randi([1,length(fullList)],[1,1]));
k=k+1;
if k>sub2ind([rows,cols],i,j)
break
end
else
indMat(ti,tj)=0;
k=k-1;
end
end
end
end
catch
end
end
function fList=fillij(indMat,imgAdjList,N,i,j)
fList=1:N*N;
% 右侧图的左侧可行图 --------------------------------------------------------
if j+1>N,rInd=0;else,rInd=indMat(i,j+1);end
if rInd==0,rIndList=1:N*N;else,rIndList=imgAdjList(rInd).l;end
fList=intersect(fList,rIndList);
% 左侧图的右侧可行图 --------------------------------------------------------
if j-1<1,lInd=0;else,lInd=indMat(i,j-1);end
if lInd==0,lIndList=1:N*N;else,lIndList=imgAdjList(lInd).r;end
fList=intersect(fList,lIndList);
% 上侧图的下侧可行图 --------------------------------------------------------
if i-1<1,uInd=0;else,uInd=indMat(i-1,j);end
if uInd==0,uIndList=1:N*N;else,uIndList=imgAdjList(uInd).d;end
fList=intersect(fList,uIndList);
% 下侧图的上侧可行图 --------------------------------------------------------
if i+1>N,dInd=0;else,dInd=indMat(i+1,j);end
if dInd==0,dIndList=1:N*N;else,dIndList=imgAdjList(dInd).u;end
fList=intersect(fList,dIndList);
end
工具函数完整代码
function newImg=waveCollapse(img,N,rows,cols)
% @author : slandarer
% gzh : slandarer随笔
img=double(img);err=40;
% =========================================================================
% 图片切分
imgListN*N=[];
pixNum=size(img,1)/N;
for i=1:N
for j=1:N
imgListsub2ind([N,N],i,j)=...
img(((i-1)*pixNum+1):(i*pixNum),...
((j-1)*pixNum+1):(j*pixNum),:);
end
end
% =========================================================================
% 构建联通表
imgAdjList(N*N).r=[];
imgAdjList(N*N).l=[];
imgAdjList(N*N).u=[];
imgAdjList(N*N).d=[];
for i=1:N*N
imgC=imgListi;
imgAdjList(i).r=[];
imgAdjList(i).l=[];
imgAdjList(i).u=[];
imgAdjList(i).d=[];
for j=1:N*N
imgS=imgListj;
% 以下是均方根误差检测部分
% 检测是否右联通 -----------------------------------------------------------
rImgC=imgC(:,end,:);rImgC=rImgC(:);
rImgS=imgS(:,1,:);rImgS=rImgS(:);
rErr=sqrt(mean((rImgC-rImgS).^2));
if rErr<err
imgAdjList(i).r=[imgAdjList(i).r,j];
end
% 检测是否左联通 -----------------------------------------------------------
lImgC=imgC(:,1,:);lImgC=lImgC(:);
lImgS=imgS(:,end,:);lImgS=lImgS(:);
lErr=sqrt(mean((lImgC-lImgS).^2));
if lErr<err
imgAdjList(i).l=[imgAdjList(i).l,j];
end
% 检测是否上联通 -----------------------------------------------------------
uImgC=imgC(1,:,:);uImgC=uImgC(:);
uImgS=imgS(end,:,:);uImgS=uImgS(:);
uErr=sqrt(mean((uImgC-uImgS).^2));
if uErr<err
imgAdjList(i).u=[imgAdjList(i八度 - 生成方波(信号/脉冲)
无尽虚拟城市来了!Demo可走可飞,“波函数坍缩”开源算法蹿红