繼續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;
}