トップ | puarts.com
ロゴ
「OpenCV」に関連する記事一覧
0  
OpenCVについているcvWatershedはマーカー画像と元画像からWatershed(分水嶺)アルゴリズムを用いて未決定の領域を分割してくれる関数です。ざっくりとしたマスクから細かいマスクを切ってくれれば、マスク作成に使えるんじゃないかと思って試してみました。

こちらが実験に使うソース画像です。

こちらがペイントソフトでざっくりと描いたマーカー画像。黒の領域を自動的に周りのマーカーを元に埋めながら領域分割を行ってくれるようです。

こちらがcvWatershedによって得られた最終的なセグメンテーション画像。

こちらが、ソース、ざっくりマスク、領域分割後のそれぞれの画像を重ねてみたものです。


重ねてみるとよくわかりますが、この画像ではちゃんと境界にそった結果になりました。

Watershedアルゴリズムは中心となるマーカーから徐々に領域を広げていって、ちょうど分水嶺になるような場所を分割点として切るというアルゴリズムのようです。

私はこれに加えてエッジの特徴量も利用しているのかなぁと予想していたんですが、予想通りエッジに沿った輪郭を自動的に形成してくれました。

マスク作成に割と使えそうです。ちなみにこの分割領域から背景をマスキングした画像がこちら。

OpenCVは簡単に実装できるけど精度はイマイチのものが多い気がしますが、この関数はそのまま使えそうで良かったです。

マスク作成用のソフトはいろいろと売られていますが、自作のものをひとつ持っているといろいろと好き勝手にカスタマイズできるので、OpenCVのソースに手を加えてマスク作成用のツールを作っておきたいところです。



追記  ----------------------------------------
最初にこの記事を書いたときに結果の境界がジャギジャギになってしまったと記しましたが、それはWatershedの問題ではなくて別のところのミスがあったためとわかりましたので、この記事の内容は改めて更新させていただきました。

先日リリースされたOpenCV2.3.0をとりあえず入れてみました。

Windows版のダウンロード
http://sourceforge.net/projects/opencvlibrary/files/opencv-win/2.3/

OpenCV.jpで新機能や特徴が日本語で紹介されています
http://opencv.jp/opencv2-x-tips/changelog_from_22

今まで使っていた2.2.9の時点でCUDA4.0とOpenNIは使えていたので、そんなに喜びは感じませんでしたが、パッケージ化されているということでインストールが楽ちんです。GPUサポートのバイナリも公開されているので、自分でコンパイルしなくてもGPU機能を使えます。

新しい機能で個人的には変分法を用いたステレオ対応点探索アルゴリズムが気になります。あとは複数写真からパノラマ機能を生成できるopencv_stitching が気になります。これは2.2.9にもあったのですが使ってみたことないので。

研究の中間発表が明日あるので、それが終わったら少しさわってみたいと思います。
OpenCV 2.2のGPU機能の速度を評価するべく、CPUとGPUでの簡単な比較実験を行ってみました。
平滑化フィルタであるcv::blurとcv::gpu::blurを窓サイズや画像の解像度を変えながら30回分の処理時間を計測して比較する実験です。

実験に使ったCPUはcore-i7 930、GPUはQuadro FX 580です。性能的にちょっとGPUが不利なので、それを踏まえて実験結果を見る必要があります。

まずこちらは4096x4096の画像に対して平滑化カーネルサイズを2x2から10x10まで2ずつ増やしながらCPUとGPUで比較したものです。

カーネルサイズが4x4まではGPUの方が速度が上回っています。カーネルサイズが大きくなるほどGPUの処理速度は2次曲線的に増加しているのに対してCPUの処理速度は直線的に増加しています。

平滑化カーネルサイズが小さいほど、すなわち単純な処理ほどGPUは高速化できるという特徴がよく表れている実験結果が得られました。


こちらのグラフは横軸に画像の解像度をとり、平滑化カーネルサイズごとにグラフを作ってみたものです。


画像の解像度が大きくなるとCPUとGPUで速度の差がはっきりと表れてきます。やはり、平滑化カーネルのサイズが小さくないとGPUの方が遅くなってしまう。

