opencv学习记录2

**

OPENCV学习

**
基础数据结构
主要是图像处理中需要用到的数据结构:
1.Point(点)
点在图像处理中通常用来标记特征点(交点、角点、拐点等)
Point( intx,int y )表示二维整型坐标,以(0,0)基点
Point2f(float x,float y)表示浮点坐标,以(0,0)为基点
图像上两点,坐标为A(200,300)和B(150.2,260.5)在代码中表示为
Point A A={200,300}或者 A.x=200; A.y=300; Point2f B B={150.2,260.5} 或 B.x=150.2;B=260.5;
2.矩阵Mat
opencv中的矩阵计算很大程度上与matlab相似,从OpenCV2开始,开始使用Mat类存储图像,具有以下优势:
(1)图像的内存分配和释放由Mat类自动管理
(2)Mat类由两部分数据组成:矩阵头(包含矩阵尺寸、存储方法、存储地址等)和一个指向存储所有像素值的矩阵(根据所选存储方法的不同,矩阵可以是不同的维数)的指针。Mat在进行赋值和拷贝时,只复制矩阵头,而不复制矩阵,提高效率。如果矩阵属于多个Mat对象,则通过引用计数来判断,当最后一个使用它的对象,则负责释放矩阵。
(3)可以使用clone和copyTo函数,不仅复制矩阵头还复制矩阵。
2.1构造Mat函数

  1. 使用构造函数(使用Mat图像容器类创建Mat类的对象)
    //! default constructor
    Mat();
    //! constructs 2D matrix of the specified size and type
    // (_type is CV_8UC1, CV_64FC3, CV_32SC(12) etc.)
    Mat(int rows, int cols, int type);
    Mat(Size size, int type);
    //! constucts 2D matrix and fills it with the specified value _s.
    Mat(int rows, int cols, int type, const Scalar& s);
    Mat(Size size, int type, const Scalar& s);

    //! constructs n-dimensional matrix
    Mat(int ndims, const int* sizes, int type);
    Mat(int ndims, const int* sizes, int type, const Scalar& s);

例:

    cv::Mat M1(3, 3, CV_8UC4, cv::Scalar(0, 0, 0, 255));
	std::cout << "M1 = " << std::endl << M1 << std::endl;

这里指定矩阵的行和列,并表示为4通道的矩阵,每个点的颜色值为(0, 0, 0, 255)。输出结果如下:
M1 =
[ 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255;
0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255;
0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255]

  1. 通过数组初始化矩阵维数
	int sz[2] = { 3, 3 };
	cv::Mat M2(2, sz, CV_8UC1, cv::Scalar::all(0));
	std::cout << "M2 = " << std::endl << M2 << std::endl;

如上,构造函数的第一个参数指定的是矩阵的维数,那么sz数组表示的是每一维数的数量,即这里表示的是3行3列。如果第一个参数是3的话,数组的大小也应该是3,表示的就是x,y,z三个维度,每个维度有3个。输出如下:
M2 =
[ 0, 0, 0;
0, 0, 0;
0, 0, 0]

3. 通过create函数来初始化

 cv::Mat M3;
 M3.create(4, 4, CV_8UC(1));
 std::cout << "M3 = " << std::endl << M3 << std::endl;

这里是4*4的二维单通道矩阵,矩阵中的数据为随机值。如下:

M3=
[205, 205, 205, 205;
205, 205, 205, 205;
205, 205, 205, 205;
205, 205, 205, 205]

4. 通过opencv提供的类matlab的函数创建

//! Matlab-style matrix initialization
    static MatExpr zeros(int rows, int cols, int type);
    static MatExpr zeros(Size size, int type);
    static MatExpr zeros(int ndims, const int* sz, int type);
    static MatExpr ones(int rows, int cols, int type);
    static MatExpr ones(Size size, int type);
    static MatExpr ones(int ndims, const int* sz, int type);
    static MatExpr eye(int rows, int cols, int type);
    static MatExpr eye(Size size, int type);

例:

 cv::Mat Me = cv::Mat::eye(4, 4, CV_64F);
 std::cout << "Me = " << std::endl << Me << std::endl;

 cv::Mat Mo = cv::Mat::ones(4, 4, CV_64F);
 std::cout << "Mo = " << std::endl << Mo << std::endl;

 cv::Mat Mz = cv::Mat::zeros(4, 4, CV_64F);
 std::cout << "Mz = " << std::endl << Mz << std::endl;

