2013年1月6日日曜日

C++ AMP 2 モザイク

C++ AMP の AMP は (Accelerated Massive Parallelism) の略
意訳すると、C++で加速される、ちょー大きい並列処理 のこと?
Massive が気になる

4GBのメモリを積んだウルトラハイエンドなグラボがあるらしい

あと、msdnのリファレンスの文章がおかしい、特に C++ AMP mad関数の説明なんかが変
「きちがい関数」www ではない x * y + z を返すだけ

モザイク処理のテスト
出力画像を拡大して確認 → 指定した領域にモザイクがかかっていた

何がどう動いているのかイメージしにくいので、
キーワード tile_static tiled_extent などを後で調査

ドメイン固有言語 なんだけど C++で書けることなのかなー

そういえば、タイルレンダリングのテストもしていた気がする
シェーダーとは、GPU 上で実行される、ドメインに固有の小容量プログラム なんですか?

main.cpp

#include <windows.h>
#include <wincodec.h>

#include <tchar.h>
#include <assert.h>

#include <d3d11.h>
#include <amp.h>
#include <amp_graphics.h>

#include <DirectXTex.h>

#pragma comment(lib, "d3d11.lib")

using namespace concurrency;
using namespace concurrency::graphics;
using namespace concurrency::direct3d;

#define DIMENSION   2

ID3D11Device*     g_pd3dDevice = nullptr;
ID3D11DeviceContext*  g_pImmediateContext = nullptr ;
ID3D11Texture2D*    g_pInputTexture = nullptr;

texture<unorm_4, 2>*  g_pAmpProcessedTexture = nullptr;

// タイルのサイズ
static const UINT sTileSize = 32;
//static const UINT sTileSize = 48; // compile ERROR

// 「C++ AMP でのタイリングの概要」で検索
// extentは範囲
tiled_extent<sTileSize, sTileSize> GetTiledExtent(const extent<DIMENSION>& ext)
{
  // タイルエクステント内の総数は1024以下ならOK
    tiled_extent<sTileSize, sTileSize> text(ext);
    return text.pad();
}

// カーネル関数
void ApplyEffectKernelFunc001(const texture<unorm_4, 2>& input_tex, writeonly_texture_view<unorm_4, 2> output_tex_view, tiled_index<sTileSize, sTileSize> idx) restrict(amp)
{
    // タイル毎の共有メモリ
    tile_static float_4 local_pixels[sTileSize][sTileSize];

    const UINT globalY = idx.global[0];
    const UINT globalX = idx.global[1];
    const UINT localY = idx.local[0];
    const UINT localX = idx.local[1];

  local_pixels[localY][localX] = static_cast<float_4>(input_tex[idx.global].rgba);
//  local_pixels[idx.local] = static_cast<float_4>(input_tex[idx.global].rgba);   // ERROR

  idx.barrier.wait();

  if((globalY >= 100 && globalY < 250) && (globalX > 500 && globalX < 720)) {
    // 特定の領域にモザイクをかける
    output_tex_view.set(idx.global, unorm_4(local_pixels[0][0].r, local_pixels[0][0].g, local_pixels[0][0].b, 1.0));
  }
  else
  {
    // 入力値をコピー
    float_4 pixel = static_cast<float_4>(input_tex[idx.global].rgba);
    output_tex_view.set(idx.global, unorm_4(pixel.r, pixel.g, pixel.b, 1.0));
  }
}


void ApplyEffect(const texture<unorm_4, DIMENSION> & input_tex,  writeonly_texture_view<unorm_4, DIMENSION>& output_tex_view)
{
  // タイルのエクステント
  tiled_extent<sTileSize, sTileSize> computeDomain = GetTiledExtent(input_tex.extent);

  // 並列計算を起動
  parallel_for_each(computeDomain, [=, &input_tex](tiled_index<sTileSize, sTileSize> idx) restrict(amp)
  {
    ApplyEffectKernelFunc001(input_tex, output_tex_view, idx);
  });
}


void TestAMP(_TCHAR* filePath)
{
  HRESULT hr;

  hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);

    unsigned int createDeviceFlags = 0;
