チュートリアル: インテル® IPP 9.0 による画像の回転とブラー

画像を回転してブラーするアプリケーションの作成

BMP ファイルから画像をロードし、ユーザーが左/右または上/下矢印キーを押した後に画像を回転してブラーする単純なアプリケーションのサンプルコードを以下に示します。

このアプリケーションの C ソースコードは <install-dir>\samples_2016\ja\ipp\ipp_blur_rotate_sample.zip (Windows*) または <install-dir>/samples_2016/ja/ipp/ipp_blur_rotate_sample.tar.gz (Linux*) にあります。

ipp_blur_rotate.cpp は、インテル® Parallel Studio XE 内にインストールされるインテル® IPP 用に作成されたサンプルコードです。このサンプルコードは、インテル® System Studio やインテル® Integrated Developer Experience (インテル® INDE) のようなほかの製品スイート内でも利用できます (グラフィカル・レンダリング部分を除く)。
/* C++ ソースコードは ipp_blur_rotate.cpp を参照 */

/* sqrt 用 */
#include "math.h"

/* インフラストラクチャー・コード */
#include "base.inc"

/* IPP ヘッダー */
#include "ippcore.h"
#include "ipps.h"
#include "ippi.h"

#include <iostream>

IppStatus warpAffine(Ipp8u* pSrc, IppiSize srcSize, int srcStep, Ipp8u* pDst, IppiSize dstSize, int dstStep, const double coeffs[2][3])
{
    /* IPP 関数のステータス */
    IppStatus status = ippStsNoErr;

    /* 画像チャネルの数 */
    const Ipp32u numChannels = 3;

    /* ソース画像を拡張する境界値 */
    Ipp64f pBorderValue[numChannels];

    /* WarpAffine データ構造、初期化バッファー、ワークバッファーのサイズ */
    int specSize = 0, initSize = 0, bufSize = 0;

    /* ワークバッファーのポインター */
    Ipp8u* pBuffer  = NULL;

    /* WarpAffine データ構造のポインター */
    IppiWarpSpec* pSpec = NULL;

    /* 処理するデスティネーション ROI のオフセットを設定 */
    IppiPoint dstOffset = {0, 0};

    /* アフィン変換の境界タイプ */
    IppiBorderType borderType = ippBorderConst;

    /* ワープアフィン変換の方向 */
    IppiWarpDirection direction = ippWarpForward;

    /* ソース画像を拡張する境界値を設定 */
    for (int i = 0; i < numChannels; ++i) pBorderValue[i] = 255.0;

    /* WarpAffine データ構造と初期化バッファーのバッファーサイズを計算 */
    status = ippiWarpAffineGetSize(srcSize, dstSize, ipp8u, coeffs, ippLinear, direction, borderType,
        &specSize, &initSize);

    /* メモリーを割り当て */
    pSpec = (IppiWarpSpec*)ippsMalloc_8u(specSize);

    /* アフィン変換のデータを初期化 */
    if (status >= ippStsNoErr) status = ippiWarpAffineLinearInit(srcSize, dstSize, ipp8u, coeffs, direction, numChannels, borderType, pBorderValue, 0, pSpec);

    /* ワークバッファーのサイズを取得 */
    if (status >= ippStsNoErr) status = ippiWarpGetBufferSize(pSpec, dstSize, &bufSize);

    /* ワークバッファーのメモリーを割り当て */
    pBuffer = ippsMalloc_8u(bufSize);

    /* アフィン変換処理 */
    if (status >= ippStsNoErr) status = ippiWarpAffineLinear_8u_C3R(pSrc, srcStep, pDst, dstStep, dstOffset, dstSize, pSpec, pBuffer);

    /* 割り当てたメモリーを解放 */
    ippsFree(pSpec);
    ippsFree(pBuffer);

    return status;
}


