OpenCV(C++)学习笔记(一)

OpenCV(C++)学习笔记(一)

OpenCV Mat类

Mat类的定义和部分属性

class CV_EXPORTS Mat
{
    public:
    /*flag参数中包含一些关于矩阵的信息:
    	——矩阵标识
    	——数据是否连续
    	——深度
    	——通道数目
    */
    int flag;
    //矩阵的维数,取值大于等于2
    int dims;
    //矩阵的行数和列数,如果矩阵超过二维,这两个变量的值都为-1
    int rows,cols;
    //指向数据的指针
    uchar* data;
}

创建构造函数

无参数构造函数:
Mat::Mat();
创造指定大小,类型type的图像
Mat::Mat(int rows,int cols,int type);
Mat::Mat(Size size,int type);
Mat::Mat(int ndims,const int *sizes,int type);
Mat::Mat(const std::vector<int>& sizes,int type);
创建指定大小,类型type,所有元素都初始化为s值的图像
Mat::Mat(int rows,int cols,int type,const Scalar& s);
Mat::Mat(Size size,int type,const Scalar& s);
Mat::Mat(int ndims,const int* sizes,int type,const Scalar& s);
Mat::mat(const std::vector<int>& sizes,int type,const Scalar& s);
创建指定大小,类型type,步长为step的图像
Mat::Mat(int rows,int cols,int type,void* data,size_t step=AUTO_STEP);
Mat::Mat(Size size,int type,void* data,size_t step=AUTO_STEP);
Mat::Mat(int ndims,const int* sizes,int type,void* data,size_t steps=0);
Mat::Mat(const std::vector<int>& sizes,int type,void* data,const size_t* steps=0);(行步长指矩阵每行所占的字节数;此函数不创建内存,直接使用data所指的内存)


例子:
//创建行数为3,列数为2,类型为8位无符号整形,所有元素都初始化为(0,0,255)的三通道图像
Mat M(3,2,CV_8UC3,Scalar(0,0,255));
//创建行数为3,列数为2,通道数为5的图像
Mat M(3,2,CV_8UC(5));
创建大小,类型与m相同的图像
Mat::Mat(const Mat& m);
创建大小,类型与指定m部分相同的图像
Mat::Mat(const Mat& m,const Range& rowRange,const Range& colRange=Range::all());
Mat::Mat(const Mat& m,const Rect& roi);
Mat::Mat(const Mat& m,const Range* ranges);
Mat::Mat(const Mat& m,const std::vector<Range>& ranges);

create()函数方法

Mat::create(int rows,int cols,int type);
Mat::create(Size size,int type);
Mat::create(int ndims,const int* sizes,int type);
Mat::create(const std::vector<int>& sizes,int type);
//create()函数不能设置图像像素/矩阵元素的初始值

例子:
//构造函数创建图像
Mat M(3,2,CV_8UC3);
//释放内存重新创建图像
M.create(2,2,CV_8UC2);

注:create()函数指定的参数与当前的图像参数相同,则不进行内存申请,如果参数不同,则会减少当前图像数据内存的引索,并重新申请内存。

创建一些特殊矩阵的方法

全0矩阵
Mat::zeros(int rows,int cols,int type);
Mat::zeros(Size size,int type);
Mat::zeros(int ndims,const int* sz,int type);
全1矩阵
Mat::ones(int rows,int cols,int type);
Mat::ones(Size size,int type);
Mat::ones(int ndims,const int* sz,int type);
单位矩阵
Mat::eye(int rows,int cols,int type);
Mat::eye(Size size int type);

矩阵元素的表达

单通道和多通道图像的元素类型一般为8U,也可以为16S,32F等,这些类型可以uchar,short,float等基本数据类型表达。

对于M * N * C多通道图像,此时矩阵元素已经不是基本数据类型,而是一个向量。

OpenCV定义了一个模板类Vec,可用来表示一个向量

2/3/4维uchar向量
typedef Vec<uchar,2> Vec2d;
typedef Vec<uchaer,3> Vec3d;
typedef Vec<uchar,4> Vec4d;

