CGプログラミング演習
5 画像、PDF、ムービーデータの入出力方法

これまでの講義で画像処理とムービー処理を学んできましたが、ぜひともこの技術をみなさんの作品制作に生かしてほしいと思います。
ここでは、実際の作品制作に Processing を生かすため、画像/PDF/ムービーデータの入出力方法を学びます。

1 画像データの入出力

  • キャンバスの描画内容を画像データとして保存するには、saveFrame 関数を利用します。
  • たとえば、下記のようなプログラムがあったとして……
// キャンバスサイズの指定
// 幅400ピクセル、高さ200ピクセルのウインドウを開く
size(400, 200);

// 点
// 座業(200, 100)に点を描きます
point(200, 100);

// 線
// 座標(25, 175)から(175, 175)に線を描きます
line(25, 175, 175, 175);

// 長方形
// 左上の座標を(225, 25)として、150ピクセルの幅と 75ピクセルの高さを持つ長方形を描きます
rect(225, 25, 150, 75);

// 三角形
// みっつの頂点がそれぞれ(300, 125)(225, 175)(375, 175)の三角形を描きます
triangle(300, 125, 225, 175, 375, 175);

// 円、楕円
// 中心の座標を(100, 90)として、幅 140ピクセル、高さ 140ピクセルの円を描きます
ellipse(100, 90, 140, 140);

画像を描画するサンプルプログラムの実行結果

  • この描画内容をファイルに保存するには、上記プログラムの最後に saveFrame();を追加します。
...(略)
saveFrame();
  • saveFrame関数の部分を、saveFrame("ファイル名の指定.jpg");とすることで、書き出すファイル名を指定することが可能です。
  • また、拡張子を .tiff, .tga, .gif, .jpg, .pngのいずれかに指定すると、そのフォーマットで画像を保存してくれます。

2 PDF データの出力

  • 次に、Processing の描画内容を PDF として書き出してみましょう。
  • PDF として保存することができれば、Processing を利用してポスター用にデータを作成するなど、その可能性がぐっと広がります。

2.1 PDF の出力方法

  • Processing から PDF を出力するには、以下の手順をとります:
    1. プログラムの冒頭に下記の行を記し、ライブラリを追加する。
      import processing.pdf.*;
    2. size 命令を書き換える。
      size(400, 200);となっているとすると、「size(400, 200, PDF, "test.pdf");」のように、「PDF, "保存したいファイル名.pdf"」を追加する。
    3. プログラムの最終行に「exit();」を追加する。
    4. プログラムを実行する。
      この状態でプログラムを実行すると、ウインドウが表示されないまま、プログラムがすぐに終了します。その後プロジェクトフォルダを開いて、「test.pdf」ができていれば成功です。
  • 以下に、先ほどのプログラムを PDF 出力用に書き換えたコードを記します。
  • 変更箇所は、コメントの冒頭に「★」を記した部分です。
// ★ PDF 出力用ライブラリの読み込み
import processing.pdf.*;

// ★ 幅400ピクセル、高さ200ピクセルの PDF を「test.pdf」として保存する。
size(400, 200, PDF, "test.pdf");

// 点
// 座業(200, 100)に点を描きます
point(200, 100);

// 線
// 座標(25, 175)から(175, 175)に線を描きます
line(25, 175, 175, 175);

// 長方形
// 左上の座標を(225, 25)として、150ピクセルの幅と 75ピクセルの高さを持つ長方形を描きます
rect(225, 25, 150, 75);

// 三角形
// みっつの頂点がそれぞれ(300, 125)(225, 175)(375, 175)の三角形を描きます
triangle(300, 125, 225, 175, 375, 175);

// 円、楕円
// 中心の座標を(100, 90)として、幅 140ピクセル、高さ 140ピクセルの円を描きます
ellipse(100, 90, 140, 140);

// ★ PDF 出力用に exit(); 命令を追加する。
exit();
  • 書き出した PDF は、Illustrator などで編集可能です!

3 ムービーデータの入出力

3.1 ムービーデータの入力

3.1.1 練習用データのダウンロード

3.1.2 Processing 用にイメージシーケンスを作成する

  • Proessing では、ムービーデータをそのまま処理することはできません。
  • そこで、あらかじめ QuickTime を用いてイメージシーケンスを作成する必要があります。
  • 以下は、QuickTime でのイメージシーケンスの作成方法です。

ダウンロードしたムービーファイルを QuickTime で開く

「ファイル」メニューから「書き出す...」を選択する

書き出しを「イメージシーケンス」とし、「オプション」ボタンをクリックする

「書き出しイメージシーケンスの設定」で、Framerate を適当な値に設定する

3.1.3 作成したイメージシーケンスの読み込み

  • 作成したイメージシーケンスを読み込むためには、あらかじめ Processing でプロジェクトを保存しておく必要があります。
  • その上で、作成したプロジェクトフォルダに、イメージシーケンスが保存されたフォルダを移動しておきます。

プロジェクトフォルダにイメージシーケンスの保存されたフォルダを保存した状態
ここではフォルダ名に「sequence」を設定しています。

  • これで準備は整いました。
  • さっそく、イメージシーケンスを読み込んでみます。
