2008年7月3日 星期四

資料結構操作與運算-IplImage資料結構(1)

這邊就簡單的介紹IplImage資料結構到底是什麼東西啦,IplImage資料結構裡面有很多的變數,而他的數值大多都被IplImage專用的函數初始化,所以不太需要用到它資料結構裡面的資料,以及直接設定它資料結構的數據,以下簡單的列出IplImage所存到的數據資訊.

IplImage資料結構
#include <cv.h>
#include <highgui.h>
#include <stdio.h>

int main()
{
    IplImage *Image1;
    CvSize ImageSize1 = cvSize(320,240);
    Image1 = cvCreateImage(ImageSize1,IPL_DEPTH_8U,3);

    printf("The IplImage Size is : %d\n",sizeof(IplImage));
    printf("The nSize            is : %d\n",Image1->nSize);
    printf("The width           is : %d\n",Image1->width);
    printf("The height          is : %d\n",Image1->height);
    printf("The nChannels     is : %d\n",Image1->nChannels);
    printf("The depth           is : %d\n",Image1->depth);
    printf("The widthStep     is : %d\n",Image1->widthStep);
    printf("The imageSize     is : %d\n",Image1->imageSize);
    printf("The dataOrder     is : %d\n",Image1->dataOrder);
    printf("The origin           is : %d\n",Image1->origin);
    printf("The align            is : %d\n",Image1->align);

    uchar Blue[240][320];
    uchar Green[240][320];
    uchar Red[240][320];

    for(int i=0;i<Image1->height;i++)
    {
        for(int j=0;j<Image1->widthStep;j=j+3)
        {
            Blue[i][(int)(j/3)]=Image1->imageData[i*Image1->widthStep+j];
            Green[i][(int)(j/3)]=Image1->imageData[i*Image1->widthStep+j+1];
            Red[i][(int)(j/3)]=Image1->imageData[i*Image1->widthStep+j+2];

            Image1->imageData[i*Image1->widthStep+j]=0;
            Image1->imageData[i*Image1->widthStep+j+1]=0;
            Image1->imageData[i*Image1->widthStep+j+2]=255;
        }
    }
    cvNamedWindow("Red",1);
    cvShowImage("Red",Image1);
    cvWaitKey(0);

    cvReleaseImage(&Image1);
    cvDestroyWindow("Red");

}

執行結果:


以上的圖片,是由cvCreateImage()自己創造的8bits RGB圖形,cvCreateImage()的數據3代表著色域的數目,也就是R+G+B的三原色組成的啦,而下面是印出IplImage資料結構的數據資訊,IplImage裡面有很多的資料結構的變數可用,這也只是IplImage的一小部分,其他的,在cvCreateImage()創造的圖形是用不到的.

1.Image1->nSize
這個部分是IplImage的空間大小為IplImage數值型別的位元組大小,跟上面的sizeof(IplImage)是一樣的.

2.Image1->width
圖像的寬度.

3.Image1->height
圖像的高度

4.Image1->nChannels
圖像的色域數目(通道).

5.Image1->depth
圖像的深度,這裡指的是單一一個通道的空間大小,執行結果出來是8也就表示它是8bits的空間大小.

6.Image1->widthStep
總共的寬度大小,一張圖片是用BGRBGRBGR...所排列而成的二維陣列,這邊的widthStep表示width*nChannels的寬度大小.

7.Image1->imageSize
一張圖片的空間大小,這邊的數據其實是height*width*nChannels,如果將這張圖存成BMP圖檔的時候,總磁碟空間會是imageSize+54(圖片標頭檔).

8.Image1->dataOrder
色域的排列方式,如果dataOrder=0的話將會是BGRBGR...的排列,如果dataOrder=1的話會是BBBBBB...的分開排列方式,cvCreateImage()只能做到dataOrder=0的交叉排列.

9.Image1->origin
圖像的起始點,Bmp圖檔都是上下顛倒的origin的值為1,但是如果由cvCreateImage()及cvLoadImage()初始化IplImage資料結構都非上下顛倒的,其值為0.

10.Image1->align
這個部分就要說到計算機組織的排列限制(alignment restriction)了,這個表示,每一個位元的起始位置為4的倍數,也就是32bits,而如果出現的結果為8那就是8bytes,為64bits.詳細則去參考計算機組織的排列限制.

