- 积分
 - 3799
 
	- 贡献
 -  
 
	- 精华
 
	- 在线时间
 -  小时
 
	- 注册时间
 - 2015-7-6
 
	- 最后登录
 - 1970-1-1
 
 
 
 
 
 
 | 
	
 
登录后查看更多精彩内容~
您需要 登录 才可以下载或查看,没有帐号?立即注册 
 
 
 
x
 
 本帖最后由 Lighting 于 2020-5-17 16:40 编辑  
 
 
 
写在最前: 
 
最近重新整理了一下白化的程序,把支持m_map工具箱的功能完善了一下。内容都发在 https://i-lightning.cn/2020/05/matlab_mask/ 这里了,代码也都开源了。此外还加入了一个简单的函数m_mapshow,支持添加任意shapefile文件到地图中。 
 
 
 ================================================== 
        感谢那些对程序的完善提出宝贵意见的朋友。 
        @kc121   对程序的进一步修改提出了宝贵的意见。在此表示由衷的感谢! 
================================================== 
 
       最近看到python板块提供了不少对地图进行完美白化的方法。 
       比如@平流层的萝卜     python完美白化 
              @非对称   利用scipy和sympy扩大三角网格形成的轮廓 
       也看到了MATLAB版对白化功能的讨论,也给出了一些方法。 
       比如 @斥鷃     提供的        matlab中地图边界与掩膜的实现 
               @raul928    提供的        也提供一个去地图外边界的方法 
       上述两种方法都能很好的对地图进行白化。 
       本来想将@非对称 的方法用matlab实现的,大部分代码已经写好,但有一点不是太明白就暂时放置在一旁了。然后在无意之间发现了mapshow函数利用 facecolor属性可以设置区域内白化,经过一番探索,便有了下面的白化方法。 
 
       1)  如果需要白化某一区域内的话,只需要使用mapshow函数即可,以shapefile文件为例                     
 - z = peaks(1000);
 
 - lon = [60 150];
 
 - lat = [10 60];
 
 - [LON,LAT] = meshgrid(linspace(lon(1),lon(2),1000), linspace(lat(1), lat(2),1000));
 
 - c = contourf(LON,LAT,z,'linestyle', 'none');
 
 - mapshow('E:\MATLAB\shp\bou2_4p.shp','displaytype','polygon', 'facecolor','w')
 
  复制代码                 
         mapshow 的 displaytype 属性默认为 'line',这里要设置为'polygon'。 
 
      2) 白化区域外部分 
 
    
 - function maskMap(shapefile, masktype, varargin)
 
 -     %  对所绘制图形进行白化
 
 -     %  输入参数:
 
 -     %      shapefile  :  shapefile文件。 字符串型或元胞型
 
 -     %              为元胞数组时可通过指定多个省份的shp文件进行白化。
 
 -     %              比如要白化江苏省,江西省,黑龙江省。使用元胞数组白化多个省份,需要手动添加中国边界地图
 
 -     %              shapefile = {'path\江苏省.shp', 'path\江西省.shp', 'path\黑龙江省.shp'}
 
 -     %                  其中path为shp文件所在路径
 
 -     %       masktype  : 逻辑值。
 
 -     %           true  :  对区域外进行白化
 
 -     %                可选参数:
 
 -     %                    longitudes : 图形的经度范围,二元素向量。 数值型。
 
 -     %                    latitudes  :  图形的纬度范围,二元素向量。 数值型。
 
 -     %                    multiprovinces : 元胞数组。
 
 -     %                    用于指定要白化的多个区域。使用此参数需要shapefile为字符型且要包含省份名称
 
 -     %                    此处建议大家使用 bou2_4p.shp 进行白化
 
 -     %                              比如要白化江苏省,江西省,黑龙江省,则
 
 -     %                         multipro = {'江苏省','江西省','黑龙江省'}
 
 -     %                    reversemask  :  指定要白化的是 multiprovinces 元胞中指定的区域还是
 
 -     %                                  元胞中指定的区域以外的部分。 逻辑值。
 
 -     %                                true  :  表示白化元胞中指定的区域。 默认值。
 
 -     %                                false :  表示白化元胞中指定区域以外的部分。
 
 -     %           false :  对区域内进行白化
 
 -     %      共享可选参数值对:
 
 -     %           facecolor :  用于指定白化区域的颜色。 默认为白色。 字符型或数值型。
 
 -     %                        取值为 'none'时,不起作用。数值型时为RGB三元组。
 
 -     %           edgecolor :  指定的边界线的颜色。 默认为黑色。 字符型或数值型。同上。
 
 -     %           linewidth :  边界线宽度。 默认为1. 数值型。
 
 -     %%
 
 -     p = inputParser;
 
 -     validShape = @(x) ischar(x) || iscell(x);
 
 -     validLLFcn = @(x) isvector(x) && length(x) == 2;
 
 -     validFaceFcn = @(x) (ischar(x) && ~strcmp(x, 'none')) || (isvector(x) && length(x) == 3);
 
 -     validEdgeFcn = @(x) ischar(x) || (isvector(x) && length(x) == 3);
 
 -     defaultLon = [];  defaultLat = []; defaultProv = {}; defaultReve = true;
 
 -     defaultFace = 'w';  defaultLine = 'k';  defaultWidth = 1;
 
  
