programing tip

비디오 스트림에 이미지 시퀀스?

itbloger 2021. 1. 8. 07:54
반응형

비디오 스트림에 이미지 시퀀스?


많은 사람들이 이미 가지고있는 것처럼 보입니다 (여기에이 주제에 대한 여러 스레드가 있습니다). 저는 이미지 시퀀스에서 비디오를 만드는 방법을 찾고 있습니다.

내 기능을 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
}

Splicer ( http://splicer.codeplex.com/ ) 라는 프로젝트가 있다는 것을 알고 있지만 적절한 문서 나 따를 수있는 명확한 예제를 찾을 수 없습니다 ( 이것들 은 내가 찾은 예제입니다).

CodePlex에서 가장 가까운 방법 은 다음과 같습니다. C #의 이미지 디렉터리에서 비디오를 만들려면 어떻게해야합니까?

또한 대한 몇 가지 스레드를 읽고 는 FFmpeg을 (예를 들어,이 : C #과는 FFmpeg 바람직 쉘 명령없이? 이 : 변환 이미지 시퀀스 사용는 FFmpeg )하지만 난 내 문제에 대한 도움 나에게 아무도 찾을 나는 생각하지 않는다 는 FFmpeg - 명령 줄 스타일이 저에게 가장 적합한 솔루션입니다 (이미지의 양 때문에).

Splicer 프로젝트를 어떤 식 으로든 (?) 사용할 수 있다고 생각합니다 .

제 경우에는 각 이미지가 약 200ms 동안 표시되어야하는 약 30,000 개의 이미지입니다 (내가 만들고 싶은 비디오 스트림에서).

(동영상 내용? 식물 성장 ...)

누구든지 내 기능을 완료하도록 도울 수 있습니까?


글쎄,이 답변은 조금 늦었지만 최근에 원래 질문에 대한 활동을 발견했기 때문에 (그리고 작동하는 해결책이 제공되지 않았다는 사실) 마침내 저에게 도움이 된 것을 제공하고 싶습니다.

내 대답을 세 부분으로 나눌 것입니다.

  • 배경
  • 문제
  • 해결책

배경

(이 섹션은 솔루션에 중요하지 않음)

내 원래 문제는 많은 양의 이미지 (즉, 엄청난 양)가 데이터베이스에 개별적으로 바이트 배열로 저장된 이미지가 있다는 것입니다. 이 모든 이미지로 비디오 시퀀스를 만들고 싶었습니다.

내 장비 설정은 다음과 같은 일반적인 도면이었습니다. 여기에 이미지 설명 입력

이미지는 다른 주에서 자라는 토마토 식물을 묘사했습니다. 모든 이미지는 낮 시간에 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 테이블)이 하나만있었습니다. 여기에 이미지 설명 입력


문제

ffmpeg에 대한 많은 기사를 읽었지만 (원래 질문을 참조하십시오) 이미지 모음에서 비디오로 이동하는 방법에 대해 찾을 수 없었습니다.


해결책

마침내 작업 솔루션을 얻었습니다! 그것의 주요 부분은 오픈 소스 프로젝트 AForge.NET 에서 비롯됩니다 . 간단히 말해 AForge.NET은 C #의 컴퓨터 비전 및 인공 지능 라이브러리 라고 말할 수 있습니다. (프레임 워크의 사본이 필요하면 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'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 Framework를 다운로드하십시오 (전체 ZIP 아카이브를 다운로드하면 비디오와 같은 프로젝트가 포함 된 흥미로운 Visual Studio 솔루션을 찾을 수 있습니다 AForge.NET Framework-2.2.5\Samples folder...)
  2. 네임 스페이스 : AForge.Video.FFMPEG( 문서에서 )
  3. 어셈블리 : AForge.Video.FFMPEG(에서 AForge.Video.FFMPEG.dll) ( 문서에서 ) ( 폴더 AForge.Video.FFMPEG.dll에서 찾을 수 있습니다 AForge.NET Framework-2.2.5\Release)

당신이 만들려면 자신의 솔루션을 , 당신이 참조해야 할 AForge.Video.FFMPEG.dll프로젝트에 있습니다. 그러면 VideoFileWriter 클래스를 쉽게 사용할 수 있습니다 . 당신이 따르는 경우에 링크 클래스에 당신은 아주 좋은 (그리고 간단한 예를) 찾을 수 있습니다. 코드에서, 그들은 함께 VideoFileWriter을 공급하는 Bitmap imageA의 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.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();
    }

폴더에서 모든 이미지를 읽고 그로부터 비디오를 만듭니다.

If you want to make it nicer you could probably read the image dimensions instead of hard coding, but you got the point.


This function is based on Splicer.Net library.Took me ages to understand how that library works. Make sure that your fps(frame per second )is correct. By the way standard 24 f/s.

In my case I have 15 images and I now that I need 7 seconds video-> so fps =2. Fps may vary according to platform...or developer usage.

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

Hope this helps.


This is a solution for creating a video from an image sequence using Visual Studio using C#.

My starting point was "Hauns TM"'s answer below but my requirements were more basic than theirs so this solution might be more appropriated for less advanced users ( like myself )

Libraries:

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

"도구-> NuGet 패키지 관리자-> 솔루션에 대한 NuGet 패키지 관리 ..."에서 FFMPEG를 검색하여 FFMPEG 라이브러리를 가져올 수 있습니다.

함수에 전달한 변수는 다음과 같습니다.

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

함수:

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

참조 URL : https://stackoverflow.com/questions/9744026/image-sequence-to-video-stream

반응형