eye函数表示的是单位矩阵,ones顾名思义是全是1的矩阵,zeros表示全是0的矩阵。输出如下:
Me =
[1, 0, 0, 0;
0, 1, 0, 0;
0, 0, 1, 0;
0, 0, 0, 1]
Mo =
[1, 1, 1, 1;
1, 1, 1, 1;
1, 1, 1, 1;
1, 1, 1, 1]
Mz =
[0, 0, 0, 0;
0, 0, 0, 0;
0, 0, 0, 0;
0, 0, 0, 0]

5. 数据自定义矩阵Mat创建

 cv::Mat M4 = (cv::Mat_<double>(3, 3) << 0, -1, 0, -1, 0, 0, 0, 0, 1);
 std::cout << "M4 = " << std::endl << M4 << std::endl;

我们可以自己定义自己需要的数据量比较小的矩阵,然后通过如上的方式将其封装到cv::Mat中。如下:

M4 =
[0, -1, 0;
-1, 0, 0;
0, 0, 1]

6. 通过clone函数创建不同的Mat
cv::Mat M5 = M4.row(1).clone();
std::cout << "M5 = " << std::endl << M5 << std::endl;

通过克隆函数clone获取我们需要的某一行或列的数据,这里构建出来的矩阵是深拷贝出来的Mat类对象。输出如下:

M5 =
[-1, 0, 0]

创建Mat矩阵/图像容器类的很多构造方法或者其他成员方法在创建Mat对象的时候,都需要指定type–所创建图像/矩阵的类型。
(_type is CV_8UC1, CV_64FC3, CV_32SC(12) etc.)
通过转到定义法,看一下CV_8UC1,CV_64FC3等这些宏到底是什么,OpenCv的源代码显示如下(源代码在在types_c.h中):

#define CV_CN_MAX     512
#define CV_CN_SHIFT   3
#define CV_DEPTH_MAX  (1 << CV_CN_SHIFT)

#define CV_8U   0
#define CV_8S   1
#define CV_16U  2
#define CV_16S  3
#define CV_32S  4
#define CV_32F  5
#define CV_64F  6
#define CV_USRTYPE1 7

#define CV_MAT_DEPTH_MASK       (CV_DEPTH_MAX - 1)
#define CV_MAT_DEPTH(flags)     ((flags) & CV_MAT_DEPTH_MASK)

#define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth) + (((cn)-1) << CV_CN_SHIFT))
#define CV_MAKE_TYPE CV_MAKETYPE

#define CV_8UC1 CV_MAKETYPE(CV_8U,1)
#define CV_8UC2 CV_MAKETYPE(CV_8U,2)
#define CV_8UC3 CV_MAKETYPE(CV_8U,3)
#define CV_8UC4 CV_MAKETYPE(CV_8U,4)
#define CV_8UC(n) CV_MAKETYPE(CV_8U,(n))

#define CV_8SC1 CV_MAKETYPE(CV_8S,1)
#define CV_8SC2 CV_MAKETYPE(CV_8S,2)
#define CV_8SC3 CV_MAKETYPE(CV_8S,3)
#define CV_8SC4 CV_MAKETYPE(CV_8S,4)
#define CV_8SC(n) CV_MAKETYPE(CV_8S,(n))

#define CV_16UC1 CV_MAKETYPE(CV_16U,1)
#define CV_16UC2 CV_MAKETYPE(CV_16U,2)
#define CV_16UC3 CV_MAKETYPE(CV_16U,3)
#define CV_16UC4 CV_MAKETYPE(CV_16U,4)
#define CV_16UC(n) CV_MAKETYPE(CV_16U,(n))

#define CV_16SC1 CV_MAKETYPE(CV_16S,1)
#define CV_16SC2 CV_MAKETYPE(CV_16S,2)
#define CV_16SC3 CV_MAKETYPE(CV_16S,3)
#define CV_16SC4 CV_MAKETYPE(CV_16S,4)
#define CV_16SC(n) CV_MAKETYPE(CV_16S,(n))

