Подтвердить что ты не робот

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

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

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

Вот что я не буду делать:

/*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/), но я не могу найти подходящую документацию или ясные примеры, которые я могу выполнить (эти являются примерами, которые я нашел).

Ближайшее, что я хочу сделать, которое я нахожу здесь, в CodePlex: Как создать видео из каталога изображений на С#?

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

Я считаю, что я могу использовать Splicer -project каким-то образом (?).

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

(Что такое видео? Растения растут...)

Может ли кто-нибудь помочь мне выполнить мою функцию?

4b9b3361

Ответ 1

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

Я разберу свой ответ на три части:

  • Фон
  • Проблема
  • Решение

Фон

(этот раздел не важен для решения)

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

Моя настройка оборудования была чем-то вроде этого общего рисунка: enter image description here

На изображениях изображены растущие растения томатов в разных состояниях. Все изображения снимались каждые 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
}

У меня был очень простой db для хранения изображений, в нем была только одна таблица (таблица ImageSet): enter image description here


Проблема

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


Решение

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

В 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 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?)

  • Загрузите AForge.NET Framework с страница загрузки (Загрузите полный ZIP-архив, и вы найдете много интересных решений Visual Studio с проектами, такими как Video, в AForge.NET Framework-2.2.5\Samples folder...)
  • Пространство имен: AForge.Video.FFMPEG (из документация)
  • Сборка: AForge.Video.FFMPEGAForge.Video.FFMPEG.dll) (из документация) (вы можете найти это AForge.Video.FFMPEG.dll в AForge.NET Framework-2.2.5\Release)

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


Ответ 2

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

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

Ответ 3

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

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

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