www.gusucode.com > map 案例源码 matlab代码程序 > map/mapexwmsanimate.m

    %% Compositing and Animating Web Map Service (WMS) Meteorological Layers
%
% This example shows how to composite and animate data from multiple Web
% Map Service (WMS) layers.
%
% The base layer is from the NASA Goddard Space Flight Center's Scientific
% Visualization Studio (SVS) Image Server. The data in this layer shows
% satellite cloud data during Hurricane Katrina from August 23 through
% August 30, 2005. The layer consists of cloud data extracted from GOES-12
% imagery and overlaid on a color image of the southeast United States.
%
% Next-Generation Radar (NEXRAD) images, collected by the Iowa State
% University's Iowa Environmental Mesonet (IEM) Web map server, are
% composited with the cloud data at regular intervals of time.
%
% In particular, this example will show you how to:
%
% * Use the WMS database to find the Katrina and NEXRAD layers
% * Retrieve the Katrina base map from a WMS server at a particular time-step
% * Retrieve the NEXRAD map from a WMS server at the same time-step
% * Composite the base map with the map containing the NEXRAD imagery
% * View the composited map in a projected coordinate system
% * Retrieve, composite, and animate multiple time sequences
% * Create a video file and animated GIF file of the animation

% Copyright 2010-2015 The MathWorks, Inc.

%% Understanding Basic WMS Terminology
% If you are new to WMS, several key concepts are important to understand
% and are listed here.
%%
% 
% * _Web Map Service_  --- The Open Geospatial Consortium (OGC) defines a 
%   Web Map Service (WMS) to be an entity that "produces maps of spatially
%   referenced data dynamically from geographic information."
% * _WMS server_ --- A server that follows the guidelines of the OGC to 
%   render maps and return them to clients
% * _map_ --- The OGC definition for map is "a portrayal of geographic 
%   information as a digital image file suitable for display on a computer 
%   screen."
% * _layer_ --- A dataset of a specific type of geographic information, such 
%   as temperature, elevation, weather, orthophotos, boundaries, 
%   demographics, topography, transportation, environmental measurements, 
%   and various data from satellites
% * _capabilities document_ --- An XML document containing metadata 
%   describing the geographic content offered by a server

%% Source Function
% The code shown in this example can be found in this function:
function mapexwmsanimate(useInternet,datadir)

%% Internet Access
% Since WMS servers are located on the Internet, this example can be set to
% access the Internet to dynamically render and retrieve maps from WMS
% servers or it can be set to use data previously retrieved from the
% Internet using the WMS capabilities but now stored in local files. You
% can use a variable, |useInternet|, to determine whether to read data from
% locally stored files, or retrieve the data from the Internet.
%
% If the |useInternet| flag is set to true, then an Internet connection
% must be established to run the example. Note that the WMS servers may be
% unavailable, and several minutes may elapse before the maps are returned.
% One of the challenges of working with WMS servers is that sometimes you
% will encounter server errors. A function, such as |wmsread|, may time out
% if a server is unavailable. Often, this is a temporary problem and you
% will be able to connect to the server if you try again later. For a list
% of common problems and strategies for working around them, please see the
% Common Problems with WMS Servers section in the Mapping Toolbox(TM)
% User's Guide.
%
% You can store the data locally the first time you run the example and
% then set the |useInternet| flag to false. If the |useInternet| flag is
% not defined, it is set to false.
if ~exist('useInternet', 'var') 
    useInternet = false;
end

%% Setup: Define a Data Directory and Filename Utility Function
% This example writes data to files if |useInternet| is |true| or reads data
% from files if |useInternet| is |false|. It uses the variable |datadir| to
% denote the location of the folder containing the data files.
if ~exist('datadir','var')
    datadir = fullfile(matlabroot,'examples','map');
end
if ~exist(datadir,'dir')
    mkdir(datadir)
end

%%
% Define an anonymous function to prepend |datadir| to the input filename:
datafile = @(filename) fullfile(datadir,filename);

