เรนเดอร์ตัวเลข MATLAB ในหน่วยความจำ

มีทางเลือกอื่นนอกเหนือจากการใช้ getframe และ saveas ในการบันทึกเนื้อหาของรูปภาพลงในภาพแรสเตอร์เพื่อการประมวลผลเพิ่มเติมหรือไม่

แนวทางที่ 1: getframe

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

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

content = frame2im(getframe(h));

นี่เป็นข้อเสียเปรียบร้ายแรงในการแสดงภาพเพื่อจับภาพหน้าจอในการเรียก getframe() และเป็นปัญหาเมื่อทำการเรนเดอร์ในลักษณะวนซ้ำ (เช่น การบันทึก content ในการวนซ้ำแต่ละครั้งเป็นเฟรมวิดีโอ)

แนวทางที่ 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');

วิธีการนี้มีข้อเสียเปรียบอย่างร้ายแรงในการเขียนลงดิสก์ ซึ่งเป็นปัญหาในแอปพลิเคชันแบบมัลติเธรด รวมถึงช้ากว่าการเรนเดอร์ไปยังหน่วยความจำโดยตรง เนื่องจาก saveas() จะแสดงผลไปยังหน่วยความจำอย่างชัดเจนก่อนที่จะเรียกใช้ตัวเข้ารหัส PNG สิ่งที่ฉันต้องการจึงเป็นไปได้ แต่ฉันไม่พบฟังก์ชันใด ๆ ในเอกสาร MATLAB ที่ทำเฉพาะส่วนการเรนเดอร์เท่านั้น

คำถาม:

คุณทราบถึงวิธีอื่นในการแสดงเนื้อหา axes โดยพลการให้เป็นภาพแรสเตอร์หรือไม่?


person André Caron    schedule 09.11.2010    source แหล่งที่มา
comment
ฉันมีปัญหาที่คล้ายกัน ฉันก็สงสัยมากเช่นกันว่าทำไมคน MathWorks ถึงใช้ getframe() ด้วยวิธีนี้ ฉันคิดว่ามันบ้าไปแล้ว นอกจากนี้ เหตุใดคุณจึงสนใจเธรด (เว้นแต่ว่าคุณกำลังเรียกใช้กระบวนการ Matlab หลายกระบวนการ) คุณสามารถสร้างเธรดด้วย Matlab ได้หรือไม่?   -  person devin    schedule 16.09.2011
comment
ฉันใช้กล่องเครื่องมือการประมวลผลแบบขนาน ฉันยังมีปัญหากับการเปลี่ยนแปลงสถานะส่วนกลางเนื่องจากการคำนวณทำงานในเธรดแยกจาก UI ตัวอย่างเช่น. การเปิดไฟล์เบราว์เซอร์ใน MATLAB และการนำทางไปยังไดเร็กทอรีอื่นจะเปลี่ยนไดเร็กทอรีปัจจุบันของกระบวนการ   -  person André Caron    schedule 16.09.2011
comment
พนักงานของ MathWorks อยู่เบื้องหลังแนวคิดที่ว่าผู้คนต้องการอินเทอร์เฟซที่เรียบง่าย ไม่ใช่การควบคุมเต็มรูปแบบ ในบางครั้ง การดำเนินการนี้จะทำให้การดำเนินการเป็นเรื่องง่ายสำหรับกรณีธรรมดา และเป็นไปไม่ได้สำหรับกรณียาก   -  person André Caron    schedule 16.09.2011


คำตอบ (4)


