今天是開始看opencv源碼的第一天,想看看opencv2.0以上版本是怎麼實現的。當然,這只是最初的一步,現在我就連opencv的基本框架都還沒能弄清楚呢,現在來看只是爲了看看代碼是怎麼實現的。
好了,今天的第一課:imread()函數的解析。
聲明:
Mat imread( const string& filename, int flags );//這很標準的寫法,傳入一個string類型的常量引用。
下面是定義:
Mat imread( const string& filename, int flags )
{
Mat img;//創建一個變量
imread_( filename, flags, LOAD_MAT, &img );//這裏用的是地址符號,爲什麼呢?當然是爲了改變其裏面的數據了。
return img;
}
這個函數是就這麼幾行麼?這麼幾行能幹什麼呢?其實它把所有的事情交給了imread_()函數。下面我們跟進去:
聲明:
static void*
imread_( const string& filename, int flags, int hdrtype, Mat* mat=0 );
定義:
static void* //返回的是一個空指針,其實在上面,這個返回值時沒有用到的。
imread_( const string& filename, int flags, int hdrtype, Mat* mat=0 )//filename:文件地址 flags:標誌,讀取什麼樣(灰度,彩色)圖像 hdrtype:傳入的爲載入什麼類型(enum { LOAD_CVMAT=0, LOAD_IMAGE=1, LOAD_MAT=2 };這三個中的一個。)Mat :保存圖像的Mat對象了。
{
IplImage* image = 0;
CvMat *matrix = 0;
Mat temp, *data = &temp;
ImageDecoder decoder = findDecoder(filename);//這個是解析圖像的後綴名的,用來決定讀取特定圖像的數據,所有的事情都是它幹了。
if( decoder.empty() )
return 0;
decoder->setSource(filename);
if( !decoder->readHeader() )//讀取圖像的頭部信息
return 0;
CvSize size;//讀取圖像的大小
size.width = decoder->width();
size.height = decoder->height();
int type = decoder->type();//讀取類型?
if( flags != -1 )
{//決定什麼樣的類型
if( (flags & CV_LOAD_IMAGE_ANYDEPTH) == 0 )
type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type));
if( (flags & CV_LOAD_IMAGE_COLOR) != 0 ||
((flags & CV_LOAD_IMAGE_ANYCOLOR) != 0 && CV_MAT_CN(type) > 1) )
type = CV_MAKETYPE(CV_MAT_DEPTH(type), 3);//彩色
else
type = CV_MAKETYPE(CV_MAT_DEPTH(type), 1);//灰度
}
if( hdrtype == LOAD_CVMAT || hdrtype == LOAD_MAT )
{
if( hdrtype == LOAD_CVMAT )
{
matrix = cvCreateMat( size.height, size.width, type );
temp = cvarrToMat(matrix); //創建一個空的,即還沒有圖像數據的對象。
}
else
{
mat->create( size.height, size.width, type );
data = mat;
}
}
else//就是傳入的類型都爲IplImage*類型的
{
image = cvCreateImage( size, cvIplDepth(type), CV_MAT_CN(type) );
temp = cvarrToMat(image);
}
if( !decoder->readData( *data ))//讀取數據,這裏應該是複製數據,想一想這個是要懂硬盤上去讀取數據的。
{//失敗
cvReleaseImage( &image );
cvReleaseMat( &matrix );//c風格的釋放
if( mat )
mat->release();//c++風格的釋放
return 0;
}
return hdrtype == LOAD_CVMAT ? (void*)matrix :
hdrtype == LOAD_IMAGE ? (void*)image : (void*)mat;//最後返回c類型的圖像指針,這個是爲了考慮c風格的
}
//上面看似不長啊,可這個怎麼能幹那麼多的事情呢?那麼就一步步的來分析吧。
這個看了半天,是不是沒有什麼實質性的東西?一個到底怎麼讀圖還沒完全瞭解吧。全都封裝了起來(decoder),你看不到所有的細節,而只是一個大概的流程。這個流程不是自己都知道了麼?
不管怎麼樣,我不想關注這個圖是怎麼解析的,只看這函數怎麼把數據給讀進了Mat中,先保持這個目標不變:
首先:傳入了一個Mat類型的變量,這個變量是傳了地址的,也就是會改變這個mat類型變量。Mat在構造函數中開始會構造什麼呢?尤其是默認構造函數?其實他什麼也沒有構造,因爲什麼都不知道。
其次:Mat類型需要記錄圖像的哪些數據呢?一個是頭:圖像是灰度或彩色(這裏姑且只考慮這兩種),一個圖像數據的大小(圖像的寬與高);一個數據體:二維數組或是一維數組。
最後:從decoder中讀入data數據。當然這裏會牽涉到圖像解碼過程的(這個如果特別感興趣就看看了,否則不用了)。