winforms 如何逐一显示pictureBox1中的图像?

oogrdqng  于 2022-11-16  发布在  其他
关注(0)|答案(1)|浏览(166)

也许我需要一个计时器?
我希望在图像保存之前或保存之后,但显示图像一个接一个。现在它只是做循环,所以它不会显示设计师在所有,直到循环将结束。

using Accord.Video.FFMPEG;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Net.Mime.MediaTypeNames;

namespace Extract_Frames
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            backgroundWorker1.RunWorkerAsync();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }
        
        private void button1_Click(object sender, EventArgs e)
        {
            
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            using (var vFReader = new VideoFileReader())
            {
                vFReader.Open(@"C:\Users\Chocolade 1972\Downloads\MyVid.mp4");
                for (int i = 0; i < vFReader.FrameCount; i++)
                {
                    Bitmap bmpBaseOriginal = vFReader.ReadVideoFrame();
                    //bmpBaseOriginal.Save(@"d:\frames\frame" + i + ".bmp");
                    pictureBox1.Image  = bmpBaseOriginal;
                    //bmpBaseOriginal.Dispose();
                }
                vFReader.Close();
            }
        }
    }
}

它工作了一段时间,但在一些图像之后,它在行上抛出异常:

pictureBox1.Image  = bmpBaseOriginal;

异常表明对象正在使用中。
系统操作无效异常:'对象目前正在使用中

kb5ga3dv

kb5ga3dv1#

您的程式码可能应该是这样:

private readonly Queue<Image> images = new Queue<Image>();

private void Form1_Load(object sender, EventArgs e)
{
    backgroundWorker1.RunWorkerAsync();
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    using (var vFReader = new VideoFileReader())
    {
        vFReader.Open(@"C:\Users\Chocolade 1972\Downloads\MyVid.mp4");

        for (var i = 0; i < vFReader.FrameCount; i++)
        {
            images.Enqueue(vFReader.ReadVideoFrame());
        }

        // Not sure that this would be required as it might happen implicitly at the end of the 'using' block.
        vFReader.Close();
    }
}

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    pictureBox1.Image = images.Dequeue();
    timer1.Start();
}

private void timer1_Tick(object sender, EventArgs e)
{
    pictureBox1.Image.Dispose();

    var image = images.Dequeue();

    pictureBox1.Image = image;

    if (images.Count == 0)
    {
        timer1.Stop();
    }
}

所有的Images都被添加到队列中,然后一个接一个地出列。第一个Images在加载完成后立即显示,其余的Images将定期显示。此代码将每个Image显示一次,然后销毁并丢弃它。如果要在到达最后一个集合时再次显示所有集合,则可以使用不同类型的集合,并在到达结束。
编辑:
我可能有点误解了你的要求。这段代码应该在生成Images时显示它们:

private void Form1_Load(object sender, EventArgs e)
{
    backgroundWorker1.RunWorkerAsync();
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    using (var vFReader = new VideoFileReader())
    {
        vFReader.Open(@"C:\Users\Chocolade 1972\Downloads\MyVid.mp4");

        for (var i = 0; i < vFReader.FrameCount; i++)
        {
            backgroundWorker1.ReportProgress(0, vFReader.ReadVideoFrame());
        }

        // Not sure that this would be required as it might happen implicitly at the end of the 'using' block.
        vFReader.Close();
    }
}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    pictureBox1.Image?.Dispose();
    pictureBox1.Image = (Image)e.UserState;
}

你可以放弃TimerQueue,我唯一担心的是这可能会导致OutOfMemoryException,如果是这样,你可以间歇地显式调用GC.Collect,比如每100帧调用一次。

相关问题