Render angka MATLAB dalam memori

Apakah ada alternatif selain menggunakan getframe dan saveas untuk menyimpan konten gambar ke gambar raster untuk diproses lebih lanjut?

Pendekatan 1: getframe

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

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

content = frame2im(getframe(h));

Ini memiliki kelemahan serius dalam menampilkan gambar untuk melakukan tangkapan layar dalam panggilan ke getframe() dan ini menjadi masalah saat melakukan render seperti itu dalam satu lingkaran (yaitu menyimpan content pada setiap iterasi sebagai bingkai video).

Pendekatan 2: 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');

Pendekatan ini memiliki kelemahan serius dalam menulis ke disk, yaitu bermasalah dalam aplikasi multithread, serta lebih lambat dibandingkan merender langsung ke memori. Karena saveas() jelas akan dirender ke memori sebelum memanggil encoder PNG, apa yang saya inginkan mungkin terjadi, tetapi saya tidak dapat menemukan fungsi apa pun di dokumentasi MATLAB yang hanya melakukan bagian rendering.

Pertanyaan:

Apakah Anda mengetahui cara alternatif untuk merender konten axes sembarang ke gambar raster?


person André Caron    schedule 09.11.2010    source sumber
comment
Saya mengalami masalah serupa, saya juga sangat penasaran mengapa orang-orang MathWorks menerapkan getframe() dengan cara ini. Menurutku itu benar-benar gila. Juga, mengapa Anda peduli dengan utas (kecuali Anda menjalankan beberapa proses matlab)? Bisakah Anda menelurkan thread dengan matlab?   -  person devin    schedule 16.09.2011
comment
Saya menjalankan kotak alat pemrosesan paralel. Saya juga mengalami masalah dengan perubahan status global karena komputasi berjalan di thread terpisah dari UI. Misalnya. membuka browser file di MATLAB dan menavigasi ke direktori lain akan mengubah direktori proses saat ini.   -  person André Caron    schedule 16.09.2011
comment
Orang-orang MathWorks beroperasi di balik gagasan bahwa orang menginginkan antarmuka yang sederhana, bukan kontrol penuh. Terkadang, hal ini membuat pengoperasian menjadi mudah untuk kasus sederhana dan tidak mungkin dilakukan untuk kasus sulit.   -  person André Caron    schedule 16.09.2011


Jawaban (4)


Jika Anda membuat file avi dengan avifile, dan kemudian menambahkan bingkai ke dalamnya dengan addframe, MATLAB tidak membuka gambar tambahan yang terlihat seperti dengan getframe.

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

% ...
for something = 1:1000
    cla
    % (draw stuff...)
    avi = addframe(avi, figure_handle);
end
person rescdsk    schedule 09.11.2010
comment
Maaf tentang jawaban sebelumnya, saya tidak mengerti dari mana angka tambahan itu berasal. Dapatkan sekarang! - person rescdsk; 10.11.2010
comment
Wow, saya tidak tahu addframe pegangan angka yang diterima! Namun, ini tidak menjawab pertanyaan saya, karena tidak membuat gambar menjadi gambar raster: Saya perlu melakukan pasca-proses gambar sebelum menghasilkan video. - person André Caron; 10.11.2010
comment
Ah, sayang sekali. Saya sedang mencari sumber untuk addframe, dan sepertinya data perantara tidak disimpan dengan cara yang berguna. Pada subfungsi getFrameForFigure dari addframe, sepertinya ada fungsi tidak berdokumen bernama hardcopy yang dapat mengambil konten gambar, tetapi tentu saja tidak berdokumen + mungkin berubah... - person rescdsk; 10.11.2010
comment
@rescdsk: Meskipun ini tidak menjawab pertanyaan awal saya, ini adalah alternatif yang paling memungkinkan. Saya telah menulis ulang kode saya untuk menggunakan subplot dan mengatur ulang konten saya sehingga saya dapat menggunakan solusi yang Anda usulkan. - person André Caron; 10.11.2010
comment
@rescdsk: Saya telah melihat getFrameForFigure() addframe(), dan itu persis yang saya inginkan, jadi saya akan menggunakan pendekatan itu. Juga, ada referensi ke hardcopy di situs web MathWorks: mathworks. com/support/solutions/archived/1-15KWU.html . Itu cukup baik bagi saya. - person André Caron; 10.11.2010

Saya menyadari ini adalah topik lama, namun saya mengalami masalah ini lagi akhir-akhir ini, jadi saya ingin merangkum temuan saya. Sumber utama saya adalah laman ini (di-cache). Menurutnya, ada tiga alternatif:

  1. menggunakan ADDFRAME langsung dengan pegangan gambar (tanpa menggunakan GETFRAME). Inilah yang @rescdsk tunjukkan dalam jawabannya.

    hFig = figure('Visible','off');
    
    aviobj = avifile('file.avi');
    for k=1:N
        %#plot(...)
        aviobj = addframe(aviobj, hFig);
    end
    aviobj = close(aviobj);
    
  2. menggunakan PRINT/SAVEAS/HGEXPORT untuk mengekspor gambar ke file gambar, lalu membaca kembali gambar tersebut dari disk. Ini adalah pendekatan #2 yang Anda cantumkan sendiri dalam pertanyaan di atas.

    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. menggunakan fungsi HARDCOPY yang tidak berdokumen untuk menangkap gambar di memori.

    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);
    

    Faktanya, ini adalah fungsi dasar yang digunakan oleh fungsi lain baik secara langsung maupun tidak langsung. Dengan memeriksa kode sumber jika memungkinkan, berikut adalah ilustrasi ketergantungan fungsi terkait di mana A --> B menunjukkan 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]
    

    Di sisi lain, GETFRAME tidak memanggil HARDCOPY tetapi fungsi bawaan yang tidak terdokumentasi bernama CAPTURESCREEN (walaupun tampaknya ia akan menggunakan PRINT untuk sistem HG2 yang memiliki tanda cetak -RGBImage baru):

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