#ifdef _DEBUG
    createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

    // DirectX11の初期化
    D3D_FEATURE_LEVEL FeatureLevel = D3D_FEATURE_LEVEL_11_0;
  hr = D3D11CreateDevice( nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, &FeatureLevel, 1, D3D11_SDK_VERSION, &g_pd3dDevice, nullptr, &g_pImmediateContext );
  assert( hr == S_OK );

  // リソースが解放されない? 実行すると何かが残る
  accelerator_view g_av = create_accelerator_view(reinterpret_cast<IUnknown *>(g_pd3dDevice));

  std::wstring desc = g_av.get_accelerator().get_description();
  bool is_debug = g_av.get_is_debug();
  queuing_mode qmode = g_av.get_queuing_mode();


  // 画像ファイルを読み込む
  DirectX::TexMetadata mdata;
  DirectX::ScratchImage image;

  hr = DirectX::LoadFromWICFile(filePath, DirectX::DDS_FLAGS_NONE, &mdata, image);
  assert( hr == S_OK );

  // ID3D11Texture2Dを作成
  hr = DirectX::CreateTexture( g_pd3dDevice, image.GetImages(), image.GetImageCount(), mdata, reinterpret_cast<ID3D11Resource **>(&g_pInputTexture) );
  assert( hr == S_OK );


  // Concurrency::graphics::textureを作成
  UINT img_width = mdata.width;
    UINT img_height = mdata.height;
#if 1
  // OK
    g_pAmpProcessedTexture = new texture<unorm_4, DIMENSION>(static_cast<int>(img_height), static_cast<int>(img_width), 8U, g_av);
#else
  // NG ApplyEffect内でエラー発生する
//    g_pAmpProcessedTexture = new texture<unorm_4, DIMENSION>(static_cast<int>(img_height), static_cast<int>(img_width), 8U);
#endif

  // 画像データを加工する

  // 出力先
  writeonly_texture_view<unorm_4, DIMENSION> output_tex_view(*g_pAmpProcessedTexture);

  // 入力データ
  // ID3D11Texture2D g_pInputTextureからConcurrency::graphics::textureを作成
  const texture<unorm_4, DIMENSION> input_tex = graphics::direct3d::make_texture<unorm_4, DIMENSION>(g_av, reinterpret_cast<IUnknown *>(g_pInputTexture));

  // 加工処理
  ApplyEffect(input_tex, output_tex_view);

  // 加工結果を取り出す

  // Concurrency::graphics::texture の g_pAmpProcessedTexture から ID3D11Texture2Dを取得
    ID3D11Texture2D* processedTexture = reinterpret_cast<ID3D11Texture2D *>(graphics::direct3d::get_texture<unorm_4, DIMENSION>(*g_pAmpProcessedTexture));

  DirectX::ScratchImage output_image;

  // processedTextureをoutput_imageにキャプチャーする
  hr = DirectX::CaptureTexture(g_pd3dDevice, g_pImmediateContext, reinterpret_cast<ID3D11Resource *>(processedTexture), output_image);
  assert( hr == S_OK );

  // Jpeg形式で画像を保存
  GUID containerFormat = GUID_ContainerFormatJpeg;
  DWORD flags = 0;
  const DirectX::Image* pImage = output_image.GetImages();
  size_t numImage = output_image.GetImageCount();

  hr = DirectX::SaveToWICFile(pImage, numImage, flags, containerFormat, L"output.jpg");
  assert( hr == S_OK );

  // 解放
    processedTexture->Release();

    if (g_pInputTexture) g_pInputTexture->Release();
  if (g_pAmpProcessedTexture) delete g_pAmpProcessedTexture;

    if (g_pImmediateContext) g_pImmediateContext->Release();
    if (g_pd3dDevice) g_pd3dDevice->Release();
  CoUninitialize();
}

int _tmain(int argc, _TCHAR* argv[])
{
  if(argc > 1) {
    TestAMP(argv[1]);
  }
  return 0;
}

2013年1月3日木曜日

C++ AMP 1 グレースケール

C++ AMPで画像処理のテスト
VC 2012 Express版では不可?みたいなので、
テスト用のPCをWindows8 にUpgrade & Visual Studio 2012のPro版をInstall
ようやくテストすることができた。

AMPについて詳しくないので、
「C++ AMP の概要」 でググって読む
なんやらかんやらが、裏でいろいろ動いているはず

