opencv Mat類

圖像的方向

一般教科書上默認圖像左上角爲(0,0)原點,沿原點向右爲x正方向,向下爲y正方向。這與在小孔成像模型中,我們面朝小孔看到的圖像座標一致。
即使存在Mat類中,左上方的第一個像素點也是mat[0][0],即行列首個下標均爲0

Mat定義

是一個類,由兩個數據部分構成,矩陣頭(包含矩陣尺寸,存儲方法,存儲地址等等)和一個指向存儲所有像素值的矩陣的指針

成員變量

int cv::Mat::cols;     //返回矩陣的列數(寬度) 
int cv::Mat::rows      // 返回矩陣行數(高度) 
cv::Mat::total;            //返回圖像的像素數
uchar* cv::Mat::data   // 指向矩陣的數據單元的指針 
int cv::Mat::dims      // 返回矩陣維度,該維度≥2 
MatSize cv::Mat::size  // 返回矩陣大小

//不常用
cv::Mat::step    //step代表以字節爲單位的圖像的有效寬度
cv::Mat::elemSize    //elemSize返回像素的大小=顏色大小(字節)*通道數
uchar* cv::Mat::data        //存儲圖像內容的首地址指針,定義爲uchar*類型

如果要獲取數據,參考

Mat depth;
float* dat=(float*)depth.data
//或者
float* dat=reinterpret_cast<float*>(depth.data);

成員函數

  • 獲取圖像位深度,(即矩陣元素的存儲方式,存儲每個像素所用的位數):
mat_name.depth()
  • 獲取矩陣通道的數目:
mat_name.channnels()
  • 獲取存儲的矩陣元素的數據類型(包括位深度,通道數,數據類型):
mat_name.type()
  • 矩陣轉置
mat_name.t()
  • 矩陣提取
Mat Rcw=Tcw.rowRange(0,3).colRange(0,3);  //提取變換矩陣Tcw4*4的前三行和前三列組成旋轉矩陣
Mat tcw=Tcw.rowRange(0,3).col(3);  //提取變換矩陣Tcw的平移向量部分
  • 矩陣拷貝
    徹底拷貝矩陣頭和矩陣內容(深拷貝),而不僅僅是使用智能指針引用。注意採用Mat的拷貝構造函數時淺拷貝
Mat Mat::clone()  //拷貝矩陣到新的矩陣中
void Mat::copyTo(Mat )   //拷貝到參數所代表的矩陣中去

創建二維Mat對象

參考淺談Opencv Mat類(常用構造函數和成員函數整理)
常見的初始化的示例:

Mat Matrix_name(行數,列數,存儲元素的數據類型,每個矩陣點的通道數)
Mat m(640,480,CV_8UC1,255);    //創建一個mat,每個元素都是255白、
Mat m(640,480,CV_8UC3,cv::Scalar(255,255,255));

Mat m(640,480,CV_8UC1);    //創建一個mat
Mat m(cv::Size(640,480),CV_8UC1);

Mat examples=(Mat_<float>(3,3)<<1,0,0,0,1,0,0,0,1);  //先行後列輸入

存儲元素的數據類型

CV_[位數][帶符號與否][類型前綴]C[通道數]

帶符號與否:S爲符號整型,U爲無符號整型,F爲浮點型
例如CV_8UC3

通道數賦值cv::Scalar()

Scalar是一個short型的向量,能夠使用指定的定製化值來初始化矩陣,還可以用來表示顏色。cv::Scalar(0)代表每個像素值只有1個通道,值爲0,cv::Scalar(0,0,0,0)代表每個像素值四個通道都初始化爲0。

cv::Mat mat;
mat.setTo(cv::Scalar(0));    //將mat的所有像素的所有通道都設爲0
cv::Scalar::all(0)    //所有通道都設爲0

矩陣尺寸cv::Size()

cv::Size(cols,rows);    //注意先列後行,先寬後高,與Mat構造函數不同