#define CV_32SC1 CV_MAKETYPE(CV_32S,1)
#define CV_32SC2 CV_MAKETYPE(CV_32S,2)
#define CV_32SC3 CV_MAKETYPE(CV_32S,3)
#define CV_32SC4 CV_MAKETYPE(CV_32S,4)
#define CV_32SC(n) CV_MAKETYPE(CV_32S,(n))

#define CV_32FC1 CV_MAKETYPE(CV_32F,1)
#define CV_32FC2 CV_MAKETYPE(CV_32F,2)
#define CV_32FC3 CV_MAKETYPE(CV_32F,3)
#define CV_32FC4 CV_MAKETYPE(CV_32F,4)
#define CV_32FC(n) CV_MAKETYPE(CV_32F,(n))

#define CV_64FC1 CV_MAKETYPE(CV_64F,1)
#define CV_64FC2 CV_MAKETYPE(CV_64F,2)
#define CV_64FC3 CV_MAKETYPE(CV_64F,3)
#define CV_64FC4 CV_MAKETYPE(CV_64F,4)
#define CV_64FC(n) CV_MAKETYPE(CV_64F,(n))

这里的type可以是任何的预定义类型,预定义类型的结构如下所示:CV_<bit_depth>(S|U|F)C<number_of_channels>

  1--bit_depth---比特数---代表8bite,16bites,32bites,64bites---举个例子吧--比如说,如
        如果你现在创建了一个存储--灰度图片的Mat对象,这个图像的大小为宽100,100,那么,现在这张
        灰度图片中有10000个像素点,它每一个像素点在内存空间所占的空间大小是8bite,8--所以它对
        应的就是CV_8
     2--S|U|F--S--代表---signed int---有符号整形
               U--代表--unsigned int--无符号整形
               F--代表--float---------单精度浮点型
     3--C<number_of_channels>----代表---一张图片的通道数,比如:
         1--灰度图片--grayImg-----单通道图像
         2--RGB彩色图像-----------3通道图像
         3--带Alph通道的RGB图像----4通道图像

OpenCv的矩阵类型源代码解释:

//【1】CV_8UC1---则可以创建----8位无符号的单通道---灰度图片------grayImg
#define CV_8UC1 CV_MAKETYPE(CV_8U,1)
#define CV_8UC2 CV_MAKETYPE(CV_8U,2)
//【2】CV_8UC3---则可以创建----8位无符号的三通道---RGB彩色图像---colorImg 
#define CV_8UC3 CV_MAKETYPE(CV_8U,3)
//【3】CV_8UC4--则可以创建-----8位无符号的四通道---带透明色的RGB图像 
#define CV_8UC4 CV_MAKETYPE(CV_8U,4)

2.2 Mat的基本计算
1.初始化

Mat I(img,Rect(10,10,100,100));//用一块地方初始化。
Mat I=img(Range:all(),Range(1,3));//所有行,1~3列
Mat I=img.clone();//完全复制
img.copyTo(I);//传递矩阵头
Mat I(2,2,CV_8UC3,Scalar(0,0,255));//I=[0,0,255,0,0,255;0,0,255,0,0,255];
Mat E=Mat::eye(4,4,CV_64F);//对角矩阵
Mat O=Mat::ones(2,2,CV_32F);//全一矩阵
Mat Z=Mat::zeros(3,3,CV_8UC1);//全零矩阵
Mat C=(Mat_(2,2)<<0,-1,2,3);//如果是简单矩阵的初始化
Mat::row(i);Mat::row(j);Mat::rowRange(start,end);Mat::colRange(start,end);都只是创建个头
Mat::diag(int d);d=0是是主对角线,d=1是比主低的对角线,d=-1....
static Mat Mat::diag(const Mat& matD)
Mat::setTo(Scalar &s);以s初始化矩阵
Mat::push_back(Mat);在原来的Mat的最后一行后再加几行
Mat::pop_back(size_t nelems=1);//移出最下面几行
    b=a.clone(); 

2.运算符