%% Step 1: Find Katrina Layers From Local Database
% One of the more challenging aspects of using WMS is finding a WMS server
% and then finding the layer that is of interest to you. The process of
% finding a server that contains the data you need and constructing a
% specific and often complicated URL with all the relevant details can be 
% very daunting. 
%
% The Mapping Toolbox(TM) simplifies the process of locating WMS servers
% and layers by providing a local, installed, and pre-qualified WMS
% database, that is searchable, using the function |wmsfind|. You can
% search the database for layers and servers that are of interest to you.
% Here is how you find layers containing the term |katrina| in either the
% |LayerName| or |LayerTitle| field of the database:
katrina = wmsfind('katrina');
whos katrina

%%
% The search for the term |'katrina'| returned a |WMSLayer| array
% containing multiple layers. To inspect information about an individual
% layer, simply display it like this:
katrina(1)

%%
% If you type, |katrina|, in the command window, the entire contents of the
% array are displayed, with each element's index number included in the
% output. This display makes it easy for you to examine the entire array
% quickly, searching for a layer of interest. You can display only the
% |LayerTitle| property for each element by executing the command:
% 
% |disp(katrina,'Properties','layertitle','Index','off','Label','off');|

%%
% As you've discovered, a search for the generic word |'katrina'| returned
% results of many layers and you need to select only one layer. In general,
% a search may even return thousands of layers, which may be too large to
% review individually. Rather than searching the database again, you may
% refine your search by using the |refine| method of the |WMSLayer| class.
% Using the |refine| method is more efficient and returns results faster
% than |wmsfind| since the search has already been narrowed to a smaller
% set. Supplying the query string,
% |'goes-12*katrina*visible*close*up*animation'|, to the |refine| method
% returns a |WMSLayer| array whose elements contain a match of the query
% string in either the |LayerTitle| or |LayerName| properties. The |*|
% character indicates a wild-card search. If multiple entries are returned,
% select only the first one from the svs.gsfc.nasa.gov server.
katrina = refine(katrina,'goes-12*katrina*visible*close*up*animation');
katrina = refine(katrina,'svs.gsfc.nasa.gov','Searchfield','serverurl');
katrina = katrina(1);
whos katrina

%% Step 2: Synchronize WMSLayer Object with Server
% The database only stores a subset of the layer information. For example,
% information from the layer's abstract, details about the layer's
% attributes and style information, and the coordinate reference system of
% the layer are not returned by |wmsfind|. To return all the information,
% you need to use the |wmsupdate| function. |wmsupdate| synchronizes the
% layer from the database with the server, filling in the missing
% properties of the layer.
%
% Synchronize the first |katrina| layer with the server in order to obtain
% the abstract information. Since this action requires access to the
% Internet, call |wmsupdate| only if the |useInternet| flag is true.
cachefile = datafile('katrina.mat');
if useInternet
    katrina = wmsupdate(katrina);
    if ~exist(cachefile,'file')
        save(cachefile,'katrina')
    end
else
    cache = load(cachefile);
    katrina = cache.katrina;
end

%%
% Display the abstract information of the layer. Use |isspace| to help
% determine where to line wrap the text.
abstract = katrina.Abstract;
endOfLine = find(isstrprop(abstract,'cntrl'),1);
abstract = abstract(1:endOfLine);
numSpaces = 60;
while(~isempty(abstract))
    k = find(isspace(abstract));
    n = find(k > numSpaces,1);
    if ~isempty(n)
        fprintf('%s\n',abstract(1:k(n)))
        abstract(1:k(n)) = [];
    else
        fprintf('%s\n',abstract)
        abstract = '';
    end
end

%%
% Note that this abstract information, including any typographical issues
% and incomplete fragments, was obtained directly from the server.

%% Step 3: Explore Katrina Layer Details
% You can find out more information about the |katrina| layer by exploring
% the |Details| property of the |katrina| layer. The |Details.Attributes|
% field informs you that the layer has fixed width and fixed height
% attributes, thus the size of the requested map cannot be modified.
katrina.Details.Attributes

%%
% The |Details.Dimension| field informs you that the layer has a |time|
% dimension 
katrina.Details.Dimension

%%
% with an extent from |2005-08-23T17:45Z| to |2005-08-30T17:45Z|
% with a period of |P1D| (one day), as shown in the
% |Details.Dimension.Extent| field. 
katrina.Details.Dimension.Extent