C++ AMPの本の付属サンプルを参考に作成したはず
http://ampbook.codeplex.com/

画像の読み込みにDirectXTex ライブラリを使用
ライブラリをDL & ビルドしてリンクに追加
http://directxtex.codeplex.com/

concurrency::indexクラス N次元のインデックス
concurrency::extentクラス N次元の範囲

RunImageProcessing()の parallel_for_each が肝 そういえばラムダ式

concurrency::accelerator_viewが怪しい
concurrency::direct3d::create_accelerator_view() で作成した
リソースが残っていたはず

8K解像度の画像でもサクサク処理できるかテスト中

namespaceを使わないとナガイ & < >が抜けていた?

main.cpp

#include <wincodec.h>

#include <iostream>
#include <tchar.h>
#include <assert.h>

#include <d3d11.h>
#include <DirectXTex.h>
#include <amp.h>
#include <amp_graphics.h>

#pragma comment(lib, "d3d11.lib")

// 今回は使用しない
//using namespace concurrency;
//using namespace concurrency::graphics;
//using namespace concurrency::direct3d;

ID3D11Device*       g_pd3dDevice = nullptr;
ID3D11DeviceContext*    g_pImmediateContext = nullptr ;

ID3D11Texture2D*      g_pInputTexture = nullptr;
Concurrency::graphics::texture<Concurrency::graphics::direct3d::unorm4, 2>*                 g_pAmpProcessedTexture = nullptr;

// 簡易タイマー
class Timer
{
  LARGE_INTEGER start, end;
public:
  void Start() {
    QueryPerformanceCounter(&start);
  }
  void Stop() {
    QueryPerformanceCounter(&end);
  }

  double ElapsedTime() {
    LARGE_INTEGER freq;
    QueryPerformanceFrequency(&freq);
    return (double(end.QuadPart) - double(start.QuadPart)) * 1000.0 / double(freq.QuadPart);
  }
};


// ↓今回のテスト対象 画像処理を行う
void RunImageProcessing(const Concurrency::graphics::texture<Concurrency::graphics::unorm_4, 2> & input_tex,  const Concurrency::graphics::writeonly_texture_view<Concurrency::graphics::unorm_4, 2> output_tex_view)
{
    parallel_for_each(input_tex.accelerator_view, output_tex_view.extent, [=, &input_tex] (Concurrency::index<2> idx) restrict(amp) {

    Concurrency::graphics::float_4 pixel = static_cast<Concurrency::graphics::float_4>(input_tex[idx].rgba);

    // RGB値をグレースケールに変更
    float Y = pixel.r * 0.2126f + pixel.r * 0.7152f + pixel.b * 0.0722f;

    output_tex_view.set(idx, Concurrency::graphics::unorm_4(Y, Y, Y, pixel.a));
  });
}

// AMPのテスト
// 画像ファイルを読み込んだ後に、グレースケールに変換して保存する
void TestAMP(_TCHAR* imgFilePath)
{
  Timer timer;
  HRESULT hr;

  // LoadFromWICFile 用にCOMを初期化
  hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);

  // DirectX11の初期化
    unsigned int createDeviceFlags = 0;