//注意Mat的行列号是从0开始的
	//定义矩阵a,b,c
 	Mat a,b,c; 
	//生成三行四列的全一矩阵 CV_64F表示精度
 	a=Mat::ones(3,4,CV_64F);
	//a=mat::zeros(3,4,CV_64F);为生成全0
	//把矩阵a复制给矩阵b  注意不能用b=a
 	b=a.clone();
	//矩阵a每一个元素乘以2
	a=a.mul(2);
	//矩阵b每一个元素乘以4
 	b=b.mul(4);
	//矩阵a点乘矩阵b
 	c=a.mul(b);
   	cout<<"a"<<a<<endl;
   	cout<<"b"<<b<<endl;
   	cout<<"c"<<c<<endl;

在这里插入图片描述

//常用的矩阵运算
 	Mat d,e,f,g;
	//带权重的矩阵加法  d=a*1+b*1+4,4为常数,1,1,4均可以改变值
 	addWeighted(a,1,b,1,4,d);
	//矩阵a除以a,结果为e
 	divide(d,a,e);
	//常数6除以矩阵e中的每一个元素,结果为f
 	divide(6,e,f);
	//常数2加矩阵f的每一个元素,结果为g,其中2可以为矩阵
 	add(2,f,g);
	cout<<"d"<<d<<endl;
	cout<<"e"<<e<<endl;
	cout<<"f"<<f<<endl;
 	cout<<"g"<<g<<endl;

在这里插入图片描述
3.Mat类成员函数
//更改矩阵的行数。

Mat::resize
//更改矩阵的行数。

C++: void Mat::resize(size_t sz)

C++: void Mat::resize(size_t sz, const Scalar& s)

//参数

//sz –新的行数。

//s –分配给新添加的元素的值。

//该方法更改矩阵的行数。如果矩阵重新分配,第一最少(Mat::rows,sz) 行数
//要保留下来。该方法模拟相应的 STL 向量类的方法

//保留一定数量的行的空间。

C++: void Mat::reserve(size_t sz)

//参数

//sz –的行数。

//该方法sz行存储空间。如果矩阵已经有足够的空间来存储sz行,没有任何异常
//发生。如果矩阵重新分配,保留前(Mat::rows) 行。该方法模拟了相应的
//STL 向量类的方法。

//将元素添加到矩阵的底部

C++: template<typename T> voidMat::push_back(const T& elem)

C++: void Mat::push_back(const Mat& elem)

//参数

//elem –增加的一个或多个元素。

//该方法将一个或多个元素添加到矩阵的底部。他们是模拟相应的 STL 向量类的
//方法。元素为Mat时,其类型和列的数目必须和矩阵容器是相同的。

//从底部的列表中删除元素

C++: template<typename T> voidMat::pop_back(size_t nelems=1)

//参数

//nelems –删除的行的数目。如果它大于总的行数,则会引发异常。

//该方法从底部的列表中删除一行或多行。

//提取矩形子阵
C++: Mat Mat::operator()(Range rowRange, RangecolRange) const

C++: Mat Mat::operator()(const Rect& roi) const

C++: Mat Mat::operator()(const Ranges* ranges) const

//参数:

//rowRange –提取的子阵的开始和结束的行。不包括的上限。若要选择的所有
//行,请使用 Range::all()。

//colRange –提取的子阵的开始和结束的列。不包括的上限。若要选择的所有
//列,请使用 Range::all()。

//roi – 抽出子阵 specified 作为一个矩形。

//ranges – 选定范围沿每个数组维度的数组。

//该运算符为*this的子数组创建新的头。他们是Mat::row()、 Mat::col()、 //Mat::rowRange(),和Mat::colRange()最普遍的形式。例如,A(Range(0, 10),Range::all()) 是相当于A.rowRange(0, 10)。与上述所有操作相同,该操
//作运算符是复杂度为O(1)的操作,就是没有矩阵数据将被复制。
//矩阵第二行到第三行
	h = M4.rowRange(1, 3);
	//取矩阵第二行,行数和列数从0开始
	I = M4.row(1);
Mat::size
//返回一个矩阵大小。

C++: Size Mat::size() const

//该方法返回一个矩阵大小:Size(cols, rows)。矩阵超过 2 维时返回大小为(-1,-1)。

Mat::empty
//如果数组有没有 elemens,则返回 true。

C++: bool Mat::empty() const

//如果 Mat::total() 是 0 或 Mat::data 为 NULL,则方法返回 true。
//因为pop_back() 和 resize()方法M.total()= = 0,并不意味着M.data = =NULL。

指针

Mat::ptr
//返回指定矩阵行的指针。

