2014-06-24

OpenCLでlanczos3を使った画像の拡大処理(4)

呼出側を書いておく。
実行する場合は、カレントディレクトリに前回の lanczos3.cl を置いておく。
カーネルの文字コードには注意した方が良いかもしれない。

//////// begin: main.cpp
#include <Windows.h>
#include <comdef.h>
#include <wincodec.h>
#include <Shlwapi.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <CL/cl.hpp>

#pragma comment(lib, "Windowscodecs")
#pragma comment(lib, "Shlwapi")
#pragma comment(lib, "OpenCL")

using namespace std;
using namespace cl;

HRESULT read(void **ppData, UINT *pWidth, UINT *pHeight, LPCWSTR pName);
HRESULT writeBmp(LPCWSTR pName, void *pData, UINT width, UINT height);


int main()
{
    CoInitializeEx(NULL, COINIT_MULTITHREADED| COINIT_DISABLE_OLE1DDE);

    vector<Platform> platforms;
    Platform::get(&platforms);
    cl_context_properties cps[3] = {CL_CONTEXT_PLATFORM, (cl_context_properties)(platforms[0])(), 0};
    Context context(CL_DEVICE_TYPE_ALL, cps);
    vector<Device> devices = context.getInfo<CL_CONTEXT_DEVICES>();
    CommandQueue queue = CommandQueue(context, devices[0], 0);
   
    cout << platforms.size() << " platforms" << endl;
    cout << devices.size() << " devices" << endl;
   
    ifstream sourceFileName("lanczos3.cl", ios::in);
    string sourceFile(istreambuf_iterator<char>(sourceFileName), (istreambuf_iterator<char>()));
    Program::Sources source(1, make_pair(sourceFile.c_str(), sourceFile.length()+1));
    Program program(context, source);
    program.build(devices);

    cl::Kernel kernel_setupTable(program, "lanczos3_setupTable");
    cl::Kernel kernel_passFirst(program, "lanczos3_passFirst");
    cl::Kernel kernel_passSecond(program, "lanczos3_passSecond");


    const cl_int widthDst = 1920;
    const cl_int heightDst = 1080;
    cl_int elementsHor;
    cl_int elementsVert;
    void *pData;
    UINT width, height;

   
    read(&pData, &width, &height, L"src.bmp");

    if (widthDst < width)
        elementsHor = 6 * width / widthDst;
    else
        elementsHor = 6;

    if (heightDst < height)
        elementsVert = 6 * height / heightDst;
    else
        elementsVert = 6;

    Buffer *pBufferTable = new Buffer(context, CL_MEM_READ_WRITE, (sizeof (float))*((elementsHor*widthDst)+(elementsVert*heightDst)));
    ImageFormat format(CL_BGRA, CL_UNORM_INT8);
    Image2D *pImgSrc = new Image2D(context, CL_MEM_READ_ONLY, format, width, height);
    Image2D *pImgDst = new Image2D(context, CL_MEM_WRITE_ONLY, format, widthDst, heightDst);
    Image2D *pImgTmp = new Image2D(context, CL_MEM_READ_WRITE, format, widthDst, height);

    //src
    cl::size_t<3> origin, region;
    region[0] = width;
    region[1] = height;
    region[2] = 1;
    queue.enqueueWriteImage(*pImgSrc, CL_TRUE, origin, region, 0, 0, pData);
   
    //table
    kernel_setupTable.setArg(0, *pBufferTable);
    kernel_setupTable.setArg(1, cl_int(width));
    kernel_setupTable.setArg(2, cl_int(height));
    kernel_setupTable.setArg(3, cl_int(widthDst));
    kernel_setupTable.setArg(4, cl_int(heightDst));

    NDRange wsGlobalTable(widthDst+heightDst);
    queue.enqueueNDRangeKernel(kernel_setupTable, NullRange, wsGlobalTable);
    queue.finish();


    //pass 1
    kernel_passFirst.setArg(0, *pImgTmp);
    kernel_passFirst.setArg(1, *pImgSrc);
    kernel_passFirst.setArg(2, *pBufferTable);
    NDRange wsGlobal(widthDst, height);
    queue.enqueueNDRangeKernel(kernel_passFirst, NullRange, wsGlobal);
    queue.finish();

    //pass 2
    kernel_passSecond.setArg(0, *pImgDst);
    kernel_passSecond.setArg(1, *pImgTmp);
    kernel_passSecond.setArg(2, *pBufferTable);
    kernel_passSecond.setArg(3, width);
    NDRange wsGlobal2(widthDst, heightDst);
    queue.enqueueNDRangeKernel(kernel_passSecond, NullRange, wsGlobal2);
    queue.finish();
   
    BYTE *pData2 = new BYTE[4*widthDst*heightDst];
    region[0] = widthDst;
    region[1] = heightDst;
    queue.enqueueReadImage(*pImgDst, CL_TRUE, origin, region, 0, 0, pData2);
    writeBmp(L"dst.bmp", pData2, widthDst, heightDst);

    CoUninitialize();

    return 0;
}