#ifdef _DEBUG
    createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

    D3D_FEATURE_LEVEL FeatureLevel = D3D_FEATURE_LEVEL_11_0;
  hr = D3D11CreateDevice( nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags,
        &FeatureLevel, 1, D3D11_SDK_VERSION, &g_pd3dDevice, nullptr, &g_pImmediateContext );
  assert( hr == S_OK );


  // 画像ファイルを読み込む
  DirectX::TexMetadata mdata;
  DirectX::ScratchImage image;

  hr = DirectX::LoadFromWICFile(imgFilePath, DirectX::DDS_FLAGS_NONE, &mdata, image);
  assert( hr == S_OK );

  // ID3D11Texture2Dを作成
  hr = DirectX::CreateTexture( g_pd3dDevice, image.GetImages(), image.GetImageCount(), mdata, reinterpret_cast<ID3D11Resource **>(&g_pInputTexture) );
  assert( hr == S_OK );


  // concurrency::accelerator_viewを作成  実行するとリソースが解放されない何か残っている?
  concurrency::accelerator_view g_av = concurrency::direct3d::create_accelerator_view(reinterpret_cast<IUnknown *>(g_pd3dDevice));


  // 出力先の作成
  UINT img_width = mdata.width;
    UINT img_height = mdata.height;

    g_pAmpProcessedTexture = new Concurrency::graphics::texture<Concurrency::graphics::direct3d::unorm4, 2>(static_cast<int>(img_height), static_cast<int>(img_width), 8U, g_av);

  // writeonly_texture_viewに書き込む
  Concurrency::graphics::writeonly_texture_view<Concurrency::graphics::direct3d::unorm4, 2> output_tex_view(*g_pAmpProcessedTexture);

  // 入力データ
  // ID3D11Texture2D g_pInputTextureからConcurrency::graphics::textureを作成
  const Concurrency::graphics::texture<Concurrency::graphics::direct3d::unorm4, 2> input_tex = Concurrency::graphics::direct3d::make_texture<Concurrency::graphics::direct3d::unorm4, 2>(g_av, reinterpret_cast<IUnknown *>(g_pInputTexture));

  timer.Start();

  // 入出力データの用意ができたので、画像処理を行う
  RunImageProcessing(input_tex, output_tex_view);

  timer.Stop();

  std::wcout << "ElapsedTime: " << timer.ElapsedTime() << " (ms)" << std::endl;

  // 処理結果を取り出す

  // Concurrency::graphics::texture の g_pAmpProcessedTexture から ID3D11Texture2Dを取得
    ID3D11Texture2D* processedTexture = reinterpret_cast<ID3D11Texture2D *>(Concurrency::graphics::direct3d::get_texture<Concurrency::graphics::direct3d::unorm4, 2>(*g_pAmpProcessedTexture));

  // processedTextureをoutput_imageにキャプチャーする
  DirectX::ScratchImage output_image;

  hr = DirectX::CaptureTexture(g_pd3dDevice, g_pImmediateContext, reinterpret_cast<ID3D11Resource *>(processedTexture), output_image);
  assert( hr == S_OK );

  // キャプチャーした画像を保存する
  GUID containerFormat = GUID_ContainerFormatJpeg;  // Jpeg
  DWORD flags = 0;
  const DirectX::Image* pImage = output_image.GetImages();
  size_t numImage = output_image.GetImageCount();

  hr = DirectX::SaveToWICFile(pImage, numImage, flags, containerFormat, L"output.jpg");
  assert( hr == S_OK );

  // 解放
    processedTexture->Release();

  if (g_pInputTexture) g_pInputTexture->Release();
  if (g_pAmpProcessedTexture) delete g_pAmpProcessedTexture;
  
  if (g_pImmediateContext) g_pImmediateContext->Release();
  if (g_pd3dDevice) g_pd3dDevice->Release();
  CoUninitialize();
}

int _tmain(int argc, _TCHAR* argv[])
{
  if(argc > 1) {
    TestAMP(argv[1]);
  }
  return 0;
}

2012年12月16日日曜日

Windows 8にアップグレード & SSDに引っ越し

TEST用のWin7のPC、
マザボがGIGABYTEのH55M-D2H

ディスクドライブ
HDD 1TB (システム予約領域:100MB C:112GB E:416GB F:402GB)
SSD 240GB

ソフトの再インストールや設定がめんどくさい & 年末で時間がもったいないので、
Win8にアップグレード後、SSDに起動ドライブを引っ越した際の作業内容のメモ

「SSDって何?」から開始したはず

【手順】
■Win8にアップグレード
CCleanerでCドライブのごみ掃除 使用領域が60GB -> 40GBに減ったはず
アップグレードアシスタントで×印の付いたソフトをアンインストールした気がする
Windows 8のディスクをDVDドライブに入れてセットアップ
特に問題無かったはず(約1時間~2時間)

■SSDへの引っ越し
SSDを、なんとかして接続
MiniTool Partition Wizard Home Edition 7.6.1を実行
システム予約領域とCドライブをSSDにコピー後に、Applyボタンを押す
再起動後の、ブート中に HDD -> SSDにコピーされた
コピー中に経過時間の表示があった、

SSDにコピーされているのを確認したらシャットダウン
HDDのSATAの接続ケーブルを外しておく

