25

是否有任何替代方法可以使用getframe并将saveas图形的内容保存到光栅图像以供进一步处理?

方法一:getframe

h = figure('visible', 'off');
a = axes('parent', h);

% render using `scatter3()` or other plot function.

content = frame2im(getframe(h));

这具有在调用中显示图形以执行屏幕捕获的严重缺点,getframe()并且在循环中执行此类渲染时存在问题(即content在每次迭代中保存为视频帧)。

方法二:saveas

h = figure('visible', 'off');
a = axes('parent', h);

% render using `scatter3()` or other plot function.

saveas(h, '/path/to/file.png');
content = imread(/path/to/file.png');

这种方法具有写入磁盘的严重缺点,这在多线程应用程序中存在问题,并且比直接渲染到内存要慢。由于saveas()在调用 PNG 编码器之前显然会渲染到内存,所以我想要的是可能的,但我在 MATLAB 文档中找不到任何只执行渲染部分的函数。

问题

您是否知道将任意axes内容渲染到光栅图像的另一种方法?

4

4 回答 4

18

我意识到这是一个旧线程,但我最近又遇到了这个问题,所以我想总结一下我的发现。我的主要来源是这个页面缓存)。根据它,有三种选择:

  1. 直接使用ADDFRAME和图形句柄(不使用GETFRAME)。这正是@rescdsk在他的回答中所显示的。

    hFig = figure('Visible','off');
    
    aviobj = avifile('file.avi');
    for k=1:N
        %#plot(...)
        aviobj = addframe(aviobj, hFig);
    end
    aviobj = close(aviobj);
    
  2. 使用PRINT / SAVEAS / HGEXPORT将图形导出到图像文件,然后从磁盘读取图像。这是您在上面的问题中列出的方法#2。

    hFig = figure('Visible','off');
    set(hFig, 'PaperPositionMode','auto', 'InvertHardCopy','off')
    
    aviobj = avifile('file.avi');
    for k=1:N
        %#plot(...)
        print(['-f' num2str(hFig)], '-zbuffer', '-r0', '-dpng', 'file.png')
        img = imread('file.png');
        aviobj = addframe(aviobj, im2frame(img));
    end
    aviobj = close(aviobj);
    
  3. 使用未记录的 HARDCOPY 函数来捕获内存中的图形。

    hFig = figure('Visible','off');
    set(hFig, 'PaperPositionMode','auto')
    
    aviobj = avifile('file.avi');
    for k=1:N
        %#plot(...)
        img = hardcopy(hFig, '-dzbuffer', '-r0');
        aviobj = addframe(aviobj, im2frame(img));
    end
    aviobj = close(aviobj);
    

    事实上,这是其他函数直接或间接使用的底层函数。通过在可能的情况下检查源代码,这里是相关函数的依赖关系的说明,其中A --> B表示A calls B

    saveas [M-file] --> print [M-file] --> render [private M-file] --> hardcopy [P-file]
    hgexport [P-file] --> print [M-file] --> ...
    @avifile/addframe [M-file] --> hardcopy [P-file]
    

    另一方面,GETFRAME 不调用 HARDCOPY,而是调用了一个名为 CAPTURESCREEN 的未记录的内置函数(尽管它似乎将 PRINT 用于即将推出的HG2 系统,其中有一个新的-RGBImage打印标志):

    getframe [M-file] --> capturescreen [builtin]
    

注意:由于AVIFILE现在已弃用,您可以在 (2) 和 (3) 中将其替换为较新的VIDEOWRITER,但不能在 (1) 中替换,因为它不支持直接传递图形句柄。

于 2012-10-25T22:51:29.240 回答
10

如果您使用 创建一个 avi 文件avifile,然后使用 向其添加帧addframe,MATLAB 不会像使用getframe.

avi = avifile('/path/to/output');
figure_handle = figure('visible', 'off');

% ...
for something = 1:1000
    cla
    % (draw stuff...)
    avi = addframe(avi, figure_handle);
end
于 2010-11-09T21:09:06.560 回答
7

以无头模式启动 MATLAB:matlab -noFigureWindows

MATLAB 以无头模式运行。图形窗口将不显示。

然后像往常一样简单地绘制并保存数字(当然你不会看到任何图形输出)。例子:

surf(peaks);
print output.eps     %# SAVEAS works as well
close

我在运行 R2010a 的 Windows 机器上测试了上述内容。我现在无法访问 Unix 机器,但我过去回答了一个类似的问题,当时它工作得很好(您需要$DISPLAY在启动 MATLAB 之前取消设置变量)


编辑

如果您想保留正常的工作区,另一种选择是在后台启动一个新的 MATLAB 实例,该实例将生成并保存绘图(source)。

在当前 MATLAB 会话的命令提示符下运行此命令(都在同一行):

!start /B /MIN matlab -noFigureWindows 
                      -automation 
                      -r "cd('c:\yourpath'); myscript; quit"

这将在后台启动一个新的 MATLAB 会话(使用 COM 自动化),并执行一个名为myscript(一个简单的 M 文件)的脚本,其中包含您的所有绘图代码:

c:\yourpath\myscript.m

surf(peaks);
saveas(gcf, 'output.eps');
于 2010-11-09T21:05:26.550 回答
2

随着avifile被弃用,这就是您使用 VideoWriter 的方式:

hFig = figure('Visible','off');
set(hFig, 'PaperPositionMode','auto')

aviobj = VideoWriter('file','Archival');
for k=1:N
    %#plot(...)
    img = hardcopy(hFig, '-dzbuffer', '-r0');
    writeVideo(aviobj, im2frame(img));
end
close(aviobj);
于 2015-05-06T07:18:49.853 回答