_COM_SMARTPTR_TYPEDEF(IWICImagingFactory, __uuidof(IWICImagingFactory));
_COM_SMARTPTR_TYPEDEF(IWICBitmapDecoder, __uuidof(IWICBitmapDecoder));
_COM_SMARTPTR_TYPEDEF(IWICBitmapFrameDecode, __uuidof(IWICBitmapFrameDecode));
_COM_SMARTPTR_TYPEDEF(IWICBitmapSource, __uuidof(IWICBitmapSource));
_COM_SMARTPTR_TYPEDEF(IStream, __uuidof(IStream));
_COM_SMARTPTR_TYPEDEF(IWICBitmapEncoder, __uuidof(IWICBitmapEncoder));
_COM_SMARTPTR_TYPEDEF(IWICBitmapFrameEncode, __uuidof(IWICBitmapFrameEncode));

HRESULT read(void **ppData, UINT *pWidth, UINT *pHeight, LPCWSTR pName)
{
    IWICImagingFactoryPtr pFactory;
    IWICBitmapDecoderPtr pDecoder;
    IWICBitmapFrameDecodePtr pFrame;
    IWICBitmapSourcePtr pBitmap;
    UINT stride;
    UINT size;


    pFactory.CreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER);
    pFactory->CreateDecoderFromFilename(pName, NULL, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &pDecoder);
    pDecoder->GetFrame(0, &pFrame);
    WICConvertBitmapSource(GUID_WICPixelFormat32bppBGR, pFrame, &pBitmap); //DIB section compatible
    pBitmap->GetSize(pWidth, pHeight);
    stride = 4 * *pWidth;
    size = stride * *pHeight;
    *ppData = new BYTE[size];
    pBitmap->CopyPixels(NULL, stride, size, (BYTE *)*ppData);

    return S_OK;
}

HRESULT writeBmp(LPCWSTR pName, void *pData, UINT width, UINT height)
{
    IWICImagingFactoryPtr pFactory;
    IWICBitmapEncoderPtr pEncoder;
    IStreamPtr pStream;
    IWICBitmapFrameEncodePtr pFrame;
    WICPixelFormatGUID guidFormat;


    pFactory.CreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER);
    pFactory->CreateEncoder(GUID_ContainerFormatBmp, NULL, &pEncoder);
    SHCreateStreamOnFileEx(pName, STGM_READWRITE| STGM_CREATE, FILE_ATTRIBUTE_NORMAL, TRUE, NULL, &pStream);
    pEncoder->Initialize(pStream, WICBitmapEncoderNoCache);
    pEncoder->CreateNewFrame(&pFrame, NULL);
    pFrame->Initialize(NULL);
    guidFormat = GUID_WICPixelFormat32bppBGR;
    pFrame->SetPixelFormat(&guidFormat);
    pFrame->SetSize(width, height);
    pFrame->WritePixels(height, 4*width, 4*width*height, (BYTE *)pData);
    pFrame->Commit();
    pEncoder->Commit();

    return S_OK;
}
//////// end: main.cpp

0 件のコメント:

コメントを投稿