opencv和cv::Mat常用属性和函数

opencv的安装请参考:ubuntu16.04(14.04)(重)安装OpenCV3.3.0与opencv_contrib3.3.0
 

这篇文章包括:

1. opencv常用头文件及作用
2. cv::Mat常见初始化
  - 初始化:自定义初始化、从已有结构初始化、从图像初始化
  - 访问和块操作
  - 常用类:cv::Point2f、 cv::Vec3b、 cv::Rect 、cv::Size
  - cv::Mat转Eigen::Matrix
  - 从深度图读取深度信息
3. cv::Mat常见属性
4. cv::Mat常见函数
  - clone()和copyTo()的区别
5.cv::Mat的RGB赋值(改颜色)
6.sum()函数,mat矩阵求和
7.opencv图像处理链接
8.mat与特征相关的函数
 


1. opencv常用头文件:

1.1 最常用头文件:

#include 
#include 

1.2 基本头文件及功能

//包含所有opencv头文件
#include 

/* OpenCV基本数据结构, 动态数据结构, 绘图函数, 数组操作相关函数,
辅助功能与系统函数和宏, 与OpenGL的互操作*/
#include 

/* 图像显示(cv::Mat, cv::imread(), cv::imshow(), cv::waitKey()等 ),
 滑块, 鼠标交互, I/O */
#include 
#include 

/* 特征检测, 目标检测等内容, 线性和非线性的图像滤波, 图像的几何变换,
 其它(Miscellaneous)图像转换, 直方图相关*/
#include 

//照片处理, 照片恢复
#include 

/*特征检测和描述, 特征检测器(Feature Detectors)通用接口, 描述符提取器(Descriptor Extractors)通用接口,
 描述符匹配器(Descriptor Matchers)通用接口, 通用描述符(Generic Descriptor)匹配器通用接口,
 关键点绘制函数和匹配功能绘制函数*/
#include 

//快速近似最近邻搜索, 聚类
#include 

//视频跟踪和背景分割
#include 

//校准和立体
#include 

//机器学习,图像识别
#include 

 

2. cv::Mat初始化:

2.1 自定义赋值初始化

//m为3*5的矩阵,float型的单通道,把每个点都初始化为1
cv::Mat m(3,5,CV_32FC1,1);
//或者
cv::Mat m(3, 5, CV_32FC1, cv::Scalar(1));

cv::Mat m2 = (cv::Mat_<float>(2,2) << 1,2,3,4);

int data[] = {1,2,3,4,5,6};
cv::Mat m3(2,3,CV_32SC1,data);

//用cv::Size定义大小
cv::Mat img = cv::Mat(cv::Size(480,640),CV_8UC3);//注意宽和高的定义,这个(480,640)才是我们常说的640*480图像
//m为:
[1, 1, 1, 1, 1;
  1, 1, 1, 1, 1;
  1, 1, 1, 1, 1]
using namespace cv;
//m为3*5的矩阵,float型的2通道,把每个点都初始化为1 2
Mat m(3, 5, CV_32FC2, Scalar(1, 2));
//m为:
[1, 2, 1, 2, 1, 2, 1, 2, 1, 2;
  1, 2, 1, 2, 1, 2, 1, 2, 1, 2;
  1, 2, 1, 2, 1, 2, 1, 2, 1, 2]

2.2 从已有的数据结构初始化

double *data = new double[15];
for (int i = 0; i < 15; i++)
{
   data[i] = 1.2;
}
Mat m(3, 5, CV_32FC1, data);
//m为:
[1.2, 1.2, 1.2, 1.2, 1.2;
  1.2, 1.2, 1.2, 1.2, 1.2;
  1.2, 1.2, 1.2, 1.2, 1.2]

注意,这里是对data数据的浅拷贝,data所占内存数据改变,则m也会改变,例如:

delete [] data;
[-1.456815990147463e+144, -1.456815990147463e+144, -1.456815990147463e+144, -1.456815990147463e+144, -1.456815990147463e+144;
  -1.456815990147463e+144, -1.456815990147463e+144, -1.456815990147463e+144, -1.456815990147463e+144, -1.456815990147463e+144;
  -1.456815990147463e+144, -1.456815990147463e+144, -1.456815990147463e+144, -1.456815990147463e+144, -1.456815990147463e+144]

可见,删除data之后,m就开始乱码了
 

2.3 从图像初始化

Mat m = imread("1.jpg", CV_LOAD_IMAGE_GRAYSCALE);

