OpenCV-影象處理(03、Mat物件)
阿新 • • 發佈:2019-01-05
Mat物件與IplImage物件
- Mat物件 OpenCV2.0之後引進的影象資料結構、自動分配記憶體、不存在記憶體洩漏的問題,是面向物件的資料結構。分了兩個部分,頭部與資料部分
- IplImage 是從2001年OpenCV釋出之後就一直存在,是C語言風格的資料結構,需要開發者自己分配與管理記憶體,對大的程式使用它容易導致記憶體洩漏問題
Mat物件使用
建構函式(部分常用的) | 說明 |
---|---|
Mat(); | 無參構造方法 |
Mat(int rows, int cols, int type); | 建立行數為rows,列數為cols,型別為type的影象 |
Mat(Size size, int type); | 建立大小為size,型別為type的影象 |
Mat(int rows, int cols, int type, const Scalar& s); | 建立行數為rows,列數為cols,型別為type的影象,並且將所有元素初始化為s |
Mat(Size size, int type, const Scalar& s); | 建立大小為size,型別為type的影象,並且將所有元素初始化為值s |
Mat(int ndims, const int* sizes, int type); | |
Mat(int ndims, const int* sizes, int type, const Scalar& s); | |
Mat(const Mat& m) | 將m賦值給新建立的物件,此處不會對影象資料進行復制,m和新物件共用影象資料 |
其中:type可以是:CV_8UC1、CV_16SC1、… … 、CV_64FC3 等。C[The channel number]、U(unsigned integer)表示的是無符號整數,S(signed integer)是有符號整數, F(float)是浮點數。
裡面的 8U 表示8位無符號整數(0 ~ 255),16S 表示16位有符號整數(-32768 ~ 32767),64F 表示64位浮點 double資料型別,C後面的數表示通道數,例如:C1表示一個通道數的影象,C3表示3通道影象,以此類推。
#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>
using namespace std;
using namespace cv;
int main(int argc,char** argv){
Mat src;
src=imread("E:/Experiment/OpenCV/Pictures/dog2.jpg");
if(!src.data){
cout<<"Could not load image ... "<<endl;
return -1;
}
//建構函式示例
Mat dst1(250,250,CV_8UC1);//建立200行200列型別為8位單通道矩陣
Mat dst2(Size(250,250),CV_8UC3);//建立300行400列型別為8位3通道矩陣
// CV_8UC1 8表示8位,UC表示unsigned char,1表示1個通道, Scalar表示向量長度,要與通道數目一致
Mat dst3(300, 300, CV_8UC3, Scalar(0, 0, 255));//3*3個畫素點,CV_8UC3表示畫素點為三個通道顏色資料,CV_8UC1表示畫素點為單通道,對應的傳 Scalar(255)
Mat dst4(Size(300,300),CV_8UC1,Scalar(127));//500*500個畫素點,CV_32FC2表示32位浮點型資料,2通道影象,127表示灰色
Mat dst5(src);//將src賦值給dst1,共用資料物件
Mat dst6 = Mat(src.size(), src.type());
dst6 = Scalar(127, 0, 255);//給矩陣所有的畫素點設定顏色資料,緋紅,這裡的 = 號運算子過載了。Scalar引數順序是 B G R
namedWindow("input",CV_WINDOW_AUTOSIZE);
imshow("input",src);
namedWindow("output1",CV_WINDOW_AUTOSIZE);
imshow("output1",dst1);
namedWindow("output2",CV_WINDOW_AUTOSIZE);
imshow("output2",dst2);
namedWindow("output3",CV_WINDOW_AUTOSIZE);
imshow("output3",dst3);
namedWindow("output4",CV_WINDOW_AUTOSIZE);
imshow("output4",dst4);
namedWindow("output5",CV_WINDOW_AUTOSIZE);
imshow("output5",dst5);
namedWindow("output6",CV_WINDOW_AUTOSIZE);
imshow("output6",dst6);
waitKey(0);
return 0;
}
執行截圖:
函式 | 功能 |
---|---|
row | 行數 |
col | 列數 |
rowRange | 為指定的行span建立一個新的矩陣頭,可去指定行區間元素 |
colRange | 為指定的列span建立一個新的矩陣頭,可去指定列區間元素 |
Mat clone() | 建立一個數組及其基礎資料的完整副本 |
void copyTo(Mat mat) | 完全複製一份 |
void convertTo(Mat dst, int type) | 轉換,比如8位的轉換為float |
int channels() | 通道數 |
int depth() | 深度 |
bool empty(); | 是否空,如果陣列沒有elements,則返回true |
uchar* ptr(i=0) | 矩陣資料指標 |
Mat::zeros | 返回指定大小和型別的0陣列 |
Mat::ones | 返回一個指定的大小和型別全為1的陣列 |
Mat::at | 返回對指定陣列元素的引用 |
#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>
using namespace std;
using namespace cv;
int main(int argc,char** argv){
Mat src;
src=imread("E:/Experiment/OpenCV/Pictures/dog2.jpg");
if(src.empty()){
cout<<"Could not laod image ..."<<endl;
return -1;
}
//圖片的複製操作
Mat dst1=src.clone();//完全拷貝
Mat dst2;
src.copyTo(dst2);//完全拷貝
Mat dst3(src);//只是複製部分,Mat物件頭部與資料的指標,不會複製資料
namedWindow("input",CV_WINDOW_AUTOSIZE);
imshow("input",src);
namedWindow("output1",CV_WINDOW_AUTOSIZE);
imshow("output1",dst1);
namedWindow("output2",CV_WINDOW_AUTOSIZE);
imshow("output2",dst2);
namedWindow("output3",CV_WINDOW_AUTOSIZE);
imshow("output3",dst3);
//其他函式測試
Mat dst4;//測試channels()、ptr()、cols()、rows();
cvtColor(src, dst4, CV_BGR2GRAY);//dst4物件輸出影象的記憶體是自動分配的
printf("rgb.channels=%d, gray.channels=%d,src.type=%d,dst4.type=%d\n", src.channels(), dst4.channels(), src.type(), dst4.type());//rgb通道數為3,gray通道數為1,16,0
const uchar* firstRow = dst4.ptr<uchar>(0);//影象第一行顏色資料
printf("first pixel value : %d\n", *firstRow);
printf("dst.cols=%d, dst.rows=%d\n\n", dst4.cols, dst4.rows);
// CV_8UC1 8表示8位,UC表示unsigned char,1表示1個通道, Scalar表示向量長度,要與通道數目一致
Mat dst5(3, 3, CV_8UC3, Scalar(0, 0, 255));//3*3個畫素點,CV_8UC3表示畫素點為三個通道顏色資料,CV_8UC1表示畫素點為單通道,對應的傳 Scalar(255)
cout << "dst5 = " << endl << dst5 << endl<<endl;//列印每個通道顏色資料
/* m =
[ 0, 0, 255, 0, 0, 255, 0, 0, 255;
0, 0, 255, 0, 0, 255, 0, 0, 255;
0, 0, 255, 0, 0, 255, 0, 0, 255 ]
*/
imshow("scalar", dst5);
Mat dst6;
dst6.create(src.size(), src.type());//以create方式建立Mat
dst6 = Scalar(0, 0, 255);//Scalar引數順序是 B G R
imshow("create", dst6);
//Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0); //定義小陣列,以 << 運算子過載 建立Mat
Mat zeros = Mat::zeros(2, 2, CV_8UC1);//初始值0
cout << "zeros = " << endl << zeros << endl<<endl;
/*
zeros =
[0, 0;
0, 0]
eye =
[1, 0;
0, 1;
0, 0]
*/
Mat eye = Mat::eye(3, 2, CV_8UC1);//沿著主對角線的畫素點(不是通道)的第一個通道的資料設定為1,其他都為0,對於CV_8UC1的方陣可以生成單一矩陣
cout << "eye = " << endl << eye << endl;
waitKey(0);
return 0;
}
執行截圖:
- 部分複製:一般情況下只會複製Mat物件的頭和指標部分,不會複製資料部分
Mat A= imread(imgFilePath);
Mat B(A) // 只複製
- 完全複製:如果想把Mat物件的頭部和資料部分一起復制,可以通過如下兩個API實現
Mat F = A.clone();
或Mat G; A.copyTo(G);
- Mat物件使用-四個要點:
- 輸出影象的記憶體是自動分配的
- 使用OpenCV的C++介面,不需要考慮記憶體分配問題
- 賦值操作和拷貝建構函式只會複製頭部分
- 使用clone與copyTo兩個函式實現資料完全複製
Mat定義陣列
-
cv::Mat建構函式
Mat M(2,2,CV_8UC3, Scalar(0,0,255))
其中前兩個引數分別表示行(row)跟列(column)、第三個CV_8UC3中的8表示每個通道佔8位、U表示無符號、C表示Char型別、3表示通道數目是3,第四個引數是向量表示初始化每個畫素值是多少,向量長度對應通道數目一致 -
建立多維陣列cv::Mat::create
int sz[3] = {2,2,2};
Mat L(3,sz, CV_8UC1, Scalar::all(0));
-
cv::Mat::create實現
Mat M;
M.create(4, 3, CV_8UC2);
M = Scalar(127,127);
cout << “M = " << endl << " " << M << endl << endl;
uchar* firstRow = M.ptr(0);
printf(”%d", *firstRow);
- 定義小陣列
Mat C = (Mat_(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
cout << "C = " << endl << " " << C << endl << endl;
程式程式碼見上