Vec3d color;//描述RGB颜色的color变量
color[0]=255;//B分量
color[1]=0;//G分量
color[2]=0;//R分量

像素的读写

使用at()函数

at函数为模板函数,它返回指定矩阵元素的引用
请添加图片描述
tips:at()函数优点是代码可读性高,但是函数效率不是很高,并不推荐使用at()函数遍历图像。at()函数只在debug模式下进行越界检查。

使用迭代器

Mat类支持C++ STL库中的迭代器(iterator)进行遍历

Mat gray(480,640,CV_8UC1);
MatIterator <uchar> grayItr,grayEnd;
for(grayItr = gray.begin<uchar>(),
   grayEnd = gray.end<uchar>();
   grayItr!=grayEnd;grayItr++)
    *grayItr=rand()%255;
使用指针
Mat gray(480,640,CV_8UC1);
for(int i=0;i<gray.rows;i++)
{
    uchar* p=gray.ptr<uchar>(i);
    for(int j=0;j<gray.cols;j++)
    {
        p[j]=(i+j)%255;
    }
}

tips:在重视程序速度的情况下,建议使用指针进行遍历。如果指针访问出错,程序运行时可能出现“段错误”(segment fault)

选取图像局部区域

选取单行或单列
Mat::row(int y)const;
Mat::col(int x)const;

//取出A矩阵的第i行
Mat line =A.row(i);

//取出A中数据的第i行将这行乘2后赋值给第j行
A.row(j) A.row(i)*2;
选取多行或多列

通过使用Range类,可以选取矩阵的多行或多列

//创建一个单位阵
Mat A=Mat::eye(10,10,CV_32S);
//提取全部行和1到3列(不包括第3列)
Mat B=A(Range::all(),Range(1,3));
//提取5到9行(不包括第9行),提取全部列
Mat C=B(Range(5,9),Range::all());

//可直接写为
Mat A=Mat::eye(10,10,CV_32S);
Mat C=A(Range(5,9),Range(1,3));
选取感兴趣区域

可使用Rect()类

//创建宽为320,高度为240的3通道图像
Mat img(320,240,CV_8UC3);
//选取img中的Rect(10,10,100,100)的区域为ROI
//使用构造函数
Mat roi(img,Rect(10,10,100,100));
Mat roi2(img,Range(10,100),Range(10,100));
使用括号运算符
Mat roi3=img(Rect(10,10,100,100));
Mat roi4=img(Range(10,100),Range(10,100));
选取对角线
Mat::diag(int d=0)const

请添加图片描述

tips:选取局部区域的方法都不进行内存的复制操作,新对象与原始对象共享相同的数据区域,因此执行速度快。

输出

Mat类重载的<<操作符,可以使用流操作输出矩阵内容,并支持不同的输出格式

Mat R(3,2,CV_8UC3);
randu(R,Scalar::all(0),Scalar::all(255));
cout<<R<<endl;//默认输出模式
cout<<format(R,Formatter:FMt_PYTHON)<<endl;//python输出模式
cout<<format(R,Fprmatter::FMT_NUMPY)<<endl;//numpy输出模式
cout<<format(R,Fprmatter::FMT_C)<<endl;//C语言输出模式
cout<<format(R,Fprmatter::FMT_CSV)<<endl;//CSV输出模式

Mat表达式

——加减取负:A+B,A+s,s+A,-A

——缩放:A*alpha

——对应元素的乘除:A.mul(B),A/B,alapha/A

——矩阵乘法:A*B

——转置:A.t()

——求逆和求伪逆A.inv()

——比较运算:A cmpop B,alpha cmpop A(cmpop可为>,>=,==,!=,<)。若条件成立,结果矩阵的对应元素被置为255,否则为0。

——位逻辑运算:A logicop B,A logicop s ,s logicop A,~A(logicop可为&,|和^)

——对应元素的最大最小:min(A,B),min(A,alpha),max(A,B) ,max(A,alpha)

——元素的绝对值:abs(A)

——叉乘和点乘:A.cross(B),A.dot(B)

Mat_ 类

