歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

OpenCV學習筆記與源碼分析: imread( )函數

引言

imread()函數在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_()中&img用的是地址符號,為什麼呢?當然是為了改變其裡面的數據了。imread( )函數是就這麼幾行麼?這麼幾行能干什麼呢?其實它把所有的事情交給了imread_()函數。所以,我們進一步分析imread_()函數。

imread_()函數

聲明:

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對象了。

定義: 

static void* imread_(const string& filename, int flags, int hdrtype, Mat* mat=0)
{
    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數據。當然這裡會牽涉到圖像解碼過程的(這個如果特別感興趣就看看了,否則不用了)。

在第一篇處,我們只是在最表層的上面操作函數,當別人問我們時,我們其實什麼也不知道的。就知道,imread是讀取函數了,然後掉用其它的函數的樂樂。當然,上面我們可以好好學習人家為什麼要這樣做了!這裡,看一個函數finddecoder()。這個函數主要是獲取decoder對象,從而決定讀取什麼樣後綴名的圖像(jpg,bmp等等)

Copyright © Linux教程網 All Rights Reserved