スポンサーリンク

VTKでクライアント領域の画像を取得してファイル保存

クライアント領域を画像化して保存(背景透明)

vtkWindowToImageFilter で画像を取得し、vtkPNGWriterで画像を保存する。

以下はタイマーが起動するたびに画面更新し、その結果を連番画像にして保存している。

#pragma warning(disable:4996)


#include <iostream>

//VTK_MODULE_INITに必要
#include <vtkAutoInit.h>


#include <vtkSmartPointer.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>

//円筒とその表示に必要
#include <vtkCylinderSource.h>
#include <vtkPolyDataMapper.h>

#include <vtkActor.h>
#include <vtkCubeSource.h>
#include <vtkProperty.h>

#include <vtkAssembly.h>
#include <vtkTransform.h>

#pragma comment(lib,"opengl32.lib")
#pragma comment(lib,"psapi.lib")
#pragma comment(lib,"dbghelp.lib")
#pragma comment(lib,"ws2_32.lib")


// コールバック関数を使用するのに必要
#include <vtkCallbackCommand.h>

// スクリーンショットを取得するのに必要
#include <vtkWindowToImageFilter.h>
#include <vtkPNGWriter.h>

//必須
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);


///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
 
void GetClientImage(vtkRenderWindow* renderWindow) {
  // スクリーンショットを取得
  vtkSmartPointer<vtkWindowToImageFilter> windowToImageFilter = vtkSmartPointer<vtkWindowToImageFilter>::New();
  windowToImageFilter->SetInput(renderWindow);
  windowToImageFilter->SetScale(1);  // スクリーンショットのサイズ(スケール)を設定
  windowToImageFilter->SetInputBufferTypeToRGBA();  // バッファの種類を設定
  windowToImageFilter->ReadFrontBufferOff();  // フロントバッファをオフに設定
  windowToImageFilter->Update();

  static int counter = 0;
  char filename[256];
  sprintf(filename, "C:/test/ss/screenshot_%03d.png", counter++);
  // スクリーンショットを保存
  vtkSmartPointer<vtkPNGWriter> writer = vtkSmartPointer<vtkPNGWriter>::New();
  writer->SetFileName(filename);
  writer->SetInputConnection(windowToImageFilter->GetOutputPort());
  writer->Write();

}
 
 

// コールバック関数に渡すデータ
struct MyData
{
  vtkSmartPointer<vtkAssembly> assembly;
};

// タイマーのコールバック関数
void MyTimerCallbackFunction(vtkObject* caller, long unsigned int eventId, void* clientData, void* callData)
{
  MyData* data = static_cast<MyData*>(clientData);

  static int angle = 0;

  vtkSmartPointer<vtkTransform> tra = vtkSmartPointer<vtkTransform>::New();
  tra->RotateWXYZ(angle+=10, 0, 0, 1);
  tra->Update();

  data->assembly->SetUserTransform(tra);

  // 画面更新
  auto interactor = static_cast<vtkRenderWindowInteractor*>(caller);
  interactor->Render();

  // スクリーンショットを保存
  vtkRenderWindow* renderWindow = interactor->GetRenderWindow();
  GetClientImage(renderWindow);


}
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////


vtkSmartPointer<vtkActor> createActor1();
vtkSmartPointer<vtkActor> createActor2();



int main(int /*argc*/, char** /*argv*/)
{
  // アクタを作成
  vtkSmartPointer<vtkActor> actor1 = createActor1();
  vtkSmartPointer<vtkActor> actor2 = createActor2();

  // アクタをまとめてアセンブリを作成
  vtkSmartPointer<vtkAssembly> assembly = vtkSmartPointer<vtkAssembly>::New();
  assembly->AddPart(actor1);
  assembly->AddPart(actor2);

  //////////////////////////////////////
  auto renderer = vtkSmartPointer<vtkRenderer>::New();
  renderer->ResetCamera();

  // アセンブリをレンダラに追加
  renderer->AddActor(assembly);


  //////////////////////////////////////

  auto interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();

  auto renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
  renderWindow->AddRenderer(renderer);
  renderWindow->SetInteractor(interactor);
  renderWindow->Render();

  //////////////////////////////////////
  //////////////////////////////////////

  // タイマーに渡す構造体の作成
  MyData callbackData{ assembly };

  // タイマー作成
  auto timerCallback = vtkSmartPointer<vtkCallbackCommand>::New();
  timerCallback->SetCallback(MyTimerCallbackFunction); // コールバック関数を設定
  timerCallback->SetClientData(&callbackData); // コールバック関数に渡すデータを設定

  interactor->AddObserver(vtkCommand::TimerEvent, timerCallback); // タイマーイベントにコールバック関数を設定

  interactor->Initialize();
  interactor->CreateRepeatingTimer(100); // 100msごとにタイマーイベントを発生させる

  //////////////////////////////////////
  //////////////////////////////////////

  interactor->Start(); //イベントループへ入る

  return 0;
}