C++: uchar* Mat::ptr(int i=0)

C++: const uchar* Mat::ptr(int i=0) const

C++: template<typename _Tp> _Tp* Mat::ptr(inti=0)

C++: template<typename _Tp> const _Tp*Mat::ptr(int i=0) const

//参数:

//i –一个基于0的行索引。

//该方法返回uchar*,或指向由输入指定矩阵行的指针。参看Mat::isContinuous()的中示例了解如何使用这些方法。

At访问Mat矩阵

Mat::at
返回对指定数组元素的引用。

C++: template<typename T> T& Mat::at(int i)const

C++: template<typename T> const T&Mat::at(int i) const

C++: template<typename T> T& Mat::at(int i,int j)

C++: template<typename T> const T&Mat::at(int i, int j) const

C++: template<typename T> T& Mat::at(Pointpt)

C++: template<typename T> const T&Mat::at(Point pt) const

C++: template<typename T> T& Mat::at(int i,int j, int k)

C++: template<typename T> const T&Mat::at(int i, int j, int k) const

C++: template<typename T> T& Mat::at(constint* idx)

C++: template<typename T> const T&Mat::at(const int* idx) const

//参数

//i –索引 0 维度

//j – 1 维度的索引

//k – 沿 2 维度的索引

//pt – Point(j,i) 作为指定元素的位置。

//idx – Mat::dims 数组的索引。

//该模板方法返回指定数组元素的引用。为了具有更高的性能,索引范围检查只
//在调试配置下执行。请注意使用具有单个索引 (i) 的变量可以访问的单行或单
//列的2 维的数组元素。也就是比方说,如果A是1 x N 浮点矩阵和B是M x 1的
//整数矩阵,您只需编写A.at<float>(k+4) 和 B.at<int>(2*i+1) 分别代替A.at<float>(0,k+4)和

B.at<int>(2*i+1,0)//下面的示例将初始化希尔伯特矩阵:

Mat H(100, 100, CV_64F);

for(inti= 0; i<H.rows; i++)

for(intj= 0; j<H.cols; j++)

H.at<double>(i,j)=1./(i+j+1);

迭代器

Mat::begin
//返回矩阵迭代器,并将其设置为第一矩阵元。

C++: template<typename _Tp>MatIterator_<_Tp> Mat::begin()

C++: template<typename _Tp>MatConstIterator_<_Tp> Mat::begin() const

//该方法返回矩阵的只读或读写的迭代器。矩阵迭代器的使用和双向 STL 迭代器
//的使用是非常相似的。在下面的示例中,alpha融合函数是使用矩阵迭代器重写:

template<typename T>

void alphaBlendRGBA(const Mat& src1,const Mat& src2, Mat& dst)

{
typedef Vec<T, 4> VT;

const float alpha_scale =(float)std::numeric_limits<T>::max(),

inv_scale = 1.f/alpha_scale;

CV_Assert( src1.type() == src2.type()&&

src1.type() == DataType<VT>::type&&

src1.size() == src2.size());

Size size = src1.size();

dst.create(size, src1.type());

MatConstIterator_<VT> it1 =src1.begin<VT>(), it1_end = src1.end<VT>();

MatConstIterator_<VT> it2 =src2.begin<VT>();

MatIterator_<VT> dst_it =dst.begin<VT>();

for( ; it1 != it1_end; ++it1, ++it2,++dst_it )

{
VT pix1 = *it1, pix2 = *it2;

float alpha = pix1[3]*inv_scale, beta =pix2[3]*inv_scale;

*dst_it =VT(saturate_cast<T>(pix1[0]*alpha + pix2[0]*beta),

saturate_cast<T>(pix1[1]*alpha + pix2[1]*beta),

saturate_cast<T>(pix1[2]*alpha +pix2[2]*beta),

saturate_cast<T>((1 -(1-alpha)*(1-beta))*alpha_scale));

}

}

Mat::end
//返回矩阵迭代器,并将其设置为 最后元素之后(after-last)的矩阵元。

C++: template<typename _Tp>MatIterator_<_Tp> Mat::end()

C++: template<typename _Tp>MatConstIterator_<_Tp> Mat::end() const

//该方法返回矩阵只读或读写的迭代器,设置为紧随最后一个矩阵元素的点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值