หากคุณสร้างไฟล์ 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
person rescdsk    schedule 09.11.2010
comment
ขออภัยสำหรับคำตอบก่อนหน้านี้ ฉันไม่เข้าใจว่าตัวเลขพิเศษมาจากไหน เข้าใจแล้ว! - person rescdsk; 10.11.2010
comment
ว้าว ฉันไม่รู้เลย addframe ด้ามจับฟิกเกอร์ที่ยอมรับ! อย่างไรก็ตาม สิ่งนี้ไม่ได้ตอบคำถามของฉัน เนื่องจากไม่ได้แสดงภาพเป็นภาพแรสเตอร์: ฉันจำเป็นต้องปรับแต่งภาพก่อนที่จะส่งออกเป็นวิดีโอ - person André Caron; 10.11.2010
comment
อ่า แย่จังเลย ฉันกำลังดูแหล่งที่มาของ addframe และดูเหมือนว่าข้อมูลระดับกลางจะไม่ถูกจัดเก็บในลักษณะที่เป็นประโยชน์ ในฟังก์ชันย่อย getFrameForFigure ของ addframe ดูเหมือนว่ามีฟังก์ชันที่ไม่มีเอกสารเรียกว่า hardcopy ซึ่งสามารถดึงเนื้อหาของตัวเลขได้ แต่แน่นอนว่าฟังก์ชันดังกล่าวไม่มีเอกสาร + อาจมีการเปลี่ยนแปลง... - person rescdsk; 10.11.2010
comment
@rescdsk: แม้ว่านี่จะไม่ค่อยตอบคำถามเดิมของฉัน แต่ก็เป็นทางเลือกที่เหมาะสมที่สุด ฉันได้เขียนโค้ดใหม่เพื่อใช้ subplot และจัดเรียงเนื้อหาใหม่เพื่อให้สามารถใช้โซลูชันที่คุณเสนอได้ - person André Caron; 10.11.2010
comment
@rescdsk: ฉันได้ดู addframe()'s getFrameForFigure() แล้ว และนั่นก็ตรงตามที่ต้องการตามที่ฉันต้องการ ดังนั้นฉันจะใช้แนวทางนั้น นอกจากนี้ยังมีการอ้างอิงถึง hardcopy บนเว็บไซต์ของ MathWorks: mathworks com/support/solutions/archived/1-15KWU.html นั่นก็ดีพอสำหรับฉัน - person André Caron; 10.11.2010

ฉันรู้ว่านี่เป็นกระทู้เก่า แต่ฉันพบปัญหานี้อีกครั้งเมื่อเร็ว ๆ นี้ ดังนั้นฉันจึงต้องการสรุปสิ่งที่ฉันค้นพบ แหล่งที่มาหลักของฉันคือหน้านี้ (แคช) ตามนั้น มีทางเลือกสามทาง:

  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 เลิกใช้งานแล้ว คุณจึงสามารถแทนที่ด้วย ใหม่กว่า VIDEOWRITER ใน (2) และ (3) แต่ไม่ใช่ใน (1) เนื่องจากไม่รองรับการส่งผ่านฟิกเกอร์โดยตรง

person Amro    schedule 25.10.2012
comment
ขอบคุณสำหรับบทสรุปค่ะ โปรดทราบว่าแนวทาง #3 ได้รับการแนะนำแล้วในความคิดเห็นต่อคำตอบของ @rescdsk และนั่นคือสิ่งที่ฉันใช้ในที่สุด - person André Caron; 27.10.2012
comment
การอภิปรายที่น่าสนใจอย่างแท้จริงเมื่อฉันตกอยู่ในปัญหาเดียวกันและกำลังดำน้ำในโค้ด print และ getframe เพื่อดูวิธีรับข้อมูลแรสเตอร์จริงโดยไม่ต้องไปที่ไฟล์ของคลิปบอร์ด ขอบคุณมาก! - person CitizenInsane; 20.01.2013
comment
เยี่ยมมาก แอมโร ฉันกำลังสร้างไฟล์ avifile ที่ใหญ่กว่า 2Gb ดังนั้น VideoWriter จึงเป็นสิ่งจำเป็นสำหรับฉัน และ getframe ทำให้ฉันแทบคลั่งเพราะหน้าต่างฟิกเกอร์ของฉันขยายเกินหน้าจอแล็ปท็อปของฉัน - person Stretch; 16.03.2014
comment
แทนที่จะโทร hardcopy โดยตรง โทร getFrameForFigure( figHandle ) อาจจะดีกว่า getFrameForFigure( figHandle ) เป็นฟังก์ชันย่อยภายใน addframe และดูเหมือนว่าจะตั้งค่าต่างๆ สำหรับการป้อนเข้า hardcopy getFrameForFigure( figHandle ) ก็ไม่มีเอกสารเช่นกัน หากคุณต้องการใช้ คุณจะต้องเปิดซอร์สโค้ดไปที่ addframe คัดลอกและวางลงในไฟล์ m ใหม่ และติดไฟล์ m บนเส้นทางของคุณ - person Stretch; 16.03.2014
comment
@Amro แล้วถ้าเราจำเป็นต้องแทรก legend หรือ title ลงในเฟรมที่กำหนดล่ะ? ในบริบทของ videoWriter class - person Tin; 18.03.2014

เริ่ม MATLAB ในโหมดไม่มีหัว: matlab -noFigureWindows

MATLAB ทำงานในโหมดไม่มีหัว หน้าต่างรูปภาพจะไม่แสดงขึ้นมา

