如何在不同线程中处理视频帧(C#)

How to process video frames in different thread (C#)

背景

我正在开发一个需要对视频流进行一些图像处理并并排显示原始视频和处理后视频的应用程序。

情况

下面是从相机接收到新帧时的事件处理程序。 pictureBox1是显示原始视频的地方。 GetInputImage() 函数将从 pictureBox1 窃取一个,以便可以对该帧执行一些图像处理。

private void camera_NewFrame(object sender, ref Bitmap image)
{
    if (!isReadingPictureBox)
    {
       if (pictureBox1.Image != null)
           pictureBox1.Image.Dispose();
       pictureBox1.Image = (Bitmap)image.Clone();
    }
}

private void GetInputImage()
{
    if (inputImage != null)
        inputImage.Dispose();

    isReadingPictureBox = true;
    if (pictureBox1.Image != null)
        inputImage = new Bitmap(pictureBox1.Image);
    isReadingPictureBox = false;
}

图片处理繁重,单张图片处理耗时。因此,输出视频的帧率预计会比原始视频低很多。

应用程序必须在不受图像处理影响的情况下显示原始视频。所以我想在不同的线程中执行图像处理。

private void ProcessThread(some args)
{
    GetInputImage();
    if (inputImage != null) {
        // Do Image Processing on "inputImage"
        // Show result in pictureBox2
    }
}

问题

[1] 抓帧的方法(上图)好吗?或者下面那个更好?

private void camera_NewFrame(object sender, ref Bitmap image)
{
    pictureBox1.Image = image; // picturBox1's image will not be read for processing

    if(!isReadingInputImage) {
        if (inputImage != null)
            inputImage.Dispose();
        inputImage = (Bitmap)image.Clone(); // GetInputImage() is not required now.
    }
}

[2] 如何让每个 ProcessMyThread(), 运行 前一帧完成处理时可用的帧?这个(下面的)方法可以吗?

private void ProcessMyThread(some args)
{
    do {
        GetInputImage();
        if (inputImage != null) {
            // Do Image Processing on inputImage;
            // Show result in pictureBox2
        }
    }while(someCondition);
}

或者我应该为 camera_NewFrame() func 中的每一帧触发一个处理事件吗?

我自己使用后台工作者解决了这个问题。

private void camera_NewFrame(object sender, ref Bitmap image)
{
    pictureBox1.Image = image;

    if (backgroundWorker1.IsBusy != true)
    {
        lock (locker)
        {
            if (inputImage != null)
                inputImage.Dispose();
            inputImage = (Bitmap)image.Clone();
        }
        backgroundWorker1.RunWorkerAsync();
    }
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    lock (locker)
    {
         baseImage = (Bitmap)inputImage.Clone();
    }
    // Do Image processing here on "baseImage"
    // show result in pictureBox2
}