OpenCV的Mat類用於獲取圖像信息的常用屬性與方法

前言:Mat是OpenCV的最基本的類型,他有很多常見的屬性和方法,可以獲取這張圖片的基本信息,幫助我們更好地理解圖片,本文做了一個簡單的小結,並說明了一些常見的易錯點。

一、Mat對象常見的屬性以及方法一覽

cout << image.cols << endl;         //相片的列數,一共有多少列,對應width
cout << image.rows << endl;         //相片的行數,一共有多少行,對應height
cout << image.dims << endl;         //相片的維度,這裏都是二維

cout << image.type() << endl;       //16,其實是CV_8U3,即8位無符號三通道
cout << image.total() << endl;      //156500  總共有多少個元素,即rows*cols
cout << image.channels() << endl;   //相片的通道數,可能是1、3、4
	
//幾個需要特別注意的方法,在下面一個一個說明
cout << image.step << endl;         //1500
cout << image.step1() << endl;      //1500
cout << image.elemSize() << endl;   //3
cout << image.elemSize1() << endl;  //1

	cout << typeid(image.data).name() << endl;

1、type()方法

該方法返回的是一個int類型的整數,表示的是每一個像素(i,j)的數據類型,常見的比如:

  • CV_8U:8位單通道無符號,即灰度圖像,返回的是0
  • CV_8UC3:8位三通道無符號,即常見的RGB圖像,返回的是16
  • CV_32FC3:32位浮點數三通道,返回的是21
  • 等等

2、elemSize1()方法

每一個像素位置(i,j)處單個通道所佔用的字節數,是以字節byte爲單位的。

  • CV_8U:8位單通道無符號,即灰度圖像,只有一個通道,它爲1byte
  • CV_8UC3:8位三通道無符號,即常見的RGB圖像,每一個通道是8bit,依然爲1byte
  • CV_32FC3:32位浮點數三通道,每一個通道是32位,所以爲4byte
  • 等等

3、elemSize()方法

每一個像素位置(i,j)處所有通道所佔用的字節數,是以字節byte爲單位的。

  • CV_8U:8位單通道無符號,即灰度圖像,只有一個通道,它爲1byte
  • CV_8UC3:8位三通道無符號,即常見的RGB圖像,每一個通道是8bit,有三個通道,所以爲3byte
  • CV_32FC3:32位浮點數三通道,每一個通道是32位,即4byte,一共有三個通道所以是 12byte
  • 等等

注意:elemSize() 和elemSize1()的區別。

4、step屬性

這個屬性表示的是圖片每一行的字節數,一字節byte爲單位,

  • 單通道8位灰度圖:由於每一個像素只有一個通道,且爲8位,即1字節,所以 step=1*cols;
  • 三通道8位RGB圖:由於每一個像素包含三個通道,每一個通道爲1字節,所以一個像素佔3字節,所以step=3*cols;
  • 對於三通道32位浮點數:即上面的CV_32FC3,每一個像素有三個通道,每一個通道佔用32位即4字節,所以每一個像素佔用3*4字節,所以step=3*4*cols。

5、step1()方法

這個是最容易出錯的,step1()=step/elemSize1()

 

二、Mat類的元素高效遍歷方法

Mat類的元素便利有很多的方法,但是油的方法比較慢,這裏提供一種高校的元素遍歷方法,即通過image.data指針來實現。

2.1 data指針到底是什麼意思

需要特別注意的是,

  • data指針指向的是Mat的首元素的指針,即位置(0,0)處的指針,它是將每一個像素點當成一個一維數組,然後指向這個數組的首元素,如果是單通道,則這個一位數組只有一個元素,如果是三通道,則這個一維數組是三個元素;
  • 而且無論圖像是什麼類型,他總是返回的是unsigned char * 指針類型,即uchar類型,所以需要注意類型轉換。

(1)對於單通道灰度圖

//8位單通道,每個像素僅僅佔用 1 byte
for (int i = 0; i < rows; i++)
{
    uchar * pixel = a.data + i * a.step;  //將指針移動到每一行的開始
	for (int j = 0; j < 5; j++)
	{
		cout << pixel[0] << endl;  //單通道只有一個元素
        pixel+=1;   //將指針移動到下一列
	}
	cout << endl;
}

(2)對於三通道RGB圖像

//8位單通道,每個像素僅僅佔用 1 byte
for (int i = 0; i < rows; i++)
{
    uchar * pixel = a.data + i * a.step;  //將指針移動到每一行的開始
	for (int j = 0; j < 5; j++)
	{
		cout << pixel[0] << endl;  //三通道第一個元素
        cout << pixel[1] << endl;  //三通道第二個元素
        cout << pixel[2] << endl;  //三通道第三個元素

        pixel+=3;   //將指針移動到下一列的首元素
	}
	cout << endl;
}

(3)對於三通道32位浮點數,即CV_32FC3

//8位單通道,每個像素僅僅佔用 1 byte
for (int i = 0; i < rows; i++)
{
    float * pixel = (float *)a.data + i * a.step/4;  //將指針移動到每一行的開始需要轉換,爲什麼需要除以4,一定要弄清楚它的本質
	for (int j = 0; j < 5; j++)
	{
		cout << pixel[0] << endl;  //三通道第一個元素
        cout << pixel[1] << endl;  //三通道第二個元素
        cout << pixel[2] << endl;  //三通道第三個元素

        pixel+=3;   //將指針移動到下一列的首元素
	}
	cout << endl;
}

兩個需要注意的點:

(1)第一:什麼時候需要除以一個數,這取決於每一個像素的每一個通道佔用幾個字節

 float * pixel = (float *)a.data + i * a.step/4; 

(2)第二:什麼時候加1,什麼時候加3,這取決於相片的通道數目

pixel+=3; 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章