これらの実験結果からGPUで高速化しやすい処理対象は1画素辺りの処理が単純(1つの処理におけるプロセッサの仕事量とメモリの使用量が少なめ)でかつ、画像の解像度が大きい場合(並列化できる処理が多い場合)であるということが改めて実感できました。

ついでにGPGPUを利用すると消費電力もCPUで処理するより抑えられるとか。

私の環境ではGPUで高速化できた平滑化カーネルサイズが4x4程度ということで、そんなにGPUの恩恵を受けられそうにないのが少し残念です。もっとプロセッサ数が多くてかつクロック周波数が高くて、メモリを多く積んでいれば並列処理の恩恵をたくさん受けられるのに。性能の高いGPUで試してみたいです。

CUDAで画像処理を高速化させたいならQuadroにする必要ないし、GeForce GTX580辺りを買った方がコストパフォーマンスはかなり高そうですね。今までMayaのためにQuadroにしてましたが描画の速さであまりメリットを感じていません。これを期にGeForceに買い替えようか迷います。


ついでに実験に使ったソースコードも載せておきます。

#include <sys/timeb.h>
#include <time.h>
#include <iostream>
#include<opencv2/gpu/gpu.hpp>
 

static struct _timeb g_tstruct;

void StartTimer()
{
    _ftime(&g_tstruct);
}
float StopTimer()
{
    struct _timeb tstruct_new;
    float t;

    _ftime(&tstruct_new);
    t = (float)(tstruct_new.time - g_tstruct.time) + (float)(tstruct_new.millitm - g_tstruct.millitm)/(float)1000;
    return t;
}

int main()
{
    cv::gpu::DeviceInfo di(cv::gpu::getDevice());
    std::cout << di.name() << std::endl;
    double time_gpu, time_cpu;
    int numRepeat, w_st, w_max;

    numRepeat=30;
    w_st=2;
    w_max=10;

    //** Gaussian Filter CPU
    printf("CPU Processing Time\n");
    for(int wsize=w_st; wsize<=w_max; wsize+=2){
        printf(" %d", wsize);
    }
    printf("\n");
    for(int size=16; size<=4096; size*=2){
        time_cpu=0.0;
        printf("%dx%d ", size, size);
        for(int wsize=w_st; wsize<=w_max; wsize+=2){
            for(int i=0; i<numRepeat; i++){
                cv::Mat mat(size, size, CV_8U,cv::Scalar(0));
                StartTimer();
                cv::blur(mat, mat, cv::Size(wsize, wsize));
                time_cpu+=StopTimer();
            }
            printf("%.5f ", time_cpu);
        }
        printf("\n");
    }
  
    //** Gaussian Filter GPU
    printf("GPU Processing Time\n");
    for(int size=16; size<=4096; size*=2){
        time_gpu=0.0;
        printf("%dx%d ", size, size);
        for(int wsize=w_st; wsize<=w_max; wsize+=2){
            for(int i=0; i<numRepeat; i++){
                cv::gpu::GpuMat gpumat(size, size, CV_8U, cv::Scalar(0));
                StartTimer();
                cv::gpu::blur(gpumat, gpumat, cv::Size(wsize, wsize));
                time_gpu+=StopTimer();
            }
            printf("%.5f ", time_gpu);
        }
        printf("\n");
    }

    return 0;
}
 

OpenCV2.2のcv::gpu::dftを使って4x4の複素行列をフーリエ変換、逆フーリエ変換をする例です。なかなかネット上にサンプルコードがなくて少し使い方に苦労したので、同じようにOpenCVのdftをGPU機能つきで使用したい方の参考になればと思います。

This is a sample code to apply fourier transform and inverse fourier transform with cv::gpu::dft function in OpenCV 2.2.

Source code

#include<opencv2/gpu/gpu.hpp>

