前回はマンデルブロ集合をカラーで表示させましたが、今回は少しずつ拡大させていき、これを動画として公開する方法を考えます。
Contents
マンデルブロ集合を少しずつ拡大する
まず少しずつ拡大する処理ですが、ボタンをクリックしたら以下のような処理をおこなわせます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
public partial class Form1 : Form { private void button1_Click(object sender, EventArgs e) { ParDot *= 0.99; // 拡大の中心座標は(-0.70126220703125, 0.356876220703125)とする CenterX = -0.70126220703125; CenterY = 0.356876220703125; // 表示&保存すべきBitmapの作成(CreateMandelbrotSetBitmapメソッドは前回と同じ) CreateMandelbrotSetBitmap(); // フォーム内に描画させる Invalidate(); // Y座標が上下逆なので反転させる // Cloneを作る Bitmap clone = (Bitmap)Bitmap.Clone(); clone.RotateFlip(RotateFlipType.RotateNoneFlipY); // 左上に拡大率を表示させる Graphics graphics = Graphics.FromImage(clone); string str = Math.Round((InitParDot / ParDot), 2).ToString() + " 倍"; graphics.DrawString(str, new Font("MS ゴシック", 10), Brushes.White, new Point(10, 10)); graphics.Dispose(); // Bitmapをpng形式で保存する // 保存すべきフォルダが存在しない場合は作成する string folderPath = Application.StartupPath + "\\img"; if (!System.IO.Directory.Exists(folderPath)) System.IO.Directory.CreateDirectory(folderPath); // ファイル名は連番にしてフォルダ内に保存するする string filePath = folderPath + "\\" + num + ".png"; clone.Save(filePath, System.Drawing.Imaging.ImageFormat.Png); num++; // Cloneはもう使わないのでDisposeする clone.Dispose(); } } |
あとはボタンをポチポチクリックするか、自動で処理をさせます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public partial class Form1 : Form { private void button2_Click(object sender, EventArgs e) { // UIがフリーズしないように非同期処理をする Task.Run(()=> { SaveBitmaps(); MessageBox.Show("完了"); }); } void SaveBitmaps() { ParDot = 0.00500; while (true) { // Button1をクリックしたのと同じ動作をさせる button1_Click(this, new EventArgs()); // 適当なところで終了させる if (ParDot < 0.00005) return; } } } |
複数の画像ファイルから動画を生成する
次に集まったpngファイルから動画を生成します。
OpenCvSharp4とAForgeをインストール
まずNuGetからOpenCvSharp4.Windowをインストールします。それからAForge.dll と AForge.Video.dll と AForge.Video.VFW.dllが必要です。ここからZipファイルをダウンロードしてください。解凍するとReleaseフォルダのなかに必要なdllがあるので、これを参照に追加しておきます。NuGetでインストールできれば簡単なのですが、なぜかうまくできません。
実行ファイルがあるフォルダのなかにあるimgフォルダのなかにpngファイルが連番で存在するので、以下の方法でファイルのパスをすべて取得することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public partial class Form1 : Form { List<string> GetPngPaths() { List<string> pngPaths = new List<string>(); string folderPath = Application.StartupPath + "\\img"; if (!System.IO.Directory.Exists(folderPath)) System.IO.Directory.CreateDirectory(folderPath); int num = 0; while (true) { string filePath = folderPath + "\\" + num + ".png"; // ファイルは連番になっているので次のファイルが見つからなければ終了 if (!System.IO.File.Exists(filePath)) break; pngPaths.Add(filePath); num++; } return pngPaths; } } |
AForge.Video.VFW.AVIWriterで動画に変換する
次に取得したファイルパスのリストからaviファイルを生成するメソッドを作成します。
リストの各要素のパスが第二引数の時間(ミリ秒)だけ動画として追加されます。aviファイルなのでサイズが大きくなりやすいです。実質的に 2GB が上限となので、これを超えてしまう場合は分割の処理が必要です。あとはWindows Movie Makerなどで別の形式(mp4など)に変換します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public partial class Form1 : Form { void CreateAviFromBitmaps(List<string> bmpFilePaths, int interval) { if (bmpFilePaths.Count == 0) return; Bitmap bitmap1 = new Bitmap(bmpFilePaths[0]); int width = bitmap1.Width / 2 * 2; int height = bitmap1.Height / 2 * 2; bitmap1.Dispose(); AForge.Video.VFW.AVIWriter aviWriter = new AForge.Video.VFW.AVIWriter(); aviWriter.FrameRate = 1000 / interval; aviWriter.Open(@"保存したいフォルダへのパス\test.avi", width, height); foreach(string path in bmpFilePaths) { Bitmap bitmap = new Bitmap(path); aviWriter.AddFrame(bitmap); bitmap.Dispose(); } aviWriter.Close(); } } |
Button3をクリックしたら画像ファイルから動画を生成します。
1 2 3 4 5 6 7 8 9 |
public partial class Form1 : Form { private void button1_Click(object sender, EventArgs e) { List<string> pngPaths = GetPngPaths(); CreateAviFromBitmaps(pngPaths, 80); MessageBox.Show("完了しました。"); } } |