Séquence d'Image au flux vidéo?

comme beaucoup de gens semblent déjà avoir (il y a plusieurs fils sur ce sujet ici) je cherche des façons de créer la vidéo à partir d'une séquence d'images.

je veux implémenter ma fonctionnalité en C#!

voici ce que je ne veux pas faire:

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

je sais qu'il y a un projet appelé Épisseur ( http://splicer.codeplex.com / ) mais je ne peux pas trouver approprié documentation ou exemples clairs que je peux suivre ( ces sont les exemples que j'ai trouvés).

le plus proche que je veux faire, que je trouve ici sur CodePlex est ceci: Comment puis-je créer une vidéo à partir d'un répertoire d'images en C#?

j'ai aussi lu quelques threads sur ffmpeg (par exemple ceci: C# et FFmpeg de préférence sans commandes shell? et ce: convert image sequence using ffmpeg ) mais je ne trouve personne pour m'aider avec mon problème et je ne pense pas ffmpeg - commande-LIGNE-style est la meilleure solution pour moi (en raison de la quantité d'images).

je crois que je peux utiliser le Colleuse -projet d'une certaine façon (?).

dans mon cas, il s'agit d'environ > 30 000 images où chaque image devrait être affichée pendant environ 200 ms (dans le videostream que je veux créer).

(Ce que la vidéo est sur? La croissance des plantes ...)

quelqu'un Peut-il m'aider à remplir ma fonction?

48
demandé sur Community 2012-03-17 00:23:53

4 réponses

Eh bien, cette réponse arrive un peu tard, mais puisque j'ai remarqué une certaine activité avec ma question originale dernièrement (et le fait qu'il n'y avait pas de solution de travail) je voudrais vous donner ce qui a finalement fonctionné pour moi.

Je diviserai ma réponse en trois parties:

  • arrière-plan
  • problème
  • Solution

arrière-plan

(cette section n'est pas importante pour la solution)

mon problème original était que j'avais beaucoup d'images (i.e. une quantité énorme), des images qui étaient individuellement stockées dans une base de données comme tableaux de bytes. je voulais faire une séquence vidéo avec toutes ces images.

mon équipement était quelque chose comme ce dessin général: enter image description here

les images représentent la culture de plantes de tomate dans différents états. Toutes les images ont été prises toutes les minutes en journée.

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

j'ai eu un db très simple pour stocker des images, il n'y avait qu'une table (La Table ImageSet) : enter image description here


problème

j'avais lu de nombreux articles sur ffmpeg (voir ma question originale) mais je n'ai pas pu en trouver sur la façon de passez d'une collection d'images à une vidéo.


Solution

enfin, j'ai trouvé une solution! La majeure partie provient du projet open source AForge.NET . En bref, on pourrait dire que AForge.NET est une bibliothèque de vision informatique et d'intelligence artificielle en C# . (Si vous voulez une copie du framework, il suffit de le récupérer dans http://www.aforgenet.com/ )

In AForge.NET, il y a cette classe VideoFileWriter (une classe pour écrire des videofiles avec l'aide de ffmpeg). Cela fait presque tout le travail. (Il y a aussi un très bon exemple ici )

C'est la classe finale (réduite) que j'ai utilisée pour récupérer et convertir des données d'image en une vidéo à partir de ma base de données d'image:

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

    }
}

mise à jour 2013-11-29 (comment faire) (J'espère que c'est ce que vous avez demandé pour @Kiquenet?)

  1. télécharger AForge.NET cadre de la téléchargements page (télécharger archive ZIP complète et vous trouverez de nombreuses solutions de Studio visuel intéressantes avec des projets, comme la vidéo, dans le AForge.NET Framework-2.2.5\Samples folder ...)
  2. espace de Noms: AForge.Video.FFMPEG (de la documentation )
  3. assemblage: AForge.Video.FFMPEG (in AForge.Video.FFMPEG.dll ) (du documentation ) (vous pouvez trouver ce AForge.Video.FFMPEG.dll dans le dossier AForge.NET Framework-2.2.5\Release )

si vous voulez créer votre propre solution , assurez-vous d'avoir une référence à AForge.Video.FFMPEG.dll dans votre projet. Ensuite, il devrait être facile d'utiliser la classe VideoFileWriter . Si vous suivez le lien à la classe, vous trouverez un très bon (et exemple simple). Dans le code, ils sont alimenter le Vidéofilewriter avec Bitmap image dans un for - boucle


56
répondu Hauns TM 2014-01-17 13:45:14

j'ai trouvé ce code dans le trancheur samples , ressemble assez proche de ce que vous voulez:

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();
  }
}
9
répondu Adam 2012-03-16 20:58:39

Je n'ai pas réussi à faire fonctionner l'exemple ci-dessus. Cependant j'ai trouvé une autre bibliothèque qui fonctionne étonnamment bien une fois. Essayez via NuGet " accord.extensions.imagerie.io", puis j'ai écrit la petite fonction suivante:

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

Il lit toutes les images d'un dossier et fait une vidéo.

si vous voulez le rendre plus agréable, vous pouvez probablement lire les dimensions de l'image au lieu de codage dur, mais vous avez le point.

8
répondu Sebastian 2015-05-29 15:39:04

cette fonction est basée sur Splicer.Net bibliothèque.M'a pris âge de comprendre comment cette bibliothèque fonctionne. Assurez-vous que votre fps(image par seconde )est correcte. Au fait, standard 24 f / s.

dans mon cas j'ai 15 images et je maintenant que j'ai besoin de vidéo de 7 secondes-> so fps =2. Fps peuvent varier selon la plateforme...ou développeur d'utilisation.

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

Espérons que cette aide.

0
répondu Jevgenij Kononov 2018-04-05 15:59:00