图像序列到videostream?

像许多人似乎已经(这里有这个主题有几个线程),我正在寻找方法来创buildvideo序列的图像。

我想用C#实现我的function!

这是我不想做的事情:

/*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 } 

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

我想要做的最接近我在CodePlex上find的是这样的: 如何从C#中的图像目录创buildvideo?

我也读了一些关于ffmpeg的线程(例如: C#和FFmpeg最好不带shell命令?这个: 使用ffmpeg转换图像序列 ),但我找不到任何人来帮助我的问题,我不认为ffmpeg -命令行式对我来说是最好的解决scheme(因为大量的图像)。

我相信我可以以某种方式使用Splicer -project(?)。

在我的情况下,大约大约30000个图像,每个图像应该显示大约200ms(在我想创build的videostream中)。

(什么video是关于植物生长…)

任何人都可以帮我完成我的function?

那么这个答案有点晚了,但是由于我最近注意到了一些与我原来的问题有关的活动(而且事实上没有提供一个可行的解决scheme),所以我想给你最后为我工作的东西。

我将我的答案分为三部分:

  • 背景
  • 问题

背景

(本节对解决scheme不重要)

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

我的设备设置是这样的总图: 在这里输入图像描述

这些图像描绘了在不同的州种植番茄植物。 所有图像在白天每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 } 

我有一个非常简单的数据库存储图像,只有一个表(表ImageSet)在其中: 在这里输入图像描述


问题

我已经阅读了许多关于ffmpeg的文章(请参阅我原来的问题),但我无法find任何关于如何从图像集合到video。


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

在AForge.NET中,有这个VideoFileWriter类(用ffmpeg的帮助来写video文件的类)。 这几乎完成了所有的工作。 (这里也有一个很好的例子)

这是我用来从我的图像数据库中获取图像数据并将其转换为video的最终类(简化版):

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

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

  1. 从下载页面下载AForge.NET框架(下载完整的ZIP存档,您将在AForge.NET Framework-2.2.5\Samples folderfind很多有趣的Visual Studio解决scheme,包括video等项目)
  2. 命名空间: AForge.Video.FFMPEG (来自文档 )
  3. 程序集: AForge.Video.FFMPEG (在AForge.Video.FFMPEG.dll )(从文档 )(您可以在AForge.NET Framework-2.2.5\Release文件夹中find此AForge.Video.FFMPEG.dll

如果你想创build你自己的解决scheme ,请确保你的项目中有一个对AForge.Video.FFMPEG.dll的引用。 那么应该很容易使用VideoFileWriter类。 如果你按照课程的链接 ,你会发现一个很好的(简单的例子)。 在代码中,他们在for-loop中for VideoFileWriter提供Bitmap image


我在切片机示例中发现了这个代码,看起来非常接近你想要的:

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

我无法设法让上面的例子工作。 不过,我确实find了一个令人惊讶的另一个图书馆。 尝试通过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(); } 

它读取一个文件夹中的所有图像,并从中制作一个video。

如果你想使它更好,你可能会阅读图像的尺寸,而不是硬编码,但你明白了。