-     addRequired(p, 'shapefile', validShape)
 
 -     addRequired(p, 'masktype', @islogical);
 
 -     addParameter(p, 'longitudes', defaultLon, validLLFcn);
 
 -     addParameter(p, 'latitudes', defaultLat, validLLFcn);
 
 -     addParameter(p, 'multiprovinces', defaultProv, @iscell);
 
 -     addParameter(p, 'reversemask', defaultReve, @islogical);
 
 -     addParameter(p, 'facecolor', defaultFace, validFaceFcn)
 
 -     addParameter(p, 'edgecolor', defaultLine, validEdgeFcn)
 
 -     addParameter(p, 'linewidth', defaultWidth, @isnumeric)
 
  
-     parse(p, shapefile, masktype, varargin{:});
 
  
-     if p.Results.masktype
 
 -         longitudes = p.Results.longitudes;
 
 -         latitudes = p.Results.latitudes;
 
 -         if isempty(longitudes) || isempty(latitudes)
 
 -             error('需指定经纬度范围!')
 
 -         end
 
 -         loninc = longitudes(1):longitudes(end);
 
 -         latinc = latitudes(1):latitudes(end);
 
 -         lone = ones(1,length(latinc)-2)*longitudes(end);
 
 -         lons = ones(1,length(latinc)-1)*longitudes(1);
 
 -         lats = ones(1,length(loninc)-1)*latitudes(1);
 
 -         late = ones(1,length(loninc)-2)*latitudes(end);
 
 -         LON = [loninc lone loninc(end:-1:1) lons NaN];
 
 -         LAT = [lats latinc late latinc(end:-1:1) NaN];
 
 -         [LON,LAT] = poly2cw(LON,LAT);
 
 -        
 
 -         if ischar(p.Results.shapefile)
 
 -             s = shaperead(p.Results.shapefile);
 
 -             if isfield(s,'NAME')
 
 -                 allprovs = {s.NAME}';
 
 -                 allprovnum = length(allprovs);
 
 -                 maskindex = zeros(allprovnum,1);
 
 -             elseif isfield(s,'NAME99')
 
 -                 allprovs = {s.NAME99}';
 
 -                 allprovnum = length(allprovs);
 
 -                 maskindex = zeros(allprovnum,1);
 
 -             end
 
 -             long = [s.X];  lati = [s.Y];
 
 -             % 获取指定的多个省份的边界点
 
 -             if ~isempty(p.Results.multiprovinces)
 
 -                 provinces = p.Results.multiprovinces;
 
 -                 pronum = length(p.Results.multiprovinces);
 
 -                 for ii = 1:pronum
 
 -                     sindex = strfind(allprovs, provinces{ii});
 
 -                     if any(cell2mat(sindex))
 
 -                         for jj = 1: allprovnum
 
 -                             if isempty(sindex{jj}) ; sindex{jj} = 0; end;
 
 -                         end
 
 -                         maskindex = maskindex | cell2mat(sindex);
 
 -                     else
 
 -                         error('所选省份 %s 不在指定的shp文件中或省份名错误!',provinces{ii})
 
 -                     end
 
 -                 end
 
 -                 if p.Results.reversemask
 
 -                     maskindex = ~maskindex;  % 指定省份以外的省份在shapefile中的索引
 
 -                 end
 
 -                 LON = [LON s(maskindex).X];
 
 -                 LAT = [LAT s(maskindex).Y];
 
 -             end
 
 -         elseif iscell(p.Results.shapefile)
 
 -             s = shaperead(p.Results.shapefile{1});
 
 -             long = s.X;  lati = s.Y;
 
 -             for jj = 2:length(p.Results.shapefile)
 
 -                 s = shaperead(p.Results.shapefile{jj});
 
 -                 [long, lati] = polybool('union',long,lati, s.X, s.Y);
 
 -             end
 
 -         end
 
 -        
 
 -         [xc, yc] = polybool('xor', LON,LAT , long, lati);
 
 -         [f, v] = poly2fv(xc, yc);
 
 -         %此处edgecolor必须为none,否则facecolor属性值将失效
 
 -         patch('Faces', f, 'Vertices', v, 'FaceColor', p.Results.facecolor, 'edgecolor', 'none');
 
 -         mapshow(long ,lati, 'color', p.Results.edgecolor, 'linewidth', p.Results.linewidth);
 
 -         set(gca, 'xlim', p.Results.longitudes,'ylim', p.Results.latitudes)
 
 -     else
 
 -         if ischar(p.Results.shapefile)
 
 -             mapshow(p.Results.shapefile,'displaytype','polygon','facecolor',p.Results.facecolor,'edgecolor',p.Results.edgecolor,'linewidth',p.Results.linewidth)
 
 -         else
 
 -             error('仅支持单文件白化!')
 
 -         end
 
 -     end
 
 -     end
 
  复制代码 
 
 
        maskMap函数提供了一个逻辑值选项用于选择区域内白化还是区域外白化。如果是区域内白化,只需要提供shapefile和masktype两个参数即可,如果选择区域外白化,除上述两个参数之外,还需要提供‘longitudes’ 和 'latitudes' 两个参数,调用方式和matlab内置函数调用方式类似。     
        参考@平流层的萝卜 的python完美白化的帖子,也支持了白化几个省份的部分。
   
         无论是白化区域内还是白化区域外,均可以通过设置  facecolor, edgecolor, linewidth等属性值设置 白化区域的颜色,边界线颜色,线宽等。鉴于白化时通常只需要改变这几个属性,目前仅支持这几个属性。 
         下图是放大之后的,可以看出已经 完美白化了,没有任何锯齿存在!
  
            直接调用上述函数即可。使用精确到县级的shp文件。示例代码如下:
 - z = peaks(1000);
 
 - lon = [60 135];
 
 - lat = [10 60];
 
 - [LON,LAT] = meshgrid(linspace(lon(1),lon(2),1000), linspace(lat(1), lat(2),1000));
 
 - c = contourf(LON,LAT,z,'linestyle', 'none');
 
 - maskMap('E:\MATLAB\shp\BOUNT_poly.shp',true,'lon',lon,'lat',lat,'linewidth',0.5, 'edgecolor','b')
 
 
  复制代码            可以看出,使用县级文件进行白化也毫无问题!           
