Как сделать анимацию в MATLAB и сохранить видео в формате mp4

Часто учёным намного проще анализировать данные, когда они представлены в виде анимации. Сегодня мы сделаем простую анимацию в MATLAB и сохраним её в виде видео-файла в формате MPEG-4.

Для построения картинок мы будем использовать NCEP/NCAR Reanalysis с этого сайта. Я скачал ежедневные значения температуры воздуха у поверхности для 2018 года. Если хотите себе такие же, прямая ссылка вот.

Для начала загрузим наши данные в рабочую область Matlab:

air = ncread('air.sig995.2018.nc','air')-273.15;
lat = ncread('air.sig995.2018.nc','lat');
lon = ncread('air.sig995.2018.nc','lon');

Обратите внимание, что мы вычли 273.15 из значений температуры, для того чтобы перевести их в градусы Цельсия (исходные данные в Кельвинах). Для последующих построений нам нужно будет перевести векторы lat и lon в матрицы:

[lon,lat]=ndgrid(lon,lat);

Вектор с датами проще будет создать вручную:

t = datetime(2018,01,01):datetime(2018,12,31);

Теперь можно построить карту. Пока, всё что мы делаем и дальнейшие построения карт не должны вызывать сложностей, так как всё уже было описано здесь на сайте. Однако на всякий случай сделаю некоторые краткие комментарии.

Строим карту (подложку) и ориентируем её так, чтобы по центру располагался 180 градус долготы:

worldmap('world')
setm(gca,'Origin', [0 180 0])

Строим карту распределения температуры для первой даты нашего массива и добавляем на рисунок colorbar:

geoshow(lat,lon,air(:,:,1),'displaytype','texture')
colorbar

Строим для ориентировки береговую черту и закрашиваем её белым цветом (белый только контур, сами берега прозрачные):

geoshow('landareas.shp','FaceColor','none','EdgeColor','w')

В качестве заголовка к рисунку используем дату:

title(datestr(t(1)))

Ну и при желании заменяем цветовую шкалу (сработает только если у вас установлен пакет cmocean):

cmocean('thermal')

Все строки кода для построения выглядят так:

worldmap('world')
setm(gca,'Origin', [0 180 0])
geoshow(lat,lon,air(:,:,1),'displaytype','texture')
geoshow('landareas.shp','FaceColor','none','EdgeColor','w')
cmocean('thermal')
colorbar
title(datestr(t(1)))

и приводят к следующему результату:

Допустим, вам нужно посмотреть на картину в динамике, т.е. в нашем случае - посмотреть, как изменяется температура со временем. Можно создать цикл и просто смотреть, как постепенно строятся картинки одна за одной. Если у вас не слишком мощный компьютер, то этот вариант будет выглядеть как анимация. Если же у вас мощный компьютер, которые строит карты слишком быстро, вы можете в середине цикла поставить паузу. Например, это может выглядеть так:

for n =1:365
worldmap('world')
setm(gca,'Origin', [0 180 0])
geoshow(lat,lon,air(:,:,n),'displaytype','texture')
geoshow('landareas.shp','FaceColor','none','EdgeColor','w')
caxis([-80 40])
cmocean('thermal')
colorbar
title(datestr(t(n)))
pause(0.5)
end

В данном коде pause(0.5) означает паузу 0.5 секунд. Кроме того, я добавил caxis([-80 40]) - это жёсткое ограчинение границ цветов, чтобы они не менялись от карты к карте.

Однако, такая анимация годится только для быстрого анализа при работе с данными. Если же вы хотите получить анимацию в виде видео-файла, то сделать это можно следующим образом. На каждом витке цикла построенная картинка записывается в виде отдельного кадра при помощи специальной функции getframe. Например, мы создадим переменную frame, куда запишем все 365 построенных карт.

for n =1:10
worldmap('world')
setm(gca,'Origin', [0 180 0])
geoshow(lat,lon,air(:,:,n),'displaytype','texture')
geoshow('landareas.shp','FaceColor','none','EdgeColor','w')
caxis([-80 40])
cmocean('thermal')
colorbar
title(datestr(t(n)))
frame(n) = getframe(gcf);
close(gcf)
end

Обратите внимание, что кроме строки frame(n) = getframe(gcf) мы добавили ещё и close(gcf). В нашем случае это было делать не обязательно, так как функция worldmap закроет предыдущую карту в начале каждого цикла. Однако вы можете столкнуться с проблемой, когда все ваши кадры останутся открытыми, так что пусть будет.

Теперь, для того, чтобы записать анимацию в видео-файл нужно сделать следующее. Во-первых создать видеофайл и присвоить резултат этого действия какой-нибудь переменной (у нас это v), с помощью которой мы затем будем к нему обращаться:

v = VideoWriter('air_temp2018.mp4','MPEG-4');

При желании можно внести некоторые изменения в свойства файла, настроить всё под себя. Например, мне часто приходится менять частоту кадров:

v.FrameRate = 10; %10 frames per second

После всех настроек осталось открыть ваш созданный видео-файл, записать туда все кадры и закрыть файл:

open(v)
writeVideo(v,frame)
close(v)

Целиком весь код выглядит так:

for n =1:365
worldmap('world')
setm(gca,'Origin', [0 180 0])
geoshow(lat,lon,air(:,:,n),'displaytype','texture')
geoshow('landareas.shp','FaceColor','none','EdgeColor','w')
caxis([-80 40])
cmocean('thermal')
colorbar
title(datestr(t(n)))
frame(n) = getframe(gcf);
close(gcf)
end

v = VideoWriter('air_temp2018.mp4','MPEG-4');
v.FrameRate = 10;
open(v)
writeVideo(v,frame)
close(v)

В следующий раз сделаем анимацию в формате GIF.

 telegram

Чтобы не пропустить новые материалы с рецептами по работе с океанологическими данными, подпишитесь на канал в Telegram: https://t.me/koldunovaleksey

Данные для заметки:

NCEP Reanalysis data provided by the NOAA/OAR/ESRL PSD, Boulder, Colorado, USA, from their Web site at https://www.esrl.noaa.gov/psd/

Kalnay et al., The NCEP/NCAR 40-year reanalysis project, Bull. Amer. Meteor. Soc., 77, 437-470, 1996