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;
}
|
0 件のコメント:
新しいコメントは書き込めません。