MBRを作成
Win8をDVDからブートさせて、システムの修復を選択
コマンドプロンプトを起動させて、bootrecコマンドを使用
bootrec /fixmbr
bootrec /fixboot
bootrec /ScanOs スキャン結果が出たらアップグレードしたWindowsを選択
bootrec /RebuildBcd
exit 後 PCの電源OFF

電源ON -> SSDでブートできたらOK
電源OFF HDDのSATAケーブルを接続
電源ON BIOSでHDDのブート優先順位 SSDを上にする
"Windows の修復なんとか"が 英文から日本語に切り替わった ! ?
"修復 し よ う としています" の画面が5分くらい表示されてた

Windows 8が起動したら 窓+E でハードディスクをチェック
C, E, Fドライブが表示されて、HDDのシステム予約領域とCドライブは見えなくなっていた
SSDのシステム予約領域とCドライブを最適化しておく

以上で作業終了

一番疲れたのがSATAケーブルの抜き差し
グラボを外さないと 手が・・届かない・・ ラジオペンチで解決

EaseUS Todo Backup、EaseUS Partition Masterでコピーしても、うまくいかなかった?


SSD ガリガリ音が無いので静か、アプリの起動が早くなった気がする

2012年12月8日土曜日

Android Walkman NW-F805のテスト 1

本体の裏を見ると、下側の左上にDIGITAL MEDIA PLAYERと記載されているのが
「何コレ?」

電車内でポケットに入るサイズの端末(電話嫌いなので、携帯電話はない)で、
ソースコードを無料で見るために、1週間テストした感想ですが、

(a). 本体上部の左側にある電源ボタンが押しにくい
(b). タッチパネルの反応がおかしい 「押してないよ!」
(c). なんとなく持ちにくい 片手で操作できない
(d). iPod Touch 5thより表示面積が小さいのに重い
(e). Androidに無料で、普通に使えるテキストビューアが無い?
(f). iOSでもテキストビューア無い?

(e)が問題、文字化け、50KB程度のファイルで固まる、複数ファイルを開けない・・・
使えるアプリが無い・・・
920 Text Editor が使えそうなんだけど200KBのテキストを開くと重い
https://github.com/jecelyin/920-Text-Editor にソースがあり
落として、Eclipseでビルドして動作確認 SDKなどのUpdateがめんどくさい、
JecEditText::drawView() でテキストを描画しているみたい
jniでgrep, syntax highlight, Universal Character Set Detector C Library
うーん、どうしようかなー。

(f)もあれだ、林檎教にお布施をしないとアプリが開発できない そういえば脱獄があった
あっ、XcodeするのにMac OSがいる・・・

おっ、ダクソ2が出るーーーーー
センの古城~アノールロンド突破がおもしろかった、
360のアジア版を買って連日朝までだった気がする。

2012年12月2日日曜日

iPod touch 5thで動画再生のテスト

をしていたらフリーズしました。

■フリーズした場合 電源とホームボタンを同時に長押しすると再起動するはず

■PCに接続するとitunesが起動して何かするのをやめさる方法
編集/設定/デバイスから xxxのiPod touch を選択
「iPod、iPhone、およびiPadを自動的に同期しない」

それにしても薄い&軽い

2012年11月4日日曜日

PCL メッシュの再構築のテスト2

pcl::GreedyProjectionTriangulationのテスト

入力元の点群


フィルタリング結果


再構築結果

残念、欠けている部分がちらほらとある



pcl::GreedyProjectionTriangulationのテスト

#include <stdio.h>
#include <boost/thread/thread.hpp>
// pcl
#include <pcl/point_cloud.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/features/normal_3d.h>
#include <pcl/surface/gp3.h>