Mat_ 类是对Mat类的一个轻量级包装,它是一个模板类,使得访问元素不需要指定元素类型。减少出错可能。

Mat grayImg(480,640,CV_8UC1);
Mat_ <uchar> grayImg1=(Mat_ <uchar>&)grayImg;
for(int i=0;i<grayImg1.rows;i++)
{
    uchar* p=grayImg1.ptr(i);
    for(int j=0;j<grayImg1.cols;j++)
    {
        double d1=(double)((i+j)%255);
        grayImg1(i,j)=d1;
        double d2=grayImg1(i,j);
    }
}

Mat类的内存管理

Mat 类由两个数据部分组成:矩阵头和一个指向所有像素值的内存的指针uchar* data。

OpenCV使用了引用计数机制,既让矩阵指针data指向同一地址,同时引用计数增加。OpenCV中很多函数及很多操作只复制矩阵头信息,而不复制矩阵数据。

Mat的相关函数

读取,显示和保存图像的函数

Mat cv::imread(const String &fliname,int flags=IMREAD_COLOR);
	filename:图片文件的绝对或相对路径
	flags:读取图片的的形式(灰度/彩色/alpha通道)
    	(cv2.IMREAD_COLOR:默认参数,读入一副彩色图片,忽略alpha通道,可以直接写1
		cv2.IMREAD_GRAYSCALE:读入灰度图片,可以直接写0
		cv2.IMREAD_UNCHANGED:顾名思义,读入完整图片,包括alpha通道,可以直接写-1)
	return:读取的图像数据
void cv::imshow(const String& winname,InputArray mat);
	winname:显示图片的窗口的名称
	mat:要显示的图像
Mat cv::imwrite(const String& filename,
               InputArray img,
               const std::vector<int>& params=std::vector<int>());
	filename:图像保存为文件的文件名
    img:要保存的图像数据
    params:附加信息,如指定JPEG压缩质量等

缩放图像的函数

void cv::resize(InputArray src,
               OutputArray dst,
               Size size,
               double fx=0,
               double fy=0,
               int interpolation=INTER_LINEAR);
	src:输入图像
    dst:输出缩放的图像
    dsize:输出图像的大小
    fx:沿水平方向的缩放因子
    fy:沿竖直方向的缩放因子
    interpolation:插值方式(INTER_LINEAR,INTER_NEAREST,etc)

图像通道

void cv::split(const &src,Mat* mvbegin);
	src:输入的多通道图像
    mvbegin:输出矩阵,矩阵个数等于src.channels()
void cv::merge(const Mat* mv,size_t count,OutputArray dst);
	mv:要合并的矩阵,所有矩阵的大小和数据类型必须相同
    count:当mv是一个矩阵时输入矩阵个数,值必须大于0
    dst:输出矩阵,大小和数据类型与mv[0]相同,矩阵的通道数为count

利用某些图像性质生成掩膜

void cv::inRange(InputArray src,InputArray lowerb,InputArray upperb,OutputArray dst);
	src:输入图像
    lowerb:下边界矩阵或数值
    upperb:上边界矩阵或数值
    dst:输出类型为CV_8U的图像,大小与输入类型相同

OpenCV中常用的绘制函数

//绘制直线
void cv::line(InputOutArray img,Point pt1,Point pt2,const Scalar& color,
              int thickness=1,int lineType=LINE_8,int shift=0);
//绘制圆
void cv::circle(InputoutArray img,Point center,int rsdius,const Scalar& color,int thickness=1,
                int lineType=LINE_8,int shift=0);
//绘制矩形
void cv::rectangle(InputOutputArray img,Point pt1,Point pt2,const Scalar& color,int thickness=1,
                   int lineType=LINE_8,int shift=0);
void cv::rectangle(InputOutputArray img,Rect rect,const Scalar& color,int thickness=1,int lineType=LINE_8,int shift=0);
//绘制文字
void cv::putText(InputOutputArray img,const String& text,Point org,int fontFace,double fontScale,
                Scalar color,int thickness=1,int lineType=LINE_8,bool bottomLeftOrigin=false);
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值