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与特征相关的函数
#include
#include
//包含所有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
//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]
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就开始乱码了
Mat m = imread("1.jpg", CV_LOAD_IMAGE_GRAYSCALE);
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]*/
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;
cv::Point3f p3(1.f,2.f,3.f);
float x = p3.x;
float y = p3.y;
float z = p3.z;
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);
Vec3f是3通道的float类型,一般用来访问3通道图像的各个通道值,具体见5.1
//定义
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;
}
cv::Size类跟cv::Point类类似,cv::Point也有Point2f,Point2i
注意,头文件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);
//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;
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
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的内存.
//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);
定义三通道图像:
cv::Mat img (640, 480, CV_8UC3, cv::Scalar::all(0));
注意,img.at
中的(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;
}
}
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;
}
}
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;
}
sum(cv::Mat)
,返回cv::Scalar类型.
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]
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]
参考这位博主的博客:c++ opencv图像处理—好博客收藏
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);