// PCLVisualizer のテスト
void TestCloudViewer003(const char* pFilePath)
{
  // テキストファイルから頂点を取得
  FILE* fp = fopen(pFilePath, "rt");
  
  int n;
  char buf[256];
  fscanf(fp, "%s %d", buf, &n);

  int num = n;

  // 点群の作成
  pcl::PointCloud::Ptr cloud( new pcl::PointCloud );

  cloud->width = num;
  cloud->height = 1;
  cloud->points.resize( cloud->width * cloud->height );

  int txtFmt = 1;
  float x, y, z;
  for(int i = 0; i < num; i++)
  {
    switch(txtFmt) {
    case 0:
      fscanf(fp, "%f %f %f", &x, &y, &z);
      break;
    case 1:
      fscanf(fp, "%f, %f, %f", &x, &y, &z);
      break;
    }
    cloud->points[i] = pcl::PointXYZ(x, y, z);
  }
  fclose(fp);

  // 点群の削減

  // フィルタリング結果の格納用
  pcl::PointCloud::Ptr filtered_cloud( new pcl::PointCloud );

  // ボクセルグリッドで点群のフィルタリングを行う
  pcl::VoxelGrid sor;
  sor.setInputCloud (cloud);
  sor.setLeafSize(1.0f, 1.0f, 1.0f);
  sor.filter(*filtered_cloud);

  // 点群の数を出力
  printf("source cloud size = %d\n", cloud->size());
  printf("filtered cloud size = %d\n", filtered_cloud->size());

  // 元データ
  pcl::PointCloud::Ptr src_cloud = filtered_cloud;

  pcl::PolygonMesh polyMesh;

  // KdTreeを作成
  pcl::search::KdTree::Ptr tree(new pcl::search::KdTree);
  float epsilon = tree->getEpsilon();
  tree->setEpsilon(0.01f);
    tree->setInputCloud(src_cloud); 

  // 法線ベクトルの推定
  pcl::NormalEstimation ne; 
    ne.setInputCloud(src_cloud); 
    ne.setSearchMethod(tree); 
    ne.setKSearch(8);

  // 法線ベクトル格納用
  pcl::PointCloud::Ptr norm(new pcl::PointCloud); 
    ne.compute(*norm);

  // 座標と法線ベクトルの点群
  pcl::PointCloud::Ptr clPosNormal(new pcl::PointCloud);
    pcl::concatenateFields(*src_cloud, *norm, *clPosNormal); 

  // ↓今回のテスト対象
  pcl::GreedyProjectionTriangulation gpt;

  pcl::search::KdTree::Ptr tree2 (new pcl::search::KdTree);
    tree2->setInputCloud(clPosNormal); 

  // パラメータをいろいろ設定
  gpt.setSearchRadius(20.0);
  gpt.setMu(2.5);
  gpt.setMaximumNearestNeighbors (150);
//  gpt.setMaximumSurfaceAngle(M_PI/4);
//  gpt.setMinimumAngle(M_PI/18);
//  gpt.setMaximumAngle(2*M_PI/3);
//  gpt.setNormalConsistency(false);

  // 入力データ等をセット
  gpt.setInputCloud (clPosNormal);
  gpt.setSearchMethod (tree2);

  // 再構築
  gpt.reconstruct (polyMesh);

  // 点群のビューア
  pcl::visualization::PCLVisualizer viewer("Cloud Viewer");
  
  viewer.setBackgroundColor (0.0, 0.2, 0.6);

  // 原点に座標軸を追加
  viewer.addCoordinateSystem(100.0, 0.0, 0.0, 0.0);

  // カメラ座標のセット
  double camPos[] = { 0.0, 60.0, 350.0 };
  double camLookAt[] = { 0.0, 60.0, 0.0 };
  double camUp[] = { 0.0, 1.0, 0.0 };
  viewer.setCameraPose(camPos[0], camPos[1], camPos[2], 
    camLookAt[0], camLookAt[1], camLookAt[2], camUp[0], camUp[1], camUp[2]);

  // ビューアに点群を追加
//  viewer.addPointCloud(filtered_cloud);
  viewer.addPointCloud(cloud);

  // ビューアにポリゴンメッシュを追加
//  viewer.addPolygonMesh(polyMesh);

    while (!viewer.wasStopped ())
    {
    viewer.spinOnce(10);

    boost::this_thread::sleep (boost::posix_time::microseconds (100000));
    }
}

int main(int argc, char** argv)
{
  TestCloudViewer003(argv[1]);

  return 0;
}

2012年10月28日日曜日

PCL メッシュの再構築のテスト1

input cloud からポリメッシュを作成するテスト (失敗例)

入力した点群↓





実行結果が↓の画像


テスト結果 何かが変? 何だチミは?


Point Cloud Library(v1.6.0)のテスト

#include <stdio.h>
#include <boost/thread/thread.hpp>

#include <pcl/point_cloud.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/features/normal_3d.h>
#include <pcl/surface/marching_cubes_hoppe.h>