void cvGpuTest_DFT_IDFT(){
 int w=4, h=4;
 int len=w*h*2;
 cv::Mat dst;
 cv::gpu::GpuMat gpuMat;

 //** make source data -----
 float *srcData;
 srcData=new float[len];
 for(int i=0; i<len/2; i++){
  srcData[i*2]=i;
  srcData[i*2+1]=0;
 }
 cv::Mat srcMat(w, h, CV_32FC2, srcData);

 //** Print Source Data ----
 printf("SRC------------\n");
 for(int y=0; y<h; y++){
  for(int x=0; x<w; x++){
   printf("%d %d: %f %f\n", x, y, srcMat.at<float>(y, x*2), srcMat.at<float>(y, x*2+1));
  }
 }

 //** DFT ------------------
 gpuMat = srcMat;

 cv::gpu::dft(gpuMat, gpuMat, cv::Size(w, h));

 dst=gpuMat;

 //** Print DFT Result ------
 printf("DFT------------\n");
 for(int y=0; y<h; y++){
  for(int x=0; x<w; x++){
   printf("%d %d: %f %f\n", x, y, dst.at<float>(y,x*2), dst.at<float>(y, x*2+1));
  }
 }

 //** IDFT -----------------
 gpuMat=dst;

 cv::gpu::dft(gpuMat, gpuMat, cv::Size(w, h),

              cv::DFT_INVERSE);

 dst=gpuMat;

 //** Print IDFT Result -----
 printf("IDFT------------\n");
 for(int y=0; y<h; y++){
  for(int x=0; x<w; x++){
   printf("%d %d: %f %f\n", x, y, dst.at<float>(y,x*2)/(w*h), dst.at<float>(y, x*2+1));
  }
 }
}

int main()
{
 cvGpuTest_DFT_IDFT();
 return 0;
}


Result

SRC------------ 

0 0: 0.000000 0.000000

1 0: 1.000000 0.000000

2 0: 2.000000 0.000000

3 0: 3.000000 0.000000

0 1: 4.000000 0.000000

1 1: 5.000000 0.000000

2 1: 6.000000 0.000000

3 1: 7.000000 0.000000

0 2: 8.000000 0.000000

1 2: 9.000000 0.000000

2 2: 10.000000 0.000000

3 2: 11.000000 0.000000

0 3: 12.000000 0.000000

1 3: 13.000000 0.000000

2 3: 14.000000 0.000000

3 3: 15.000000 0.000000

DFT------------ 

0 0: 120.000000 0.000000

1 0: -8.000000 8.000000

2 0: -8.000000 0.000000

3 0: -8.000000 -8.000000

0 1: -32.000000 32.000000

1 1: 0.000000 0.000000

2 1: 0.000000 0.000000

3 1: 0.000000 0.000000

0 2: -32.000000 0.000000

1 2: 0.000000 0.000000

2 2: 0.000000 0.000000

3 2: 0.000000 0.000000

0 3: -32.000000 -32.000000

1 3: 0.000000 0.000000

2 3: 0.000000 0.000000

3 3: 0.000000 0.000000

IDFT------------ 

0 0: 0.000000 0.000000

1 0: 1.000000 -0.000000

2 0: 2.000000 0.000000

3 0: 3.000000 0.000000

0 1: 4.000000 0.000000

1 1: 5.000000 -0.000000

2 1: 6.000000 0.000000

3 1: 7.000000 0.000000

0 2: 8.000000 0.000000

1 2: 9.000000 -0.000000

2 2: 10.000000 0.000000

3 2: 11.000000 0.000000

0 3: 12.000000 0.000000

1 3: 13.000000 -0.000000

2 3: 14.000000 0.000000

3 3: 15.000000 0.000000

OpenCV2.2.0を先日コンパイルしてGPU機能を使おうとしたのですが、ドキュメントに載っている関数が入っていなかったので、OpenCVのリポジトリから2.2.9をダウンロードしてきてコンパイルしました。しかし、やはりopencv_gpuのコンパイルのところでエラーが出てすんなりとはコンパイルできない状況に陥りましたので、そのときのエラーと解決策を記しておきます。

VC++2010でのエラーメッセージ
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include\objbase.h(240): error:  identifier "IUnknown" is undefined

NVIDIA Forumsに解決策が載っていました。
http://forums.nvidia.com/index.php?showtopic=67822

ここに載っていたようにエラーが起こったObjBase.hを修正したら私の場合は無事にコンパイルが通りました。
次のようにObjBase.hの240行目付近にwtypes.hとunknwn.hをインクルードする文を追加します。

#include <wtypes.h>
#include <unknwn.h>


修正前

extern "C++"

{

    template void** IID_PPV_ARGS_Helper(T** pp) 

    {

        // make sure everyone derives from IUnknown

        static_cast(*pp);

        

        return reinterpret_cast(pp);

    }

}