================================================= 
          2016.9.8   解决调用 maskMap 函数白化区域内出错的问题。程序已经更改,复制替换源程序即可。 
     2016.9.9    解决白化时设置edgecolor 属性值为非'none'值时出现一条直线的问题。 
     2016.9.14   解决设置等值线线型后无法白化区域外等值线的问题(2016a版本可行,2014a版本不可行。应该是语法有更新导致);同时通过更改白化方法解决了设置线宽过大时或颜色不为黑色时,坐标轴会出现粗线或多颜色相间的问题。 
     2016.9.23   释放使用RGB三元组设置facecolor 和 edgecolor 属性值。 
 
      把重新编辑后的内容以PDF文档的形式上传,其中包括了对函数的详细解释,以及最新更新(当然最新的程序也已更新在 2)中)。白化算法有更新,但是文档内程序未更新,不过用法是相同的。 
 
       注意:如果使用过程中出现以下错误提示,说明你使用的MATLAB版本较低,请更换到更高版本,建议更新到2015版之后。 
- Undefined function 'addParameter' for input arguments of type 'inputParser'.
 
  复制代码   
==== 插播更新利用m_map工具箱生成海岸线数据进行白化 ==== 
     最近看了一下m_map工具箱中关于生成海岸线的部分,发现可以自定义常用的绘图区,结合上面的白化方法,便想着利用m_map工具箱和 gshhs 高精度地形数据制作用于白化的数据。 
      废话不多说,直接上程序。 
      
- lon = [60 150]; lat = [10 60]; 
 
 - FILNAME = 'private/gshhs_i.b';
 
 - h = figure;
 
 - m_proj('mercator', 'longitudes', lon, 'latitudes', lat)
 
 - m_grid('box','on')
 
 -  % mu_coast一般情况下是不可调用的,可把private文件夹下的函数复制到另一个文件夹下
 
 - % 把该文件夹加入到搜索路径中
 
 - mu_coast('i',FILNAME,'tag','m_gshhs_i');  
 
 - m_gshhs_i('save','test')  % 保存 ncst , area ,k 数据到 test.mat 文件中
 
 - set(h , 'visible','off')   % 不显示图形。如果想显示图形到窗口可注释此语句
 
 
  复制代码 
     上面这部分用于生成绘图海岸线数据。 
      下一步就是调用函数生成用于白化的海岸线数据。 