2.4 cv::Mat块访问和常用操作

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

/*m is:
[1, 2, 3, 4;
 5, 6, 7, 8;
 9, 10, 11, 12;
 13, 14, 15, 16]*/
 
//访问(i,j)位置的元素
float f_ij = m.at<float>(i,j);

//访问第i行
cv::Mat m_i = m.row(i);

//访问第j列
cv::Mat m_j = m.col(j);

//访问第u行到第d - 1行
cv::Mat m_u_d_1 = m.rowRange(u,d);
m_u_d_1 = m.rowRange(cv::Range(u,d));

//访问第l列到第r - 1列
cv::Mat m_l_r_1 = m.colRange(l,r);
m_l_r_1 = m.colRange(cv::Range(l,r);

//访问 第u行到第d - 1行,第l列到第r - 1列 围成的矩形范围
cv::Mat m_lurd = m(cv::Range(u,d), cv::Range(l,r));
m_lurd = m(cv::Range(1,4), cv::Range(0,2));//访问的是第1到3行,0到1列的矩阵,是3 * 2的矩阵
/* m_lurd is: 
[5, 6;
 9, 10;
 13, 14]*/

//访问以点(l,u)为左上角,宽高为w和h的矩形,注意w是宽,也就是列,h是高,也就是行
cv::Mat m_luwh = m(cv::Rect(l,u,w,h));
m_luwh = m(cv::Rect(1,0,3,2));
/* m_luwh is: 
[2, 3, 4;
 6, 7, 8]*/

//方位偏移量为n的对角线矩阵
cv::Mat m_diag_n = m.diag(n);
m_diag_n = m.diag();//访问的是对角线元素
m_diag_n = m.diag(1);
/* m_diag_n is:
[2; 
 7;
 12]*/

2.5 cv::Point2f

(1) 定义和初始化

cv::Point2f p(1.f,2.f);//也对应有cv::Point3f
p = cv::Point2f(1.f,2.f);

//深拷贝
cv::Point2f p2(p);

//隐式转换成cv::Vect2f
cv::Vec2f v = p2;

(2) 访问

cv::Point3f p3(1.f,2.f,3.f);
float x = p3.x;
float y = p3.y;
float z = p3.z;

(3) 运算

cv::Point3f p4(1.f,2.f,3.f);
cv::Point3f p5(1.1,1.2,1.3);

//点乘
cv::Point3f p6 = p4.dot(p5);

//叉乘
cv::Point3f p7 = p4.cross(p5);

2.6 cv::Vec3f - 3通道类型

Vec3f是3通道的float类型,一般用来访问3通道图像的各个通道值,具体见5.1

2.7 cv::Rect - 矩形类

//定义
cv::Rect rect(100,50,20,30);//绘制了一个左上角坐标为(100,50),宽为20,高为30的矩形,注意100是列数,50是行数
//注意,不包含120这一列,50这一行

//常用操作
int area = rect.area();     //返回rect的面积   
cv::Size s = rect.size();     //返回rect的尺寸 [20 × 30]  
cv::Point2f p_tl = rect.tl();       //返回rect的左上顶点的坐标 [100, 50]  
cv::Point2f p_br = rect.br();       //返回rect的右下顶点的坐标 [120, 80]  
int w = rect.width();    //返回rect的宽度 50  
int h = rect.height();   //返回rect的高度 100  
bool isContain = rect.contains(Point(x, y));  //返回布尔变量,判断rect是否包含Point(x, y)点,注意(120,80)不包含,(119,79)包含

//对矩形Rect进行平移和缩放
rect += cv::Point(10,20);//左上角点变成了(110,70),size依然是[20x30]
rect ++ cv::Size(10,20);//左上角点是(110,70),size变成了[30x50]

//矩形之间对比,返回bool
bool isEqual = (rect1 == rect2);//当左上角点相同,大小相同时,返回true,否则返回false;
isEqual = (rect1 != rect2);

//判断rect2是否在rect1里面
bool isInside(cv::Rect r1, cv::Rect r2){
	return (r1 & r2) == r2;
}

2.8 cv::Size,cv::Size2f, cv::Size2i

cv::Size类跟cv::Point类类似,cv::Point也有Point2f,Point2i

2.9 cv::Mat矩阵转换成Eigen::Matrix

注意,头文件eigen库一定要在opencv库前面,否则报错

#include 
#include 

cv::Mat mat = (cv::Mat_<float>(2,2) << 1.f,2.f,3.f,4.f);
Eigen::MatrixXf matrix;
cv::cv2eigen(mat,matrix);

2.10 读取深度图,并获取深度

//CV_LOAD_IMAGE_UNCHANGED表示在每个通道中,每个像素的位深为8 bit,通道数(颜色)保持不变。
//而CV_LOAD_IMAGE_GRAYSCALE – 位深=8 bit 通道数=1(颜色变灰)
cv::Mat depth_img = cv::imread("depth1.pgm",CV_LOAD_IMAGE_UNCHANGED);
//获取深度
unsigned int d = depth_img.ptr<unsigned short> ( v )[u]; // 深度值,(u,v)为像素坐标
//一般会有个深度scale,然后对深度<= 0的数据表示没有测量到.
if ( d <= 0 ) continue; // 表示没有测量到
double depth = double(d) / depth_scale;

 

3. cv::Mat常用属性:

cv::Mat m(3, 5, CV_32FC1, Scalar(1));

int r = m.rows;//
int c = m.cols;//
cv::Size size = m.size();//输出c * r,而不是r * c;

int n = m.channels();

bool isEmpty = m.empty();//no element,return true;

m.type();//返回m中元素的标识符,如CV_32FC3

 

4. 常用函数

4.1 clone()和copyTo()的区别

Mat img(3, 5, CV_32FC1, Scalar(1));
Mat m = img.clone();

/**
mask作为一个掩模板,如果在某个像素点(i, j)其值为1(只看第一通道,所以mask单通道即可)则把
img.at(i, j)处的值直接赋给m.at(i, j),如果其值为0则m.at(i, j)处保留其原始像素值
*/
img.copyTo(m);//
img.copyTo(m,mask);


//clone(), 总是为目标重新分配内存;
//copyTo(),当目标矩阵和源矩阵有相同的大小和类型(CV_32F)时,不为目标矩阵重新分配内存,
//若不一样,则为目标矩阵重新分配内存.下面举例说明:
cv::Mat m1 = cv::Mat::ones(1,5,CV_32F);
cv::Mat m2 = m1;//浅拷贝,m2指向m1的内存 
//m1 m2 均为: [1.0 , 1.0 , 1.0 , 1.0 , 1.0]

m2.at<float>(0,1) = 2.f; //由于是浅拷贝,m1和m2指向相同的内存,所以m1和m2均变为:[1.0 , 2.0 , 1.0 , 1.0 , 1.0]

Mat m3 = Mat::zeros(1,5,CV_32F);
m3.copyTo(m1);//m1和m3有相同的大小,所以,不给m1重新分配内存,m1和m2依然指向相同内存,m1和m2均变为[0,0,0,0,0]
m2.at<float>(0,4) = 10.f;//由于m1和m2依然指向相同内存,所以,m1和m2均为:[0, 0, 0, 0, 10]
m1 = m3.clone();//因为clone函数总是(给m1)重新分配内存,所以m1不再指向m2的内存,m2不变,即m2仍为[0, 0, 0, 0, 10],m1变为[0,0,0,0,0]

cv::Mat m4 = m1;//浅拷贝,m1和m4指向相同内存
m4 = (cv::Mat_<float>(1,5) << 4.f,4.f,4.f,4.f,4.f);//这个时候给m4重新分配内存了,所以m4不再指向m1的内存.

4.2 其他常用函数

//covertTo(),将img元素换成TYPE类型,缩放SCALE,便宜OFFSET,加入m中;
img.covertTo(m,TYPE,SCALE,OFFSET);
Mat m4, m5;
m.convertTo(m4,CV8UC1);
m.convertTo(m5,CV_32FC1,0.1,1);//m2的元素 乘以 0.1 + 1 赋给m5

//setTo(),将img中所有元素设定成s,若有mask,则只设定mask中的非零元素相应位置的img元素成s;
img.setTo(s,mask);

//img为m*n矩阵,在img末尾扩展1*n的矩阵,元素为val;
int val = 5;
img.push_back(val);
//img为m*n矩阵,在img的末尾扩展k*n的m矩阵
img.push_back(m);//m是前面定义的cv::Mat

//移除末尾n行
img.pop_back(n);

 

5. 给三通道cv::Mat赋RGB值( 颜色 )

 定义三通道图像:

cv::Mat img (640, 480, CV_8UC3, cv::Scalar::all(0));

5.1 用at<>()方法*

注意,img.at(i,j)[0]中的(i,j),i是列数,j是行数.

#include 
srand((undigned int)time(0));
for (int i = 0; i< image.cols; i++)
{
	for (int j = 0; j< image.rows; j++)
	{
		img.at<cv::Vec3b>(i, j)[0] = rand() / 255;
		img.at<cv::Vec3b>(i, j)[1] = rand() / 255;
		img.at<cv::Vec3b>(i, j)[2] = rand() / 255;
	}                
}

5.2 用ptr<>()方法

int nr = img.rows;
int nc = img.cols * img.channels();
for (int i = 0; i< nr; i++)
{
	uchar *ptr = img.ptr<uchar>(i);
	for (int j = 0; j< nc; j++)
	{
		ptr[j] = rand() / 255;
	}                
}

5.3 用迭代器遍历

cv::Mat_<cv::Vec3b>::iterator it = img.begin<cv::Vec3b>();
cv::Mat_<cv::Vec3b>::iterator itend = img.end<cv::Vec3b>();
for (; it != itend; ++it)
{
	(*it)[0] = rand() / 255;
	(*it)[1] = rand() / 255;
	(*it)[2] = rand() / 255;
}

 

6. sum()函数,mat矩阵求和

sum(cv::Mat),返回cv::Scalar类型.

6.1 对于单通道

    Mat mat = Mat::ones(3, 3, CV_8UC1);
    Scalar sum_mat = sum(mat);
    cout << sum_mat[0] << endl;//或者 cout << sum(mat)[0] << endl;
    //如果
    cout << sum(mat) << endl;

输出: 9
  [9,0,0,0]

6.2 对于三通道

	cv::Mat mat = cv::Mat::ones(3,3,CV_8UC3);
	mat.at<cv::Vec3b>(0,0)[1] = 5;
	mat.at<cv::Vec3b>(0,0)[2] = 7;
	cout << "mat :\n " << mat << endl;
	cout << "sum: " << sum(mat) << endl;

输出:

mat :
 [  1,   5,   7,   1,   0,   0,   1,   0,   0;
   1,   0,   0,   1,   0,   0,   1,   0,   0;
   1,   0,   0,   1,   0,   0,   1,   0,   0]
sum: [9, 5, 7, 0]

 

7. 图像处理

参考这位博主的博客:c++ opencv图像处理—好博客收藏

8. 与特征相关的函数

(1) 特征提取

vector<cv::KeyPoint> kpts1,kpts2;
cv::Ptr<cv::FeatureDetector> detector = cv::ORB::create();
cv::Ptr<cv::DescriptorExtractor> descriptor = cv::ORB::create();
cv::Ptr<cv::DescriptorMatcher> matcher = cv::DescriptorMatcher::create("BruteForce-Hamming");

//-- 第一步:检测 Oriented FAST 角点位置
detector->detect ( img_1,kpts1 );
detector->detect ( img_2,kpts2 );

//-- 第二步:根据角点位置计算 BRIEF 描述子
descriptor->compute ( img_1, kpts1, descriptors_1 );
descriptor->compute ( img_2, kpts2, descriptors_2 );

//画提出来的点
cv::Mat outimg1;
cv::drawKeypoints( img_1, keypoints_1, outimg1, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
cv::imshow("ORB特征点",outimg1);

//画两张图:
cv::Mat img_match;
cv::drawMatches ( img_1, kpts1, img_2, kpts1, matches, img_match );

//第三步:对两幅图像中的BRIEF描述子进行匹配,使用 Hamming 距离
vector<cv::DMatch> matches;
//BFMatcher matcher ( NORM_HAMMING );
matcher->match ( descriptors_1, descriptors_2, matches );

 上面代码中,DMatch结构存放的是匹配的左右图中点对信息,包括左右点序号,匹配对的汉明距离:

matches[i].queryIdx;//存放的是匹配点对左点在左图中提取的关键点kpts1中的序号
cv::Point2f pt_left(kpts1[matches[i].queryIdx].pt.x , kpts1[matches[i].queryIdx].pt.y)
matches[i].trainIdx;存放的是匹配点对右点在右图中提取的关键点kpts1中的序号
cv::Point2f pt_right(kpts1[matches[i].trainIdx].pt.x , kpts1[matches[i].trainIdx].pt.y)
double dist = matches[i].distance;//汉明距离

 将cv::Mat转Eigen::Matrix

#include 
#include 
cv::Mat mat(3,3,CV_32FC1,1);
Eigen::Matrix3f matrix;
cv::cv2eigen(mat,matrix);

你可能感兴趣的:(C++,operation,and,syntax)