元胞自动机(Cellular Automata)与城市规划及其MATLAB实现——莆田市城市发展预测

github:https://github.com/Myoontyee/CA-city-planning-for-Putian-by-MATLAB

前言

探索元胞自动机用于城市规划,是由于前不久在CSDN上看到相关案例后大开眼界,兴趣使然,想对家乡做一个城市发展预测,遂在巨人的肩膀上做一些探索与更正。文章末尾有这些案例的链接,感谢并致敬这些先行者。

背景

概念
元胞自动机(cellular automata,CA) 是一种时间、空间、状态都离散,空间相互作用和时间因果关系为局部的网格动力学模型,具有模拟复杂系统时空演化过程的能力。
不同于一般的动力学模型,元胞自动机不是由严格定义的物理方程或函数确定,而是用一系列模型构造的规则构成。凡是满足这些规则的模型都可以算作是元胞自动机模型。因此,元胞自动机是一类模型的总称,或者说是一个方法框架。其特点是时间、空间、状态都离散,每个变量只取有限多个状态,且其状态改变的规则在时间和空间上都是局部的。
城市模型

  • 1950s~1960s
    静态、均衡、宏观
  • 1980s+
    动态、微观

环境

Windows7 x64
MATLAB R2016a

特点

i)简单、直观
ii)离散
iii)灵活、开发
iv)易与GIS、遥感数据处理系统结合

用法

  • 输入
    图像
  • f(x)
    CA for city planning
  • 输出
    城市规模仿真模拟结果

参数

针对程序中的可修改参数给出释义。
1)扩散因子
代码:

diffuseFactor=0.2;          % 扩散因子

影响城市化过程中,元胞的扩散速率

  • 输入
    扩散因子数值
  • 输出
    定义扩散因子
  • Tip
    输入应为正数,接受>1的数值

2)繁殖因子
代码:

proliferateFactor=0.2;      % 繁殖因子

影响城市化过程中,元胞的繁殖速率

  • 输入
    繁殖因子数值
  • 输出
    定义繁殖因子
  • Tip
    输入应为正数,接受>1的数值

3)传播因子
代码:

propagateFactor=0.2;        % 传播因子

影响城市化过程中,元胞的传播速率

  • 输入
    传播因子数值
  • 输出
    定义传播因子
  • Tip
    输入应为正数,接受>1的数值

4)城市化因子
代码:

Urbanization=0.0004;        % 城市化因子

影响城市化速率

  • 输入
    城市化因子数值
  • 输出
    定义城市化因子
  • Tip
    输入应为正数,接受>1的数值,但数值过大会导致求解失真,下图为城市化因子为2,迭代次数为3的结果,是不正确的结果。
    元胞自动机(Cellular Automata)与城市规划及其MATLAB实现——莆田市城市发展预测

代码

使用的图片
i)莆田市地图
元胞自动机(Cellular Automata)与城市规划及其MATLAB实现——莆田市城市发展预测
ii)经过二值化处理的莆田市地图
元胞自动机(Cellular Automata)与城市规划及其MATLAB实现——莆田市城市发展预测

1)CityCA.m

clear;close all
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% Author: Myoontyee.Chen
%% Data:20181227
%% License:BSD 3.0
%% CA - City Planning

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% 图像预处理
I=imread('city.png');
level=graythresh(I);   % 图像灰度处理
bw=im2bw(I,level);  % 图像二值化处理
I=bw;
cells=double(I);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% button定义
plotbutton=uicontrol('style','pushbutton',...
'string','Run',...
'fontsize',12,...
'position',[100,400,50,20],...
'callback','runModel=1;');
erasebutton=uicontrol('style','pushbutton',...
'string','Stop',...
'fontsize',12,...
'position',[300,400,50,20],...
'callback','stopModel=1;');
Iterations=uicontrol('style','text',...
'string','1',...
'fontsize',12,...
'position',[20,400,50,20]);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% Initialization参数初始化
cells(33,44)=2;
cells(88,31)=2;
cells(33,80)=2;

%% 可修改参数
diffuseFactor=0.2;          % 扩散因子
proliferateFactor=0.2;      % 繁殖因子
propagateFactor=0.2;        % 传播因子
Urbanization=0.0004;        % 城市化因子