%% Step 4: Retrieve Katrina Map from Server
% Now that you have found a layer of interest, you can retrieve the raster
% map using the function |wmsread| and display the map using the function
% |geoshow|. Since |Time| is not specified when reading the layer, the
% default time, |2005-08-30T17:45Z|, is retrieved as specified by the
% |Details.Dimension.Default| field. If the |useInternet| flag is set to
% true, then cache the image and referencing matrix in a GeoTIFF file.
cachefile = datafile('katrina.tif');
if useInternet
    [katrinaMap,R] = wmsread(katrina);
    if ~exist(cachefile,'file')
        geotiffwrite(cachefile,katrinaMap,R)
    end
else
    [katrinaMap,R] = geotiffread(cachefile);
end

%%
% Display the |katrinaMap| and overlay the data 
% from the |usastatehi.shp| file.
states = shaperead('usastatehi.shp','UseGeoCoords',true);
figure
usamap(katrina.Latlim, katrina.Lonlim)
geoshow(katrinaMap,R)
geoshow(states,'FaceColor','none')
title({katrina.LayerTitle, katrina.Details.Dimension.Default}, ...
    'Interpreter','none')

%% Step 5: Find NEXRAD Radar Layer
% NEXRAD radar images for the United States are stored on the Iowa State
% University's IEM Web map server. The server conveniently stores NEXRAD
% images in five minute increments from |1995-01-01| to the present time.
% You can find the layer by first searching for the term |IEM WMS Service|
% in the |ServerTitle| field of the WMS database, then refining the search
% by requesting the layer of interest, |nexrad-n0r-wmst|.
iemLayers = wmsfind('IEM WMS Service','SearchField','servertitle');
nexrad = refine(iemLayers,'nexrad-n0r-wmst');

%%
% Synchronize the layer with the server.
cachefile = datafile('nexrad.mat');
if useInternet
    nexrad = wmsupdate(nexrad);
    if ~exist(cachefile,'file')
        save(cachefile,'nexrad')
    end
else
    cache = load(cachefile);
    nexrad = cache.nexrad;
end

%% Step 6: Obtain Extent Parameters
% To composite the |nexrad| layer with the |katrina| layer, you need to
% obtain the |nexrad| layer at coincidental time periods, and concurrent
% geographic and image extents. The |Details.Dimension| field informs you
% that the layer has a time dimension,
nexrad.Details.Dimension

%%
% and the |Details.Dimension.Default| field informs you that the layer's
% time extent includes seconds.
nexrad.Details.Dimension.Default

%%
% Obtain a time value coincidental with the |katrina| layer, and add
% seconds to the time specification.
nexradTime = [katrina.Details.Dimension.Default(1:end-1) ':00Z'];

%%
% Assign |latlim| and |lonlim| variables to specify the limits for the
% |nexrad| layer. Set the values to the limits of the |katrina| layer so
% that the geographic areas match. Note that the |nexrad| layer's southern
% latitude limit does not extend as far south as the |katrina| layer's
% southern latitude limit.  The values that lie outside the geographic
% bounding quadrangle of the |nexrad| layer are set to the background
% color.
fprintf('%s%d\n','Southern latitude limit of NEXRAD  layer: ',nexrad.Latlim(1))
fprintf('%s%d\n','Southern latitude limit of Katrina layer: ',katrina.Latlim(1))

%%
latlim = katrina.Latlim;
lonlim = katrina.Lonlim;

%%
% Assign |imageHeight| and |imageWidth| variables.
imageHeight = katrina.Details.Attributes.FixedHeight;
imageWidth  = katrina.Details.Attributes.FixedWidth;

%% Step 7: Retrieve NEXRAD Radar Map from Server
% You can retrieve the |nexradMap| from the server, specified at the same
% time as the |katrinaMap| and for the same geographic and image extents,
% by supplying parameter/value pairs to the |wmsread| function. To
% accurately retrieve the radar signal from the map, set the |ImageFormat|
% parameter to the |image/png| format. In order to easily retrieve the
% signal from the background, set the background color to black (|[0 0 0]|).
%
% Retrieve the |nexradMap|.
black = [0 0 0];
cachefile = datafile('nexrad.tif');
if useInternet
    [nexradMap,R] = wmsread(nexrad, ...
        'Latlim',latlim,'Lonlim',lonlim,'Time',nexradTime, ...
        'BackgroundColor',black,'ImageFormat','image/png', ...
        'ImageHeight',imageHeight,'ImageWidth',imageWidth);
    if ~exist(cachefile, 'file')
        geotiffwrite(cachefile,nexradMap,R)
    end
