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在我电脑上没有用,不会显示那些缩放按钮。怪事

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