it-swarm.com.de

Bildsequenz zum Videostream?

Wie viele Leute bereits zu haben scheinen (es gibt mehrere Threads zu diesem Thema), suche ich nach Möglichkeiten, Video aus einer Sequenz von Bildern zu erstellen.

Ich möchte meine Funktionalität in C # implementieren!

Folgendes möchte ich tun:

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

Ich weiß, dass es ein Projekt namens Splicer ( http://splicer.codeplex.com/ ) gibt, aber ich kann keine geeignete Dokumentation oder klare Beispiele finden, denen ich folgen kann ( diese sind die Beispiele, die ich gefunden habe).

Das nächste, was ich tun möchte, das ich hier auf CodePlex finde, ist folgendes: Wie kann ich ein Video aus einem Verzeichnis von Bildern in C # erstellen?

Ich habe auch ein paar Threads über ffmpeg gelesen (zum Beispiel diese: C # und FFmpeg vorzugsweise ohne Shell-Befehle? und diese: Bildsequenz mithilfe von ffmpeg konvertieren), aber ich finde keine Hilfe Ich mit meinem Problem und ich glaube nicht, dass ffmpeg -Kommandozeilenstil die beste Lösung für mich ist (wegen der Menge an Bildern).

Ich glaube, dass ich das Splicer -Projekt irgendwie verwenden kann (?). 

In meinem Fall handelt es sich um etwa 30 000 Bilder, bei denen jedes Bild für etwa 200 ms angezeigt werden soll (in dem Videostrom, den ich erstellen möchte). 

(Worum es in dem Video geht? Pflanzen wachsen ...)

Kann mir jemand helfen, meine Funktion zu vervollständigen?

52
Hauns TM

Nun, diese Antwort kommt etwas spät, aber da ich in letzter Zeit etwas Aktivität mit meiner ursprünglichen Frage bemerkt habe (und die Tatsache, dass es keine funktionierende Lösung gab), möchte ich Ihnen gerne sagen, was für mich letztendlich funktioniert hat.

Ich werde meine Antwort in drei Teile teilen:

  • Hintergrund
  • Problem
  • Lösung

Hintergrund

(Dieser Abschnitt ist für die Lösung nicht wichtig)

Mein ursprüngliches Problem war, dass ich viele Bilder hatte (d. H. Sehr viele), Bilder, die einzeln in einer Datenbank als Byte-Arrays gespeichert wurden. Ich wollte mit all diesen Bildern eine Videosequenz erstellen.

Mein Equipment-Setup war so etwas wie eine allgemeine Zeichnung: enter image description here

Die Bilder zeigten wachsende Tomatenpflanzen in verschiedenen Zuständen. Alle Bilder wurden alle 1 Minute unter Tage aufgenommen.

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

Ich hatte eine sehr einfache Datenbank zum Speichern von Bildern, es gab nur eine Tabelle (die Tabelle ImageSet) darin: enter image description here


Problem

Ich hatte viele Artikel über ffmpeg gelesen (siehe meine ursprüngliche Frage), aber ich konnte keine Informationen finden, wie ich von einer Bildersammlung zu einem Video komme.


Lösung

Schließlich bekam ich eine funktionierende Lösung! .__ Der Hauptteil davon stammt aus dem Open Source-Projekt AForge.NET . Zusammenfassend könnte man sagen, dass AForge.NET eine Bibliothek für Computervision und künstliche Intelligenz in C # ..__ ist. (Wenn Sie eine Kopie des Frameworks erhalten möchten, greifen Sie einfach auf http: // www. aforgenet.com/ )

In AForge.NET gibt es diese VideoFileWriter-Klasse (eine Klasse zum Schreiben von Videodateien mit Hilfe von ffmpeg). Das erledigte fast die ganze Arbeit. (Es gibt auch ein sehr gutes Beispiel hier )

Dies ist die letzte (reduzierte) Klasse, die ich zum Abrufen und Konvertieren von Bilddaten aus meiner Bilddatenbank in ein Video verwendet habe:

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) (Hoffe, das haben Sie nach @Kiquenet gefragt?)

  1. Laden Sie AForge.NET Framework von der downloads-Seite herunter (Laden Sie das vollständige Zip-Archiv herunter und Sie finden viele interessante Visual Studio-Lösungen mit Projekten wie Video im AForge.NET Framework-2.2.5\Samples folder...).
  2. Namensraum: AForge.Video.FFMPEG (aus der Dokumentation )
  3. Assembly: AForge.Video.FFMPEG (in AForge.Video.FFMPEG.dll) (aus der Dokumentation ) (Sie finden diesen AForge.Video.FFMPEG.dll im Ordner AForge.NET Framework-2.2.5\Release)

Wenn Sie Ihr eigene Lösung erstellen möchten, stellen Sie sicher, dass Sie in Ihrem Projekt einen Verweis auf AForge.Video.FFMPEG.dll haben. Dann sollte es einfach sein, die Klasse VideoFileWriter zu verwenden. Wenn Sie dem link der Klasse folgen, finden Sie ein sehr gutes (und einfaches Beispiel). Im Code füttern sie den VideoFileWriter mit Bitmap image in einer for-Schleife


58
Hauns TM

Ich habe diesen Code im Slicer samples gefunden, sieht ziemlich nah an dem, was Sie wollen:

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

Ich konnte das obige Beispiel nicht zum Laufen bringen. Ich habe jedoch eine andere Bibliothek gefunden, die einmal erstaunlich gut funktioniert. Versuche es über NuGet "accord.extensions.imaging.io", dann habe ich die folgende kleine Funktion geschrieben:

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

Es liest alle Bilder aus einem Ordner und erstellt daraus ein Video.

Wenn Sie es schöner machen möchten, können Sie wahrscheinlich die Bildabmessungen anstelle der harten Kodierung lesen, aber Sie haben den Punkt verstanden.

8
Sebastian

Diese Funktion basiert auf der Splicer.Net-Bibliothek. Ich habe lange gewusst, wie diese Bibliothek funktioniert. Stellen Sie sicher, dass Ihre fps (Frame pro Sekunde) korrekt sind. Übrigens serienmäßig 24 f/s.

In meinem Fall habe ich 15 Bilder und ich brauche jetzt 7 Sekunden Video-> also fps = 2 . Fps kann je nach Plattform oder Entwickler variieren. 

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

Hoffe das hilft.

1

Dies ist eine Lösung zum Erstellen eines Videos aus einer Bildsequenz mit Visual Studio mit C #.

Mein Ausgangspunkt war "Hauns TM" Antwort unten, aber meine Anforderungen waren grundlegender als ihre, so dass diese Lösung für weniger fortgeschrittene Benutzer (wie ich) eher geeignet wäre.

Bibliotheken:

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

Sie können die FFMPEG-Bibliothek erhalten, indem Sie in "Extras -> NuGet Package Manager -> NuGet-Pakete für eine Lösung verwalten ..." nach FFMPEG suchen.

Die Variablen, die ich an die Funktion übergeben habe, sind: 

  • 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"]

Funktion:

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