IplImage的詳細資訊就這樣子啦,但是,最重要的,就是要知道如何讀圖檔啦,一張圖片的顏色資訊都被放在imageData裡面,不過IplImage必須要支援多個不同格式大小的圖片,因此,就用一維陣列表示,跟一般寫Bitmap演算法的方式有點不一樣,因此,要分別取得它們的R值B值G值,就要像上面程式碼那樣啦,上面的雙重for迴圈將一維陣列的組合轉換成二維陣列了,因此要使用的時候直接用它的R陣列G陣列B陣列就好了.上面的程式實際上RGB值是顛倒的,因為其實把圖形檔案存在硬碟裡也是顛倒的,而且圖形是上下相反的,但是一般性的說法都是用RGB的稱呼,如果使用Visual C++或是Borland C++ Builder的Bitmap物件則沒有此問題(因為物件導向會自動轉換).


上面是一張xxx.bmp檔的檔案排列方式

cvCreateImage()
創造一個全黑的基本圖片,需要給它設定空間CvSize資料結構,以及它的輸入格式參數,再來是它的通道數(Channel).以下為輸入格式參數列表

IPL_DEPTH_1U
IPL_DEPTH_8U
IPL_DEPTH_16U
IPL_DEPTH_32F
IPL_DEPTH_8S
IPL_DEPTH_16S
IPL_DEPTH_32S


cvCreateImage()最多可以輸入1~4個通道.
cvCreateImage(CvSize圖形大小資料結構,IplImage格式參數,通道數)



11 意見:

匿名 提到...

請問一下 我不大懂下列這一行的意思Image1->imageData[i*Image1->widthStep+j]
我只知道它好像是在算每一列Blue這一個顏色的位置
可是既然是這樣 它為什麼還要乘一 i 呢

我有試過把 i 去掉 結果好像是不變
如下
Image1->imageData[Image1->widthStep+j]

匿名 提到...

讓我來回答您吧!^^
乘上i主要是為了累加每一列的變數i高度
您結果不變是因為
程式下面的imageData[i*Image1->widthStep+j]=0
因而沒有改顏色,故您看起來不會變
假若原程式碼
將0改成255就會發現顏色改變

Sun 提到...

請問
imge = cvCreateImage(size,IPL_DEPTH_8U, 1);
其中 IPL_DEPTH_8U代表 存取在0~255之間。那如果我改成 IPL_DEPTH_32F,是不是就可以儲存浮點數??
如果是那是儲存在哪裡 imageData 是uchar的型態應該次能儲存浮點數吧

nowonderg 提到...

你好
Image1->widthStep的widthStep表示width*nChannels的寬度大小
應改為

Image1->widthStep的widthStep表示width*nChannels*sizeof(uchar)的寬度大小

若img為float型態時則為
width*nChannels*sizeof(float)

因此在取step時應這樣取

step = img->widthStep/sizeof(data type);不然取到的step是錯的

justin 提到...

您好,
在實作上若以兩個迴圈讀資料,是費時間的,有沒有其他的方法能夠更快的讀出影像資料?
謝謝

阿貝 提到...

這對初學很有幫助阿!! 不知道你同不同意我借轉到我的部落格?? 我會註明出處

阿貝 提到...
作者已經移除這則留言。
wa114040@gmail.com 提到...

ok

fly 提到...

你好
我將opencv跟android作結合(利用jni)

我想問說,我將鏡頭的畫面轉成rgb(android),那我要再opencv這要將rgb做處理,
opencv怎麼將rgb載入,我用cvLoadImage是不行的

yvette 提到...

您好,我是初學者><
如果問錯請不要見怪
請問imageData括號裡的是什麼呢?
因為我不是很懂這行:Blue[i][(int)(j/3)]=Image1->imageData[i*Image1->widthStep+j];
imageData看起來像是取一維 但是為什麼可以存成二維

maninblack 提到...

請問一下
我是超初學者
image1=cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1);
uchar *ptr;
ptr = image1->imageData;

這是我之前有個同學寫的 image1是一個
據我所知ptr的值是是這個圖片最左上角的位址
那*ptr是不是0(全黑,因為cvcreatimage是全黑視窗)?

Copyright 2008-2009,yester