- function coast = creatCoast(longitudes,latitudes, ncst)
 
 - % 生成用于掩膜的经纬度数组
 
 - %   输入参数:
 
 - %       longitudes  : 经度起止坐标. 二元素向量.
 
 - %       latitudes   : 纬度起止坐标. 二元素向量.
 
 - %          ncst     : 由m_gshhs_* 函数生成的高精度经纬度坐标信息
 
 - %                     N X 2 数组。 其中第一列为经度信息
 
 - %                                      第二列为纬度信息
 
 - %   输出参数:
 
 - %        coast 为结构体变量. 包含了用于白化的经纬度信息
 
 - %            coast.long  存储的是经度信息
 
 - %            coast.lat   存储的是纬度信息
 
 - %%
 
 - validateattributes(longitudes,{'double'}, {'vector','numel',2})
 
 - validateattributes(latitudes,{'double'}, {'vector', 'numel',2})
 
 - validateattributes(ncst,{'double'}, {'ncols',2})
 
  
- loninc = longitudes(1):longitudes(end);
 
 - latinc = latitudes(1):latitudes(end);
 
 - lone = ones(1,length(latinc)-2)*longitudes(end);
 
 - lons = ones(1,length(latinc)-1)*longitudes(1);
 
 - lats = ones(1,length(loninc)-1)*latitudes(1);
 
 - late = ones(1,length(loninc)-2)*latitudes(end);
 
 - LON.index = [loninc lone loninc(end:-1:1) lons NaN];
 
 - LAT.index = [lats latinc late latinc(end:-1:1) NaN];
 
 - LON.index = [LON.index ncst(:,1)'];
 
 - LAT.index = [LAT.index ncst(:,2)'];
 
  
- coast.long = LON.index;
 
 - coast.lat = LAT.index;
 
  
- end
 
  复制代码 
         注意: 从头到尾所使用的经纬度的起止范围要是相同的,不要频繁更改经纬度起止范围。
 - z = peaks(1000);
 
 - lon = [60 150];
 
 - lat = [10 60];
 
 - [LON,LAT] = meshgrid(linspace(lon(1),lon(2),1000), linspace(lat(1), lat(2),1000));
 
 - figure
 
 - contourf(LON,LAT,z,'linestyle' , 'none')
 
 - load test.mat
 
 - coast = creatCoast(lon,lat,ncst);
 
 - % displaytype 要设置为 'polygon' 
 
 - mapshow(coast.long,coast.lat, 'Displaytype', 'polygon', 'facecolor', 'w', 'edgecolor', 'k', 'linewidth', 1);
 
  复制代码 
       执行后会发现有一点问题!竟然凭空的多出一块出来!应该是自定义海岸线时,多了一部分,但是究竟是怎么回事暂时不清楚。 
不用担心,解决这个问题很简单!只要执行以下语句限制坐标轴范围就行了! 
 - set(gca, 'xlim', lon, 'ylim', lat)
 
  复制代码          除直接限制坐标轴范围外,还可以进行数据筛选,把超出范围部分找出,然后去除即可。 
        以上部分仅供参考。 
 
=========  提供一种 MATLAB Central 中提到的一种白化方法 ============== 
        首先附上链接: ocean mask 
         
        文中提到的白化方法是利用MATLAB自带的coast.mat文件进行白化,主要是反转全球海岸线经纬度向量的顶点方向进行白化。尝试着反转中国的shp数据和gshhs数据进行白化,但是均以失败告终。如果大家有兴趣可以尝试一下。成功了的话欢迎科普  
 
        测试代码: 
- coast = load('coast');
 
 - z = peaks(1000);
 
 - lon = [60 150];
 
 - lat = [10 60];
 
 - figure('Color','w')
 
 - axesm('mercator','MapLatLimit',lat,'MapLonLimit', lon)
 
 - axis off; framem on; gridm on; mlabel on; plabel on;
 
 - setm(gca,'MLabelLocation',60)
 
  
- R=makerefmat('RasterSize',size(z),'Lonlim', lon,'Latlim',lat);
 
 - contourfm(z,R,'linestyle','none')
 
 - geoshow(flipud(coast.lat),flipud(coast.long),'DisplayType','polygon','facecolor','w')
 
  复制代码 
 
 
 
maskMap.pdf
(780.95 KB, 下载次数: 477)
 |   
 
评分
- 
查看全部评分
 
 
 
 
 
 |