%% 建议默认参数
sch=[];skz=[];t=1;
[x,y]=size(cells);
runModel=0;
stopModel=0;
stop=0;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% 法则定义
while (stop==0)
    
    %% 按下Run
    if(runModel==1)
        for i=2:x-1
            for j=2:y-1
                if(cells(i,j)~=1)
                    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
                
                  %% 自然增长
                    if(cells(i,j)==0) 
                        if(rand<Urbanization)
                        cells(i,j)=2;
                        end
                        if(aroundCenter(i,j,cells))
                            if(rand<propagateFactor)
                            cells(i,j)=2;
                            end
                        end
                    end
                
                    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
                
                 %% 边界增长
                    if(cells(i,j)==2 && rand<diffuseFactor)  
                        if(existCase(i,j,cells))   
                        m=1+3*rand;
                            switch  m
                                case 1
                                    ii=i-1;jj=j;
                                case 2
                                    ii=i;jj=j-1;
                                case 3
                                    ii=i;jj=j+1;
                                otherwise 4
                                    ii=i+1;jj=j;
                            end
                            if(canCity(ii,jj,cells))  
                            cells(ii,jj)=2;
                            end
                        end
                    end
                
                    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
              
                  %% 新扩展中心型
                    if(cells(i,j)==2 && existCase(i,j,cells))
                        if(rand<proliferateFactor)
                            if(canCity(i,j,cells))
                            cells(i,j)=3;
                            end
                        end
                    end
                
                    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
                end
            end
        end

        ch=0;kzch=0;

        for i=1:x
            for j=1:y
                if(cells(i,j)==2) ch=ch+1;end
                if(cells(i,j)==3) kzch=kzch+1;end
            end
        end

        sch(t)=ch;skz(t)=kzch;
        t=t+1;

        [A,B]=size(cells);
        Area(1:A,1:B,1)=zeros(A,B);
        Area(1:A,1:B,2)=zeros(A,B);
        Area(1:A,1:B,3)=zeros(A,B);

        for i=1:A
            for j=1:B
                if cells(i,j)==1
                    Area(i,j,:)=[1,1,1]; % 黑色
                elseif cells(i,j)==0
                    Area(i,j,:)= [255, 255, 255]; % 白色
                elseif cells(i,j)==3
                    Area(i,j,:)= [255,0,0]; % 红色
                elseif cells(i,j)==2
                    Area(i,j,:)= [255,177,0]; % 橙色
                end
            end
        end

        pause(0.0005);
        Area=uint8(Area);
        imagesc(Area);
        axis equal;
        axis tight;

        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
       
       %% 迭代次数记录
        IterationNum=1+str2num(get(Iterations,'string'));
        set(Iterations,'string',num2str(IterationNum));
    end
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    
    %% 按下Stop
    if stopModel==1
    runModel=0;
    stopModel=0;
    end
    
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%   

%% 暂停并刷新图像
drawnow
end

2)existCase.m

function result= existCase(i,j,cells)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% Author: Myoontyee.Chen
%% Data:20181227
%% License:BSD 3.0
%% existCase - Correspondence rule

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
a=0;
if(cells(i-1,j)==2)  a=a+1; end
if(cells(i,j-1)==2)  a=a+1;end
if(cells(i,j+1)==2)  a=a+1;end
if(cells(i+1,j)==2)  a=a+1;end
if(a>=2)
    result=1;
else
    result=0;
end
end

3)canCity.m

function result=canCity(i,j,cells)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% Author: Myoontyee.Chen
%% Data:20181227
%% License:BSD 3.0
%% canCity - Correspondence rule

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
s=0
if(cells(i-1,j-1)==1)   s=s+1;end
if(cells(i-1,j)==1)     s=s+1;end
if(cells(i-1,j+1)==1)   s=s+1;end
if(cells(i,j-1)==1)     s=s+1;end
if(cells(i,j+1)==1)     s=s+1;end
if(cells(i+1,j-1)==1)   s=s+1;end
if(cells(i+1,j)==1)     s=s+1;end
if(cells(i+1,j+1)==1)   s=s+1;end
if(s>=4)
    result=0;
else 
    result=1;
end
end

4)aroundCenter.m

function a=aroundCenter(i,j,cells)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% Author: Myoontyee.Chen
%% Data:20181227
%% License:BSD 3.0
%% aroundCenter - Correspondence rule

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
a=0;
if(cells(i-1,j)==3)  a=1; end
if(cells(i,j-1)==3)  a=1;end
if(cells(i,j+1)==3)  a=1;end
if(cells(i+1,j)==3)  a=1;end
end

输出

城市发展模拟过程如下图:
元胞自动机(Cellular Automata)与城市规划及其MATLAB实现——莆田市城市发展预测
元胞自动机(Cellular Automata)与城市规划及其MATLAB实现——莆田市城市发展预测

其他

结果与真实情况相差较大,内部算法有待改善。
若你来自兰州,也可以用文件夹里的兰州地图跑一遍程序,是有意思的小例子。

参考

[1]基于元胞自动机的城市规划
[2]【matlab】基于元胞自动机的城市规划(程序修正)
[3]https://wenku.baidu.com/view/ddf76d8c50e2524de4187e45.html