จากนั้นเพียงพล็อตและบันทึกตัวเลขตามปกติ (คุณจะไม่เห็นผลกราฟิกใด ๆ แน่นอน) ตัวอย่าง:

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

ฉันทดสอบข้างต้นบนเครื่อง Windows ที่ใช้ R2010a ฉันไม่สามารถเข้าถึงเครื่อง Unix ได้ในขณะนี้ แต่ฉันตอบ คำถามที่คล้ายกันในอดีต และมันก็ใช้ได้ดีในเวลานั้น (คุณจะต้องยกเลิกการตั้งค่าตัวแปร $DISPLAY ก่อนที่จะเริ่ม MATLAB)


แก้ไข

อีกทางเลือกหนึ่ง ในกรณีที่คุณต้องการคงพื้นที่ทำงานปกติของคุณไว้ คือการเริ่มต้นอินสแตนซ์ MATLAB ใหม่ในพื้นหลัง ซึ่งจะสร้างและบันทึกพล็อต (แหล่งที่มา)

เรียกใช้สิ่งนี้จากพรอมต์คำสั่งของเซสชัน MATLAB ปัจจุบันของคุณ (ทั้งหมดในบรรทัดเดียวกัน):

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

สิ่งนี้จะเริ่มต้นเซสชัน MATLAB ใหม่ในเบื้องหลัง (โดยใช้ COM Automation) และรันสคริปต์ชื่อ myscript (ไฟล์ M แบบธรรมดา) ที่มีโค้ดการลงจุดทั้งหมดของคุณ:

c:\yourpath\myscript.m

surf(peaks);
saveas(gcf, 'output.eps');
person Amro    schedule 09.11.2010
comment
เจ๋งมาก ฉันไม่รู้เกี่ยวกับโหมดหัวขาดเลย อย่างไรก็ตาม นี่ไม่ใช่สิ่งที่ฉันกำลังมองหาเนื่องจากฉันมักจะตรวจสอบข้อมูลของฉันโดยใช้ตัวเลขอื่นก่อนที่จะรันงานเอาท์พุต - person André Caron; 10.11.2010
comment
ฉันคิดว่านี่จะมีประโยชน์สำหรับการใช้งาน getframe() แต่ฉันไม่แน่ใจว่ามันจะได้ผล เอกสารระบุว่าตรวจสอบให้แน่ใจว่ามีหน้าต่างที่จะบันทึกโดย getframe อยู่บนเดสก์ท็อปที่ใช้งานอยู่ในปัจจุบัน ฉันจะทำการทดสอบเมื่อฉันมีเวลาอีกสองสามนาที - person André Caron; 10.11.2010
comment
คุณพูดถูกเกี่ยวกับ GETFRAME มันจะบ่นว่า Figure window not valid during getframe หากคุณรันภายใต้เงื่อนไขข้างต้น อย่างไรก็ตาม PRINT/SAVEAS ก็ทำงานได้ดี - person Amro; 10.11.2010
comment
+1. ฉันไม่เคยคิดที่จะเริ่มต้น Matlab จากภายใน Matlab คุณอาจใช้สิ่งนี้เป็นฟังก์ชันการประมวลผลแบบขนานของคนจนได้ - person Jonas; 10.11.2010
comment
@Amro: วิธีแก้ปัญหาทั้งหมดของคุณนั้นขึ้นอยู่กับการพยายามให้ getframe() ทำงานโดยไม่ทำให้รูปแตก ดังนั้นถ้ามันไม่สามารถทำได้ มันก็ไม่ได้แก้ปัญหาของฉันจริงๆ ตอนนี้ แทนที่จะให้การเรนเดอร์ราคาแพงส่งผ่านฮาร์ดไดรฟ์ของฉัน ฉันกลับมีการเรนเดอร์ราคาแพงส่งผ่านฮาร์ดไดรฟ์ของฉัน และฉันต้องเริ่มกระบวนการพิเศษ - person André Caron; 10.11.2010
comment
ขอขอบคุณที่ตรวจสอบเรื่องนี้ ฉันชอบวิธีการประมวลผลหลายอย่างของชายผู้น่าสงสาร :-) - person André Caron; 10.11.2010
comment
ภายใต้ระบบปฏิบัติการยูนิกซ์ คุณไม่จำเป็นต้องยกเลิกการตั้งค่า $DISPLAY เพียงเพิ่มไปที่บรรทัดคำสั่ง -nodisplay (mathworks.com/help/techdoc/ref/matlabunix .html) - person yuk; 10.11.2010

เมื่อ 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);
person Uri Cohen    schedule 06.05.2015