else
    [nexradMap,R] = geotiffread(cachefile);
end

%%
% Display the |nexradMap|.
figure
usamap(latlim,lonlim)
geoshow(nexradMap,R)
geoshow(states,'FaceColor','none','EdgeColor','white')
title({nexrad.LayerTitle, nexradTime},'Interpreter','none');

%% Step 8: Composite NEXRAD Radar Map with Katrina Map
% To composite the |nexradMap| with a copy of the |katrinaMap|, you need to
% identify the non-background pixels in the |nexradMap|. The |nexradMap|
% data is returned as an image with class double, because of how this web
% map server handles |PNG| format, so you need convert it to |uint8| before
% merging.
%
% Identify the pixels of the |nexradMap| image
% that do not contain the background color.
threshold = 0;
index = any(nexradMap > threshold, 3);
index = repmat(index,[1 1 3]);

%%
% Composite the |nexradMap| with the |katrinaMap|.
combination = katrinaMap;
combination(index) = uint8(nexradMap(index)*255);

%%
% Display the composited map.
figure
usamap(latlim,lonlim)
geoshow(combination,R)
geoshow(states,'FaceColor','none')
title({'GOES 12 Imagery of Hurricane Katrina', ...
    'Composited with NEXRAD Radar',nexradTime})

%% Step 9: Initialize Variables to Animate the Katrina and NEXRAD Maps
% The next step is to initialize variables in order to  animate the 
% composited |katrina| and |nexrad| maps.
%
% Create variables that contain the time extent 
% of the |katrina| layer. 
extent = katrina.Details.Dimension.Extent;
slash = '/';
slashIndex = strfind(extent,slash);
startTime = extent(1:slashIndex(1)-1);
endTime = extent(slashIndex(1)+1:slashIndex(2)-1);

%%
% Calculate numeric values for the start and end days. 
% Note that the time extent is in |yyyy-mm-dd| format.
hyphen = '-';
hyphenIndex = strfind(startTime,hyphen);
dayIndex = [hyphenIndex(2) + 1, hyphenIndex(2) + 2];
startDay = str2double(startTime(dayIndex));
endDay = str2double(endTime(dayIndex));

%%
% Assign the initial katrinaTime.
katrinaTime = startTime;

%%
% Since multiple requests to a server are required for animation, it is
% more efficient to use the |WebMapServer| and |WMSMapRequest| classes.
%
% Construct a |WebMapServer| object for each layer's server.
nasaServer = WebMapServer(katrina.ServerURL);
iemServer  = WebMapServer(nexrad.ServerURL);

%%
% Create |WMSMapRequest| objects.
katrinaRequest = WMSMapRequest(katrina, nasaServer);
nexradRequest  = WMSMapRequest(nexrad, iemServer);

%%
% Assign properties.
nexradRequest.Latlim = latlim;
nexradRequest.Lonlim = lonlim;
nexradRequest.BackgroundColor = black;
nexradRequest.ImageFormat = 'image/png';
nexradRequest.ImageHeight = imageHeight;
nexradRequest.ImageWidth  = imageWidth;

%% Step 10: Create Animation Files
% An animation can be viewed in the browser when the browser opens an
% animated GIF file or an AVI video file. To create the animation frames of
% the WMS basemap and vector overlays, create a loop through each day, from
% |startDay| to |endDay|, and obtain the |katrinaMap| and the |nexradMap|
% for that day. Composite the maps into a single image, display the image,
% retrieve the frame, and store the results into a frame of an AVI file and
% a frame of an animated GIF file.
%
% To share with others or to post to web video services, create an AVI
% video file containing all the frames using the VideoWriter class.
videoFilename = fullfile(pwd,'wmsanimated.avi');
if exist(videoFilename,'file')
    delete(videoFilename)
end
writer = VideoWriter(videoFilename);
writer.FrameRate = 1;
writer.Quality = 100;
open(writer)

%%
% The animation is viewed in a single map display. Outside the animation
% loop, create a map display. Initialize |hmap|, used in the loop as the
% return handle from the function |geoshow|, so it can be deleted on the
% first pass through the loop. Loop through each day, retrieve and display
% the WMS map, and save the frame.
fig = figure;
usamap(latlim,lonlim)
hstates = geoshow(states,'FaceColor','none');
hmap = [];

