Последовательность изображений в видеопотоке?

Как и многие люди, кажется, уже есть (здесь есть несколько тем на эту тему), я ищу способы создания видео из последовательности изображений.

Я хочу реализовать свою функциональность в C#!

вот что я не хочу делать:

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

Я знаю, что есть проект под названием сварочный аппарат (http://splicer.codeplex.com/) но я не могу найти подходящую документацию или четкие примеры, которые я могу следовать (эти те примеры, которые я нашел).

самое близкое, что я хочу сделать, что я нахожу здесь на CodePlex это: как я могу создать видео из каталога изображений в C#?

Я также прочитал несколько тем о ffmpeg (например: C# и FFmpeg предпочтительно без команд оболочки? и так: преобразование последовательности изображений с помощью ffmpeg) но я не нахожу никого, кто помог бы мне с моей проблемой, и я не думай!--8-->ffmpeg-стиль командной строки-лучшее решение для меня (из-за количества изображений).

Я считаю, что я могу использовать сварочный аппарат-проект в некотором роде (?).

в моем случае речь идет о > 30 000 изображениях, где каждое изображение должно отображаться примерно за 200 мс (в видеопотоке, который я хочу создать).

(о чем видео? Растениеводство. ..)

может ли кто-нибудь помочь мне завершить мой функции?

4 ответов


Ну, этот ответ приходит немного поздно, но так как я заметил некоторую активность с моим первоначальным вопросом в последнее время (и тот факт, что не было предоставлено рабочего решения), я хотел бы дать вам то, что, наконец, сработало для меня.

Я разделю свой ответ на три части:

  • фон
  • Я прочитал много статей о ffmpeg (см. мой первоначальный вопрос), но я не мог найти ни одного о том, как перейти от коллекции изображений к видео.


    решение

    наконец, я получил рабочее решение! Основная часть его исходит из проекта с открытым исходным кодомAForge.NET. Короче говоря, можно сказать, что AForge.NET библиотека компьютерного зрения и искусственного интеллекта в C#. (Если вам нужна копия фреймворка, просто возьмите его изhttp://www.aforgenet.com/)

    In AForge.NET, есть этот класс VideoFileWriter (класс для записи видеофайлов с помощью ffmpeg). Это сделало почти всю работу. (Есть также очень хороший пример здесь)

    это окончательный класс (уменьшенный), который я использовал для извлечение и преобразование данных изображения в видео из моей базы данных изображений:

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-архив, и вы найдете много интересных решений Visual Studio с проектами, такими как видео, в AForge.NET Framework-2.2.5\Samples folder...)
  2. пространство имен: AForge.Video.FFMPEG (от документация)
  3. сборка: AForge.Video.FFMPEG (in AForge.Video.FFMPEG.dll) (С документация) (вы можете найти этот AForge.Video.FFMPEG.dll на )

если вы хотите создать свой решение убедитесь, что у вас есть ссылка на AForge.Video.FFMPEG.dll в вашем проекте. Тогда это должно быть легко использовать VideoFileWriter класса. Если вы следуете ссылке в класс вы найдете очень хороший (и простой образец.) В коде они скармливают видеофайлу Bitmap image на for-loop



Я нашел этот код в овощерезка образцы, выглядит довольно близко к тому, что вы хотите:

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

мне не удалось заставить приведенный выше пример работать. Однако я нашел другую библиотеку, которая работает удивительно хорошо. Попробуйте через NuGet " accord.расширения.визуализация.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();
    }

он считывает все изображения из папки и делает из них видео.

Если вы хотите сделать его лучше вы бы читали размеры изображения вместо жесткого кодирования, но вы попали в точку.


эта функция основана на Splicer.Net библиотека.Мне понадобилась целая вечность, чтобы понять, как работает эта библиотека. Убедитесь, что ваш fps(кадр в секунду )правильный. Кстати Стандарт 24 к/с.

в моем случае у меня есть 15 изображений, и теперь мне нужно 7 секунд видео - > так fps =2. ФПС может варьироваться в зависимости от платформы...или использование разработчиком.

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

надеюсь, что это помогает.