フリーで使えるVisual Studio Expressの入手

2012年10月現在、最新版はVisual Studio 2012となりました。

VS2012 Expressについては、下記、記事にまとめました。

Visual Studio 2012 Expressが公開されました

 

以下は、旧版の内容です。

———————————————————

VB.NET、C#、C++/CLIをこれから始めようとしている方は、まずは無料で使えるVisual Studio Expressを試すのがオススメです。
このVisual Studio Expressは、プログラム初心者や学生向けという位置づけですが、そこそこの事ができます。

 

入手先はこちら

 

http://www.microsoft.com/japan/msdn/vstudio/express/

 

旧版のVisual Studio 2008 Express Editionもこちらから入手可能です。

 

http://www.microsoft.com/japan/msdn/vstudio/2008/product/express/

 

Visual Studio 2010のC++/CLIではIntellisense(携帯で言うところの予測入力みたいなもの)が使えないので、C++/CLIをやりたい場合は、VS2008の方がいいと思います。

 

 

このExpressでは何ができないか?というと、細かい事はVisual Studio 2005の場合ですが、

 

@IT
http://www.atmarkit.co.jp/fdotnet/special/vs2005compare/vs2005compare_01.html

 

に任せるとして、私がExpressで不便に感じたのは

 

  • C++/CLIのExpressにはリソースエディタが無い
    →バージョン管理ができない、SDKのウィンドウが作れない。
  • ユーザーコントロールが作れない
  • マクロ機能が無い
  • ソリューションが多言語をまたげない
    →VB.NETやC#の混在が出来ない。

 

などなど。

 

と、言いながらもちょっとしたアプリケーションを作るだけなら、かなりの事が出来るので、まずはこのExpressから初めてみては如何でしょうか?

 

Visual Studioへ戻る

【OpenCV2.2】新規プロジェクトの作成方法(C言語版)

OpenCVのサンプルプログラムはHPを検索すればいくらでも転がっていますが、最初の頃はこれを、どのように使えば良いのか?私にはよく分かりませんでした。

 

という事で、OpenCV2.2およびVisual Studio2010 Express を使って、サンプルプログラムを作成する方法を紹介します。

 

何はともあれ、サンプルプログラムはこちらです。

opencv22sample.zip

 

新規プロジェクトの作成方法

Visual Studio を起動し、新しいプロジェクトをクリックします。

 

 

開いたウィンドウのWin32コンソールアプリケーションを選択し、任意の名前および場所を指定します。

 

 

OKボタンをクリックし、次へをクリックします。

 

 

さらに表示されたウィンドウの完了をクリックします。

 

 

すると、空の状態のソースコードが作成されます。

 

 

OpenCV.jpのサンプルとは、mainの部分がちょっと異なりますが、気にせず、そのままにしておいて下さい。

 

次にOpenCV2.2の入手、ダウンロード、インストール、環境設定の最後の部分でも紹介していますが、ヘッダファイルをプログラムから参照できるように、OpenCVのヘッダファイルのディレクトリを指定します。

 

 

プロジェクトのプロパティで構成プロパティ→C/C++→全般の追加のインクルードディレクトリ

C:\OpenCV2.2\include

を指定します。

 

あとは、作成したcppファイル(上記の例ではOpenCV2.2Sample.cpp)にプログラムをしていけばOKです。

 

以下、画像を開き、ガウシアンフィルタ処理を行い、処理前、処理後の画像を表示するだけの簡単なサンプルプログラムを示します。

// OpenCV2.2Sample.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"

//プロジェクトのプロパティ⇒C/C++⇒全般 の追加のインクルードディレクトリに
// 『C:\OpenCV2.2\include』を追加のこと
#include "opencv2\\opencv.hpp"

#ifdef _DEBUG
    //Debugモードの場合
    #pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_core220d.lib")
    #pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_imgproc220d.lib")
    #pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_highgui220d.lib")
    #pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_objdetect220d.lib")
    //以下、必要に応じて追加
    //#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_ml220d.lib")
    //#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_features2d220d.lib")
    //#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_video220d.lib")
    //#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_calib3d220d.lib")
    //#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_flann220d.lib")
    //#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_contrib220d.lib")
    //#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_legacy220d.lib")
    //#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_gpu220d.lib")
#else
    //Releaseモードの場合
    #pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_core220.lib")
    #pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_imgproc220.lib")
    #pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_highgui220.lib")
    #pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_objdetect220.lib")
    //以下、必要に応じて追加
    //#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_ml220.lib")
    //#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_features2d220.lib")
    //#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_video220.lib")
    //#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_calib3d220.lib")
    //#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_flann220.lib")
    //#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_contrib220.lib")
    //#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_legacy220.lib")
    //#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_gpu220.lib")
#endif

int _tmain(int argc, _TCHAR* argv[])
{
    //画像データの読込
    IplImage* src_img = cvLoadImage("C:\\OpenCV2.2\\samples\\c\\lena.jpg", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);
    if (src_img == NULL){
        return 0;
    }

    //表示ウィンドウの作成
    cvNamedWindow("src");
    cvNamedWindow("dst");

    //処理後画像データの確保
    IplImage* dst_img = cvCreateImage(cvGetSize(src_img), src_img->depth, src_img->nChannels);

    //画像処理例(ガウシアンフィルタ)
    cvSmooth(src_img, dst_img, CV_GAUSSIAN, 9);

    //画像の表示
    cvShowImage ("src", src_img);
    cvShowImage ("dst", dst_img);

    //キー入力待ち
    cvWaitKey (0);

    //全てのウィンドウの削除
    cvDestroyAllWindows();

    //画像データの解放
    cvReleaseImage(&src_img);
    cvReleaseImage(&dst_img);

    return 0;
}

OpenCVへ戻る

 

【OpenCV2.2】ライブラリ構成(*.lib,*.hなど)

OpenCV2.2からはライブラリの構成が再構築されています。
旧バージョンと、OpenCV2.2の構成の概略は以下の通りとなっています。

 

OpenCV2.2 旧バージョン ヘッダファイル ライブラリファイル 概要
opencv_core CXCORE core_c.h (C言語用)
core.hpp (C++用)
opencv_core220.lib
opencv_core220d.lib
メモリ確保/解放、行列、
演算、描画など
opencv_imgproc CV imgproc_c.h (C言語用)
imgproc.hpp (C++用)
opencv_imgproc220.lib
opencv_imgproc220d.lib
画像処理
一般的なフィルタ処理など
opencv_highgui HighGUI highgui_c.h (C言語用)
highgui.hpp (C++用)
opencv_highgui220.lib
opencv_highgui220d.lib
ウィンドウなどのGUI、
ファイル読込/保存、
ビデオファイル、カメラなど
opencv_ml ml ml.hpp opencv_ml220.lib
opencv_ml220d.lib
サポートベクタマシン、
ブースティングなどの
機械学習
opencv_features2d features2d.hpp opencv_features2d220.lib
opencv_features2d220d.lib
SURF、FASTなどの
特徴抽出
opencv_video background_segm.hpp opencv_video220.lib
opencv_video220d.lib
前景/背景分離
tracking.hpp トラッキング
opencv_objdetect objdetect.hpp opencv_objdetect220.lib
opencv_objdetect220d.lib
Haar、LBP、HOGなどの
オブジェクト検出器
opencv_calib3d calib3d.hpp opencv_calib3d220.lib
opencv_calib3d220d.lib
カメラキャリブレーション、
ステレオカメラなど
opencv_flann flann.hpp opencv_flann220.lib
opencv_flann220d.lib
高速最近傍処理(FLANN)
など
opencv_contrib contrib.hpp opencv_contrib220.lib
opencv_contrib220d.lib
肌検出、MeanShiftなど
完全な状態ではない
opencv_legacy legacy.hpp opencv_legacy220.lib
opencv_legacy220d.lib
旧関数との互換用
opencv_gpu gpu.hpp opencv_gpu220.lib
opencv_gpu220d.lib
GPU(CUDA)による行列演算、
画像処理など。(β版の扱い)

 

ライブラリファイル(*.lib)はReleaseモードの場合、『d』のつかないlibファイルを、Debugモードの場合、『d』の付いたlibファイルを、参照設定して下さい。

 

ヘッダファイルはopencv.hppにまとめてインクルードされているので、このファイル(opencv.hpp)一つをインクルードすると、すべてインクルードされます。

 

また、OpenCV-2.2.0-win32-vs2010.exeを使ってデフォルト状態でOpenCV2.2をインストールした時の主なファイルのフォルダ構成は以下の通りです。

 

