1. 程式人生 > >OpenCV3入門(二)Mat操作

OpenCV3入門(二)Mat操作

1、Mat結構

1.1、Mat資料

Mat本質上是由兩個資料部分組成的類:

矩陣頭:包含資訊有矩陣的大小,用於儲存的方法,矩陣儲存的地址等

資料矩陣指標:指向包含了畫素值的矩陣。

矩陣頭部的大小是恆定的,矩陣本身的大小因影象的不同而不同,通常是較大的數量級。

在程式中傳遞影象並在有些時候建立影象副本需要花費很大的代價生成影象矩陣本身,而不是影象的頭部。為了解決這一問題 OpenCV 使用引用計數系統。其思想是Mat的每個物件具有其自己的頭,但可能他們通過讓他們矩陣指標指向同一地址的兩個例項之間共享該矩陣。此外,拷貝運算子將只能複製矩陣頭部,也還將複製指標到大型矩陣,但不是矩陣本身。如果需要複製矩陣的本身,要使用 clone() 或 copyTo() 函式。

其中 Mat 類中有一些基本屬性:

cols :矩陣列數

rows:矩陣行數

channels:通道數

type:資料型別

total:矩陣總元素數

data:指向矩陣資料塊的指標

1.2、Mat資料型別定義

其中 Mat 排列方式如下:

CV_[位數][帶符號與否][型別字首]C[通道數]

帶符號與否:S為符號整型,U為無符號整型,F為浮點型

例如CV_8UC3

 多通道資料型別的定義如下:

#define CV_8U   0
#define CV_8S   1
#define CV_16U  2
#define CV_16S  3
#define CV_32S  4
#define CV_32F  5
#define CV_64F  6
#define CV_USRTYPE1 7

#define CV_MAT_DEPTH_MASK       (CV_DEPTH_MAX - 1)
#define CV_MAT_DEPTH(flags)     ((flags) & CV_MAT_DEPTH_MASK)
#define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth) + (((cn)-1) << CV_CN_SHIFT))
#define CV_MAKE_TYPE CV_MAKETYPE

#define CV_8UC1 CV_MAKETYPE(CV_8U,1)
#define CV_8UC2 CV_MAKETYPE(CV_8U,2)
#define CV_8UC3 CV_MAKETYPE(CV_8U,3)
#define CV_8UC4 CV_MAKETYPE(CV_8U,4)

2、Mat應用

2.1 建構函式

(1) Mat::Mat()
(2) Mat::Mat(int rows, int cols, int type)
(3) Mat::Mat(Size size, int type)
(4) Mat::Mat(int rows, int cols, int type, const Scalar& s)
(5) Mat::Mat(Size size, int type, const Scalar& s)
(6) Mat::Mat(const Mat& m)
(7) Mat::Mat(int rows, int cols, int type, void* data, size_t step = AUTO_STEP)
(8) Mat::Mat(Size size, int type, void* data, size_t step = AUTO_STEP)
(9) Mat::Mat(const Mat& m, const Range& rowRange, const Range& colRange)
(10) Mat::Mat(const Mat& m, const Rect& roi)
(11) Mat::Mat(const CvMat* m, bool copyData = false)
(12) Mat::Mat(const IplImage* img, bool copyData = false)
(13) template<typename T, int n>explicit Mat::Mat(const Vec<T, n>& vec, bool copyData = true)
(14) template<typename T, int m, int n> explicit Mat::Mat(const Matx<T, m, n>& vec, bool copyData = true)
(15) template explicit Mat::Mat(const vector& vec, bool copyData = false)
(16) Mat::Mat(const MatExpr& expr)
(17) Mat::Mat(int ndims, const int* sizes, int type)
(18) Mat::Mat(int ndims, const int* sizes, int type, const Scalar& s)
(19) Mat::Mat(int ndims, const int* sizes, int type, void* data, const size_t* steps = 0)

2.2 建立Mat型別資料

1)使用Mat建構函式建立

Mat mat = Mat(2, 3, CV_8UC1);

cout << "rows="<<mat.rows << ",cols=" << mat.cols << endl;

cout << mat << endl;

輸出:

rows=2,cols=3

[205, 205, 205;

 205, 205, 205]

建立三通道矩陣Mat mat(2, 3, CV_8UC3);輸出如下。

rows=2,cols=3

[205, 205, 205, 205, 205, 205, 205, 205, 205;

 205, 205, 205, 205, 205, 205, 205, 205, 205]

建立三通道矩陣Mat mat(2, 3, CV_8UC3,  Scalar(0,0,255)

rows=2,cols=3

[  0,   0, 255,   0,   0, 255,   0,   0, 255;

   0,   0, 255,   0,   0, 255,   0,   0, 255]

 2)使用Create函式進行初始化

Mat M;
M.create(2, 3, CV_8UC1);
cout << "M = " << endl << " " << M << endl << endl;

輸出如下。

M =

 [205, 205, 205;

 205, 205, 205]

3)使用標準函式進行特定矩陣初始化

Mat M;
M = Mat::eye(4, 4, CV_8U);
Mat M1 = Mat::ones(4, 4, CV_8U);
Mat M2= Mat::zeros(4, 4, CV_8U); cout << "M = " << endl << " " << M << endl << endl; cout << "M1 = " << endl << " " << M1 << endl << endl; cout << "M2 = " << endl << " " << M2 << endl << endl;

輸出如下。

M =

 [  1,   0,   0,   0;

   0,   1,   0,   0;

   0,   0,   1,   0;

   0,   0,   0,   1]

M1 =

 [  1,   1,   1,   1;

   1,   1,   1,   1;

   1,   1,   1,   1;

   1,   1,   1,   1]

M2 =

 [  0,   0,   0,   0;

   0,   0,   0,   0;

   0,   0,   0,   0;

   0,   0,   0,   0]

