C# 图像序列到视频流?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9744026/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 08:41:00  来源:igfitidea点击:

Image sequence to video stream?

c#imagevideoffmpegaforge

提问by Hauns TM

Like many people already seem to have (there are several threads on this subject here) I am looking for ways to create video from a sequence of images.

就像很多人似乎已经有了(这里有几个关于这个主题的线程)我正在寻找从一系列图像创建视频的方法。

I want to implement my functionality in C#!

我想用 C# 实现我的功能!

Here is what I wan't to do:

这是我不想做的:

/*Pseudo code*/
void CreateVideo(List<Image> imageSequence, long durationOfEachImageMs, string outputVideoFileName, string outputFormat)
{
    // Info: imageSequence.Count will be > 30 000 images
    // Info: durationOfEachImageMs will be < 300 ms

    if (outputFormat = "mpeg")
    {
    }
    else if (outputFormat = "avi")
    {      
    }
    else
    {
    }

    //Save video file do disk
}

I know there's a project called Splicer(http://splicer.codeplex.com/) but I can't find suitable documentation or clear examples that I can follow (theseare the examples that I found).

我知道有一个名为Splicer( http://splicer.codeplex.com/)的项目,但我找不到合适的文档或我可以遵循的清晰示例(这些是我找到的示例)。

The closest I want to do, which I find here on CodePlex is this: How can I create a video from a directory of images in C#?

我最想做的事,我在 CodePlex 上找到的是: 如何从 C# 中的图像目录创建视频?

I have also read a few threads about ffmpeg(for example this: C# and FFmpeg preferably without shell commands?and this: convert image sequence using ffmpeg) but I find no one to help me with my problem and I don't think ffmpeg-command-line-style is the best solution for me (because of the amount of images).

我还阅读了一些关于ffmpeg 的线程(例如:C# 和 FFmpeg 最好没有 shell 命令?还有这个:使用 ffmpeg 转换图像序列)但我发现没有人帮助我解决我的问题,我不认为ffmpeg-命令行样式对我来说是最好的解决方案(因为图像的数量)。

I believe that I can use the Splicer-project in some way (?).

我相信,我可以使用熔接机-项目以某种方式(?)。

In my case, it is about about > 30 000 images where each image should be displayed for about 200 ms (in the videostream that I want to create).

就我而言,大约有 > 30 000 张图像,其中每张图像应显示约 200 毫秒(在我想要创建的视频流中)。

(What the video is about? Plants growing ...)

(视频是关于什么的?植物生长......)

Can anyone help me complete my function?

谁能帮我完成我的功能?

采纳答案by Hauns TM

Well, this answer comes a bit late, but since I have noticed some activity with my original question lately (and the fact that there was not provided a working solution) I would like to give you what finally worked for me.

好吧,这个答案来得有点晚,但由于我最近注意到我的原始问题有一些活动(以及没有提供有效解决方案的事实),我想给你最终对我有用的东西。

I'll split my answer into three parts:

我将把我的答案分成三个部分:

  • Background
  • Problem
  • Solution
  • 背景
  • 问题
  • 解决方案


Background

背景

(this section is not important for the solution)

(此部分对解决方案不重要)

My original problem was that I had a lot of images (i.e. a huge amount), images that were individually stored in a database as byte arrays. I wanted to make a video sequence with all these images.

我最初的问题是我有很多图像(即大量图像),这些图像作为字节数组单独存储在数据库中。我想用所有这些图像制作一个视频序列。

My equipment setup was something like this general drawing: enter image description here

我的设备设置类似于这张总图: 在此处输入图片说明

The images depicted growing tomato plants in different states. All images were taken every 1 minute under daytime.

这些图像描绘了在不同状态下生长的番茄植物。所有图像都是在白天每 1 分钟拍摄一次。

/*pseudo code for taking and storing images*/
while (true)
{
    if (daylight)
    {
        //get an image from the camera
        //store the image as byte array to db
    }
    //wait 1 min
}

I had a very simple db for storing images, there were only one table (the table ImageSet) in it: enter image description here

我有一个用于存储图像的非常简单的数据库,其中只有一个表(表 ImageSet): 在此处输入图片说明



Problem

问题

I had read many articles about ffmpeg (please see my original question) but I couldn't find any on how to go from a collection of images to a video.

我已经阅读了很多关于 ffmpeg 的文章(请参阅我的原始问题),但我找不到任何关于如何从图像集合转换为视频的文章。



Solution

解决方案

Finally, I got a working solution! The main part of it comes from the open source project AForge.NET. In short, you could say that AForge.NET is a computer vision and artificial intelligence library in C#. (If you want a copy of the framework, just grab it from http://www.aforgenet.com/)

最后,我得到了一个有效的解决方案!它的主要部分来自开源项目AForge.NET。简而言之,您可以说AForge.NET 是 C# 中的计算机视觉和人工智能库。(如果您想要该框架的副本,只需从http://www.aforgenet.com/ 获取

In AForge.NET, there is this VideoFileWriter class (a class for writing videofiles with help of ffmpeg). This did almost all of the work. (There is also a very good example here)

在 AForge.NET 中,有这个 VideoFileWriter 类(在 ffmpeg 的帮助下编写视频文件的类)。这几乎完成了所有工作。(还有一个很好的例子在这里

This is the final class (reduced) which I used to fetch and convert image data into a video from my image database:

这是我用来从我的图像数据库中获取图像数据并将其转换为视频的最后一个类(减少的):

public class MovieMaker
{

    public void Start()
    {
        var startDate = DateTime.Parse("12 Mar 2012");
        var endDate = DateTime.Parse("13 Aug 2012");

        CreateMovie(startDate, endDate);
    }    


    /*THIS CODE BLOCK IS COPIED*/

    public Bitmap ToBitmap(byte[] byteArrayIn)
    {
        var ms = new System.IO.MemoryStream(byteArrayIn);
        var returnImage = System.Drawing.Image.FromStream(ms);
        var bitmap = new System.Drawing.Bitmap(returnImage);

        return bitmap;
    }

    public Bitmap ReduceBitmap(Bitmap original, int reducedWidth, int reducedHeight)
    {
        var reduced = new Bitmap(reducedWidth, reducedHeight);
        using (var dc = Graphics.FromImage(reduced))
        {
            // you might want to change properties like
            dc.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
            dc.DrawImage(original, new Rectangle(0, 0, reducedWidth, reducedHeight), new Rectangle(0, 0, original.Width, original.Height), GraphicsUnit.Pixel);
        }

        return reduced;
    }

    /*END OF COPIED CODE BLOCK*/


    private void CreateMovie(DateTime startDate, DateTime endDate)
    {
        int width = 320;
        int height = 240;
        var framRate = 200;

        using (var container = new ImageEntitiesContainer())
        {
            //a LINQ-query for getting the desired images
            var query = from d in container.ImageSet
                        where d.Date >= startDate && d.Date <= endDate
                        select d;

            // create instance of video writer
            using (var vFWriter = new VideoFileWriter())
            {
                // create new video file
                vFWriter.Open("nameOfMyVideoFile.avi", width, height, framRate, VideoCodec.Raw);

                var imageEntities = query.ToList();

                //loop throught all images in the collection
                foreach (var imageEntity in imageEntities)
                {
                    //what's the current image data?
                    var imageByteArray = imageEntity.Data;
                    var bmp = ToBitmap(imageByteArray);
                    var bmpReduced = ReduceBitmap(bmp, width, height);

                    vFWriter.WriteVideoFrame(bmpReduced);
                }
                vFWriter.Close();
            }
        }

    }
}

Update 2013-11-29(how to) (Hope this is what you asked for @Kiquenet?)

2013 年 11 月 29 日更新(如何)(希望这是您对 @Kiquenet 的要求?)

  1. Download AForge.NET Framework from the downloads page(Download full ZIP archive and you will find many interesting Visual Studio solutions with projects, like Video, in the AForge.NET Framework-2.2.5\Samples folder...)
  2. Namespace: AForge.Video.FFMPEG(from the documentation)
  3. Assembly: AForge.Video.FFMPEG(in AForge.Video.FFMPEG.dll) (from the documentation) (you can find this AForge.Video.FFMPEG.dllin the AForge.NET Framework-2.2.5\Releasefolder)
  1. 下载页面下载 AForge.NET Framework (下载完整的 ZIP 存档,您会发现许多有趣的 Visual Studio 解决方案,其中包含项目,例如 Video,AForge.NET Framework-2.2.5\Samples folder...)
  2. 命名空间:( AForge.Video.FFMPEG来自文档
  3. 程序集: AForge.Video.FFMPEG(in AForge.Video.FFMPEG.dll)(来自文档)(您可以AForge.Video.FFMPEG.dllAForge.NET Framework-2.2.5\Release文件夹中找到它)

If you want to create your own solution, make sure you have a reference to AForge.Video.FFMPEG.dllin your project. Then it should be easy to use the VideoFileWriterclass. If you follow the linkto the class you will find a very good (and simple example). In the code, they are feeding the VideoFileWriter with Bitmap imagein a for-loop

如果您想创建自己的解决方案,请确保AForge.Video.FFMPEG.dll在您的项目中有参考。那么使用VideoFileWriter类应该很容易。如果您点击该课程的链接,您会发现一个非常好的(且简单的示例)。在代码中,它们与供给VideoFileWriterBitmap imagefor-loop



回答by Adam

I found this code in the slicer samples, looks pretty close to to what you want:

我在切片器示例中找到了这段代码,看起来非常接近你想要的:

string outputFile = "FadeBetweenImages.wmv";
using (ITimeline timeline = new DefaultTimeline())
{
    IGroup group = timeline.AddVideoGroup(32, 160, 100);
    ITrack videoTrack = group.AddTrack();
    IClip clip1 = videoTrack.AddImage("image1.jpg", 0, 2); // play first image for a little while
    IClip clip2 = videoTrack.AddImage("image2.jpg", 0, 2); // and the next
    IClip clip3 = videoTrack.AddImage("image3.jpg", 0, 2); // and finally the last
    IClip clip4 = videoTrack.AddImage("image4.jpg", 0, 2); // and finally the last
}

  double halfDuration = 0.5;

  // fade out and back in
  group.AddTransition(clip2.Offset - halfDuration, halfDuration, StandardTransitions.CreateFade(), true);
  group.AddTransition(clip2.Offset, halfDuration, StandardTransitions.CreateFade(), false);

  // again
  group.AddTransition(clip3.Offset - halfDuration, halfDuration, StandardTransitions.CreateFade(), true);
  group.AddTransition(clip3.Offset, halfDuration, StandardTransitions.CreateFade(), false);

  // and again
  group.AddTransition(clip4.Offset - halfDuration, halfDuration, StandardTransitions.CreateFade(), true);
  group.AddTransition(clip4.Offset, halfDuration, StandardTransitions.CreateFade(), false);

  // add some audio
  ITrack audioTrack = timeline.AddAudioGroup().AddTrack();

  IClip audio =
     audioTrack.AddAudio("testinput.wav", 0, videoTrack.Duration);

  // create an audio envelope effect, this will:
  // fade the audio from 0% to 100% in 1 second.
  // play at full volume until 1 second before the end of the track
  // fade back out to 0% volume
  audioTrack.AddEffect(0, audio.Duration,
                 StandardEffects.CreateAudioEnvelope(1.0, 1.0, 1.0, audio.Duration));

  // render our slideshow out to a windows media file
  using (
     IRenderer renderer =
        new WindowsMediaRenderer(timeline, outputFile, WindowsMediaProfiles.HighQualityVideo))
  {
     renderer.Render();
  }
}

回答by SCBuergel.eth

I could not manage to get the above example to work. However I did find another library that works amazingly well once. Try via NuGet "accord.extensions.imaging.io", then I wrote the following little function:

我无法让上面的例子工作。但是,我确实找到了另一个运行良好的库。通过NuGet“accord.extensions.imaging.io”尝试,然后我写了以下小函数:

    private void makeAvi(string imageInputfolderName, string outVideoFileName, float fps = 12.0f, string imgSearchPattern = "*.png")
    {   // reads all images in folder 
        VideoWriter w = new VideoWriter(outVideoFileName, 
            new Accord.Extensions.Size(480, 640), fps, true);
        Accord.Extensions.Imaging.ImageDirectoryReader ir = 
            new ImageDirectoryReader(imageInputfolderName, imgSearchPattern);
        while (ir.Position < ir.Length)
        {
            IImage i = ir.Read();
            w.Write(i);
        }
        w.Close();
    }

It reads all images from a folder and makes a video out of them.

它从文件夹中读取所有图像并从中制作视频。

If you want to make it nicer you could probably read the image dimensions instead of hard coding, but you got the point.

如果你想让它更好看,你可以阅读图像尺寸而不是硬编码,但你明白了。

回答by Jevgenij Kononov

This function is based on Splicer.Net library.Took me ages to understand how that library works. Make sure that your fps(frame per second )is correct. By the way standard 24 f/s.

此功能基于 Splicer.Net 库。我花了很长时间才了解该库的工作原理。确保您的 fps(每秒帧数)是正确的。顺便说一下标准的 24 f/s。

In my case I have 15 images and I now that I need 7 seconds video-> so fps =2. Fps may vary according to platform...or developer usage.

就我而言,我有 15 张图像,现在我需要 7 秒的视频-> 所以 fps = 2。Fps 可能因平台...或开发人员使用情况而异。

public bool CreateVideo(List<Bitmap> bitmaps, string outputFile, double fps)
        {
            int width = 640;
            int height = 480;
            if (bitmaps == null || bitmaps.Count == 0) return false;
            try
            {
                using (ITimeline timeline = new DefaultTimeline(fps))
                {
                    IGroup group = timeline.AddVideoGroup(32, width, height);
                    ITrack videoTrack = group.AddTrack();

                    int i = 0;
                    double miniDuration = 1.0 / fps;
                    foreach (var bmp in bitmaps)
                    {
                        IClip clip = videoTrack.AddImage(bmp, 0, i * miniDuration, (i + 1) * miniDuration);
                        System.Diagnostics.Debug.WriteLine(++i);

                    }
                    timeline.AddAudioGroup();
                    IRenderer renderer = new WindowsMediaRenderer(timeline, outputFile, WindowsMediaProfiles.HighQualityVideo);
                    renderer.Render();
                }
            }
            catch { return false; }
            return true;
        }

Hope this helps.

希望这可以帮助。

回答by Chris Carter

This is a solution for creating a video from an image sequence using Visual Studio using C#.

这是使用 C# 使用 Visual Studio 从图像序列创建视频的解决方案。

My starting point was "Hauns TM"'s answer below but my requirements were more basic than theirs so this solution might be more appropriated for less advanced users ( like myself )

我的出发点是下面“Hauns TM”的答案,但我的要求比他们的要求更基本,所以这个解决方案可能更适合不太高级的用户(比如我自己)

Libraries:

图书馆:

using System;
using System.IO;
using System.Drawing;
using Accord.Video.FFMPEG;

You can get the FFMPEG libarary by searching for FFMPEG in "Tools -> NuGet Package Manager -> Manage NuGet Packages for a Solution..."

您可以通过在“工具 -> NuGet 包管理器 -> 为解决方案管理 NuGet 包...”中搜索 FFMPEG 来获取 FFMPEG 库。

The variables that I passed into the function are:

我传递给函数的变量是:

  • outputFileName = "C://outputFolder//outputMovie.avi"
  • inputImageSequence = ["C://inputFolder//image_001.avi", "C://inputFolder//image_002.avi", "C://inputFolder//image_003.avi", "C://inputFolder//image_004.avi"]
  • 输出文件名 = "C://outputFolder//outputMovie.avi"
  • 输入图像序列 = ["C://inputFolder//image_001.avi", "C://inputFolder//image_002.avi", "C://inputFolder//image_003.avi", "C://inputFolder//image_004.avi"]

Function:

功能:

private void videoMaker( string outputFileName , string[] inputImageSequence)
{
  int width = 1920;
  int height = 1080;
  var framRate = 25;

  using (var vFWriter = new VideoFileWriter())
  {
    // create new video file
    vFWriter.Open(outputFileName, width, height, framRate, VideoCodec.Raw);

    foreach (var imageLocation in inputImageSequence)
    {
      Bitmap imageFrame = System.Drawing.Image.FromFile(imageLocation) as Bitmap;
      vFWriter.WriteVideoFrame(imageFrame);
    }
    vFWriter.Close();
  }
}