C:\OpenCV2.2
┣ bin
┃  ┣ opencv_core220.dll
┃  ┣ opencv_core220d.dll
┃  ┣ opencv_imgproc220.dll
┃  ┣ opencv_imgproc220d.dll
┃  ┣ opencv_highgui220.dll
┃  ┣ opencv_highgui220d.dll
┃  ┣ opencv_ml220.dll
┃  ┣ opencv_ml220d.dll
┃  ┣ opencv_features2d220.dll
┃  ┣ opencv_features2d220d.dll
┃  ┣ opencv_video220.dll
┃  ┣ opencv_video220d.dll
┃  ┣ opencv_objdetect220.dll
┃  ┣ opencv_objdetect220d.dll
┃  ┣ opencv_calib3d220.dll
┃  ┣ opencv_calib3d220d.dll
┃  ┣ opencv_flann220.dll
┃  ┣ opencv_flann220d.dll
┃  ┣ opencv_contrib220.dll
┃  ┣ opencv_contrib220d.dll
┃  ┣ opencv_legacy220.dll
┃  ┣ opencv_legacy220d.dll
┃  ┣ opencv_gpu220.dll
┃  ┗ opencv_gpu220d.dll
┣ include
┃  ┣ opencv
┃  ┃ ┣ cv.h
┃  ┃ ┣ cv.hpp
┃  ┃ ┣ cxcore.h
┃  ┃ ┣ cxcore.hpp
┃  ┃ ┣ highgui.h
┃  ┃ ┗ ml.h
┃  ┣ opencv2
┃  ┃ ┣ opencv.hpp
┃  ┃ ┣ core
┃  ┃  ┃ ┣ core_c.h
┃  ┃  ┃ ┗ core.hpp
┃  ┃ ┣ imgproc
┃  ┃  ┃ ┣ imgproc_c.h
┃  ┃  ┃ ┗ imgproc.hpp
┃  ┃ ┣ highgui
┃  ┃  ┃ ┣ highgui_c.h
┃  ┃  ┃ ┗ highgui.hpp
┃  ┃ ┣ ml
┃  ┃  ┃ ┗ ml.hpp
┃  ┃ ┣ features2d
┃  ┃  ┃ ┗ features2d.hpp
┃  ┃ ┣ video
┃  ┃  ┃ ┣ background_segm.hpp
┃  ┃  ┃ ┗ tracking.hpp
┃  ┃ ┣ objdetect
┃  ┃  ┃ ┗ objdetect.hpp
┃  ┃ ┣ calib3d
┃  ┃  ┃ ┗ calib3d.hpp
┃  ┃ ┣ flann
┃  ┃  ┃ ┗ flann.hpp
┃  ┃ ┣ contrib
┃  ┃  ┃ ┗ contrib.hpp
┃  ┃ ┣ legacy
┃  ┃  ┃ ┗ legacy.hpp
┃  ┃ ┗ gpu
┃  ┃      ┗ gpu.hpp
┗ lib
┣ opencv_core220.lib
┣ opencv_core220d.lib
┣ opencv_imgproc220.lib
┣ opencv_imgproc220d.lib
┣ opencv_highgui220.lib
┣ opencv_highgui220d.lib
┣ opencv_ml220.lib
┣ opencv_ml220d.lib
┣ opencv_features2d220.lib
┣ opencv_features2d220d.lib
┣ opencv_video220.lib
┣ opencv_video220d.lib
┣ opencv_objdetect220.lib
┣ opencv_objdetect220d.lib
┣ opencv_calib3d220.lib
┣ opencv_calib3d220d.lib
┣ opencv_flann220.lib
┣ opencv_flann220d.lib
┣ opencv_contrib220.lib
┣ opencv_contrib220d.lib
┣ opencv_legacy220.lib
┣ opencv_legacy220d.lib
┣ opencv_gpu220.lib
┗ opencv_gpu220d.lib

 

C:\OpenCV2.2\include\opencv内のcv.hなどのファイルは使用可能ですが、
C:\OpenCV2.2\include\opencv2内のimgproc.hppなどを使うのを推奨とされています。

 

OpenCVへ戻る

 

OpenCV2.2の入手、ダウンロード、インストール、環境設定

OpenCVはsourceforgeにて公開されています。

http://sourceforge.net/projects/opencvlibrary/

公開される内容はOpenCVのバージョンにより異なるのですが、最近のバージョンではライブラリをコンパイル済みのセットアップファイル(*.exe)、および、ソースコードを含み、自分でコンパイルする必要のあるファイル一式(*.zip)の2通りのファイルが公開されています。

自分でコンパイルする場合は、IPP(Intel Integrated Performance Primitives)やTBB(Intel Threading Building Blocks)などにも対応させるなど、細かい設定ができるのですが、CMakeというソフトを使い開発環境に合わせたプロジェクトを作成し、コンパイルするため、少々複雑になります。

そのため、今回は比較的簡単なコンパイル済みのセットアップファイルを使ったインストール方法を紹介します。

 

OpenCV2.2の入手

OpenCV2.2は先程も書いた通りsourceforgeよりダウンロードします。

(入手HP)

http://sourceforge.net/projects/opencvlibrary/

 

このページのDownlaodと書かれた緑色のボタンをクリックして、ファイル(OpenCV-2.2.0-win32-vs2010.exe)をダウンロードします。

 

ファイル名を見ても分かるように、このファイルはWindows 32bit版のVisual Studio 2010用にコンパイルされたファイルなのですが、64bit版のOS環境下でも32bitで動作します。
また、VS2010以外でも、Microsoft Visual C++ 2010 再頒布可能パッケージをインストールすることで、旧バージョンのVisual Studioでも開発する事が可能です。

 

OpenCV2.2のインストール方法

ダウンロードしたファイル(OpenCV-2.2.0-win32-vs2010.exe)をダブルクリックしてOpenCV2.2のインストールを開始します。

 

 

上図のような画面が表示されるので、『次へ』をクリックします。

 

 

表示されたライセンス契約(いわゆるBSDライセンス)をご確認のうえ、『同意する』をクリック

 

 

Add OpenCV to the system PATH for all users
もしくは
Add OpenCV to the system PATH for current users

 

を選択して『次へ』をクリック (デフォルト設定とは異なるので注意!

 

 

インストール先を選択し、『次へ』をクリック
(今度の説明などで、このデフォルト設定を基本として説明しますので、特に変更の必要が無い場合はデフォルトのまま設定して下さい。)

 

 

スタートメニューフォルダの設定が表示されますが、このまま『次へ』をクリック

 

 

セットアップする内容も、このまま『次へ』をクリック

 

 

上図が表示されたら、『完了』をクリックして、インストールは完了です。

 

インストール出来たか?確認のため、スタートメニューの全てのプログラム→OpenCV2.2.0→C Samples 内の実行ファイル(例えば、morphology.exeなど)が実行できるかどうか確認してみて下さい。
(ここで、実行できない場合はPATHの設定がされていない可能性があります。)

 

ライブラリファイル(*.lib)とヘッダファイル(*.h)の設定

ライブラリファイル(*.lib)とヘッダファイル(*.h)の設定方法は、好みの分かれるところなので、設定方法は各個人によって異なると思いますが、私の場合は以下のようにしています。

 

OpenCV2.2の場合は、ヘッダファイルから別のヘッダファイルがインクルードされるので、プロジェクトの設定で『追加のインクルードディレクトリ』の設定は必須のようです。

 

設定方法は、Visual Studioのメニューのプロジェクト→プロパティでプロパティページを開きます。

 

構成プロパティ→C/C++→全般の追加のインクルードディレクトリに、OpenCV2.2のincludeディレクトリを指定します。
デフォルトでインストールした場合は
C:\OpenCV2.2\include
を指定します。

 

あとはソースコード中に以下のように記載します。
(プロジェクトのプロパティの構成プロパティ→リンカー→入力で設定しても構いません。)

//プロジェクトのプロパティ⇒C/C++⇒全般 の追加のインクルードディレクトリに
// 『C:\OpenCV2.2\include』を追加のこと
#include "opencv2\\opencv.hpp"

#ifdef _DEBUG
//Debugモードの場合
#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_core220d.lib")            // opencv_core
#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_imgproc220d.lib")        // opencv_imgproc
#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_highgui220d.lib")        // opencv_highgui
#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_objdetect220d.lib")    // opencv_objdetect
//以下、必要に応じて追加
//#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_ml220d.lib")            // opencv_ml
//#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_features2d220d.lib")    // opencv_features2d
//#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_video220d.lib")        // opencv_video
//#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_calib3d220d.lib")        // opencv_calib3d
//#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_flann220d.lib")        // opencv_flann
//#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_contrib220d.lib")        // opencv_contrib
//#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_legacy220d.lib")        // opencv_legacy
//#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_gpu220d.lib")            // opencv_gpu
#else
//Releaseモードの場合
#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_core220.lib")            // opencv_core
#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_imgproc220.lib")        // opencv_imgproc
#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_highgui220.lib")        // opencv_highgui
#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_objdetect220.lib")    // opencv_objdetect
//以下、必要に応じて追加
//#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_ml220.lib")            // opencv_ml
//#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_features2d220.lib")    // opencv_features2d
//#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_video220.lib")        // opencv_video
//#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_calib3d220.lib")        // opencv_calib3d
//#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_flann220.lib")        // opencv_flann
//#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_contrib220.lib")        // opencv_contrib
//#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_legacy220.lib")        // opencv_legacy
//#pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_gpu220.lib")            // opencv_gpu
#endif

#pragmaをコメントアウトしている部分は書かなくても、ほぼ大丈夫ですし、コメントアウトしなくても大丈夫です。
ただ、opencv_ml、opencv_feature2dなどの関数を使う場合にはコメントアウトは外して下さい。

 

OpenCVへ戻る

 

【OpenCV】IplImage構造体

OpenCVの画像データの大きさやビット深度、画像データのポインタなどを管理しているのがIplImage構造体になります。
(OpenCV2.0からはcv:Matクラスというのも登場してきますが、ここではIplImageについて解説したいと思います。)
C言語のBITMAPINFO、.NETのBitmapクラスのようなものです。

 

OpenCVではこのIplImage構造体をOpenCVの各種関数の引数として渡します。

 

そこで、IplImage構造体の定義のヘッダファイル【cxtypes.h(OpenCV2.2ではtypes_c.h)】をのぞいてみると、

typedef struct _IplImage
{
    int  nSize;             /* sizeof(IplImage) */
    int  ID;                /* version (=0)*/
    int  nChannels;         /* Most of OpenCV functions support 1,2,3 or 4 channels */
    int  alphaChannel;      /* Ignored by OpenCV */
    int  depth;             /* Pixel depth in bits: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16S,
                               IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F are supported.  */
    char colorModel[4];     /* Ignored by OpenCV */
    char channelSeq[4];     /* ditto */
    int  dataOrder;         /* 0 - interleaved color channels, 1 - separate color channels.
                               cvCreateImage can only create interleaved images */
    int  origin;            /* 0 - top-left origin,
                               1 - bottom-left origin (Windows bitmaps style).  */
    int  align;             /* Alignment of image rows (4 or 8).
                               OpenCV ignores it and uses widthStep instead.    */
    int  width;             /* Image width in pixels.                           */
    int  height;            /* Image height in pixels.                          */
    struct _IplROI *roi;    /* Image ROI. If NULL, the whole image is selected. */
    struct _IplImage *maskROI;      /* Must be NULL. */
    void  *imageId;                 /* "           " */
    struct _IplTileInfo *tileInfo;  /* "           " */
    int  imageSize;         /* Image data size in bytes
                               (==image->height*image->widthStep
                               in case of interleaved data)*/
    char *imageData;        /* Pointer to aligned image data.         */
    int  widthStep;         /* Size of aligned image row in bytes.    */
    int  BorderMode[4];     /* Ignored by OpenCV.                     */
    int  BorderConst[4];    /* Ditto.                                 */
    char *imageDataOrigin;  /* Pointer to very origin of image data
                               (not necessarily aligned) -
                               needed for correct deallocation */
}
IplImage;

となっています。

 

基本的にcvCreateImageもしくはcvLoadImage関数でIplImage構造体のデータを確保するので、IplImageの全てを知らなくても、なんとかなるのですが、主なメンバ変数は以下のとおりです。

 

nSize IplImage構造体のサイズ
nChannels チャンネル数 1,2,3,4のどれか
depth 1画素あたりのビット数
実質使えるのはIPL_DEPTH_8U(符号なし8ビット)と一部でIPL_DEPTH_16S(符号付き16ビット)ぐらい。
24ビットカラー(R,G,B各8ビット)の場合、8ビット、3チャンネル
nChannels = 3、depth = IPL_DEPTH_8U
とする。
origin 画像データの原点(基準)
0:左上原点(デフォルト)
1:左下原点
originはcvShowImageやcvSobelなどの画像の上下の向きが必要な場合に用いられます。
注)originの値を変えても画像データの並びは変わりません。
width 画像の幅(画素数)
height 画像の高さ(画素数)
imageSize 画像データのサイズ(バイト数) (= widthStep * height
imageData 画像データへのポインタ
widthStep 画像データの幅のバイト数(画素数ではありません。
ビットマップ(*.bmp)データと同様に4バイト単位に調整されています。

 

【補足説明】

  • nChannels
    OpenCVではチャンネルという概念が登場しますが、これは1画素をいくつの色で表現するか?
    を示します。
    例えば、一般にRGBカラーの画像は24Bitカラーなどと表現しますが、OpenCV的には
    8Bit×3チャンネルと表現します。

 

  • imageData
    画像データ(輝度値、画素値)は、このimageDataのポインタを参照する事で輝度値を参照する事が出来ます。
    ただし、構造体の宣言を見ても分かるように、imageDataは符号付き8Bitのポインタ(char*)で宣言されているので、符号無し8Bitの256階調で輝度値を参照したい場合は、imageDataのポインタをキャストして参照して下さい。
    (例)
    IplImage* Src;
    ・・・
    byte* pBuf = (byte*)Src->imageData;また、OpenCVで確保されるimageDataのメモリのアドレスは16バイト境界になるように調整されています。つまり、アドレスが0x09BE0050などのように最下位の値が0となります。
    この事からもSSEなどと非常に相性がいいのです。

 

【IplImageの確保例】

  • ファイルから確保する場合
    IplImage* src_img = cvLoadImage(“TestImage.bmp”,
    CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);

 

  • 新規に画像データを確保する場合
    IplImage* src_img = cvCreateImage(
    cvSize(640, 480), IPL_DEPTH_8U, 3);※depthの値は、符号のある/なしを区別するため、数値(8など)を指定せず、下記定数の中から指定すること。
    IPL_DEPTH_8U – 符号無し 8 ビット整数
    IPL_DEPTH_8S – 符号有り 8 ビット整数
    IPL_DEPTH_16U – 符号無し 16 ビット整数
    IPL_DEPTH_16S – 符号有り 16 ビット整数
    IPL_DEPTH_32S – 符号有り 32 ビット整数
    IPL_DEPTH_32F – 単精度浮動小数点数
    IPL_DEPTH_64F – 倍精度浮動小数点数

ただし、使い終わったら解放するのもお忘れなく。
cvReleaseImage(&src_img);

 

OpenCVへ戻る

 

ライブラリの使用方法、VisualStudioの設定方法

最近、OpenCVOpenGLDirectShowなどのライブラリを使う機会が増えてきたので、ライブラリの使い方をまとめておきます。

 

ライブラリと一言いっても、スタティックライブラリダイナミックライブラリ.NETのクラスライブラリなどとあるのですが、比較的一般的?なダイナミックライブラリの使用方法を紹介します。

 

ダイナミックライブラリを使用するには、下記の3点セットが必要となります。

 

  • ダイナミックリンクライブラリファイル(*.dll)
  • ライブラリファイル(*.lib)
  • ヘッダファイル(インクルードファイル)(*.h)

 

各ライブラリで何のファイルが必要かは調べて置いて下さい。
*.dllファイルはプログラムの実行時、*.lib、*.hファイルはプログラミング中に必要となります。
また、ライブラリのバージョン、Release用/Debug用とでファイルが異なる場合もあります。

 

ライブラリを使用するための設定方法もいくつかあるので、私の思う一般的な方法は以下の通りです。


 

ダイナミックライブラリファイル(*.dll)の参照設定方法(環境変数Pathの設定)

 

ライブラリをインストールし、*.dllファイルがインストールされたパスを環境変数のPathに設定します。
※このPathの設定はライブラリのインストーラにより自動的に設定される場合もあります。

 

設定方法は、スタートメニューから、コンピュータを右クリックし、プロパティを選択します。

 

 

次に表示されたウィンドウのシステムの詳細設定をクリック

 

 

詳細設定のタブを選択し、右下の環境変数のボタンをクリック

 

 

すると下図のように××のユーザー環境変数システム環境変数と2種類表示され、両方ともにPathの項目があるのですが、××のユーザー環境変数のPathを設定するとWindowsにログインしたときのユーザーのみでPathの設定が有効となり、システム環境変数のPathを設定すると全ユーザーでPathの設定が有効となります。
私は『ログインしたユーザーを変えるとプログラムが起動しないんだけど?!』とか言われたく無いので、システム環境変数のPathを設定 するようにしています。
そして、Pathの項目を選択し、編集ボタンをクリックします。

 

 

そして、編集値の欄に*.dllファイルがインストールされているパス(フォルダ名のフルパス)をセミコロン(;)に続けて記載します。

 

(例)
;C:\Program Files\OpenCV\bin

 


 

また、この*.dllファイルのパスは必ずしも設定する必要はなく、プログラム(*.exe)のある同一フォルダやC:\Windows\System32フォルダ内に*.dllファイルを入れておくだけでも大丈夫なのですが、プログラムから*.dllファイルを参照するときの優先順位は下記のようになっています。

 

  1. アプリケーション(*.exe)と同じフォルダ
  2. カレントディレクトリ
  3. システムディレクトリ(C:\Windows\System32 など)
  4. 16Bitシステムディレクトリ(C:\Windows\System など)
  5. Windowsディレクトリ(C:\Windows など)
  6. PATH環境変数に列挙されているディレクトリ


 

ライブラリファイル(*.lib)の参照設定方法

各ライブラリにおいて、どの*.libファイルが必要なのかは調べておき、それぞれのファイルの参照設定を行います。

 

まずは、*.libファイルが入っているパスの参照設定を行います。
メニューのプロジェクト(プロジェクト名)のプロパティをクリックします。

 

 

開いたウィンドウの構成のプロパティ→リンカ→全般を選択し、追加のライブラリディレクトリにそのまま、*.libファイルのあるパスを設定するか、右側にある・・・のボタンをクリックします。

 

 

すると追加のライブラリディレクトリのウィンドウが表示されるので、・・・のボタンをクリックし、フォルダのボタンをクリックして*.libファイルのあるフォルダを指定します。

 

 

ライブラリによっては、参照する順番を指定しなければならない物もあるので、その場合は右上にある ↓ ↑ ボタンで順番を入れ替えます。

 

次に実際に使用する*.libファイルを設定します。
構成のプロパティ→リンカ→入力の追加の依存ファイルの部分に*.libファイルを入力します。
必要な*.libファイルがある場合は、空白(スペース)で区切って入力します。

 

 

他にもプログラム中で*.libファイルを直接していする事もできます。

 

例)
#pragma comment(lib,”C:\\Program Files\\OpenCV\\lib\\cv.lib”)

 


インクルードファイル(*.h)の参照設定方法

インクルードファイル(ヘッダファイル)(*.h)のあるパスを設定します。
設定方法は
メニューのプロジェクト→(プロジェクト名)のプロパティを クリックします。

 

構成プロパティ→C/C++→全般の追加のインクルードディレクトリの欄の右側にある・・・ボタンをクリックします。

 

 

ヘッダファイルのパスを追加設定するには右上のフォルダのアイコンをクリックします。

 

 

ボタンをクリックすると、・・・のボタンをクリックすると、ディレクトリの選択のウィンドウが表示されるので、*.hファイルが入っているパスを設定します。

 

 

そして、プログラム中では

 

#include <cv.h>

 

のように設定します。

 

C++/CLIからライブラリを使用する場合

 

.NETで作られたライブラリでは無いライブラリを使う場合は、メニューのプロジェクト→(プロジェクト名)のプロパティを クリック、構成プロパティ→全般の共通言語ランタイムサポートの欄を

 

純粋MSIL共通言語ランタイムサポート(/clr:pure)
から
共通言語ランタイムサポート(/clr)
に変更します。

 

 

その他

*.libファイル、*.hファイルの設定にはDebug用とRelease用の設定がそれぞれありますので、両方設定して下さい。
DebugとReleaseとで設定するファイル名が異なる場合もあるのでご注意下さい。

 

 

また、メニューのツール→オプションで表示されたウィンドウのプロジェクトおよびソリューション→VC++ディレクトリで、インクルードファイル(*.h)、ライブラリファイル(*.lib)の参照ディレクトリの設定が可能です。(VS2010は非推奨)
逆に言うと、ここに設定されているフォルダにインクルードファイル(*.h)やライブラリファイル(*.lib)を置いても参照する事が可能です。(個人的にはあまりやりませんが...)

 

 

トラブルシューティング

  • LINK : fatal error LNK1104: ファイル ‘×××.lib’ を開くことができません。
    fatal error C1083: include ファイルを開けません。’cv.h’: No such file or directory
    *.libファイル、*.hファイルが指定したフォルダに存在しているか?
    また、*.libファイル、*.hのファイル名が正しいか?
    確認してみて下さい。
  • fatal error C1189: #error :  ERROR: EMM intrinsics not supported in the pure mode!
    共通言語ランタイムサポートの設定/clr:pureから/clrに変更して下さい。

 

Visual Studioへ戻る

 

OpenCVとは?

OpenCVとは?

 

もともとインテルが開発したオープンソースのコンピュータビジョンライブラリ(Open Computer Vision)であり現在ではWillow Garage(ウィローガレージ)という米国のロボットの研究開発を行うベンチャー会社にて開発が行われいます。
主な機能としては一般的なフィルタ処理や行列演算を備え、顔認識処理なども比較的有名です。
サンプルプログラムも各種HPで公開されているため、容易に、しかも高速な画像処理が実現できるのも特徴です。

 

 

対応環境

OSはWindowsやLinuxなどに対応したクロスプラットフォームであり、最近ではiOSやAndroidなどても動作確認されています。
開発言語はC,C++,Pythonとなります。

 

開発履歴

バージョン 公開日 備考
1.0 2007.05.24 正式公開版初版
1.1pre1 2008.10.17
2.0 2009.10.01 C++インターフェース(cv名前空間)が登場
OpenMPによるマルチコア対応
2.1 2010.04.06 マルチコア対応がTBB(Intel Threading Building Blocks)へ変更
2.2 2010.12.05 ライブラリ構成の再編成
CUDAに暫定対応

(参考)
http://opencv.willowgarage.com/wiki/OpenCV%20Change%20Logs

 

OpenCVのライセンス

OpenCVはBSDラインセンスに基づき、商用/非商用問わず、無償で使用する事が可能です。

 

このBSDライセンスに基づきという部分がポイントなのですが、OpenCVを使用する場合には下記の著作権表示、免責事項に基づき、明示的にこの著作権表示および免責事項を原文のまま(英語のまま)表示し、その内容に従う必要があります。ソースコード公開の場合、そのソース中に、実行ファイル配布の場合はマニュアル等に含めて下さい。

 

著作権、免責事項の内容↓

IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.

 By downloading, copying, installing or using the software you agree to this license.
 If you do not agree to this license, do not download, install,
 copy or use the software.

                          License Agreement
               For Open Source Computer Vision Library

Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
Copyright (C) 2008-2009, Willow Garage Inc., all rights reserved.
Third party copyrights are property of their respective owners.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

  * Redistribution's of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.

  * Redistribution's in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

  * The name of the copyright holders may not be used to endorse or promote products
    derived from this software without specific prior written permission.

This software is provided by the copyright holders and contributors "as is" and
any express or implied warranties, including, but not limited to, the implied
warranties of merchantability and fitness for a particular purpose are disclaimed.
In no event shall the Intel Corporation or contributors be liable for any direct,
indirect, incidental, special, exemplary, or consequential damages
(including, but not limited to, procurement of substitute goods or services;
loss of use, data, or profits; or business interruption) however caused
and on any theory of liability, whether in contract, strict liability,
or tort (including negligence or otherwise) arising in any way out of
the use of this software, even if advised of the possibility of such damage.

 

この内容の実体はバージョンにより異なる場合があるので、OpenCVをインストールしたフォルダの\doc内にlicense.txtというファイルを参照下さい。

 

ただし、商用で使う場合は、一部、処理アルゴリズムにおいては、研究用途に限られるものもあるので、ご注意下さい。

例えば、SIFTアルゴリズムに関しては、特許が取得されています。

(参考)SIFT Keypoint Detector

 

OpenCVの入手先

sourceforgeより
http://sourceforge.net/projects/opencvlibrary/

Windows版
http://sourceforge.net/projects/opencvlibrary/files/opencv-win/

Unix版
http://sourceforge.net/projects/opencvlibrary/files/opencv-unix/

 

主なリンク

OpenCV Wiki
http://opencv.willowgarage.com/wiki/

OpenCV.jp
http://opencv.jp/

Yahoo Groups
http://tech.groups.yahoo.com/group/OpenCV/

 

関連書籍

オススメの書籍

 

OpenCVへ戻る

 

標準画像データベースSIDBA(Standard Image Data-BAse)

画像処理をしていると、一度は見た事があるであろう、マンドリルの画像↓

ですが、これは画像処理用の  標準画像データベースSIDBA(Standard Image Data-BAse)から用いられています。このSIDBAの画像データ入手先ですが、SIDBAで検索すると、あちこちで画像が公開されているので、どこが本家なのか?良く分かりませんが、比較的入手しやすいホームページは以下のページでしょうか...

 

※女性の画像(レナ)も有名なのですが、本人の希望により、使って欲しくないとのことなので、使用は避けましょう。
(参考)https://www.zaikei.co.jp/article/20200717/576594.html

神奈川工科大学

http://www.ess.ic.kanagawa-it.ac.jp/app_images_j.html

南カリフォルニア大学

http://sipi.usc.edu/database/

 

画像処理アルゴリズムへ戻る

 

テンプレートマッチング(template matching)

画像の中から指定した画像(テンプレート)と似ている位置を探すことを
テンプレートマッチング(template matching)と言います。

 

テンプレート 画像

 

このとき、テンプレートと画像データがどれだけ似ているか?という評価値(類似度または相違度)にはいくつかあり、次に示すような値を用います。

 

以下の式において、テンプレートの輝度値の値をT(i,j)、画像の輝度値の値をI(i,j)とします。
座標の(i,j)はテンプレートの幅をm画素、高さをn画素としたとき、左上(もしくは左下)を(0,0)、右下(もしくは右上)を(m-1、n-1)とします。

 

SSD(Sum of Squared Difference)

SSDはテンプレートをラスタスキャンし、同じ位置の画素の輝度値の差の2乗の合計が用いられます。
SSDの値が小さいほど、似ている位置となります。

 

SAD(Sum of Absolute Difference)

SADはテンプレートをラスタスキャンし、同じ位置の画素の輝度値の差の絶対値の合計が用いられます。
SADの値が小さいほど、似ている位置となります。

 

正規化相互相関【NCC:Normalized Cross-Correlation】

テンプレートと画像との類似度として、以下の正規化相互相関を用いられる場合もあります。類似度が1に近いほど、似ている位置となります。

 

ちなみに、この計算式は内積の式をCosθ = の式に変形した式と同じ事にお気づきでしょうか?上式を以下のように変形すると、M×N次元のIのベクトルとTのベクトルの内積に見えてきませんか?

 

 

正規化相互相関【ZNCC:Zero-mean Normalized Cross-Correlation】

上記NCCの相互相関係数ではテンプレートや画像の明るさが変動すると、NCCの値もふらついてしまうので、テンプレートおよび画像の輝度値の平均値をそれぞれの値から引いて計算することで、明るさの変動があっても安定的に類似度を計算することができます。

ここで、この式はテンプレートの領域内の輝度値の平均値を計算してから、さらに輝度値から平均値を引くため、標準偏差の時にも説明したように、この式でそのままプログラミングすると効率の悪いプログラムとなってしまいます。そのため、今回も同様にRZNCCの式を変形します。

 

テンプレートの平均輝度値およびテンプレートと同じ領域の画像の輝度値の平均は

 

 

で求まることから、この値をRZNCCの式に代入して整理すると、

となります。この式を用いると、プログラム的には1パスで済むでの計算効率が良くなります。

 

ΣΣ×××の部分がなんだか難しく見える方は、C言語に置き換えて

 

Sum = 0;
for(j = 0; j < N; j++){
for(i = 0; i < M; i++){
Sum += ×××;
}
}

 

と置き換えて読んで下さい。

 

ここで説明しておきながら、最近の工業用途では、この正規化相関の方法よりもパターンの輪郭に基づき、回転やスケール変動などにも対応したマッチング(輪郭サーチ)が一般的になってきています。

最近では、さらにカメラが動いてもマッチングする三次元マッチングなども登場してきています。
正規化相関では明るさの変動にも強く優れたアルゴリズムのように聞こえるかもしれませんが、パターンが重なった場合や欠けた場合に意外と弱かったりもします。

 

また、このテンプレートマッチングでは、テンプレートと画像を重ね合わせたとき、同じ画素の位置の輝度値が明暗がどれだけ似ているか?という事を評価しています。
そのため、例えば顔写真を登録しておいて、撮影した画像の中から似ている人を見つけ出す!みたいな使い方はできません。
人間の感性での似ている事とはズレがある事に注意して下さい。

 

画像処理アルゴリズムへ戻る

 

疑似カラー(Pseudo-color)

三次元データやサーモグラフィのようにデータを画像にした場合には、モノクロで表示するよりも、色を付けて表示した方が見やすい場合があります。

 

モノクロ表示 疑似カラー表示

 

このグレーの色に疑似的に色を付ける方法を疑似カラー(Pseudo-color)と言います。この色の付け方は色相を使って青~緑~赤へと変化させてもいいのですが、もう少し簡単な方法を紹介します。
青~緑~赤~青へと色を変化させるには以下のようなパターンでR,G,Bの値を変化させます。

 

 

このパターンは青~緑~赤~青の色相で言うと一周分なので、一般的に用いられるのは青~緑~赤ぐらいまでなので、上図の0~240°部分を8Bitの輝度値に割り当て

 

 

のようにすると、このようなグレースケール↓に

 

疑似カラーを割りつけると、このように↓なります。

 

このようにクレースケールにカラーを割り当てることで、より画像を見やすくしています。モノクロ8Bitの画像データの場合は、画像データはそのままに、カラーテーブルを変更するだけで、疑似カラー表示する事が出来ます。

 

画像処理アルゴリズムへ戻る

 

色相、彩度、明度の計算方法

色相Hue:色合い)、彩度Saturation:鮮やかさ)、明度Brightness,Lightness,Intensity,Value:明るさ)については、以前、変換式には色相、彩度、明度ほかのページにまとめたのですが、実は訳も分からず公式だけをまとめていました。

 

で、なんだか気持ちが悪かったので色相、彩度、明度について、よ~く調べてみました。
私なりの理解ですが、以下にまとめました。

 

R、G、Bの色空間については、下図のようにRGBをXYZのように三次元座標で表すと、一辺の長さが255で表される立方体の範囲内で全ての色を表す事が出来ます。(R,G,B各8bitの場合)

 

この立方体を白(255、255、255)に位置から黒(0、0、0)の方向へ見て、R軸を右側に取ると、

 

 

のように、正六角形となります。
この時、の方向を0°として、反時計回りにの位置が120°240°色相(0~360°(2π))を定めます。
彩度は一番外側の六角形に対して、どの割合の位置に配されているかを0~1.0で表したものが彩度となります。

 

詳細は後述しますが、色相彩度はカメラやパソコンなどの性能評価(使いやすさ、価格、処理速度など)を表す時に用いるレーダーチャート(クモの巣グラフ)もどきみたいな物?!と思うと、自分の中で少し整理ができました。

 

さらに、この六角形の高さ方法に明度を割り振ると、HSV(六角錐モデル)やHLS(双六角錐モデル)となります。
それぞれの違いは明度の定義が異なり、R、G、Bの最大輝度値をImax、最小輝度値をIminとしたときに

明度V = Imax

としたものがHSV

明度L = ( Imax + Imin ) / 2

としたものがHLSとなり、明度の値は0~1.0で表されます。

これを立体で表すと

 

HSV(六角錐モデル)

HLS(双六角錐モデル)

となります。
このHSV、HLSともに、六角錐の斜面の部分が彩度が1.0となります。

 

以下、色相、彩度、明度の詳細な計算方法です。

 

HSVの計算方法

はじめにR、G、Bの輝度値の範囲を0~255から0~1.0となるように変換します。
(R、G、Bのそれぞれの値を255で割ります。)

 

【色相Hの求め方】
下図のように、0°方向にR、120°方向にG、240°方向にBだけ進み、最後の点の位置のR軸に対する角度が色相となります。

 

 

この最後の点の座標は中心を(x、y) = (0、0) とすると、R、G、Bの方向のなす角度から

 

 

となり、xとyより色相Hが求まります。

 

 

ただし、アークタンジェントの計算が出来ない場合など、この方法とは別に、近似的に求める方法もあります。(こちらの方が一般的)

 

下図を見ても分かる?ようにR、G、Bの成分の比を比べ、

Rが最大の場合、色相は-60°(300°)~60° (R方向の0°±60°)
Gが最大の場合、色相は 60°~180° (G方向の120°±60°)
Bが最大の場合、色相は 180°~300° (B方向の240°±60°)

の範囲内に色相は収まります。

 

 

以下、Rの値が最大の場合を例に取って説明したいと思います。

 

下図のように、2つの矢印の長さが分かれば、その矢印の比で角度60°を分割することで、角度(色相)を近似することが出来ます。

 

 

R、G、Bの大きさがR≧G≧Bの場合

 

色相H = 60° × (G – B) / (R – B)

R、G、Bの大きさがR≧B≧Gの場合

 

色相H = 60° × (G – B) / (R – G)

 

となります。
ただし、この場合、色相の値が負となるので、

 

色相H = 60° × (G – B) / (R – G) + 360°

 

とします。

 

と、なる理屈を理解するのに苦労しました...
図中に書いてある黄色い正三角形がポイント!
正三角形なので、三辺の長さが等しい分けで。
R以外のGやBが最大となる場合も理屈は同じです。
120°づつ回転させて考えてみると分かります。

 

この式を一般的に書くと、R、G、Bの成分のうち、最大の成分をImax、最小の成分をIminとすると

ImaxがRのとき

ImaxがGのとき

ImaxがBのとき

となります。

 

【明度Vの求め方】

明度は、もともとHSVの定義よりR、G、Bの成分のうち、最大の成分をImaxとすると

明度V = Imax

 

とします。
明度Vの範囲は0~1.0となります。

 

【彩度Sの求め方】
R、G、Bの成分のうち、最大の成分をImax、最小の成分をIminとすると

 

彩度S = (Imax – Imin) / Imax

 

となります。
彩度Sの範囲は0~1.0となります。

 

 

HLSの計算方法

【色相Hの求め方】
色相HはHSVの色相Hの求め方と同じです。

 

【明度Lの求め方】
明度Lは、もともとHLSの定義よりR、G、Bの成分のうち、最大の成分をImaxとすると

 

明度L = ( Imax + Imin ) / 2

 

とします。
明度Lの範囲は0~1.0となります。

 

【彩度Sの求め方】
R、G、Bの成分のうち、最大の成分をImax、最小の成分をIminとすると

 

L≦0.5のとき

彩度S = (Imax – Imin) / (Imax + Imin)

L>0.5のとき

彩度S = (Imax – Imin) / (2 – Imax – Imin)

 

となります。
彩度Sの範囲は0~1.0となります。

 

以下、補足説明です。
彩度Sは下図の外側の六角形に対して、内側の六角形の大きさの割合で求められます。

 

 

この六角形の大きさはR,G,Bの輝度値が最大となる軸上で考えると比較的分かりやすいと思います。
今回はRの値が最大となる場合とします。

 

HLSは双六角錐モデルであるため、明度Lが0.5以下の場合、外側の六角形の大きさ(上図のE’の位置)は

 

E’ = Imax + Imin

 

で求まります。

 

 

明度Lが0.5より大きい場合、外側の六角形の大きさ(上図のE’の位置)は

 

E’ = 2 – Imax – Imin

 

となります。

 

 

以上のことから、最初の彩度Sの式が求まります。

 

色相、彩度、明度を使った色判別時の注意点

色相および彩度を用いると、画像の明るさ(明度)が変動しても似た色の領域を抽出する事が可能となりますが、彩度の値が小さい場合、つまりR、G、Bの値がそれぞれ近い場合は色相の値が不安定になります。

 

例えば、
(R、G、B) = (121、120、120)の場合、 色相H = 0°
(R、G、B) = (120、121、120)の場合、 色相H = 120°
(R、G、B) = (120、120、121)の場合、 色相H = 240°

 

と、ほんの少しのR、G、Bの値の違いでも色相の値は大きく異なります。

 

また、色相Hは角度で表されるので、例えば1°も359°も値こそ離れていますが、どちらも0°±1°の範囲内で角度的には近いので、色相Hの値で単純に二値化処理することで色の領域を抽出する場合は注意して下さい。

 

画像処理アルゴリズムへ戻る

 

色相、彩度、明度の公式

カラーの画像処理をする時には、これら色相などの知識は必須となります。
Windows標準で付いてくるペイントで、色の作成の表示をすると、雰囲気が分かると思います。

 

 

基本的に以下の色相、彩度、明度を用いて色を表すのですが、変換式にいくつかの種類があります。

 

色相(Hue)

色合いを表します。
赤や緑、青などに色を0~360°(0~2π)の角度を用いて表します。

彩度(Saturation)

鮮やかさを表します。
と一般的に言われるのですが、鮮やかさ?と言われても、いまいちピンと来ませんが、下記に示した式から見ても分かるように、R,G,Bの値にどれだけ開きがあるか?を示しています。
このことは逆にいうと、R,G,Bの値に開きが無い場合は、グレーに近い事から、彩度は如何にグレーっぽく無いか?、という事から、どれだけ純色(赤、緑、青、黄、シアン、紫など)に近いか?を表しています。

明度(Brightness,Lightness,Intensity,Value)

色の明るさを表します。

 

HSV変換

6角錐モデルとも言います。

 

【RGB⇒HSV変換】

Imax = Max(R,G,B)
Imin = Min(R,G,B)
とすると

 

R = Imaxのとき

H = 60×(G – B) / (Imax – Imin)

G = Imaxのとき

H = 60×(B – R) / (Imax – Imin) + 120

B = Imaxのとき

H = 60×(R – G) / (Imax – Imin) + 240


S = (Imax – Imin) / Imax


V = Imax


【HSV⇒RGB変換】

h = floor(H / 60)     floor()は切り捨て処理
P = V × (1 – S)
Q = V × (1 – S × (H / 60 – h))
T = V × (1 – S × (1 – H / 60 + h))
とすると

 

h= 0のとき

R = V, G = T, B = P

h= 1のとき

R = Q, G = V, B = P

h= 2のとき

R = P, G = V, B = T

h= 3のとき

R = P, G = Q, B = V

h= 4のとき

R = T, G = P, B = V

h= 5のとき

R = V, G = P, B = Q


HLS変換

双6角錐モデルとも言います。

 

【RGB⇒HLS変換】

Imax = Max(R,G,B)
Imin = Min(R,G,B)
とすると

 

R = Imaxのとき

H = 60×(G – B) / (Imax – Imin)

G = Imaxのとき

H = 60×(B – R) / (Imax – Imin) + 120

R = Imaxのとき

H = 60×(R – G) / (Imax – Imin) + 240


L = (Imax + Imin) / 2

L ≦ 0.5のとき

S = (Imax – Imin) / (Imax + Imin)

L > 0.5のとき

S = (Imax – Imin) / (2 – Imax – Imin)


【HLS⇒RGB変換】

h < 0のとき

h’ = h  + 360

h ≧ 360のとき

h’ = h  – 360

その他

h’ = h

L ≦ 0.5のとき

M2 = L × (1 + S)

L > 0.5のとき

M2 = L + S – L × S


M1 = 2 × L – M2


h’ < 60のとき

X = M1 + (M2 – M1) × h’ / 60

60 ≦ h’ < 180のとき

X = M2

180 ≦ h’ < 240のとき

X = M1 + (M2 – M1) × (240 – h’ ) / 60

240 ≦ h’ ≦ 360のとき

X = M1

 

とすると

 

R = X ただし、h = H + 120とする

G = X ただし、h = Hとする

B = X ただし、h = H – 120とする

 

カラー変換用関数

【Win32APIの場合】 VBの表記例
‘HLS変換(Windows 2000以降、またはInternet Explorer 5.0がインストールされてある環境。(SHLWAPI.DLL Version 5.00以上)
‘h (色相)
‘赤(0)、黄(40)、緑(80)、シアン(120)、青(160)、マゼンダ(200)の順に定義0~239まで設定可
‘L (明度)
‘色の明るさをあらわす。0~240まで設定可。0が黒、240が白になる。
‘s (彩度)
‘0~240まで設定可。240が純色になる。
Public Declare Sub ColorRGBToHLS Lib “SHLWAPI.DLL” _

(ByVal clrRGB As Long, _
pwHue As Integer, _
pwLuminance As Integer, _
pwSaturation As Integer)

Public Declare Function ColorHLSToRGB Lib “SHLWAPI.DLL” _

(ByVal wHue As Integer, _
ByVal wLuminance As Integer, _
ByVal wSaturation As Integer) As Long

 

最初に紹介したペイントの色の作成では、この関数と同様の変換(設定値を含めて同じ)をしています。

 

【.NET Frameworkの場合】
System.Drawing.Color構造体にて

GetHueメソッド      HSBのH(色相)を取得
GetSaturationメソッド   HSBのS(彩度)を取得
GetBrightnessメソッド   HSBのB(明度)を取得

RGB⇒HSB変換はなし?

 

【OpenCVの場合】
cvCvtColor関数にて、以下の変換に対応
XYZ, YCrCb(YCC), HSV, HLS, L*a*b, L*u*v
その他 同じcvCvtColor関数で Bayer変換に対応

 

カラー画像処理例

そのカラー画像を色相、彩度、明度に分解し、それぞれの値(主に色相)でフィルタリング処理(バンドパスフィルタ)を行い、カラー画像に逆変換する事により、特定の色だけを抽出する事が可能になります。これにより、色の位置や個数などの検査をする事が可能となります。

処理前 処理後

ただし、彩度の値の小さな色(白やグレーに近い色)は彩度の値が不安的になりがちなので、カラー画像処理には不向きです。

 

画像処理アルゴリズムへ戻る

 

外周画像の処理

平滑化フィルタやメディアンフィルタなどの注目画素の周辺画素を用いた画像フィルタ処理では、画像の外周部分が下図のように画像の外側を参照してしまうため、処理ができなくなります。

 

 

この外周部分を処理する方法はいくつかあるのですが、代表的な方法を紹介します。
以下、5×5サイズのカーネルを用いた場合の処理を例にとって紹介します。

 

■外周部分の輝度値を画像の外側にコピーして補間する方法

5×5サイズのカーネルの場合、画像の外側に2画素分、画像の輝度値を参照
してしまうので、この2画素分の輝度値を画像の外周部分の輝度値をコピーして
輝度値を参照します。

 

おそらく?この手法が一般的だと思います。

 

■外周部分を中心にして対称の位置にある輝度値を外側にコピーして補間する方法

例えば、カーネルが座標(-1、-2)の画素を参照する場合は座標(1、2)の画素の輝度値を参照するようにします。

 

 

他にも、単純に外周部分は処理をしないで黒(輝度値=0)でマスクしたり、カーネルが画像の外側を参照する場合にカーネルを形を変えて画像の外側を参照しないようにしたりする方法などもあります。

 

画像処理アルゴリズムへ戻る

 

画像の回転

画像を回転する場合、任意点周りの回転移動でも紹介したように回転行列を使って、例えば、画像の中心周りに画像を回転させると、下図のように回転後の画像が虫食い状態になってしまいます。

 

回転前の画像 回転後の画像

 

こうならないようにするためには、回転前の画像の座標を回転行列を使って回転後の座標を計算するのではなく、回転後の座標が回転前の画像のどの座標を参照しているのかを計算し、画像を変換します。

つまり、画素を置きに行くのではなく、拾いに行くようにします。

 

【回転前の画像を回転行列を使って変換】

 

【回転後の座標が回転前のどの座標を参照しているかを計算して変換】

 

実際の変換処理は以下のように行います。

 

回転前の画像の座標を(x,y)、回転後の画像の座標を(X,Y)、画像の中心座標を(Cx,Cy)とすると単純に画像の中心周りに座標を回転すると以下のような行列で表されます。

 

 

この行列を回転前の画像の座標(x、y)に関して解けばいいので、行列の式の両辺にそれぞれ逆行列をかければいいので、以下のような手順で行列を解いていきます。

 

これで、回転前の座標(x、y)に関して解くことができます。
でも、逆行列を解くのは面倒と思う事なかれ。
(+Cx,+Cy)の平行移動の逆行列は(-Cx、-Cy)方向への移動と同じ、+θ方向への回転の逆行列は-θ方向への回転と同じなので、

 

 

とすれば、逆行列を解くことなく回転後の座標(x、y)に関して座標を解くことができます。
このようにして画像の回転処理を行うと、このようになります。

 

回転前の画像 回転後の画像

 

でも、回転後の画像はなんかギザギザしてしまっていますが、これは回転前の画像の座標を計算するとほとんどの場合、画素の画素の間の座標となってしまいますが、上図の例ではこの座標を四捨五入して輝度値を参照しているためで、bilinearやbicubicなどの補間を使うと少しは滑らかな画像となります。

今回は画像の回転について紹介していますが、画像の拡大縮小についても同様の考え方で処理することができます。

 

画像処理アルゴリズムへ戻る

 

関連記事

アフィン変換(平行移動、拡大縮小、回転、スキュー行列)

任意点周りの回転移動(アフィン変換)

画素の補間(Nearest neighbor,Bilinear,Bicubic)の計算方法

アフィン変換(平行移動、拡大縮小、回転、スキュー行列)

画像の拡大縮小、回転、平行移動などを行列を使って座標を変換する事をアフィン変換と呼びます。

X,Y座標の二次元データをアフィン変換するには、変換前の座標を(x, y)、変換後の座標を(x’,y’)とすると回転や拡大縮小用の2行2列の行列と、平行移動用に2行1列の行列を使って

$$\left(\begin{array}{c}x^{‘}\\ y^{‘}\end{array}\right)=
\left(\begin{array}{c}a & b\\ c & d\end{array}\right)
\left(\begin{array}{c}x\\ y\end{array}\right)
+ \left(\begin{array}{c}T_{x}\\ T_{y}\end{array}\right)$$

のように表現される場合もありますが、回転、拡大縮小、平行移動を1つの3x3の行列にまとめて

$$\left(\begin{array}{c}x^{‘}\\ y^{‘} \\ 1\end{array}\right)=
\left(\begin{array}{c}a & b & c\\ d & e & f\\ 0 & 0 & 1\end{array}\right)
\left(\begin{array}{c}x\\ y\\ 1\end{array}\right)$$

と3x3の行列で表現する場合もあります。

この表現を同次座標系と呼びます。

同次座標系では一見、3行目は無駄なようにも見えるのですが、この意味の無いような1行を追加する事で、平行移動も同じ行列の積で表現でき、逆行列を使う事で、アフィン変換後の座標からアフィン変換前の座標も簡単に求める事ができるようになります。

私は3行3列の行列を用いた同次座標系のアフィン変換しかしていない、というか断然おススメなので、同次座標系で説明したいと思います。

後半でアフィン変換の実用例を示しているので、その部分で、同次座標系の恩恵を感じてもらえると嬉しいです。

 

変換前の画像を以下のようにすると、

各種変換は以下の通りとなります。

 

拡大縮小

X軸方向の拡大率をSx、Y軸方向の拡大率をSyとすると拡大縮小のアフィン変換は

 

 

と表されます。

 

例)X軸方向に2倍

 

例)Y軸方向に2倍

 

例)X軸、Y軸方向に2倍

 

例)Y軸方向に-1倍

このように、ある軸(上記の例ではX軸)に対して反転する処理の事を鏡映と呼びます。

 

平行移動

X軸方向にTx、Y軸方向にTyだけ移動するアフィン変換は

 

 

のように表されます。

 

 

回転

原点を中心に反時計回りにθ°回転する時のアフィン変換は

 

 

のように表されます。

 

 

スキュー(せん断)

四角形の画像を平行四辺形に変形する処理をスキューまたはせん断といいます。
このアフィン変換は

 

 

アフィン変換の実用方法

画像処理で使われるアフィン変換は、下図のようにピクチャボックスなどの左上が原点[座標が(0, 0)]で右方向が+X、下方向が+Y、時計周りが+θ方向となる場合が多いかと思います。

また、平行移動、拡大縮小、回転などの行列を紹介しましたが、これらの行列を1回だけで処理する事はまれで、それぞれの行列を組み合わせてアフィン変換を行います。
さらに、拡大縮小、回転、スキューのアフィン変換行列は、あくまでも原点を基点として、変換される事に注意が必要です。

例えば、画像が原点の位置に無い場合、画像をX,Y方向に2倍の大きさにしようとしたとき、単に拡大縮小のアフィン変換行列で座標を計算すると、表示位置も2倍、原点の位置から離れた位置に移動します。

これらの事を踏まえ、画像を幅方向に2倍、高さ方向に3倍し、画像を反時計方向に90°回転、さらに、画像の左上の座標が(50, 50)から(30,180)へ移動するアフィン変換を例題にとって考えたいと思います。

この変換は、一発で変換するアフィン変換行列を考えるのではなく、平行移動拡大縮小回転に分けて、アフィン変換の順番を考えます。


拡大縮小と回転が原点を基点とするため、画像を原点の位置へ移動するため、x方向に-50、y方向に-50の平行移動します。

平行移動のアフィン変換行列は

$$\begin{pmatrix} 1 & 0 & -50 \\ 0 & 1 & -50 \\ 0 & 0 & 1 \end{pmatrix}$$


拡大縮小か回転のどちらからでも構いませんが、x方向に2倍、y方向に3倍の拡大縮小を行います。

拡大縮小のアフィン変換行列は

$$\begin{pmatrix} 2 & 0 & 0 \\ 0 & 3 & 0 \\ 0 & 0 & 1 \end{pmatrix}$$


反時計周りに90°回転(ー90°回転)を行います。

回転のアフィン変換行列は

$$\begin{pmatrix} cos(-90) & -sin(-90) & 0 \\ sin(-90) & cos(-90) & 0 \\ 0 & 0 & 1 \end{pmatrix}$$


最後に目的の位置へ移動するのに、x方向に+30、y方向に+180の平行移動します。

平行移動のアフィン変換行列は

$$\begin{pmatrix} 1 & 0 & 30 \\ 0 & 1 & 180 \\ 0 & 0 & 1 \end{pmatrix}$$


このようにアフィン変換を平行移動、拡大縮小、回転に分解して、変換の手順を考える事が大事です。
今回の場合は

変換前 → 平行移動 → 拡大縮小 → 回転 → 平行移動 → 変換後

としています。

画像に対してアフィン変換を行う場合、考え方としては、平行移動や拡大縮小などに分解して考えますが、画像データを毎回変換するのではなく、アフィン変換行列をまとめて計算し、一発でアフィン変換処理を行います。

具体的には、今回のアフィン変換処理を行列で表すと

$$\begin{pmatrix} { x }^{ ‘ } \\ { y }^{ ‘ } \\ 1 \end{pmatrix}=\begin{pmatrix} 1 & 0 & 30 \\ 0 & 1 & 180 \\ 0 & 0 & 1 \end{pmatrix}\begin{pmatrix} cos(-90) & -sin(-90) & 0 \\ sin(-90) & cos(-90) & 0 \\ 0 & 0 & 1 \end{pmatrix}\begin{pmatrix} 2 & 0 & 0 \\ 0 & 3 & 0 \\ 0 & 0 & 1 \end{pmatrix}\begin{pmatrix} 1 & 0 & -50 \\ 0 & 1 & -50 \\ 0 & 0 & 1 \end{pmatrix}\begin{pmatrix} x \\ y \\ 1 \end{pmatrix}$$

行列部分をまとめて計算し

$$\begin{pmatrix} { x }^{ ‘ } \\ { y }^{ ‘ } \\ 1 \end{pmatrix}=\begin{pmatrix} 0 & 3 & -120 \\ -2 & 0 & 280 \\ 0 & 0 & 1 \end{pmatrix}\begin{pmatrix} x \\ y \\ 1 \end{pmatrix}$$

となり、アフィン変換行列を一発で処理する事ができます。

さらに、変換後の座標(x’, y’)から、変換前の座標(x, y)を求める場合があるのですが、その時は、行列の左側からアフィン変換行列の逆行列を掛けて、

$$\begin{pmatrix} 0 & 3 & -120 \\ -2 & 0 & 280 \\ 0 & 0 & 1 \end{pmatrix}^{ -1 }\begin{pmatrix} { x }^{ ‘ } \\ { y }^{ ‘ } \\ 1 \end{pmatrix}=\begin{pmatrix} 0 & 3 & -120 \\ -2 & 0 & 280 \\ 0 & 0 & 1 \end{pmatrix}^{ -1 }\begin{pmatrix} 0 & 3 & -120 \\ -2 & 0 & 280 \\ 0 & 0 & 1 \end{pmatrix}\begin{pmatrix} x \\ y \\ 1 \end{pmatrix}$$

$$\begin{pmatrix} x \\ y \\ 1 \end{pmatrix}=\begin{pmatrix} 0 & 3 & -120 \\ -2 & 0 & 280 \\ 0 & 0 & 1 \end{pmatrix}^{ -1 }\begin{pmatrix} { x }^{ ‘ } \\ { y }^{ ‘ } \\ 1 \end{pmatrix}$$

$$\begin{pmatrix} x \\ y \\ 1 \end{pmatrix}=\begin{pmatrix} 0 & -0.5 & 140 \\ 0.333 & 0 & 40 \\ 0 & 0 & 1 \end{pmatrix}\begin{pmatrix} { x }^{ ‘ } \\ { y }^{ ‘ } \\ 1 \end{pmatrix}$$

として、変換前の座標を求める事ができます。

まとめ

  • アフィン変換は平行移動、拡大縮小、回転、スキューに分けて、変換の順番を考える
  • 実際のアフィン変換は、アフィン変換行列をまとめて計算し、一発で処理を行う
  • 変換前の座標は逆行列を使うと、求めることができる

この順番の考え方は、ほとんどの場合、画像を原点へ平行移動し、拡大縮小、回転を行ってから、目的の位置へ移動すると、アフィン変換行列が求まりますが、他にも、特定の点を基準に拡大縮小や回転を行う場合は、その点を原点へ移動すればアフィン変換行列が求まります。

(参考)

 

注意点

アフィン変換では任意の3×3(2×3)の行列で表す事ができるので、任意形状に変換できそうにも思えるのですが、四角形が平行四辺形にまでは変形できるものの、台形には変形できないのでご注意願います。
この台形に変形できる処理は射影変換(ホモグラフィ)と呼びます。

アフィン変換は今回の説明のように、画像を移動、変形させるための手法として説明されますが、もう少し汎用的に座標変換として捉えると応用範囲が広がります。

例えば、データのグラフを表示する時に、横方向、縦方向に拡大/縮小した時に、表示するデータの範囲を求める場合などに応用すると、少し便利です。

 

画像処理アルゴリズムへ戻る

 

関連記事

実際にOpenCVを使って行うアフィン変換については、こちらのページ↓にまとめました。

【OpenCV-Python】アフィン変換(同次座標系を使用)

 

マイクロソフトの.NETやDirectXで扱うアフィン変換行列は、行と列が逆になり、行列を掛ける順番も逆(右側から掛ける)になります。
この仕様については、下記ページ↓にまとめました。

【C#.NET】マイクロソフト仕様のアフィン変換

画素の補間(Nearest neighbor,Bilinear,Bicubic)の計算方法

画像を拡大や回転する場合など、画像の画素と画素の間の輝度値を参照する必要が出てきますが、その参照方法を紹介します。
この画素を画素の間を参照する事を一般に補間内挿(Interpolation)と言います。

 

最近傍補間(ニアレストネイバー Nearest neighbor)

Nearest neighborをそのまま訳すと、最も近いご近所、という事で参照する位置に最も近い位置にある画素の輝度値を参照します。

 

 

求める画素間の座標が(x,y)の位置の輝度値を Dst(x,y) とし、もともとの画像の輝度値をSrc(i,j) とすると

 

 

で表されます。(ただし、[  ] は小数部分の切り捨てを表します。)
つまるとこ、座標を四捨五入し、その画素の輝度値を参照します。

 

双一次補間(バイリニア補間 Bilinear)

バイリニア補間では求める位置(x,y)の周辺の2×2画素(4画素)を使って、輝度値を直線的に補間して、輝度値を求めます。

 

直線的に補間する方法は、たとえば下図のようにX座標が180と181の2点間の180.8の位置の輝度値を求めるのは、2点の位置の輝度値の比から簡単に求まります。

 

 

この処理を手前の2点間、奥の2点間についてX軸方向に補間処理を行い、さらに補間した2点の輝度値を用いて、さらにY軸方向に補間処理することで、目的の輝度値を求めます。
(Y軸方向から先に処理を行っても結果は同じです。)

 

ちなみに、このBilinearの接頭語のbi-ですが、『二つの、双方向』というような意味があるそうです。
ということで、双方向からリニア(直線的)に補間したのが、このBilinearで、次に出てくるBicubicは双方向から三次関数で補間したのが、Bicubicです。

 

 

この補間処理を式で表すと、

 

 

となります。

 

双三次補間(バイキュビック補間 Bicubic)

バイキュービック補間では求める位置(x,y)の周辺の4×4画素(16画素)を使って、輝度値を三次式で補間して輝度値を求めます。

 

 

この変換を式で書くと

 

 

となります。

 

ただし、Src(i,j)は求める座標(x,y)の周辺の輝度値を表し、下図のような配置とします。

 

 

また、1、X2、X3、X4、Y1、Y2、Y3、Y4 は求める位置から参照する画素までの距離を表し、

 

 

と定義します。
関数h(t)はsinc関数(sinc(t) = sin(πt)/πt) をテイラー展開により三次の項まで近似した関数で

 

 

だそうで...(詳細は良く分かってません。)
の値には-1前後がよく用いられます。

 

まとめ

各補間方法を使って、画像を拡大表示すると以下のようになります。

 

【元の画像】

 

赤い四角の部分を拡大表示します。

 

【Nearest neighbor】

 

【Bilinear】

 

【Bicubic】

 

これらの画像を見ても分かるようにNearest neighbor⇒Bilinear⇒Bicubicの順でギザギザなのがなめらかに拡大表示されます。

 

この変換を1次元的に輝度値のグラフで見てみると

 

 

となります。
ここで注意しないといけないのが、Bicubic補間がおおむね滑らかに輝度値を補間することが
できますが、最後のグラフを見ても分かるように、輝度値がオーバーシュート(アンダーシュート)ぎみ
になる場合があります。その場合は補間の式の  の値を -0.2 程度のよりに近い値に
すると回避することができます。

 

画像処理アルゴリズムへ戻る