2012年7月4日水曜日

グレースケールを擬似カラーに変換する

方法

0から255のグレースケール値をOpenCVのRGB値(疑似カラー)に変換する。色んなやり方があるがその1つ。

cv::Vec3b calcPseudoColor(double phase, double shift = 0.0)
{
    phase = max(min(phase,1.0), 0.0); //0から1に
    shift += PI+PI/4;     //青から赤に
    return Vec3b
    (
        uchar( 255*(sin(1.5*PI*phase + shift + PI ) + 1)/2.0 ),
        uchar( 255*(sin(1.5*PI*phase + shift + PI/2 ) + 1)/2.0 ), 
        uchar( 255*(sin(1.5*PI*phase + shift  ) + 1)/2.0 )
    );
} 

使い方

たとえばカラーバーを作ってみる。

int w = 1024;
int h = 100;
cv::Mat_<cv::Vec3b> bar(h, w);
for(int j=0; j<h; j++)
{
    for(int i=0; i<w; i++)
    {
        bar(j, i) = calcPseudoColor(double(i)/(w-1));
    }
}

結果

$1024\times 100$の画像にphase=0から1までを均等に割り当てて描画した。緑に鮮やかさがないが、青から赤まで虹色に変化するグラデーションが表現できている。

補足

この方法が良いという理由は、$sin$関数が使えるのでソースコードが短くなること以外はあまりない。HSV表色系のHueを計算するよりは単純だと思う。緑が鮮やかでなかったのは、以下の理由で説明できる。つまり、この方法は、RGBの3つのチャンネルを足した和、つまり輝度が255などの一定値にはならない。gnuplotで上記3つの関数を表示してみれば一発で確認できる。横軸がphase、縦軸が輝度値である。緑のあたりの合計輝度値$I(x)=r(x)+g(x)+b(x)$が他と比べて高くなっており、純粋なGチャンネルのみのphaseは存在しない。

gnuplotの表示に用いたコードも載せておく。よく使うので。

set xrange [0:1]
set yrange [0:600]
 
#set terminal postscript eps enhanced color
#set output 'plot.eps'
 
set terminal png color
set output 'plot.png'
 
r(x) = 255*(sin(1.5*pi*x+pi+pi/4 + pi) + 1)/2.0
g(x) = 255*(sin(1.5*pi*x+pi+pi/4 + pi/2) + 1)/2.0
b(x) = 255*(sin(1.5*pi*x+pi+pi/4) + 1)/2.0
I(x) = r(x) + g(x) + b(x)
plot r(x), g(x), b(x), I(x), 255
 
set terminal windows
set output

plot r(x), g(x), b(x), I(x), 255
 
reset