IppStatus shrink(Ipp8u* pSrc, IppiSize srcSize, int srcStep, Ipp8u* pDst, IppiSize dstSize, int dstStep)
{
    /* IPP 関数のステータス */
    IppStatus status = ippStsNoErr;

    /* 画像チャネルの数 */
    const Ipp32u numChannels = 3;

    /* WarpAffine データ構造、初期化バッファー、ワークバッファーのサイズ */
    int specSize = 0, initSize = 0, bufSize = 0;

    /* 初期化一時バッファーのポインター */
    Ipp8u* pInit    = NULL;

    /* ワークバッファーのポインター */
    Ipp8u* pBuffer  = NULL;

    /* WarpAffine データ構造のポインター */
    IppiResizeSpec_32f* pSpec = NULL;

    /* 処理するデスティネーション ROI のオフセットを設定 */
    IppiPoint dstOffset = {0, 0};

    /* アフィン変換の境界タイプ */
    IppiBorderType borderType = ippBorderRepl;

    /* WarpAffine データ構造と初期化バッファーのバッファーサイズを計算 */
    status = ippiResizeGetSize_8u(srcSize, dstSize, ippLinear, 1, &specSize, &initSize);

    /* メモリーを割り当て */
    pSpec = (IppiResizeSpec_32f*)ippsMalloc_8u(specSize);
    pInit = (Ipp8u*)ippsMalloc_8u(initSize);

    /* アフィン変換のデータを初期化 */
    if (status >= ippStsNoErr) status = ippiResizeAntialiasingLinearInit(srcSize, dstSize, pSpec, pInit);

    /* ワークバッファーのサイズを取得 */
    if (status >= ippStsNoErr) status = ippiResizeGetBufferSize_8u(pSpec, dstSize, numChannels, &bufSize);

    /* ワークバッファーのメモリーを割り当て */
    pBuffer = ippsMalloc_8u(bufSize);

    /* アフィン変換処理 */
    if (status >= ippStsNoErr) status = ippiResizeAntialiasing_8u_C3R(pSrc, srcStep, pDst, dstStep, dstOffset, dstSize, ippBorderRepl, 0, pSpec, pBuffer);

    /* 割り当てたメモリーを解放 */
    ippsFree(pInit);
    ippsFree(pSpec);
    ippsFree(pBuffer);

    return status;
}

