opencv--BaseImageDecoder

繼續opencv源碼的研讀,這裏還是imread函數的跟進,昨天遇到了ImageDecoder這個類,這個類其實就是一個圖像數據的解析類。且看下面的源代碼:

class BaseImageDecoder //這就是我們要找的ImageDecoder類
{
public:
    BaseImageDecoder();
    virtual ~BaseImageDecoder() {};

    int width() const { return m_width; };
    int height() const { return m_height; };
    int type() const { return m_type; };

    virtual bool setSource( const string& filename );
    virtual bool setSource( const Mat& buf );
    virtual bool readHeader() = 0;
    virtual bool readData( Mat& img ) = 0;

    virtual size_t signatureLength() const;//(1)
    virtual bool checkSignature( const string& signature ) const;
    virtual ImageDecoder newDecoder() const;

protected:
    int  m_width;  // width  of the image ( filled by readHeader )
    int  m_height; // height of the image ( filled by readHeader )
    int  m_type;
    string m_filename;
    string m_signature;//(2)
    Mat m_buf;
    bool m_buf_supported;
};

 

下面定義了一些類型,
typedef Ptr<BaseImageDecoder> ImageDecoder; //這裏typedef了一個類型ImageDecoder,這個最原始的類型爲Ptr,猜想是一個指針,但是在源代碼中沒能找到其聲明和定義的地方。但這不妨礙源碼的閱讀。

在findDecoder中用到了:static vector<ImageDecoder> decoders;

且在代碼中有:decoders[i]->signatureLength();的調用,且可以看到(1)處就有這個函數。

size_t BaseImageDecoder::signatureLength() const
{
    return m_signature.size();
}

上面這個函數其實返回的就是其保存的圖像簽名(signature)(2)

bool BaseImageDecoder::checkSignature( const string& signature ) const
{
    size_t len = signatureLength();
    return signature.size() >= len && memcmp( signature.c_str(), m_signature.c_str(), len ) == 0;
}

ImageDecoder BaseImageDecoder::newDecoder() const
{
    return ImageDecoder();//這裏其實就是一個直接的調用了一個構造函數
}

BaseImageDecoder::BaseImageDecoder()
{
    m_width = m_height = 0;
    m_type = -1;
    m_buf_supported = false;
}

這裏看到的只是一個Base類,那麼要真真的執行就是涉及到特定的圖像類別了。

這裏不看別的,就看一個bmp類型的吧:

class BmpDecoder : public BaseImageDecoder
{
public:
   
    BmpDecoder();
    ~BmpDecoder();
   
    bool  readData( Mat& img );//很明顯這是讀取數據
    bool  readHeader();
    void  close();

    ImageDecoder newDecoder() const;//這裏重新的給了一個聲明,表明在調用的時候調用的是子類的東西。

protected:
   
    RLByteStream    m_strm;
    PaletteEntry    m_palette[256];//調試版(palette)
    int             m_origin;
    int             m_bpp;
    int             m_offset;
    BmpCompression  m_rle_code;

/*壓縮的格式

enum BmpCompression
{
    BMP_RGB = 0,
    BMP_RLE8 = 1,
    BMP_RLE4 = 2,
    BMP_BITFIELDS = 3
};

*/
};

bmpDecoder類裏面的東西很多,這裏簡要的給看看:

ImageDecoder BmpDecoder::newDecoder() const
{
    return new BmpDecoder;
}

BmpDecoder::BmpDecoder()
{
    m_signature = fmtSignBmp;//static const char* fmtSignBmp = "BM"; 設定了自己標籤名
    m_offset = -1;  

   m_buf_supported = true;//buf設定爲true,表示可以讀取數據
}

 

這裏就完全的看到了底層的代碼了。這就需要完全的理解bmp圖像的保存格式了。還沒完全的瞭解bmp,暫且把這個代碼貼在這吧。

