1. 程式人生 > >OpenCV-影象處理(03、Mat物件)

OpenCV-影象處理(03、Mat物件)

Mat物件與IplImage物件

  • Mat物件 OpenCV2.0之後引進的影象資料結構、自動分配記憶體、不存在記憶體洩漏的問題,是面向物件的資料結構。分了兩個部分,頭部與資料部分
  • IplImage 是從2001年OpenCV釋出之後就一直存在,是C語言風格的資料結構,需要開發者自己分配與管理記憶體,對大的程式使用它容易導致記憶體洩漏問題

Mat物件使用

  • 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;
}

執行截圖:
在這裡插入圖片描述
在這裡插入圖片描述

  • Mat物件常用方法

函式 功能
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物件使用-四個要點:
    1. 輸出影象的記憶體是自動分配的
    2. 使用OpenCV的C++介面,不需要考慮記憶體分配問題
    3. 賦值操作和拷貝建構函式只會複製頭部分
    4. 使用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;
    在這裡插入圖片描述
    程式程式碼見上