#include <wincodec.h>
#include <iostream>
#include <tchar.h>
#include <assert.h>
#include <d3d11.h>
#include <DirectXTex.h>
#include <amp.h>
#include <amp_graphics.h>
#include <amp_math.h>
#pragma comment(lib, "d3d11.lib")
using namespace concurrency;
using namespace concurrency::graphics;
using namespace concurrency::graphics::direct3d;
ID3D11Device* g_pd3dDevice = nullptr;
ID3D11DeviceContext* g_pImmediateContext = nullptr ;
ID3D11Texture2D* g_pInputTexture = nullptr;
texture<unorm4, 2>* g_pAmpProcessedTexture = nullptr;
// ヒストグラムのサイズ (ビン数)
#define HIST_SIZE 256
void HistKernel(index<2> idx, array_view<int, 1> av, const texture<unorm_4, 2>& input_tex, graphics::writeonly_texture_view<unorm_4, 2> output_tex_view) restrict(amp)
{
// 入力画像のピクセル値を取得
float_4 pixel = static_cast<float_4>(input_tex[idx].rgba);
// RGB値をグレースケールに変更 (0.0 ~ 1.0)
float Y = pixel.r * 0.2126f + pixel.r * 0.7152f + pixel.b * 0.0722f;
// 配列のインデックスの算出
int index = static_cast<int>(Y * (HIST_SIZE - 1));
// int index = 8;
// アトミックに1加算
atomic_fetch_add( &av[index], 1 ); // av[index] += 1;
output_tex_view.set(idx, unorm_4(Y, Y, Y, pixel.a));
}
void RunImageProcessing(const texture<unorm_4, 2>& input_tex, graphics::writeonly_texture_view<unorm_4, 2> output_tex_view, std::vector<int> vHist, graphics::writeonly_texture_view<unorm_4, 2> hist_tex_view)
{
array_view<int, 1> av(HIST_SIZE, vHist);
// array_view<int, 1> av(HIST_SIZE); // ERROR
av.discard_data();
parallel_for_each(input_tex.accelerator_view, output_tex_view.extent, [=, &input_tex] (index<2> idx) restrict(amp) {
HistKernel(idx, av, input_tex, output_tex_view);
});
av.synchronize();
// ヒストグラムの最大値とインデックス
int maxValue = 0;
int maxIndex = 0;
int totalPixel = 0;
parallel_for(0, HIST_SIZE, [&maxValue, &maxIndex, &vHist, &av, &totalPixel](int i) {
vHist[i] = av[i];
totalPixel += av[i];
if(maxValue < av[i]) {
maxValue = av[i];
maxIndex = i;
}
});
std::wcout << "input texture width: " << input_tex.extent[1] << std::endl;
std::wcout << "input texture height: " << input_tex.extent[0] << std::endl;
std::wcout << "input texture pixel num: " << input_tex.extent[0] * input_tex.extent[1] << std::endl;
std::wcout << "histogram maxValue: " << maxValue << std::endl;
std::wcout << "histogram maxIndex: " << maxIndex << std::endl;
std::wcout << "totalPixel: " << totalPixel << std::endl;
// ヒストグラムのグラフ描画用
parallel_for_each(hist_tex_view.extent, [=] (index<2> idx) restrict(amp) {
const UINT x = idx[1];
const UINT y = idx[0];
// 背景色
float c = 1.0f;
// ヒストグラム値を 0.0 ~ 1.0 に変換
float v = av[x] / float(maxValue);
// Y座標の値を 0.0 ~ 1.0 に変換
float fy = 1.0f - (y / float(HIST_SIZE - 1));
// グラフを書く
if( v > 0 ) {
if(v >= fy) {
c = 0.0f;
}
}
hist_tex_view.set(idx, unorm_4(c, c, c, 1.0));
});
}
// textureをjpeg形式で保存
void SaveImage(LPCWSTR fileName, texture<unorm4, 2>* pTex)
{
HRESULT hr;
ID3D11Texture2D* processedTexture = reinterpret_cast<ID3D11Texture2D*>(get_texture<unorm4, 2>(*pTex));
// 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;
DWORD flags = 0;
const DirectX::Image* pImage = output_image.GetImages();
size_t numImage = output_image.GetImageCount();
hr = DirectX::SaveToWICFile(pImage, numImage, flags, containerFormat, fileName);
assert( hr == S_OK );
processedTexture->Release();
}
void TestAMP(_TCHAR* imgFilePath)
{
HRESULT hr;
// LoadFromWICFile 用にCOMを初期化
hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
// DirectX11の初期化
unsigned int createDeviceFlags = 0;
#ifdef _DEBUG
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
// createDeviceFlags |= D3D11_CREATE_DEVICE_SWITCH_TO_REF;
#endif
D3D_DRIVER_TYPE driverType = D3D_DRIVER_TYPE_HARDWARE;
// D3D_DRIVER_TYPE driverType = D3D_DRIVER_TYPE_REFERENCE;
// D3D_DRIVER_TYPE driverType = D3D_DRIVER_TYPE_SOFTWARE;
D3D_FEATURE_LEVEL FeatureLevel = D3D_FEATURE_LEVEL_11_0;
hr = D3D11CreateDevice( nullptr, driverType, 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を作成 実行するとリソースが解放されない何か残っている?
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 texture<unorm4, 2>(static_cast<int>(img_height), static_cast<int>(img_width), 8U, g_av);
// writeonly_texture_viewに書き込む
writeonly_texture_view<unorm4, 2> output_tex_view(*g_pAmpProcessedTexture);
// ヒストグラム用のテクスチャ
texture<unorm4, 2>* pAmpHistTexture = new texture<unorm4, 2>(HIST_SIZE, HIST_SIZE, 8U, g_av);
writeonly_texture_view<unorm4, 2> hist_tex_view(*pAmpHistTexture);
// 入力データ
// ID3D11Texture2D g_pInputTextureからConcurrency::graphics::textureを作成
const texture<unorm4, 2> input_tex = make_texture<unorm4, 2>(g_av, reinterpret_cast<IUnknown*>(g_pInputTexture));
std::vector<int> vHist_grayscale( HIST_SIZE );
// 入出力データの用意ができたので、画像処理を行う
RunImageProcessing(input_tex, output_tex_view, vHist_grayscale, hist_tex_view);
// 処理結果を保存
SaveImage(L"output.jpg", g_pAmpProcessedTexture);
// ヒストグラムのtextureを保存
SaveImage(L"histogram.jpg", pAmpHistTexture);
// 解放
if (g_pInputTexture) g_pInputTexture->Release();
if (g_pAmpProcessedTexture) delete g_pAmpProcessedTexture;
delete pAmpHistTexture;
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;
}
|