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可走可飞,“波函数坍缩”开源算法蹿红

使用 NAudio 无法正确生成方波

利用python和jupyter notebook交互式小部件生成方波,可以实时调节谐波个数和基波频率

正弦信号怎么变成方波信号,需要怎么处理?

图像分解基于matlab GUI二维图像小波分解含Matlab源码 2297期