bool  BmpDecoder::readData( Mat& img )
{
    uchar* data = img.data;
    int step = (int)img.step;
    bool color = img.channels() > 1;
    uchar  gray_palette[256];
    bool   result = false;
    int  src_pitch = ((m_width*(m_bpp != 15 ? m_bpp : 16) + 7)/8 + 3) & -4;
    int  nch = color ? 3 : 1;
    int  y, width3 = m_width*nch;

    if( m_offset < 0 || !m_strm.isOpened())
        return false;

    if( m_origin == IPL_ORIGIN_BL )
    {
        data += (m_height - 1)*step;
        step = -step;
    }

    AutoBuffer<uchar> _src, _bgr;
    _src.allocate(src_pitch + 32);

    if( !color )
    {
        if( m_bpp <= 8 )
        {
            CvtPaletteToGray( m_palette, gray_palette, 1 << m_bpp );
        }
        _bgr.allocate(m_width*3 + 32);
    }
    uchar *src = _src, *bgr = _bgr;

    try
    {
        m_strm.setPos( m_offset );

        switch( m_bpp )
        {
        /************************* 1 BPP ************************/
        case 1:
            for( y = 0; y < m_height; y++, data += step )
            {
                m_strm.getBytes( src, src_pitch );
                FillColorRow1( color ? data : bgr, src, m_width, m_palette );
                if( !color )
                    icvCvt_BGR2Gray_8u_C3C1R( bgr, 0, data, 0, cvSize(m_width,1) );
            }
            result = true;
            break;

        /************************* 4 BPP ************************/
        case 4:
            if( m_rle_code == BMP_RGB )
            {
                for( y = 0; y < m_height; y++, data += step )
                {
                    m_strm.getBytes( src, src_pitch );
                    if( color )
                        FillColorRow4( data, src, m_width, m_palette );
                    else
                        FillGrayRow4( data, src, m_width, gray_palette );
                }
                result = true;
            }
            else if( m_rle_code == BMP_RLE4 ) // rle4 compression
            {
                uchar* line_end = data + width3;
                y = 0;

                for(;;)
                {
                    int code = m_strm.getWord();
                    int len = code & 255;
                    code >>= 8;
                    if( len != 0 ) // encoded mode
                    {
                        PaletteEntry clr[2];
                        uchar gray_clr[2];
                        int t = 0;

                        clr[0] = m_palette[code >> 4];
                        clr[1] = m_palette[code & 15];
                        gray_clr[0] = gray_palette[code >> 4];
                        gray_clr[1] = gray_palette[code & 15];

                        uchar* end = data + len*nch;
                        if( end > line_end ) goto decode_rle4_bad;
                        do
                        {
                            if( color )
                                WRITE_PIX( data, clr[t] );
                            else
                                *data = gray_clr[t];
                            t ^= 1;
                        }
                        while( (data += nch) < end );
                    }
                    else if( code > 2 ) // absolute mode
                    {
                        if( data + code*nch > line_end ) goto decode_rle4_bad;
                        m_strm.getBytes( src, (((code + 1)>>1) + 1) & -2 );
                        if( color )
                            data = FillColorRow4( data, src, code, m_palette );
                        else
                            data = FillGrayRow4( data, src, code, gray_palette );
                    }
                    else
                    {
                        int x_shift3 = (int)(line_end - data);
                        int y_shift = m_height - y;

                        if( code == 2 )
                        {
                            x_shift3 = m_strm.getByte()*nch;
                            y_shift = m_strm.getByte();
                        }

                        len = x_shift3 + ((y_shift * width3) & ((code == 0) - 1));

                        if( color )
                            data = FillUniColor( data, line_end, step, width3,
                                                 y, m_height, x_shift3,
                                                 m_palette[0] );
                        else
                            data = FillUniGray( data, line_end, step, width3,
                                                y, m_height, x_shift3,
                                                gray_palette[0] );

                        if( y >= m_height )
                            break;
                    }
                }

                result = true;
decode_rle4_bad: ;
            }
            break;

        /************************* 8 BPP ************************/
        case 8:
            if( m_rle_code == BMP_RGB )
            {
                for( y = 0; y < m_height; y++, data += step )
                {
                    m_strm.getBytes( src, src_pitch );
                    if( color )
                        FillColorRow8( data, src, m_width, m_palette );
                    else
                        FillGrayRow8( data, src, m_width, gray_palette );
                }
                result = true;
            }
            else if( m_rle_code == BMP_RLE8 ) // rle8 compression
            {
                uchar* line_end = data + width3;
                int line_end_flag = 0;
                y = 0;

                for(;;)
                {
                    int code = m_strm.getWord();
                    int len = code & 255;
                    code >>= 8;
                    if( len != 0 ) // encoded mode
                    {
                        int prev_y = y;
                        len *= nch;

                        if( data + len > line_end )
                            goto decode_rle8_bad;

                        if( color )
                            data = FillUniColor( data, line_end, step, width3,
                                                 y, m_height, len,
                                                 m_palette[code] );
                        else
                            data = FillUniGray( data, line_end, step, width3,
                                                y, m_height, len,
                                                gray_palette[code] );

                        line_end_flag = y - prev_y;
                    }
                    else if( code > 2 ) // absolute mode
                    {
                        int prev_y = y;
                        int code3 = code*nch;

                        if( data + code3 > line_end )
                            goto decode_rle8_bad;
                        m_strm.getBytes( src, (code + 1) & -2 );
                        if( color )
                            data = FillColorRow8( data, src, code, m_palette );
                        else
                            data = FillGrayRow8( data, src, code, gray_palette );

                        line_end_flag = y - prev_y;
                    }
                    else
                    {
                        int x_shift3 = (int)(line_end - data);
                        int y_shift = m_height - y;

                        if( code || !line_end_flag || x_shift3 < width3 )
                        {
                            if( code == 2 )
                            {
                                x_shift3 = m_strm.getByte()*nch;
                                y_shift = m_strm.getByte();
                            }

                            x_shift3 += (y_shift * width3) & ((code == 0) - 1);

                            if( y >= m_height )
                                break;

                            if( color )
                                data = FillUniColor( data, line_end, step, width3,
                                                     y, m_height, x_shift3,
                                                     m_palette[0] );
                            else
                                data = FillUniGray( data, line_end, step, width3,
                                                    y, m_height, x_shift3,
                                                    gray_palette[0] );

                            if( y >= m_height )
                                break;
                        }

                        line_end_flag = 0;
                    }
                }

                result = true;
decode_rle8_bad: ;
            }
            break;
        /************************* 15 BPP ************************/
        case 15:
            for( y = 0; y < m_height; y++, data += step )
            {
                m_strm.getBytes( src, src_pitch );
                if( !color )
                    icvCvt_BGR5552Gray_8u_C2C1R( src, 0, data, 0, cvSize(m_width,1) );
                else
                    icvCvt_BGR5552BGR_8u_C2C3R( src, 0, data, 0, cvSize(m_width,1) );
            }
            result = true;
            break;
        /************************* 16 BPP ************************/
        case 16:
            for( y = 0; y < m_height; y++, data += step )
            {
                m_strm.getBytes( src, src_pitch );
                if( !color )
                    icvCvt_BGR5652Gray_8u_C2C1R( src, 0, data, 0, cvSize(m_width,1) );
                else
                    icvCvt_BGR5652BGR_8u_C2C3R( src, 0, data, 0, cvSize(m_width,1) );
            }
            result = true;
            break;
        /************************* 24 BPP ************************/
        case 24:
            for( y = 0; y < m_height; y++, data += step )
            {
                m_strm.getBytes( src, src_pitch );
                if(!color)
                    icvCvt_BGR2Gray_8u_C3C1R( src, 0, data, 0, cvSize(m_width,1) );
                else
                    memcpy( data, src, m_width*3 );
            }
            result = true;
            break;
        /************************* 32 BPP ************************/
        case 32:
            for( y = 0; y < m_height; y++, data += step )
            {
                m_strm.getBytes( src, src_pitch );

                if( !color )
                    icvCvt_BGRA2Gray_8u_C4C1R( src, 0, data, 0, cvSize(m_width,1) );
                else
                    icvCvt_BGRA2BGR_8u_C4C3R( src, 0, data, 0, cvSize(m_width,1) );
            }
            result = true;
            break;
        default:
            assert(0);
        }
    }
    catch(...)
    {
    }

    return result;
}

發佈了31 篇原創文章 · 獲贊 9 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章