vtkSmartPointer<vtkActor> createActor1()
{
  // 1つ目の立方体を作成
  vtkSmartPointer<vtkCubeSource> cubeSource1 = vtkSmartPointer<vtkCubeSource>::New();
  vtkSmartPointer<vtkPolyDataMapper> mapper1 = vtkSmartPointer<vtkPolyDataMapper>::New();
  mapper1->SetInputConnection(cubeSource1->GetOutputPort());
  vtkSmartPointer<vtkActor> actor1 = vtkSmartPointer<vtkActor>::New();
  actor1->SetMapper(mapper1);
  actor1->GetProperty()->SetColor(1, 0, 0); // 赤色

  return actor1;
}
vtkSmartPointer<vtkActor> createActor2()
{
  // 2つ目の立方体を作成
  vtkSmartPointer<vtkCubeSource> cubeSource2 = vtkSmartPointer<vtkCubeSource>::New();
  cubeSource2->SetCenter(1.2, 0, 0); // 位置を変更
  vtkSmartPointer<vtkPolyDataMapper> mapper2 = vtkSmartPointer<vtkPolyDataMapper>::New();
  mapper2->SetInputConnection(cubeSource2->GetOutputPort());
  vtkSmartPointer<vtkActor> actor2 = vtkSmartPointer<vtkActor>::New();
  actor2->SetMapper(mapper2);
  actor2->GetProperty()->SetColor(0, 1, 0); // 緑色

  return actor2;
}

クライアント領域を画像化して保存(背景色あり)

背景色が必要な場合、SetInputBufferTypeToRGBに設定する。renderer->SetBackground で設定した背景色となる。


/* ... */

void GetClientImage(vtkRenderWindow* renderWindow) {
  // スクリーンショットを取得
  vtkSmartPointer<vtkWindowToImageFilter> windowToImageFilter = vtkSmartPointer<vtkWindowToImageFilter>::New();
  windowToImageFilter->SetInput(renderWindow);
  windowToImageFilter->SetScale(1);  // スクリーンショットのサイズ(スケール)を設定
  windowToImageFilter->SetInputBufferTypeToRGB();  // バッファの種類をRGBに設定
  windowToImageFilter->ReadFrontBufferOff();  // フロントバッファをオフに設定
  windowToImageFilter->Update();

  static int counter = 0;
  char filename[256];
  sprintf(filename, "C:/test/ss/screenshot_%03d.png", counter++);
  // スクリーンショットを保存
  vtkSmartPointer<vtkPNGWriter> writer = vtkSmartPointer<vtkPNGWriter>::New();
  writer->SetFileName(filename);
  writer->SetInputConnection(windowToImageFilter->GetOutputPort());
  writer->Write();

}
 
 
/* ... */


int main(int /*argc*/, char** /*argv*/)
{
/* ... */

  //////////////////////////////////////
  auto renderer = vtkSmartPointer<vtkRenderer>::New();

/* ... */ // 背景色を設定 windowToImageFilter->SetInputBufferTypeToRGB();にすれば背景がこの色になる renderer->SetBackground(0.0, 0.0, 1.0); ////////////////////////////////////// auto interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); /* ... */ interactor->Start(); //イベントループへ入る return 0; } /* ... */

余談 アニメーションgif化

ImageMagickで、以下のコマンドでanimation gif 化できる。

magick convert -delay 20 -loop 0 -dispose Background screenshot_*.png animation.gif

背景が透明な場合、先に以下の方法で背景を黒に変換してからmagick convertする。

mogrify -background black -alpha remove screenshot_*.png

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: