簡単な画像処理フィルタの実装 - mist-team/mist GitHub Wiki
本チュートリアルでは,MISTのアルゴリズムを利用して,しきい値処理フィルタを実装してみましょう.
MISTでは,しきい値を決定するアルゴリズム(Pタイル法,判別分析法)の2種類を用意しています. これらのアルゴリズムは,しきい値を決定するだけなので,実際にしきい値処理を行う関数を実装してみたいと思います.
まずは,データを格納するMISTコンテナを準備しましょう.
#include <mist/mist.h>
さらに,今回はしきい値処理を行うために次のヘッダもインクルードします.
#include <mist/threshold.h>
今回実装するしきい値処理フィルタでは,入力となる画像がどのようなものかわかりません. つまり,どんなデータ型(double とか unsigned int とか・・・)の画像がくるかわからないということです. そこで,C++のテンプレート関数という機能を利用し,どんな画像がきてもちゃんと動作するようにしてみましょう.
MISTのコンテナを受け取るテンプレートの書き方には,大きく分けて3種類ほどあります.
コンテナを指定して入力とする
template< class T, class Allocator >
void func( mist::array2< T, Allocator > &image ){ ... }
MISTのどんなコンテナが来ても当てはまるようにする
template< class T, class Allocator >
void func( mist::array< T, Allocator > &image ){ ... }
どんなコンテナが来ても当てはまるようにする
template< class Array >
void func( Array &image ){ ... }
ここで,3番目の書き方をした場合には,Array というものがどんな型でも受け付けてしまうため,関数 func を呼び出すときには注意が必要です. たとえば,
func( "あいうえお" );
という呼び出しも受け付けてしまうということです.
今回は,しきい値処理なので,何次元の画像が入力されても同じ処理で実現できるため,2番の方法で実装してみることにします. 関数の雛形はこんな感じになります.
template< class T, class Allocator >
void thresholding( mist::array< T, Allocator > &data )
{
typedef typename mist::array< T, Allocator >::size_type size_type;
typedef typename mist::array< T, Allocator >::value_type value_type;
}
ここで,関数の内部で size_type と value_type というものを定義しています. これは,MISTコンテナの要素の型を識別するために必要です.
テンプレート関数がどんなものかわかったら,実際にしきい値処理を行う関数を実装してみましょう. MISTで用意しているしきい値決定アルゴリズムのうち,今回は判別分析法を利用します. 判別分析法は,名前空間 mist::discriminant_analysis の中で次のように定義されています.
template < class T, class Allocator >
array< T, Allocator >::value_type threshold( const array< T, Allocator > &in )
要するに,何らかの音声・画像データを受け取り,判別分析法を行ってしきい値を返すというものです. それがわかれば,しきい値処理なんて簡単です. 入力された音声・画像データを入力して,しきい値を得ればいいわけなので,次のように書けます.
value_type th = mist::discriminant_analysis::threshold( data );
ここで,戻り値を value_type 型で受けていることに注意してください. これは,入力されるコンテナのデータ型がわからない(テンプレートなので,どんな型が入ってくるかわからない)ためです. そこで,こうしておくことによりコンテナのデータ型が識別できて,キャストをする必要がなくなります(というのも,しきい値選択のアルゴリズムの戻り値がそうなっているため).
あとは,このしきい値未満のデータを 0 にし,それ以外を 1 にすれば良いわけです. まとめると,次のような関数が出来上がります.
template< class T, class Allocator >
void thresholding( mist::array< T, Allocator > &data )
{
typedef typename mist::array< T, Allocator >::size_type size_type;
typedef typename mist::array< T, Allocator >::value_type value_type;
value_type th = mist::discriminant_analysis::threshold( data );
for( size_type i = 0 ; i < data.size( ) ; i++ )
{
if( data[ i ] < th )
{
data[ i ] = 0;
}
else
{
data[ i ] = 1;
}
}
}
今回実装したしきい値処理関数を用いて,画像を2値化してみましょう. まずは,画像を読み込む処理が必要になるので,画像の入出力 を呼んで画像の入出力関数を実装してみましょう. ただし,入力画像をカラー画像として読み込むとエラーが出るので注意してください(というのも,カラー画像に対してしきい値を決定することができないためです). また,今回実装したしきい値処理関数の出力は 0 と 1 であるため,そのまま画像を保存しても何にも表示されないと思います. 今回は,画像を表示するために,しきい値処理の出力が 0 と 255 になるようにしてみましょう!!
#include <iostream>
// MISTの一番メインとなるヘッダファイル
// 1・2・3次元画像を扱うコンテナが用意されてます
#include <mist/mist.h>
// しきい値選択を行うためのアルゴリズムが用意されてます
#include <mist/threshold.h>
// ファイルから画像を読み込んでMISTで提供するコンテナにデータを格納します
// サポートされている形式は
// JPEG, PNG, TIFF, BMP, PNM です
#include <mist/io/image.h>
template< class T, class Allocator >
void thresholding( mist::array< T, Allocator > &data )
{
typedef typename mist::array< T, Allocator >::size_type size_type;
typedef typename mist::array< T, Allocator >::value_type value_type;
value_type th = mist::discriminant_analysis::threshold( data );
for( size_type i = 0 ; i < data.size( ) ; i++ )
{
if( data[ i ] < th )
{
data[ i ] = 0;
}
else
{
data[ i ] = 255;
}
}
}
int main( int argc, char *argv[ ] )
{
if( argc < 2 )
{
std::cout << "入力画像のファイル名が必要です!!" << std::endl;
}
// mist::???? という風にMISTは ''mist'' という名前空間で囲まれています
// (C++の知識が必要?なければおまじないだと思って・・・)
// MISTは全てC++のtemplateの機能を利用して作成されてます.
// なので,2次元画像といってもいろんなデータ型が作成できます
// (例えばグレースケールだったりカラーだったり・・・).
// まずは,画像のデータ形式がどんな物かを決めます(重要です!!)
typedef unsigned char value_type; // 画像の要素がRGBの3成分からなるようにします
typedef mist::array2< value_type > image_type; // RGBが要素となる2次元画像の設定
image_type image; // 画像の実体を作ります(プログラムミスを考えて,newで確保するのは控えめに・・・).
if( !mist::read_image( image, argv[ 1 ] ) )
{
// ファイルが読めないみたい・・・
return( 1 );
}
// img に画像が読み込まれてるはずなので,なんか処理してください
thresholding( image );
mist::write_image( image, std::string( argv[ 1 ] ) + ".bmp" );
return( 0 );
}