65

多くの人が既に持っているように (ここにはこのテーマに関するスレッドがいくつかあります)、一連の画像からビデオを作成する方法を探しています。

自分の機能を 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 はできればシェル コマンドなしでしょうか?およびこれ: convert image sequence using ffmpeg )。command-line-style が私にとって最良の解決策です (画像の量のため)。

Splicerプロジェクトを何らかの方法 (?) で使用できると思います。

私の場合、約 30,000 枚以上の画像があり、各画像を約 200 ミリ秒表示する必要があります (作成するビデオストリーム内)。

(動画の内容は?植物が育つ…)

誰かが私の機能を完了するのを手伝ってくれますか?

4

7 に答える 7

70

さて、この回答は少し遅れていますが、最近、元の質問でいくつかのアクティビティに気付いたので (そして、有効な解決策が提供されていないという事実)、最終的に私にとって何がうまくいったかをお伝えしたいと思います.

答えを 3 つの部分に分けます。

  • バックグラウンド
  • 問題
  • 解決

バックグラウンド

(このセクションはソリューションにとって重要ではありません)

私の最初の問題は、大量の画像 (つまり膨大な量)、つまりバイト配列としてデータベースに個別に格納された画像があることでした。これらすべての画像を使って一連のビデオを作りたかったのです。

私の機器のセットアップは、この一般的な図のようなものでした: ここに画像の説明を入力

画像は、さまざまな状態で成長しているトマトの植物を描いています。すべての画像は、日中に 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
}

画像を保存するための非常に単純なデータベースがありました。その中には1つのテーブル(テーブル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(in AForge.Video.FFMPEG.dll) (ドキュメントから) (これAForge.Video.FFMPEG.dllAForge.NET Framework-2.2.5\Releaseフォルダにあります)

独自のソリューションを作成する場合はAForge.Video.FFMPEG.dll、プロジェクトに への参照があることを確認してください。そうすれば、 VideoFileWriterクラスを簡単に使用できるはずです。クラスへのリンクをたどると、非常に優れた (そして簡単な例) が見つかります。コードでは、 -loop で VideoFileWriter にフィードしてBitmap imageforます


于 2012-09-11T19:08:04.080 に答える
11

私はスライサーのサンプルでこのコードを見つけました、あなたが望むものにかなり近いように見えます:

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();
  }
}
于 2012-03-16T20:58:39.047 に答える