1. 程式人生 > >從cvLoadImage開始--OpenCV原始碼閱讀之三[轉]

從cvLoadImage開始--OpenCV原始碼閱讀之三[轉]

cvSaveImage/cvLoadImage函式用於儲存和讀取影象,兩者的結構基本相似。
下面我們主要分析cvSaveImage函式的實現。

cvLoadImage函式位於"OpenCV/otherlibs/highgui/loadsave.cpp"檔案:

CV_IMPL IplImage*
cvLoadImage( const char* filename, int iscolor )
{
return (IplImage*)icvLoadImage( filename, iscolor, false );
}

內部基於icvLoadImage函式實現。其中icvLoadImage函式的第三個引數可以
用於裝載矩陣,這裡被忽略(false表示讀影象)。

icvLoadImage函式的主要部分如下


static void*
icvLoadImage( const char* filename, int flags, bool )
{
// 查詢影象的讀驅動

GrFmtReader* reader = g_Filters.FindReader( filename );

// 利用影象讀驅動讀出影象頭資訊(高寬等屬性)

reader->ReadHeader();

// 高度/寬度

size.width = reader->GetWidth();
size.height = reader->GetHeight();

// 是否彩色

int iscolor = reader->IsColor();

// 彩色通道數為3,灰度為1

int cn = iscolor ? 3 : 1;

// 建立影像

IplImage* image = cvCreateImage( size, type, cn );

// 利用讀驅動讀影象的所有畫素
// image->data.ptr對應資料的開始地址
// image->step表示每行畫素所在記憶體的大小

reader->ReadData( image->data.ptr, image->step, iscolor );

return image;
}

其中g_Filters是一個靜態變數:

// global image I/O filters
static CvImageFilters g_Filters;

CvImageFilters::CvImageFilters()
{
m_factories = new GrFmtFactoriesList;

m_factories->AddFactory( new GrFmtBmp() );
m_factories->AddFactory( new GrFmtJpeg() );
m_factories->AddFactory( new GrFmtSunRaster() );
m_factories->AddFactory( new GrFmtPxM() );
m_factories->AddFactory( new GrFmtTiff() );

...
}

GrFmtFactoriesList在grfmt_base.h/grfmt_base.cpp中定義,用於儲存GrFmtFilterFactory
物件指標的連結串列。GrFmtFilterFactory為各種格式影象讀寫驅動的構造工廠基類:

class GrFmtFilterFactory
{
public:

GrFmtFilterFactory();
virtual ~GrFmtFilterFactory() {};

const char* GetDescription() { return m_description; };
int GetSignatureLength() { return m_sign_len; };
virtual bool CheckSignature( const char* signature );
virtual bool CheckExtension( const char* filename );
virtual GrFmtReader* NewReader( const char* filename ) = 0;
virtual GrFmtWriter* NewWriter( const char* filename ) = 0;

protected:
const char* m_description;
// graphic format description in form:
// <Some textual description>( *.<extension1> [; *.<extension2> ...]).
// the textual description can not contain symbols '(', ')'
// and may be, some others. It is safe to use letters, digits and spaces only.
// e.g. "Targa (*.tga)",
// or "Portable Graphic Format (*.pbm;*.pgm;*.ppm)"

int m_sign_len; // length of the signature of the format
const char* m_signature; // signature of the format
};

其中GetDescription()用於獲取影象檔名的描述,類似於"文字檔案 (*.txt)"格式。

GetSignatureLength()用於獲取影象檔案的標誌大小。對於tiff格式,開頭有一個"II"或者是"MM"的標誌,長度為2。
如果是算上tiff後面的42版本號,長度則為4。長度大小和CheckSignature相關。

CheckSignature用於匹配影象檔案的標誌。如果對應的影象不需要標誌,則可以在從GrFmtFilterFactory派生的
子類中將其遮蔽。

CheckExtension匹配影象檔名的字尾名,用於也可以自己重新實現。

NewReader/NewWriter為讀寫驅動對應的建構函式,利用它們可以針對不同影象構造相應的驅動。

工廠類連結串列定義如下:

class GrFmtFactoriesList
{
public:

GrFmtFactoriesList();
virtual ~GrFmtFactoriesList();
void RemoveAll();
bool AddFactory( GrFmtFilterFactory* factory );
int FactoriesCount() { return m_curFactories; };
ListPosition GetFirstFactoryPos();
GrFmtFilterFactory* GetNextFactory( ListPosition& pos );
virtual GrFmtReader* FindReader( const char* filename );
virtual GrFmtWriter* FindWriter( const char* filename );

protected:

GrFmtFilterFactory** m_factories;
int m_maxFactories;
int m_curFactories;
};

FindReader/FindWriter用於查詢影象對應的驅動。如果想修改查詢的規則,可以通過
GetNextFactory遍歷連結串列來實現。

真正的讀寫類從GrFmtReader派生,分別對應grfmt_bmp/grfmt_jpeg等各種格式驅動。
然後通過前面的CvImageFilters::CvImageFilters()來講各個驅動串到g_Filters.m_factories連結串列中

class GrFmtReader
{
public:

GrFmtReader( const char* filename );
virtual ~GrFmtReader();

int GetWidth() { return m_width; };
int GetHeight() { return m_height; };
bool IsColor() { return m_iscolor; };
int GetDepth() { return m_bit_depth; };
void UseNativeDepth( bool yes ) { m_native_depth = yes; };
bool IsFloat() { return m_isfloat; };

virtual bool ReadHeader() = 0;
virtual bool ReadData( uchar* data, int step, int color ) = 0;
virtual void Close();

protected:

bool m_iscolor;
int m_width; // width of the image ( filled by ReadHeader )
int m_height; // height of the image ( filled by ReadHeader )
int m_bit_depth;// bit depth per channel (normally 8)
char m_filename[_MAX_PATH]; // filename
bool m_native_depth;// use the native bit depth of the image
bool m_isfloat; // is image saved as float or double?
};

GrFmtReader比較核心的地方是3個virtual函式,分表用於讀影象檔案頭、讀資料、關閉影象檔案。
影象檔案在讀影象頭的時候被開啟。

對於影象的其他屬性,可以通過在子類中直接操作m_iscolor等protected成員完成。

先大概說這麼多,下一步將在上述分析的基礎上,自己定義一個影象格式,然後提供相應的讀寫驅動,
然後整合到cvSaveImage/cvLoadImage函式中。