輸出Mat矩陣可以格式化不同的形式,如下所示。

cout <<"M = "<< endl <<" "<< format( M, Formatter::FMT_PYTHON) << endl << endl;

M =

 [[  1,   0,   0,   0],

 [  0,   1,   0,   0],

 [  0,   0,   1,   0],

 [  0,   0,   0,   1]]

 

2.3 Mat操作畫素

1. at定位符訪問

2、指標訪問

3.迭代器iterator訪問

1)Mat::at

Mat資料結構,操作灰度影象畫素點:

int gray_value = (int) image.at<uchar>(i , j) ;

操作彩色影象畫素點:

int color_value = (int) image.at<Vec3b>(i , j) [k];

其中:

gray_value中存放灰度值,image是讀入的影象,i表示行,j表示列;

color_value中存放彩色畫素值,image是讀入的影象,i表示行,j表示列,k表示通道,即R、G、B,取值範圍為2、1、0.

template<typename T> T& Mat::at(int i)const

 template<typename T> const T&Mat::at(int i) const

 template<typename T> T& Mat::at(int i,int j)

 template<typename T> const T&Mat::at(int i, int j) const

 template<typename T> T& Mat::at(Pointpt)

 template<typename T> const T&Mat::at(Point pt) const

 template<typename T> T& Mat::at(int i,int j, int k)

 template<typename T> const T&Mat::at(int i, int j, int k) const

 template<typename T> T& Mat::at(constint* idx)

 template<typename T> const T&Mat::at(const int* idx) const

引數

i –索引 0 維度

j – 1 維度的索引

k – 沿 2 維度的索引

pt – Point(j,i) 作為指定元素的位置。

idx – Mat::dims 陣列的索引

int main() {
    Mat M= Mat::eye(100, 200, CV_8U);
    for(int i=0; i<M.rows; i++)
        for (int j = 0; j < M.cols; j++)
        {
            M.at<uchar>(i, j) = j / 10 * 10;
        }

    imshow("pic1", M);
    waitKey(0);
}

 2)指標訪問

Mat mat = Mat(10, 15, CV_8UC1);
cout << "rows=" << mat.rows << ",cols=" << mat.cols << endl;
for (int i = 0; i < mat.rows; i++)
{
    uchar* row = mat.ptr<uchar>(i); // 行指標
    for (int j = 0; j < mat.cols; j++) // 遍歷每一行
    {
        row[j] = (uchar)((j / 5) * 10); 
    }
}
cout << "M = " << endl << " " << format(mat, Formatter::FMT_PYTHON) << endl << endl;
waitKey(0);

輸出如下。

rows=10,cols=15
M =
[[ 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20],
[ 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20],
[ 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20],
[ 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20],
[ 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20],
[ 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20],
[ 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20],
[ 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20],
[ 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20],
[ 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20]]

 3)迭代器iterator訪問

Mat M = Mat(100, 150, CV_8UC3);
cout << "rows=" << M.rows << ",cols=" << M.cols << endl;

Mat_<Vec3b>::iterator it = M.begin<Vec3b>();//初始位置的迭代器
Mat_<Vec3b>::iterator itend = M.end<Vec3b>();//終止位置的迭代器
for (; it != itend; it++)
{
    //處理BGR三個通道
    (*it)[0] = 182;//B
    (*it)[1] = 194;//G
    (*it)[2] = 154;//R
}
imshow("pic1", M);

 使用下面配色表實驗:

配色1: RGB(182,194,154)

 配色2:RGB(229,131, 8)

 2.4 其他資料結構

1)點的表示:Point

Point p1 = { 2,3 };
Point p2 = Point2i(3, 4);
Point2f p3;
p3.x = 1.1;
p3.y = 1.2;
cout << "p1=" << p1 << endl;
cout << "p2=" << p2 << endl;
cout << "p3=" << p3 << endl;
waitKey(0);

輸出為:

p1=[2, 3]

p2=[3, 4]

p3=[1.1, 1.2]

2)顏色表示:Scalar

Scalar(r, g, b)分別表示紅綠藍顏色。

3)尺寸的表示:Size

Size a = Size(5, 6);
cout <<"a.width=" << a.width << ":a.height=" << a.height;

輸出為:

a.width=5:a.height=6

4)矩形的表示:Rect

Rect rect = Rect(100, 50, 10, 20); // 引數:x、y、width、height
cout << rect.area() << endl;     //返回rect的面積 200
cout << rect.size() << endl;     //返回rect的尺寸 [10 × 20]
cout << rect.tl() << endl;       //返回rect的左上頂點的座標 [100, 50]
cout << rect.br() << endl;       //返回rect的右下頂點的座標 [110, 70]
cout << rect.width << endl;    //返回rect的寬度 10
cout << rect.height << endl;   //返回rect的高度 20
cout <<  rect.contains(Point(101, 51) ) << endl;  //返回布林變數,判斷是否包含Point點

輸出為:

200

[10 x 20]

[100, 50]

[110, 70]

10

20

1

3、參考文獻

1、Mat - The Basic Image Container

https://docs.opencv.org/master/d6/d6d/tutorial_mat_the_basic_image_container.html

2、cv::Mat Class Reference

https://docs.opencv.org/3.1.0/d3/d63/classcv_1_1Mat.html

3、OpenCV Mat 常用的基礎知識

https://blog.csdn.net/Librarvl/article/details/89892352

4、OpenCV Mat類詳解和用法

https://blog.csdn.net/Mason_Mao/article/details/82254285

5、《OpenCV3 程式設計入門》 , 電子工業出版社,毛星雨著

 

  尊重原創技術文章,轉載請註明。

https://www.cnblogs.com/pingwen/p/12292693.html