Visual studio メモ 3 --CImage で bmp jpeg png tifを読む (2012/08/14)--



 環境   : Visual Studio 2010 + Windows 7
 参考url : http://msdn.microsoft.com/ja-jp/library/bwea7by5

 
 Load (CImage::GetPixelを使う(遅い))

static bool t_loadImg1(const char *fname, int &W, int &H, byte* rgba)
{
    CImage pic;
    if( !SUCCEEDED( pic.Load( _T(fname) ) ) ) return false;//bmp jpeg png tiff画像の読み込み(bmp jpegのみ動作確認済み)
    
    W    = pic.GetWidth ();
    H    = pic.GetHeight();
    rgba = new byte[W*H*4];

    for( int y=0, i=0; y<H; ++y     )
    for( int x=0     ; x<W; ++x, ++i)
    {
        COLORREF c = pic.GetPixel( x, y );//画素値get (ここが非常に遅い)
        rgba [ i*4 + 0] = GetRValue(c); //画素値コピー
        rgba [ i*4 + 1] = GetGValue(c); //画素値コピー
        rgba [ i*4 + 2] = GetBValue(c); //画素値コピー
        rgba [ i*4 + 3] = 128;
    }
    return true;
}
 やってる事は
 1)CImage::Load()で画像を読み込んで
 2)CImage::GetWidth() / GetHeight()で画像サイズをもらって
 3)CImage::GetPixel()で画素値をCOLORREFでもらう


 Load (CImage::GetPixelAddressを使う)
 GetPixelが遅いので、PixelのAddressに直接アクセスした方が良い。
 画素が24bitsのときのみ、Addressから直接RGBを得るよう書き直したのが以下。
static bool t_loadImg2(const char *fname, int &W, int &H, byte* rgba)
{
    CImage pic;
    if( !SUCCEEDED( pic.Load( _T(fname) ) ) ) return false;//bmp jpeg png tiff画像の読み込み(bmp jpegのみ動作確認済み)
    
    int pitch   = pic.GetPitch();
    if( pitch < 0) pitch *= -1;
    //↑メージのピッチ(行方向のバイト数)を返します。
    //戻り値が負の値の場合、ビットマップは左下隅を起点とする逆方向 (下から上) の DIB です。
    //戻り値が正の値の場合、ビットマップは左上隅を起点とする順方向 (上から下の向き) の DIB です

    W    = pic.GetWidth ();
    H    = pic.GetHeight();
    rgba = new byte[W*H*4];

    int byteNum = pitch / W; //これが1pixelあたりのバイト数

    if( byteNum == 3 ) //24bit color 
    {
        for( int y=0, i=0; y<H; ++y     )
        for( int x=0     ; x<W; ++x, ++i)
        {
            //RGB(24bit)に対するアドレスをbyteにキャストしてるので, R G B順の一番下位のBを指すものになる
            byte *c = (byte*)pic.GetPixelAddress( x, y );
            rgba[ i*4 + 3] = 128;
            rgba[ i*4 + 2] = *c ; ++c;
            rgba[ i*4 + 1] = *c ; ++c;
            rgba[ i*4 + 0] = *c ; 
        }
    }
    else //その他
    {
        for( int y=0, i=0; y<H; ++y     )
        for( int x=0     ; x<W; ++x, ++i)
        {
            COLORREF c = pic.GetPixel( x, y );
            rgba[ i*4 + 3] = 128;
            rgba[ i*4 + 0] = GetRValue(c);
            rgba[ i*4 + 1] = GetGValue(c);
            rgba[ i*4 + 2] = GetBValue(c);
        }
    } 
    return true;
}
 このコードは、jpeg/bmpで動作確認済み。
 24bitでない画像や、Color table付きのtifなどはもう少し細かな処理が必要になる。
 
 以下は、GetPixelAddressの(私の)イメージ。24bitで1ブロック(RGB)なので、
 例えばCOLORREF(32bit)とかにキャストすると(e.g. (COLORREF*)GetPixelAddress(x,y))、
 端っこで1byte分踏み越えて、不正アクセスが発生して、最悪落ちる。

 下図では、隣の画素値が、メモリ上でも隣にあるように書いてあるが、それがいつも保障されているかは不明。

 


 このページにあるコードの動作の保証はできません。自己責任で使ってください。ライセンスはNYSL Version 0.9982です。