警告,cv::Mat的size是先列,後行,千萬別搞反了。

矩陣運算

矩陣點乘:

cv::Mat C=A*B

注意
參與點乘的兩個Mat矩陣的數據類型(type)只能是 CV_32F、 CV_64FC1、 CV_32FC2、 CV_64FC2 這4種類 型中的一種。若選用其他類型,比如CV_8UC1,編譯器會報錯“OpenCV Error:Assertion failed”

向量點乘

提取子矩陣

參考OpenCV中的提取子矩陣的函數
例如:

Mat exam=(Mat_<double>(4,4)<<
    1,2,3,4,
    5,6,7,8
    9,10,11,12,
    13,14,15,16);

cout<<exam.rowRange(0,3).colRange(0,3)<<endl;    //提取前三行前三列組成3*3矩陣

矩陣拼接

opencv:矩陣合併/拼接

訪問與修改Mat的單個像素元素

1.使用Mat的成員函數ptr<>()
推薦方法,cv::Mat中提供ptr函數訪問任意一行像素的首地址,ptr方式訪問效率高,自帶越界判定。
示例:

int nl = image.rows; //獲得圖像的行數nl
int nc = image.cols * image.channels();//獲得圖像每一列的總像素數(包括多通道)
for (int j = 0; j<nl; j++)//對每一行像素遍歷
{
    uchar* elem_ptr = image.ptr<uchar>(j);    //取圖像第j行首列元素指針爲data
    for (int i = 0; i<nc; i++){    //對同行的各個通道的像素元素逐個遍歷
        elem_ptr[i] = elem_ptr[i] / div*div + div / 2;    //修改單個元素的值
    }
}

2.使用迭代器遍歷圖像
安全,效率低,Iterator有兩種調用方式:

cv::MatIterator_<cv::Vec3b>   it;    //方式1
cv::Mat_<cv::Vec3b>::iterator    it;    //方式2

其示例:

cv::Mat_<cv::Vec3b>::iterator  it = image.begin<cv::Vec3b>();    //迭代器開始
cv::Mat_<cv::Vec3b>::iterator  itend = image.end<cv::Vec3b>();    //迭代器結束
for (; it != itend; ++it)    //迭代循環
{
    (*it)[0] = (*it)[0] / div*div + div / 2;    //對每個元素進行操作
    (*it)[1] = (*it)[1] / div*div + div / 2;
    (*it)[2] = (*it)[2] / div*div + div / 2;
}

3.使用Mat的成員函數at<>()
訪問速度最慢,

for (int j = 0; j< image.rows; j++){//這裏先按行遍歷
    for (int i = 0; i< image.cols; i++){//再按列遍歷
        image.at<cv::Vec3b>(j, i)[0] = image.at<cv::Vec3b>(j,i)[0] / div*div + div/2;
        image.at<cv::Vec3b>(j, i)[1] = image.at<cv::Vec3b>(j,i)[1] / div*div + div / 2;
        image.at<cv::Vec3b>(j, i)[2] = image.at<cv::Vec3b>(j, i)[2] / div*div + div / 2;
    }
}

注意at方式訪問像素是(y,x)方式,即先寫行數,後寫列數,跟cv::keypoint剛好相反

爲何0代表黑色,255代表白色

因爲灰度是由傳感器接收到的光強決定的,光強越強,亮度越高,所以傳感器由光強轉換的電壓也更高,所以數值就越大。

Opencv中顯示任意像素像素值

  1. 通過photoshop的吸管工具和信息面板
  2. 通過下面函數,運行後界面上方會出現一些縮放按鈕,然後某個像素放大到極致就會出現像素值
Mat src=imread("0.png",-1);
namedWindow("nihao",CV_WINDOW_AUTOSIZE);
imshow("nihao",src)

很奇怪,方法2在我電腦上沒有用,不會顯示那些縮放按鈕。怪事

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