Last modified 10 years ago Last modified on 07/11/07 19:12:52

色空間の次元を減らす?

色空間(RGBの3次元)の次元を削減して,色平面,色直線のみを用いて画像中の画素値を表現します.

  1. 画像の各画素値を3次元のベクトル(RGB)と見なし,画素値の主成分分析を行う.

  2. 得られた固有ベクトルを対応する固有値の大きいほうから順に2つ(1つ)選び,色平面(色直線)を形成する.

  3. 形成した色平面(色直線)上に各画素値を投影する.




環境設定

  1. 環境設定を参照して,LAPACKに関するライブラリディレクトリ,依存ファイルの設定を正しく行う.

  2. mist\config\mist_conf.hを開いて,#define _DESCENDING_ORDER_EIGEN_VALUE_1に設定する(固有値,固有ベクトルの順番を固有値の降順に設定).




サンプルプログラム

#include <mist/mist.h>
#include <mist/io/bmp.h>
#include <mist/matrix.h>
#include <mist/numeric.h>

int main( void )
{
    const size_t dimension = 2; // 削減後の色空間の次元

    mist::array2< mist::rgb< unsigned char > > in;
    mist::read_bmp( in, "lena.bmp" );
    
    mist::array< mist::matrix< double > > samples( in.size( ) );
    mist::matrix< double > mean( 3, 1 );
    for( size_t i = 0 ; i != in.size( ) ; ++ i )
    {
        mist::matrix< double > p = mist::matrix< double >::_31( in[ i ].r, in[ i ].g, in[ i ].b );
        samples[ i ] = p;
        mean += p;
    }
    mean /= in.size( ); // 平均ベクトル
    
    mist::matrix< double > covariance( 3, in.size( ) );
    for( size_t i = 0 ; i != in.size( ) ; ++ i )
    {
        mist::matrix< double > p = samples[ i ] - mean;
        covariance( 0, i ) = p( 0, 0 );
        covariance( 1, i ) = p( 1, 0 );
        covariance( 2, i ) = p( 2, 0 );
    }
    covariance *= covariance.t( ); // 共分散行列

    mist::matrix< double > eval, evec; // 固有値・固有ベクトル
    mist::eigen( covariance, eval, evec );  // 主成分分析
    {
        mist::matrix< double > tmp( evec );
        evec.resize( 3, dimension );
        for( size_t j = 0 ; j != evec.cols( ) ; ++ j )
        {
            for( size_t i = 0 ; i != evec.rows( ) ; ++ i )
            {
                evec( i, j ) = tmp( i, j );
            }
        }
    } // 色平面(色直線)の基底を作成
    
    mist::array2< mist::rgb< unsigned char > > out( in.width( ), in.height( ) );
    for( size_t i = 0 ; i != in.size( ) ; ++ i )
    {
        mist::matrix< double > p = evec.t( ) * ( samples[ i ] - mean ); // 画素を色平面(色直線)へ投影
        p = evec * p + mean; // 投影点の色空間上の位置を計算
        out[ i ].r = static_cast< unsigned char >( ( p( 0, 0 ) > 255 ) ? 255 : ( p( 0, 0 ) < 0 ) ? 0 : p( 0, 0 ) );
        out[ i ].g = static_cast< unsigned char >( ( p( 1, 0 ) > 255 ) ? 255 : ( p( 1, 0 ) < 0 ) ? 0 : p( 1, 0 ) );
        out[ i ].b = static_cast< unsigned char >( ( p( 2, 0 ) > 255 ) ? 255 : ( p( 2, 0 ) < 0 ) ? 0 : p( 2, 0 ) );
    }
    mist::write_bmp( out, "out.bmp" );

    return 0;
}
  • mist/matrix.h
    mist::matrix< double > mat( r, c );
    
    • rc列の要素の型がdoubleの行列matを宣言します.

    • 行列同士の和差積,行列の定数倍が演算可能です.

    • mat.t( )matの転置行列を返します.

    • mat( i, j )matij列の要素にアクセスします.

    • mat.rows( )matの行数を返します.

    • mat.cols( )matの列数を返します.

    • mat[ i ]matを1次元配列として見たときのi番目の要素にアクセスします.

    • mat.size( )matの要素数を返します.

    • mat.resize( r, c )matのサイズをr×cに変更します.

    • mist::matrix< double >::_31( ... ) … 3つの要素を指定して3×1のdouble型の行列を返します.

  • mist/numeric.h

    • 逆行列計算,主成分分析,特異値分解,LU分解,QR分解等の線形代数演算を提供します.

    • mist::eigen( mat, eval, evec )matの固有値evalと固有ベクトルevecを計算します.

      • matがn×nのとき,evalはn×1の行列の各要素として昇順(降順)に格納されます.

      • matがn×nのとき,evecはn×nの行列の各列ベクトルとして対応する固有値の昇順(降順)に格納されます.




結果

左から,入力画像,色空間を2次元にしたもの,1次元にしたもの




Attachments