// アニメーションのフレーム数を予め指定します。
// 指定する数は、QuickTime が書き出した連番名の最後の番号 + 1 とします。
int numFrames = 270;

// アニメーション画像の配列を用意します。
PImage[] images = new PImage[numFrames];

// 現在の画像を保存する変数です。
PImage currentImage;

// アニメーション開始前の準備
void setup()
{
  // キャンバスサイズの指定
  size(320, 240);

  // フレームレートの設定(QuickTime でイメージシーケンスを書き出す際に指定した値と同じ数にします。
  frameRate(12);

  // あらかじめ画像をすべて読み込んでしまいます。
  for (int i = 1; i < numFrames; i++)
  {
    // 読み込むイメージシーケンスを指定します。
    // ここでは「sequence」フォルダ内のファイルを指定しています。
    // ファイル名のところに「nf(i, 3)」とあるのは、連番の桁数を常に 3桁に保つ指定です。
    // * 1番が、「001」となり、10番が「010」となり、100番が「100」となる。
    images[i] = loadImage("sequence/1894Caicedowith_pole " + nf(i, 3) + ".png");
  }
}

// アニメーションの描画
void draw()
{
  // 現在のフレーム数「frameCount」が、最初に指定したフレーム数「numFrames」以内である場合の処理です。
  if (frameCount < numFrames)
  {
    // 現在のフレーム内容を「currentImage」に保存します。
    currentImage = images[frameCount];

    // ★ここに処理内容を記します
    image(currentImage, 0, 0);  // ここでは単純に画像を表示しています。
  }
  // それ以外の場合の処理です。
  else
  {
    // アニメーションのループを終了します。
    noLoop();
  }
}

上記プログラムの実行結果

  • これで、前回講義で学んだように、ムービーに含まれる画像シーケンスを処理可能になりました。
  • たとえばコメントにある「★ここに処理内容を記します」のすぐ下にある「image(currentImage, 0, 0); // ここでは単純に画像を表示しています。」という部分を、下記のように変更してみてください。
  • あるいは、前回のように for 文を利用した処理を加えることも考えられます。
  • 今書き換えた行を削除し、そこに下記のコードを挿入してみてください。
    // 変数を用意する。
    noStroke();
    int x, y, pos;
    for (y = 0; y < currentImage.height; y = y + 5)     // y 座標を 5ピクセルずつ進める
    {
      for (x = 0; x < currentImage.width; x = x + 5)    // x 座標を 5ピクセルずつ進める
      {
        // 現在のピクセルの位置を取得する。
        pos = (y * width) + x;

        // 現在のピクセル位置の色情報を取得する。
        color c = currentImage.get(x, y);

        // 現在のピクセル位置の色を、r, g, b それぞれ取得する。
        float r = red(c);
        float g = green(c);
        float b = blue(c);

        // ピクセルの色情報に基づいて、塗りつぶしの色を決定する。
        fill(255 - r, g, b); // ここでは r の値を反転している。

        // 読み取ったピクセルの位置に 幅と高さが 3ピクセルの円を描画する。
        ellipse(x, y, 3, 3);
      }
    }

加工されたムービーデータ(イメージシーケンス)

3.2 ムービーデータの出力

  • さて、ここまでで「イメージシーケンス」として保存されたムービーデータを加工処理することができました。
  • 次に、加工したムービーを出力します。
  • ムービーデータの出力は、やはり「イメージシーケンス」として行います。
  • それには、saveFrame() 関数を利用します。
  • ただ、書き出されるファイル数が膨大になってしまいますので、あらかじめ出力用のフォルダ「output」を用意しておきます。

イメージシーケンス用のフォルダ「output」をプロジェクトフォルダ内に用意しておく。

  • その上で、saveFrame 関数を、プログラム中の void draw() { ... }とある部分の最後に挿入するわけです。
  • が、ここでは「saveFrame("output/sequence_####.tif");」として、出力先のフォルダを「output」とし、ファイル名を「sequence_」+「####(4桁の連番)」としておきましょう。
...(略)

// アニメーションの描画
void draw()
{
    ...(略)

  // 出力先のフォルダを「output」とし、ファイル名を「sequence_」+「####(4桁の連番)」とする。
  saveFrame("output/sequence_####.tif");
}
  • プログラムを実行し、アニメーションの描画が終了すると、変換されたイメージシーケンスが「output」フォルダに保存されます。

イメージシーケンスがフォルダ「output」に保存されている状態。

  • 出力したイメージシーケンスは、QuickTime で読み込むことが可能です。
  • 「ファイル」メニューの中の「イメージシーケンスを開く」を選択し、今作成したイメージシーケンスの最初のファイルを選択してください。

Processing で出力したイメージシーケンスは、QuickTime で読み込み可能。

  • その他のアプリケーションで読み込む際は、QuickTime から各種ムービー形式でファイルを保存したものを利用することになるでしょう。
  • あとは、煮るのも焼くのも、好き放題、やりたい放題です!