Catatan: Karena AVIFILE kini tidak digunakan lagi, Anda dapat menggantinya dengan VIDEOWRITER yang lebih baru di (2) dan (3), namun tidak di (1) karena tidak mendukung passing figure handle secara langsung.

person Amro    schedule 25.10.2012
comment
Terima kasih atas ringkasan Anda. Perhatikan bahwa pendekatan #3 sudah disarankan dalam komentar untuk jawaban @rescdsk dan itulah yang akhirnya saya gunakan. - person André Caron; 27.10.2012
comment
Diskusi yang benar-benar menarik karena saya mengalami masalah yang sama dan mempelajari kode print dan getframe untuk melihat cara mendapatkan data raster nyata tanpa membuka file di clipboard. Terima kasih banyak! - person CitizenInsane; 20.01.2013
comment
Bagus sekali, Amro. Saya membuat avifile yang lebih besar dari 2Gb, jadi VideoWriter adalah suatu keharusan bagi saya, dan getframe membuat saya gila karena jendela gambar saya melampaui layar laptop saya. - person Stretch; 16.03.2014
comment
Daripada menelepon hardcopy secara langsung, mungkin lebih baik menelepon getFrameForFigure( figHandle ). getFrameForFigure( figHandle ) adalah sub-fungsi di dalam addframe dan sepertinya mengatur segalanya untuk dimasukkan ke hardcopy. getFrameForFigure( figHandle ) juga tidak berdokumen. Jika Anda ingin menggunakannya, Anda harus membuka kode sumber ke addframe, menyalinnya, menempelkannya ke m-file baru, dan menempelkan m-file di jalur Anda. - person Stretch; 16.03.2014
comment
@Amro bagaimana jika kita perlu memasukkan legend atau title ke bingkai tertentu? Dalam konteks videoWriter class - person Tin; 18.03.2014

Mulai MATLAB dalam mode tanpa kepala: matlab -noFigureWindows

MATLAB berjalan dalam mode tanpa kepala. Jendela gambar tidak akan ditampilkan.

kemudian cukup plot dan simpan gambar seperti biasa (tentu saja Anda tidak akan melihat keluaran grafis apa pun). Contoh:

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

Saya menguji hal di atas pada mesin Windows yang menjalankan R2010a. Saya tidak memiliki akses ke mesin Unix saat ini, tapi saya menjawab pertanyaan serupa di masa lalu, dan berfungsi dengan baik pada saat itu (Anda harus menghapus variabel $DISPLAY sebelum memulai MATLAB)


EDIT

Pilihan lain, jika Anda ingin mempertahankan ruang kerja normal, adalah memulai instance MATLAB baru di latar belakang yang akan menghasilkan dan menyimpan plot (sumber).

Jalankan ini dari command prompt sesi MATLAB Anda saat ini (semuanya di baris yang sama):

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

Ini akan memulai sesi MATLAB baru di latar belakang (menggunakan COM Automation), dan menjalankan skrip bernama myscript (file M sederhana) yang berisi semua kode plot Anda:

c:\jalanmu\skripku.m

surf(peaks);
saveas(gcf, 'output.eps');
person Amro    schedule 09.11.2010
comment
Ini keren, saya tidak tahu tentang mode tanpa kepala. Namun, ini bukan yang saya cari karena saya biasanya memeriksa data saya menggunakan angka lain sebelum menjalankan pekerjaan keluaran. - person André Caron; 10.11.2010
comment
Saya pikir ini akan berguna untuk menggunakan getframe() tetapi saya tidak yakin ini akan berhasil. Dokumentasinya mengatakan pastikan bahwa jendela yang akan diambil oleh getframe ada di desktop yang sedang aktif. Saya akan menjalankan tes ketika saya punya waktu beberapa menit lagi. - person André Caron; 10.11.2010
comment
Anda benar tentang GETFRAME, ia mengeluh bahwa Figure window not valid during getframe jika Anda menjalankannya dalam kondisi di atas. Tetap saja, PRINT/SAVEAS berfungsi dengan baik. - person Amro; 10.11.2010
comment
+1. Saya tidak pernah berpikir untuk memulai Matlab dari dalam Matlab. Anda mungkin bisa menggunakan ini sebagai fungsi pemrosesan paralel orang miskin. - person Jonas; 10.11.2010
comment
@Amro: seluruh solusi Anda didasarkan pada upaya membuat getframe() berfungsi tanpa memunculkan gambarnya, jadi jika tidak dapat melakukannya, maka itu tidak benar-benar menyelesaikan masalah saya. Jadi sekarang, alih-alih render mahal lewat hard drive saya, saya punya render mahal lewat hard drive saya dan saya harus meluncurkan proses tambahan. - person André Caron; 10.11.2010
comment
Terima kasih telah menyelidiki hal ini. Saya suka metode multi-pemrosesan orang malang itu :-) - person André Caron; 10.11.2010
comment
Di bawah unix Anda tidak perlu menghapus $DISPLAY. Cukup tambahkan ke baris perintah -nodisplay (mathworks.com/help/techdoc/ref/matlabunix .html) - person yuk; 10.11.2010

Karena avifile tidak digunakan lagi, inilah cara Anda melakukannya dengan 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);
person Uri Cohen    schedule 06.05.2015