OpenCV Mat的基本操作

Mat 矩阵创建

方法1. 使用Mat()构造函数

cv::Mat M1(2,2,CV_8UC3,Scalar(0,0,255))

这个函数的意思是,创建了一个名为M1的Mat,该Mat的尺寸为2,2,类型
为CV_8UC3,即8位uchar类型,该Mat通道数为3。这个mat的每一个元素
包含了3个通道或者说3个数值。然后用0,0,255为每一个元素赋值。
这里8位uchar型的取值为0~255,实际上如果一个Mat是用来表示RGB图像
的时候应该声明为CV_8UC3型

Mat型可以定义各种类型,可按F12快捷键查看头文件中的定义。定义的方式如下:CV_(位数)+(数据类型)+(通道数)
如CV_32FC1表示32位float型数据,有如下类型

  • CV_8UC1 CV_8UC2 CV_8UC3 CV_8UC4 CV_8SC1 CV_8SC2 CV_8SC3 CV_8SC4
  • CV_16UC1 CV_16UC2 CV_16UC3 CV_16UC4 CV_16SC1 CV_16SC2 CV_16SC3 CV_16SC4
  • CV_32SC1 CV_32SC2 CV_32SC3 CV_32SC4 CV_32FC1 CV_32FC2 CV_32FC3 CV_32FC4
  • CV_64FC1 CV_64FC2 CV_64FC3 CV_64FC4

方法2:使用create()函数,代码如下

cv::Mat M3;
M3.create(3,4,CV_8UC3);

表示首先声明一个mat型,名叫M3,其尺寸为3行,4列。

方法3: 使用内置函数初始化

  • 全初始化为0
Mat initZero=Mat::zeros(2,2,CV_32F);
  • 全初始化为1
Mat initOne= Mat::ones(2,2,CV_32F);
  • 全初始化为对角阵
Mat initEye=Mat::eye(2,2,CV_32F);

Mat 矩阵复制

1. 浅复制

cv::Mat srcM(2,2,CV_8UC3,Scalar(0,0,255))
cv::Mat dstM;
dstM=srcM;

表示首先声明一个mat名为 srcM,并初始化。然后声明一个mat名为dstM通过“=”把srcM复制给dstM。这样生成的矩阵,只是新生成一个矩阵头,dstM的data依然指向矩阵srcM的data,类似C++中的浅拷贝。
:

2. 深复制

cv::Mat srcM(2,2,CV_8UC3,Scalar(0,0,255))
cv::Mat dstM;
srcM.copyTo(dstM);

通过copyTo函数,可以实现深复制。也就是dstM是一个全新的矩阵,他在内存中的地址和srcM是不一样的。另外copyTo函数还可以加上掩模参数

Mat 矩阵复制遍历

当我们想读取或者修改Mat的任意内容时候,可以用以下方式访问Mat。

1. 利用指针.ptr

int height= image.rows; //行数
Int width = image.cols * image.channels(); //每行元素的总元素数量
for (int j=0; j<height; j++) 
{
//定义指针data,其值为image的第j行的头地址
uchar* data= image.ptr<uchar>(j);
for (int i=0; i<width; i++) 
{
//----开始处理每个像素,每个元素的值减少到1/2-----
data[i]= data[i]/2;
//-------------结束像素处理------------------------
} //单行处理结束
}

2.利用.at

遍历3通道的RGB图像
int height= image.rows; //行数
Int width = image.cols ; //每行元素的总元素数量
for (int j=0; j<height; j++) 
{
for (int i=0; i<width; i++) 
{
//----开始处理每个像素,每个元素的值减少到1/2-----
image.at<Vec3b>(j,i)[0]= image.at<Vec3b>(j,i)[0]/div*div + div/2;
image.at<Vec3b>(j,i)[1]= image.at<Vec3b>(j,i)[1]/div*div + div/2;
image.at<Vec3b>(j,i)[2]= image.at<Vec3b>(j,i)[2]/div*div + div/2;
//-------------结束像素处理------------------------
} //单行处理结束
}
遍历单通道的灰度图
int height= image.rows; //行数
Int width = image.cols * image.channels(); //每行元素的总元素数量
for (int j=0; j<height; j++) 
{
for (int i=0; i<width; i++) 
{
//----开始处理每个像素,每个元素的值减少到1/2-----
image.at<uchar>(j,i)= image.at<uchar>(j,i)/2;
//-------------结束像素处理------------------------
} //单行处理结束
}

3.利用迭代器

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
}

Mat 数学运算

Mat 加减乘除

相同类型的Mat 矩阵可以直接使用运算符进行加减乘除,其中代码矩阵对应位置的元素进行加减乘除

#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace cv;
int main() {
    Mat a=(Mat_<float>(2,2)<<1,1,1,1);
    Mat b=(Mat_<float>(2,2)<<1,2,3,4);
    Mat show;
    //1.add 
    //show=r.rows(0);
    show=a+b;
    cout<<show<<endl;
    //2.subtract
    show=a-b;
    cout<<show<<endl;
    //3., multiply
    show=a*b;
    cout<<show<<endl;
    //4.divide
    show=a/b;
    cout<<show<<endl;
    return 0;
}
结果如下:
[2, 3;
  4, 5]
[0, -1;
  -2, -3]
[4, 6;
  4, 6]
[1, 0.5;
  0.33333334, 0.25]

Mat 位运算

mat的位运算包含与或非、异或操作等。

  • 按位与:bitwise_and
  • 按位或:bitwise_or
  • 按位异或:bitwise_xor
  • 按位非:bitwise_not

Mat 矩阵求逆和求转置

  • 用inv()求逆
  • 用t()求转置
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main() {
    Mat r=(Mat_<float>(2,2)<<1,1,0,2);
    cout<<r<<endl;
    cout<<r.inv()<<endl;
    cout<<r.t()<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/EBDSoftware/article/details/128784515