int main(int argc, char *argv[])
{
    /* IPP 関数のステータス */
    IppStatus status = ippStsNoErr;

    /* 画像チャネルの数 */
    const Ipp32u numChannels = 3;

    /* ワークバッファーのサイズ */
    int bufSize = 0;

    /* ウィンドウを再描画 */
    bool bRedraw = false;

    /* 回転角度 */
    double angle = 0.0;

    /* 回転変換後の画像のシフト */
    double xShift = 0, yShift = 0;

    /* アフィン変換の係数 */
    double coeffs[2][3]  = {0};

    /* アフィン変換の境界 */
    double bound[2][2]   = {0};

    /* 画像ブラーのマスクサイズ */
    IppiSize maskSize    = {3,3};
    /* 画像ブラーの最大マスクサイズ */
    IppiSize maxMaskSize = {31,31};

    /* ワークバッファー */
    Ipp8u* pBuffer  = NULL;

    /* ワープアフィン変換の方向 */
    IppiWarpDirection direction = ippWarpForward;

    /* 更新したフィルターマスクを適用 */
    bool bFilterUpdate = true;

    /* 更新した回転係数 (角度とシフト) を適用 */
    bool bRotateUpdate = true;

    /* ソース画像のサイズ */
    IppiSize srcSize = {0};

    /* デスティネーション画像のサイズ (回転した画像全体を含む) */
    IppiSize dstSize = {0};

    /* 処理したソース画像の ROI を設定 */
    IppiRect srcRoi  = {0};

    /* レンダリング画像のサイズ */
    IppiSize renderSize = {0};

    /* ウィンドウ・ディスクリプター・オブジェクト (インフラストラクチャー) */
    WndDesc *pDesc = NULL;

    /* ソース画像データのポインター */
    Ipp8u *pSrc = NULL;
    /* ブラーした画像データのサイズ */
    Ipp8u *pBlur = NULL;
    /* ブラー/回転した画像データのポインター */
    Ipp8u *pBlurRot = NULL;

    /* 画像のステップ */
    int srcStep = 0, blurStep = 0, blurRotStep = 0;

    /* ソース画像オブジェクト (インフラストラクチャー) */
    Image srcData;

    /* レンダリング画像オブジェクト (インフラストラクチャー) */
    Image renderData;

    /* ファイルからデータを読み取り (bmp 形式のみサポート) */
    srcData.Read("./data/Image.bmp");

    /* 画像ファイルを開けない/読み取れない */
    if (srcData.m_pPointer == 0)
    {
        std::cout << "The file is not open or the file format is unsupported\n";
        return 0;
    }

    if (srcData.m_color != IC_BGR)
    {
        std::cout << "The file format is unsupported\n";
        return 0;
    }

    /* ソース画像のサイズを設定 */
    srcSize.width  = static_cast<int>(srcData.m_iWidth);
    srcSize.height = static_cast<int>(srcData.m_iHeight);

    /* ソース画像のステップとブラーした画像のステップを設定 */
    srcStep = blurStep = srcData.m_iStep;

    /* ソース画像の ROI を設定 */
    srcRoi.width   = srcSize.width;
    srcRoi.height  = srcSize.height;

    /* 回転した画像全体を保持するように回転した画像のサイズを設定 */
    dstSize.width  = static_cast<int>(sqrt((float)srcSize.width  * srcSize.width + srcSize.height  * srcSize.height) + 0.5f) * 2;
    dstSize.height = static_cast<int>(sqrt((float)srcSize.width  * srcSize.width + srcSize.height  * srcSize.height) + 0.5f);

    /* 出力画像のサイズを設定 (インフラストラクチャーの制限) */
    renderSize = dstSize;
    if (renderSize.width > 1024 || renderSize.height > 1024)
    {
        if (renderSize.width > 1024)
        {
            renderSize.height =  static_cast<int>(renderSize.height * (1024.0 / renderSize.width));
            renderSize.width  = 1024;
        }

        if (renderSize.height > 1024)
        {
            renderSize.width  =  static_cast<int>(renderSize.width * (1024.0 / renderSize.height));
            renderSize.height = 1024;
        }
    }
    renderData = srcData;
    renderData.m_iWidth  = renderSize.width;
    renderData.m_iHeight = renderSize.height;
    renderData.Alloc();

    /* ウィンドウを作成 (インフラストラクチャー) */
    pDesc = WindowNew("Intel® IPP - blur + rotate", WF_FIT_TO_IMAGE);

    /* 中間画像のメモリー割り当て */
    pBlur = ippsMalloc_8u(srcStep * srcSize.height);

    /* 中間画像のメモリー割り当て */
    pBlurRot = ippsMalloc_8u(dstSize.width * numChannels * dstSize.height);

    /* ブラー/回転した画像の画像ステップを設定 */
    blurRotStep = dstSize.width * numChannels;

    if(pDesc) /* ウィンドウを作成した場合 */
    {
        /* ウィンドウが開いていて (インフラストラクチャー) IPP 関数のステータスがエラーでない場合 */
        while(!WindowIsClosed(pDesc) && (status >= ippStsNoErr))
        {
            /* スリープのタイムアウト */
            vm_time_sleep(10);

            /* ウィンドウのキー押下メッセージを確認 */
            int key = WindowCheckKey(pDesc);

            /* 上または下矢印キーが押された */
            if (key == KK_UP || key == KK_DOWN)
            {
                /* キーに応じてマスクサイズを 2 増加または減少 */
                maskSize.width  = (key == KK_DOWN) ? maskSize.width  - 2 : maskSize.width  + 2;
                maskSize.height = (key == KK_DOWN) ? maskSize.height - 2 : maskSize.height + 2;

                /* マスクの幅と高さの両方が正か確認 */
                if (maskSize.width  < 1) maskSize.width  = 1;
                if (maskSize.height < 1) maskSize.height = 1;

                /* マスクの幅と高さの両方が最大マスクサイズを超えていないか確認 */
                if (maskSize.width  > maxMaskSize.width)  maskSize.width  = maxMaskSize.width;
                if (maskSize.height > maxMaskSize.height) maskSize.height = maxMaskSize.height;

                /* フィルター操作を適用 */
                bFilterUpdate = true;
                /* 再描画フラグを設定 */
                bRedraw = true;
            }

             /* 左または右矢印キーが押された */
            if(key == KK_RIGHT || key == KK_LEFT)
            {
                /* キーに応じてマスクサイズを 2 増加または減少 */
                angle = (key == KK_LEFT) ? angle + 2 : angle - 2;
                /* 回転操作をフィルター後に適用 */
                bRotateUpdate = true;
                /* 再描画フラグを設定 */
                bRedraw = true;
            }

            /* (インフラストラクチャー) */
            if(WindowIsInvalidated(pDesc))
            {
                /* 再描画フラグを設定 */
                bRedraw = true;
            }

            /* フィルタリングを実行 */
            if (bFilterUpdate)
            {
                /* ワークバッファーのサイズを取得 */
                if (status >= ippStsNoErr) status = ippiFilterBoxBorderGetBufferSize(srcSize, maskSize, ipp8u, numChannels, &bufSize);

                /* バッファーメモリーを解放 */
                if (pBuffer) ippsFree(pBuffer);
                /* バッファーメモリーを割り当て */
                pBuffer = ippsMalloc_8u(bufSize);

                /* 画像のフィルタリング */
                status = ippiFilterBoxBorder_8u_C3R(srcData.m_pPointer, srcStep, pBlur, blurStep, srcSize, maskSize, ippBorderRepl, NULL, pBuffer);

                /* 情報メッセージ */
                std::cout << "The box filter is applied to the source image with the mask size (" << maskSize.width << "x" << maskSize.height << ")" << std::endl;
                /* フィルターフラグを解除 */
                bFilterUpdate = false;
                /* 回転操作をフィルター後に適用 */
                bRotateUpdate = true;
            }

            /* 回転を実行 */
            if (bRotateUpdate)
            {
                IppiSize roiSize = {dstSize.width / 2, dstSize.height };
                Ipp8u* pDstRoi   = pBlurRot;
                /* 角度と x/y シフトでアフィン変換の係数を計算 */
                if (status >= ippStsNoErr) status = ippiGetRotateTransform(angle, xShift, yShift, coeffs);

                /* 変換した画像の境界を取得 */
                if (status >= ippStsNoErr) status = ippiGetAffineBound(srcRoi, bound, coeffs);

                /* ソース画像をデスティネーションに合わせる */
                coeffs[0][2] = -bound[0][0] + (dstSize.width / 2.f  - (bound[1][0] - bound[0][0])) / 2.f;
                coeffs[1][2] = -bound[0][1] + (dstSize.height - (bound[1][1] - bound[0][1])) / 2.f;

                /* ブラーした画像にアフィン処理を実行 */
                if (status >= ippStsNoErr) status = warpAffine(pBlur, srcSize, blurStep, pDstRoi, roiSize, blurRotStep, coeffs);

                /* ブラーしていない画像のデスティネーション ROI を設定 */
                pDstRoi = pBlurRot + roiSize.width * numChannels;

                /* 元の画像にアフィン処理を実行 */
                if (status >= ippStsNoErr) status = warpAffine(srcData.m_pPointer, srcSize, srcStep, pDstRoi, roiSize, blurRotStep, coeffs);

                /* 情報メッセージ */
                std::cout << "The image is rotated by " << angle - 360.0 * floor(angle / 360.0) << " degrees " << std::endl;

                /* 回転フラグを解除 */
                bRotateUpdate = false;
            }

            /* ウィンドウを再描画 (インフラストラクチャー) */
            if(bRedraw)
            {
                if (renderSize.width == dstSize.width && renderSize.height == dstSize.height)
                {
                    ippiCopy_8u_C3R(pBlurRot, blurRotStep, renderData.m_pPointer, renderData.m_iStep, renderSize);
                }
                else
                {
                    /* 画像を縮小 */
                    shrink(pBlurRot, dstSize, blurRotStep, renderData.m_pPointer, renderSize, renderData.m_iStep);
                }

                WindowDrawImage(pDesc, &renderData);
                /* 再描画フラグを解除 */
                bRedraw = false;
            }
        }
    }
    /* ウィンドウを解放 (インフラストラクチャー) */
    WindowRelease(pDesc);

    /* 割り当てたメモリーを解放 */
    ippsFree(pBlur);
    ippsFree(pBlurRot);
    ippsFree(pBuffer);

    return 0;
}

戻る次へ