修正後

extern "C++"

{

    #include <wtypes.h>
    #include <unknwn.h>
template void** IID_PPV_ARGS_Helper(T** pp) { // make sure everyone derives from IUnknown static_cast(*pp); return reinterpret_cast(pp); } }


同じエラーが出てしまった方は試してみてください。

OpenCV 2.2のGPU機能を64ビットで使ってみたかったので、Visual Studio 2010で64bit版のライブラリファイルをビルドしてみました。ついでにその他の機能も使えるようにしました。

こちらのブログでご丁寧にもPDFでインストール方法を紹介してくれていたので、こちらを参考にさせていただきました。

まとめ?ブログ
http://kgxpx834.blog58.fc2.com/blog-entry-23.html

私が利用したIDEと各ライブラリのバージョンです。

Visual Studio 2010 Premium

CMake 2.8.4
http://www.cmake.org/cmake/resources/software.html

OpenCV 2.2.0
http://sourceforge.net/projects/opencvlibrary/
files/opencv-win/2.2/

追記 ---------------------------------------------------
OpenCV2.2.0ではドキュメントにあるgpuの関数がすべては使えなかったので結局OpenCV SVNから2.2.9をダウンロードしてきて使いました。
https://code.ros.org/svn/opencv
----------------------------------------------------------

TBB 3.0
http://threadingbuildingblocks.org/file.php?fid=77

CUDA Toolkit 4.0.17 64bit
GPU Computing SDK code samples 4.0.17 64bit
http://developer.nvidia.com/cuda-toolkit-40

NVIDIA Performance Primitives (NPP) library 3.2.16 64bit
http://developer.nvidia.com/cuda-toolkit-32-downloads

Qt 4.7.1 64bit
http://qt.nokia.com/downloads-jp

Eigen 2.0.16
http://eigen.tuxfamily.org/index.php?
title=Main_Page#Download


しかし、64bitだからなのかわからないですが、手順通りにやってもすんなりとはうまくゆかず、うまくバイナリを生成できるまでかなり苦戦しました。

特にopencv_gpuをコンパイルするときに次のようなエラーが出て困ってしまいました。

..\..\..\modules\gpu\src\imgproc_gpu.cpp(601): error C3861: 'nppiCannyGetBufferSize': identifier not found

..\..\..\modules\gpu\src\imgproc_gpu.cpp(605): error C3861: 'nppiCanny_32f8u_C1R': identifier not found

..\..\..\modules\gpu\src\arithm.cpp(503): error C2664: 'nppiSum_8u_C1R' : cannot convert parameter 4 from 'Npp32s *' to 'Npp8u *'
          Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

..\..\..\modules\gpu\src\arithm.cpp(510): error C2664: 'nppiSum_8u_C4R' : cannot convert parameter 4 from 'Npp32s *' to 'Npp8u *'
          Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast


こちらのブログのコメント部分に同じ問題に遭遇した人が解決策を記していてくれていたので助かりました。

http://blog.cuvilib.com/2011/03/22/
how-to-build-opencv-2-2-with-gpu-cuda-on-windows-7/

コメントにあった解決策をそのまま抜き出してここにも書いておきます。

- Code generation -> runtime library -> Multithreaded dll
- Linker -> Input -> Ignore Specific Library = nothing
- C/C++ -> General -> Additional Include Libraries -> invert the order of the include path for CUDA and NPP (put first npp include folder and then CUDA include folder)

日本語でも一応書いておきます。

opencv_gpuプロジェクトのプロパティを開き、次の3つのプロパティを変更します。
1. Code generation -> runtime libraryをマルチスレッドDLLに変更(おそらく初めからこうなっている)
2. Linker -> Input -> Ignore Specific Libraryを全部無くす。(おそらくlibcがあるので、それを消す)
3. C/C++ -> General -> Additional Include LibrariesのNPPとCUDAのインクルードパスの順番を入れ替える

私の場合はこれで無事にコンパイルが通りました。同じエラーに遭遇してしまった方は一度試してみて下さい。

0  

0.0225 sec
にほんブログ村 ゲームブログ ファイアーエムブレムへ にほんブログ村 デザインブログ コンピュータグラフィックスへ

Copyright(C)2006-2018 wsp All Rights Reserved