2014-06-19

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

重みのテーブルを作成する。
構造は、
float [dstの幅][水平方向タップ数]
float [dstの高さ][垂直方向タップ数]
を隙間なく詰めた感じだ。

//////// begin: lanczos3.cl
float lanczos3(float distance)
{
    float weight;


    if (FLT_EPSILON > fabs(distance))
        weight = 1.0f;
    else if (3.0f > fabs(distance))
        weight = 3.0f * sin(M_PI_F*distance) * sin(M_PI_F*distance/3.0f) / (M_PI_F*M_PI_F*distance*distance);
    else
        weight = 0.0f;

    return weight;
}

void setupTablePartial(__global float *pWeight, int index, int lengthSrc, int lengthDst, int elements)
{
    float center = (index+0.5f) * lengthSrc / lengthDst;
    float beginSrc = trunc(center-elements/2);
    float distance;
    float sumWeight = 0.0f;


    //拡大もしくは等倍の場合
    if (lengthDst >= lengthSrc)
    {
        distance = (beginSrc+0.5f)-center;

        for (int i=0; i<elements; i++)
        {
            sumWeight += pWeight[i] = lanczos3(distance);
            distance += 1.0f;
        }
    }
    //縮小の場合
    else
    {
        float positionSrc = beginSrc + 0.5f;

        for (int i=0; i<elements; i++)
        {
            distance = (index+0.5f) - (positionSrc * lengthDst / lengthSrc);
            sumWeight += pWeight[i] = lanczos3(distance);
            positionSrc += 1.0f;
        }
    }

    //ここで割っておくことで、各ドットの計算時に割る手間をなくす
    for (int i=0; i<elements; i++)
        pWeight[i] /= sumWeight;
}


//テーブルの要素数: elementsHor*widthDst + elementsVert*heightDst;
//elementsHor: 拡大もしくは等倍の場合 6, 縮小の場合 6 * widthSrc / widthDst;
//elementsVert: 拡大もしくは等倍の場合 6, 縮小の場合 6 * heightSrc / heightDst;
__kernel void lanczos3_setupTable(__global float *pTable, int widthSrc, int heightSrc, int widthDst, int heightDst)
{
    int index = get_global_id(0);
    int elementsHor;
    int elementsVert;


    if (widthDst+heightDst <= index)
        return;

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

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

    //水平方向の場合
    if (widthDst > index)
        setupTablePartial(pTable+(elementsHor*index), index, widthSrc, widthDst, elementsHor);
    //垂直方向の場合
    else
        setupTablePartial(pTable+(elementsHor*widthDst)+(elementsVert*(index-widthDst)), index-widthDst, heightSrc, heightDst, elementsVert);
}
//////// end: lanczos3.cl
手元の環境では丸めモードがOpenCL(GPU)とC++(CPU)で異なり、OpenCL(GPU)では0方向への丸めで、C++(CPU)では直近値への丸め(同距離なら偶数寄り)だった。
他にもいくつかの相違があり同一の計算結果を得るのは難しいため、テーブルをCPUで作るのは好ましくない。

0 件のコメント:

コメントを投稿