// PCLVisualizer のテスト
void TestCloudViewer003(const char* pFilePath)
{
 // テキストファイルから頂点を取得
 FILE* fp = fopen(pFilePath, "rt");
 
 int n;
 char buf[256];
 fscanf(fp, "%s %d", buf, &n);

 int num = n;

 // 点群の作成
 pcl::PointCloud::Ptr cloud( new pcl::PointCloud );

 cloud->width = num;
 cloud->height = 1;
 cloud->points.resize( cloud->width * cloud->height );

 int txtFmt = 1;
 float x, y, z;
 for(int i = 0; i < num; i++)
 {
  switch(txtFmt) {
  case 0:
   fscanf(fp, "%f %f %f", &x, &y, &z);
   break;
  case 1:
   fscanf(fp, "%f, %f, %f", &x, &y, &z);
   break;
  }
  cloud->points[i] = pcl::PointXYZ(x, y, z);
 }
 fclose(fp);

 // 点群の削減

 // フィルタリング結果の格納用
 pcl::PointCloud::Ptr filtered_cloud( new pcl::PointCloud );

 // ボクセルグリッドで点群のフィルタリングを行う
 pcl::VoxelGrid sor;
 sor.setInputCloud (cloud);
 sor.setLeafSize(1.0f, 1.0f, 1.0f);
 sor.filter(*filtered_cloud);

 // 点群の数を出力
 printf("source cloud size = %d\n", cloud->size());
 printf("filtered cloud size = %d\n", filtered_cloud->size());

 // 元データ
 pcl::PointCloud::Ptr src_cloud = filtered_cloud;

 pcl::PolygonMesh polyMesh;

 // KdTreeを作成
 pcl::search::KdTree::Ptr tree(new pcl::search::KdTree);
 float epsilon = tree->getEpsilon();
 tree->setEpsilon(0.01f);
    tree->setInputCloud(src_cloud); 

 // 法線ベクトルの推定
 pcl::NormalEstimation ne; 
    ne.setInputCloud(src_cloud); 
    ne.setSearchMethod(tree); 
    ne.setKSearch(8);

 // 法線ベクトル格納用
 pcl::PointCloud::Ptr norm(new pcl::PointCloud); 
    ne.compute(*norm);

 // 座標と法線ベクトルの点群
 pcl::PointCloud::Ptr clPosNormal(new pcl::PointCloud);
    pcl::concatenateFields(*src_cloud, *norm, *clPosNormal); 


 // ↓今回のテスト対象
 pcl::MarchingCubesHoppe mc;  

 pcl::search::KdTree::Ptr tree2 (new pcl::search::KdTree);
    tree2->setInputCloud(clPosNormal); 

 mc.setSearchMethod(tree2); 
 mc.setInputCloud(clPosNormal); 
 mc.setIsoLevel(0.0015); // 0.0 ~ 1.0
 mc.setGridResolution(50, 50, 50); 

 // 再構築
 mc.reconstruct(polyMesh); 


 // 点群のビューア
 pcl::visualization::PCLVisualizer viewer("Cloud Viewer");
 
 viewer.setBackgroundColor (0.0, 0.2, 0.6);

 // 原点に座標軸を追加
 viewer.addCoordinateSystem(100.0, 0.0, 0.0, 0.0);

 // カメラ座標のセット
 double camPos[] = { 0.0, 60.0, 350.0 };
 double camLookAt[] = { 0.0, 60.0, 0.0 };
 double camUp[] = { 0.0, 1.0, 0.0 };
 viewer.setCameraPose(camPos[0], camPos[1], camPos[2], 
  camLookAt[0], camLookAt[1], camLookAt[2], camUp[0], camUp[1], camUp[2]);

 // ビューアに点群を追加
 viewer.addPointCloud(filtered_cloud);
// viewer.addPointCloud(cloud);

 // ビューアにポリゴンメッシュを追加
 viewer.addPolygonMesh(polyMesh);

    while (!viewer.wasStopped ())
    {
  viewer.spinOnce(10);

  boost::this_thread::sleep (boost::posix_time::microseconds (100000));
    }
}

int main(int argc, char** argv)
{
    TestCloudViewer003(argv[1]);

    return 0;
}