for k = startDay:endDay
    
    % Update the time values and assign the Time property for each server.
    currentDay = num2str(k);
    katrinaTime(dayIndex) = currentDay;
    nexradTime = [katrinaTime(1:end-1) ':00Z'];
    katrinaRequest.Time = katrinaTime;
    nexradRequest.Time = nexradTime;
    
    % Retrieve the WMS map of Katrina from the server (or file)
    % for this time period.
    cachefile = datafile(['katrina_' num2str(currentDay) '.tif']);
    if useInternet
        katrinaMap = getMap(nasaServer, katrinaRequest.RequestURL);
        if ~exist(cachefile, 'file')
            geotiffwrite(cachefile, katrinaMap, katrinaRequest.RasterRef)
        end
    else
        katrinaMap = geotiffread(cachefile);
    end
    
    % Retrieve the WMS map of the NEXRAD imagery from the server (or file)
    % for this time period.
    cachefile = datafile(['nexrad_' num2str(currentDay) '.tif']);
    if useInternet
        nexradMap = getMap(iemServer, nexradRequest.RequestURL);
        if ~exist(cachefile, 'file')
            geotiffwrite(cachefile, nexradMap, nexradRequest.RasterRef)
        end
    else
        nexradMap = geotiffread(cachefile);
    end
    
    % Identify the pixels of the nexradMap image that do not contain the
    % background color.
    index = any(nexradMap > threshold, 3);
    index = repmat(index,[1 1 3]);
    
    % Composite nexradMap with katrinaMap.
    combination = katrinaMap;
    combination(index) = uint8(nexradMap(index)*255);
    
    % Delete the old map and display the new composited map.
    delete(hmap)
    hmap = geoshow(combination, katrinaRequest.RasterRef);
    uistack(hstates,'top')
    title({'GOES 12 Imagery of Hurricane Katrina', ...
        'Composited with NEXRAD Radar',nexradTime})
    drawnow
    
    % Save the current frame as an RGB image.
    currentFrame = getframe(fig);
    RGB = currentFrame.cdata;
    
    % Create an indexed image for each RGB frame in order to display an
    % animated GIF. 
    if k == startDay
        % The first time through the loop, convert the RGB image to
        % an indexed image and save the colormap into the
        % variable, cmap. Use cmap to convert later frames.
        [frame,cmap] = rgb2ind(RGB,256,'nodither');
        
        % Use the size of the first frame and the total
        % number of frames to initialize animated with
        % a size large enough to contain all the frames.
        frameSize = size(frame);
        numFrames = endDay - startDay + 1;
        animated = zeros([frameSize 1 numFrames],'like',frame);
    else
        % Use the colormap from the first frame conversion and
        % convert this frame to an indexed image.
        frame = rgb2ind(RGB,cmap,'nodither');
    end
   
    % Store the frame into the animated array for the GIF file.
    frameCount = k - startDay + 1;
    animated(:,:,1,frameCount) = frame;
    
    % Write the RGB frame to the AVI file.
    writeVideo(writer,RGB);
end

%%
% Close the Figure window and the AVI file.
close(fig)
close(writer)

%%
% Write the animated GIF file.
filename = fullfile(pwd,'wmsanimated.gif');
if exist(filename,'file')
    delete(filename)
end
delayTime = 2.0;
loopCount = inf;
imwrite(animated,cmap,filename, ...
    'DelayTime',delayTime,'LoopCount',loopCount);

%% Step 11: View Animated GIF File
% An animation can be viewed in the browser when the browser opens an
% animated GIF file. 

%%
% <<../wmsanimated.gif>>

%% Credits
%
% _Katrina Layer_ 
% 
% The Katrina layer used in the example is from the NASA Goddard Space Flight
% Center's SVS Image Server and is maintained by the Scientific
% Visualization Studio.
%
% For more information about this server, run: 
%    
%    >> wmsinfo('http://svs.gsfc.nasa.gov/cgi-bin/wms?')
%
% _NEXRAD Layer_
%
% The NEXRAD layer used in the example is from the Iowa State University's IEM
% WMS server and is a generated CONUS composite of National Weather Service
% (NWS) WSR-88D level III base reflectivity.
%
% For more information about this server, run: 
%    
%   >> wmsinfo('http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r-t.cgi?')