Author:: Maddock

Date: 2015-03-23 16:33:49

转载请注明出处:http://blog.csdn.net/adong76/article/details/40539357

参考

http://blog.csdn.net/ljbkiss/article/details/7381208

http://blog.csdn.net/yang_xian521/article/details/7161335#comments

http://blog.csdn.net/guoming0000/article/details/8629885

http://hahack.com/wiki/opencv-basic.html

http://blog.skyoung.org/2014/03/26/OpenCV%28III%29-How-to-use-Mat/

Mat的基本数据结构

http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/core/mat%20-%20the%20basic%20image%20container/mat%20-%20the%20basic%20image%20container.html#matthebasicimagecontainer

Mat类的数据结构如下:

class CV_EXPORTS Mat

{

public:

// ... a lot of methods ...

...

/*! includes several bit-fields:

- the magic signature

- continuity flag

- depth

- number of channels

*/

int flags;

//! the array dimensionality, >= 2

int dims;

//! the number of rows and columns or (-1, -1) when the array has more than 2 dimensions

int rows, cols;

//! pointer to the data

uchar* data;

//! pointer to the reference counter;

// when array points to user-allocated data, the pointer is NULL

int* refcount;

// other members

...

};

关于Mat ,首先要知道的是你不必再手动地(1)为其开辟空间(2)在不需要时立即将空间释放。但手动地做还是可以的:大多数OpenCV函数仍会手动地为输出数据开辟空间。当传递一个已经存在的 Mat 对象时,开辟好的矩阵空间会被重用。也就是说,我们每次都使用大小正好的内存来完成任务。

基本上讲 Mat 是一个类,由两个数据部分组成:矩阵头(包含矩阵尺寸,存储方法,存储地址等信息)和一个指向存储所有像素值的矩阵(根据所选存储方法的不同矩阵可以是不 同的维数)的指针。矩阵头的尺寸是常数值,但矩阵本身的尺寸会依图像的不同而不同,通常比矩阵头的尺寸大数个数量级。因此,当在程序中传递图像并创建拷贝 时,大的开销是由矩阵造成的,而不是信息头。OpenCV是一个图像处理库,囊括了大量的图像处理函数,为了解决问题通常要使用库中的多个函数,因此在函 数中传递图像是家常便饭。同时不要忘了我们正在讨论的是计算量很大的图像处理算法,因此,除非万不得已,我们不应该拷贝 的图像,因为这会降低程序速度。

为了搞定这个问题,OpenCV使用引用计数机制。其思路是让每个 Mat 对象有自己的信息头,但共享同一个矩阵。这通过让矩阵指针指向同一地址而实现。而拷贝构造函数则 只拷贝信息头和矩阵指针 ,而不拷贝矩阵。

1

2

3

4

5

6

Mat A, C;                                 // 只创建信息头部分

A = imread(argv[1], CV_LOAD_IMAGE_COLOR); // 这里为矩阵开辟内存

Mat B(A);                                 // 使用拷贝构造函数

C = A;                                    // 赋值运算符

以上代码中的所有Mat对象最终都指向同一个也是唯一一个数据矩阵。虽然它们的信息头不同,但通过任何一个对象所做的改变也会影响其它对象。实际 上,不同的对象只是访问相同数据的不同途径而已。这里还要提及一个比较棒的功能:你可以创建只引用部分数据的信息头。比如想要创建一个感兴趣区域( ROI ),你只需要创建包含边界信息的信息头:

1

2

Mat D (A, Rect(10, 10, 100, 100) ); // using a rectangle

Mat E = A(Range:all(), Range(1,3)); // using row and column boundaries

现在你也许会问,如果矩阵属于多个 Mat 对象,那么当不再需要它时谁来负责清理?简单的回答是:最后一个使用它的对象。通过引用计数机制来实现。无论什么时候有人拷贝了一个 Mat 对象的信息头,都会增加矩阵的引用次数;反之当一个头被释放之后,这个计数被减一;当计数值为零,矩阵会被清理。但某些时候你仍会想拷贝矩阵本身(不只是信息头和矩阵指针),这时可以使用函数 clone() 或者 copyTo()

1

2

3

Mat F = A.clone();

Mat G;

A.copyTo(G);

现在改变 F 或者 G 就不会影响 Mat 信息头所指向的矩阵。总结一下,你需要记住的是

OpenCV函数中输出图像的内存分配是自动完成的(如果不特别指定的话)。

使用OpenCV的C++接口时不需要考虑内存释放问题。

赋值运算符和拷贝构造函数( ctor )只拷贝信息头。

使用函数 clone() 或者 copyTo() 来拷贝一副图像的矩阵。

Mat的初始化与构造

创建一个Mat的方法:

1 直接构造

Mat() 构造函数

Mat M(2,2, CV_8UC3, Scalar(0,0,255));

cout << "M = " << endl << " " << M << endl << endl;

OpenCV中对Mat里面depth,dims,channels,step,data,elemSize和数据地址计算的理解

http://tmjfzy.blog.163.com/blog/static/66447025201261052543349/

2 create

// create by using the create function()

M.create(4,4, CV_8UC(2));

cout << "M = "<< endl << " "  << M << endl << endl;

3 利用数组初始化

// create multidimensional matrices

//用二维数组初始化矩阵
double m[2][3] = { {1, 2, 3}, {4, 5, 6} };
Mat M = Mat(2, 3, CV_64F, m);

4 接收指针指向的数据流

void process_video_frame(const unsigned char* pixels,

int width, int height, int step)

{

Mat img(height, width, CV_8UC3, pixels, step);

GaussianBlur(img, img, Size(7,7), 1.5, 1.5);

}

5 MATLAB形式的初始化方式

// Create using MATLAB style eye, ones or zero matrix

Mat E = Mat::eye(4, 4, CV_64F);

cout << "E = " << endl << " " << E << endl << endl;

Mat O = Mat::ones(2, 2, CV_32F);

cout << "O = " << endl << " " << O << endl << endl;

Mat Z = Mat::zeros(3,3, CV_8UC1);

cout << "Z = " << endl << " " << Z << endl << endl;

访问Mat的数据元素

http://www.opencv.org.cn/opencvdoc/2.3.2/html/modules/core/doc/basic_structures.html?highlight=mat#Mat

1 指针高效访问

channel = 1

// compute sum of positive matrix elements

// (assuming that M isa double-precision matrix)

double sum=0;

for(int i = 0; i < M.rows; i++)

{

const double* Mi = M.ptr<double>(i);

for(int j = 0; j < M.cols; j++)

sum += std::max(Mi[j], 0.);

}

channel = 3

int row = src.rows;
int col = src.cols;

Mat dst = Mat(row, col, CV_16UC3);

Mat  showmask = Mat::zeros(row, col, CV_8UC1);

for (int i = 0; i < row; ++i)
{
    ushort  *dataWarpRow = dst.ptr<ushort>(i);
    for (int j = 0; j < col; ++j)
    {
        //Vec3b  *dataWarp = &(dst.at<Vec3b>(i, j));
        ushort  *dataWarpCol = dataWarpRow + j * src.channels();
        uchar *mask = &(showmask.at<uchar>(i, j));
        if ((dataWarpCol)[0] == 0 && (dataWarpCol)[1] == 0 && (dataWarpCol)[2] == 0)
        {
            *mask = 255;
        }
    }
}

2 迭代器安全访问

// compute sum of positive matrix elements, iterator-based variant

double sum=0;

MatConstIterator_<double> it = M.begin<double>(), it_end = M.end<double>();

for(; it != it_end; ++it)

sum += std::max(*it, 0.);

3 一维数据存储访问

// compute the sum of positive matrix elements, optimized variant

double sum=0;

int cols = M.cols, rows = M.rows;

if(M.isContinuous())

{

cols *= rows;

rows = 1;

}

const double* ptr = M.ptr<double>(0);
for(int i = 0; i < cols; i++)
{
    sum += std::max(ptr[i], 0.);
}

4 二维单通道数据访问

Mat矩阵中数据指针Mat.data是uchar类型指针,CV_8U系列可以通过计算指针位置快速地定位矩阵中的任意元素。

二维单通道元素可以用Mat::at(i, j)访问,i是行序号,j是列序号。

M.at<double>(i,j) += 1.f

Mat H(100, 100, CV_64F);

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

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

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

但对于多通道的非unsigned char类型矩阵来说,以上方法都不好(注:后来知道可以通过类型转换,用指针访问data数据)。可以用Mat::ptr()来获得指向某行元素的指针,在通过行数与通道数计算相应点的指针。可以通过转换指针类型,访问非uchar类型的Mat元素。例如图像是CV_64FC1格式,可以将Mat.data指针直接转换成double*类型:

// imgMat is a image.
double* pimg = (double*)(imgMat.data)
 
也可以用C++中的显式转换符static_cast,不过要通过void*类型过渡:
void* pvoid = static_cast<void*>(imgMat.data);
double* pimg = static_cast<double*>(pvoid);

这种方式在Debug模式下速度提升非常显著,但没有任何的边界检查和异常处理,使用时必须十分小心。使用Mat::ptr的速度和直接使用这种方法差不多,多一层保护总比没有保护强。

5 访问彩色图像数据

#define IMG_B(img,y,x) img.at<Vec3b>(y,x)[0]
#define IMG_G(img,y,x) img.at<Vec3b>(y,x)[1]
#define IMG_R(img,y,x) img.at<Vec3b>(y,x)[2]

Mat的一些数学运算

This is a list of implemented matrix operations that can be combined in arbitrary complex expressions (here A, B stand for matrices ( Mat ), s for a scalar ( Scalar ), alpha for a real-valued scalar ( double )):

  • Addition, subtraction, negation: A+B, A-B, A+s, A-s, s+A, s-A, -A
  • Scaling: A*alpha
  • Per-element multiplication and division: A.mul(B), A/B, alpha/A
  • Matrix multiplication: A*B
  • Transposition: A.t() (means AT)
  • Matrix inversion and pseudo-inversion, solving linear systems and least-squares problems:

A.inv([method]) (~ A-1) ,   A.inv([method])*B (~ X: AX=B)

  • Comparison: A cmpop B, A cmpop alpha, alpha cmpop A, where cmpop is one of :  >, >=, ==, !=, <=, <. The result of comparison is an 8-bit single channel mask whose elements are set to 255 (if the particular element or pair of elements satisfy the condition) or 0.
  • Bitwise logical operations: A logicop B, A logicop s, s logicop A, ~A, where logicop is one of :  &, |, ^.
  • Element-wise minimum and maximum: min(A, B), min(A, alpha), max(A, B), max(A, alpha)
  • Element-wise absolute value: abs(A)
  • Cross-product, dot-product: A.cross(B) A.dot(B)
  • Any function of matrix or matrices and scalars that returns a matrix or a scalar, such as norm, mean, sum, countNonZero, trace, determinant, repeat, and others.
  • Matrix initializers ( Mat::eye(), Mat::zeros(), Mat::ones() ), matrix comma-separated initializers, matrix constructors and operators that extract sub-matrices (see Mat description).
  • Mat_<destination_type>() constructors to cast the result to the proper type.

Mat的一些重要属性和函数

Mat::rows

Mat::cols

Mat::convertTo

Converts an array to another datatype with optional scaling.

C++: void Mat::convertTo(OutputArray m, int rtype, double alpha=1, double beta=0 ) const

Parameters:

  • m – Destination matrix. If it does not have a proper size or type before the operation, it is reallocated.
  • rtype – Desired destination matrix type or, rather, the depth since the number of channels are the same as the source has. If rtype is negative, the destination matrix will have the same type as the source.
  • alpha – Optional scale factor.
  • beta – Optional delta added to the scaled values.

Mat::type

Returns the type of a matrix element.

C++: int Mat::type() const

The method returns a matrix element type. This is an identifier compatible with the CvMat type system, like CV_16SC3 or 16-bit signed 3-channel array, and so on.

Mat::depth

Returns the depth of a matrix element.

C++: int Mat::depth() const

The method returns the identifier of the matrix element depth (the type of each individual channel). For example, for a 16-bit signed 3-channel array, the method returns CV_16S . A complete list of matrix types contains the following values:

  • CV_8U - 8-bit unsigned integers ( 0..255 )
  • CV_8S - 8-bit signed integers ( -128..127 )
  • CV_16U - 16-bit unsigned integers ( 0..65535 )
  • CV_16S - 16-bit signed integers ( -32768..32767 )
  • CV_32S - 32-bit signed integers ( -2147483648..2147483647 )
  • CV_32F - 32-bit floating-point numbers ( -FLT_MAX..FLT_MAX, INF, NAN )
  • CV_64F - 64-bit floating-point numbers ( -DBL_MAX..DBL_MAX, INF, NAN )

Mat::channels

Returns the number of matrix channels.

C++: int Mat::channels() const

The method returns the number of matrix channels.

Mat::ptr

Returns a pointer to the specified matrix row.

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

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

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

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

Parameters:

  • i – A 0-based row index.

The methods return uchar* or typed pointer to the specified matrix row. See the sample in Mat::isContinuous() to know how to use these methods.

Mat Iplimage相互转换

//cv::Mat -> IplImage

Mat srcImg;                         // Mat type variable .
srcImg =
imread("left1.png");        
// read image;  
IplImage *resIplPtr = NULL;         //
Initialize by NULL.
resIplPtr = &(IplImage(srcImg));    // Mat to IplImage
Pointer
cvShowImage("resIplPtr" ,resIplPtr);
cvWaitKey(0);

//IplImage
-> cv::Mat
IplImage* iplimg = cvLoadImage("left1.png");
cv::Mat matimg;
matimg = cv::Mat(iplimg);
namedWindow("mat",0);
imshow("mat",matimg);
waitKey(0);

和图像处理相关的几个函数

http://www.opencv.org.cn/opencvdoc/2.3.2/html/modules/core/doc/operations_on_arrays.html?highlight=split#cv.Split

Merge

merge

Composes a multi-channel array from several single-channel
arrays.

C++: void merge(const Mat* mv, size_t count, OutputArray dst)

C++: void merge(const vector<Mat>& mv, OutputArray dst)

Split

split

Divides a multi-channel array into several single-channel
arrays.

C++: void split(const Mat& mtx, Mat* mv)

C++: void split(const Mat& mtx,
vector<Mat>& mv)

获取图像的ROI

Mat img;

Mat RoiImg = img(Range(rbegin,
rend), Range(cbeign, cend));

OpenCv Mat操作总结的更多相关文章

  1. OpenCV中Mat操作clone() 与copyto()的区别

    OpenCV中Mat操作clone() 与copyto()的区别 // Mat is basically a class with two data parts: the matrix header ...

  2. OpenCV3入门(二)Mat操作

    1.Mat结构 1.1.Mat数据 Mat本质上是由两个数据部分组成的类: 矩阵头:包含信息有矩阵的大小,用于存储的方法,矩阵存储的地址等 数据矩阵指针:指向包含了像素值的矩阵. 矩阵头部的大小是恒定 ...

  3. opencv 矩阵操作

    OpenCv矩阵操作 有很多函数有mask,代表掩码,如果某位mask是0,那么对应的src的那一位就不计算,mask要和矩阵/ROI/的大小相等 大多数函数支持ROI,如果图像ROI被设置,那么只处 ...

  4. Matlab to OpenCV Mat

    convert Matlab matrix to OpenCV Mat. Support CV_32FC3 only currently. The Code int matlab2opencv(cv: ...

  5. OpenCV Mat数据类型及位数总结(转载)

    OpenCV Mat数据类型及位数总结(转载) 前言 opencv中很多数据结构为了达到內存使用的最优化,通常都会用它最小上限的空间来分配变量,有的数据结构也会因为图像文件格式的关系而给予适当的变量, ...

  6. OpenCV Mat数据类型指针ptr的使用

    OpenCV Mat数据类型指针ptr的使用 cv::Mat image = cv::Mat(400, 600, CV_8UC1); //宽400,长600 uchar * data00 = imag ...

  7. Qt QImage与OpenCV Mat转换

    本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/51029382 应一个朋友的要求,整理总 ...

  8. 快速遍历OpenCV Mat图像数据的多种方法和性能分析 | opencv mat for loop

    本文首发于个人博客https://kezunlin.me/post/61d55ab4/,欢迎阅读! opencv mat for loop Series Part 1: compile opencv ...

  9. Opencv Mat的操作

    cout << mat 有错误的原因 You are using OpenCV built with VS10. The ostream operator << in the ...

随机推荐

  1. nginx平滑升级

    1.查询原来安装配置信息 [root@t-scrmap1-v-szzb local]# netstat -unlatp | grep nginx tcp 0 0 0.0.0.0:80 0.0.0.0: ...

  2. Spring AOP动态切换数据源

    现在稍微复杂一点的项目,一个数据库也可能搞不定,可能还涉及分布式事务什么的,不过由于现在我只是做一个接口集成的项目,所以分布式就先不用了,用Spring AOP来达到切换数据源,查询不同的数据库就可以 ...

  3. hihoCoder 后缀自动机三·重复旋律6

    后缀自动机三·重复旋律6 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi ...

  4. 大二在CSDN的博客整理

    001我为什么想写博客 控制台版2048 version_1.0总结 022 囚徒困境中的均衡-----从一篇经典论文说起 021 模拟退火算法学习(一)-----求解最短连通路径 020 小记一次网 ...

  5. 设计模式 “续”

    观察者模式 再次申明,本文学习自 程杰 兄的 "大话设计模式" 根据书中的内容和自己的体会而来. 观察者模式也叫 发布.订阅模式,在这个模式里,一个目标物件管理所有依赖它的观察者物 ...

  6. eclipse安装和配置

    一.下载eclipse eclipse下载页 (选择"Eclipse IDE for Java EE Developers",适用于web和android开发) 我用的是luna的 ...

  7. RDS MySQL 空间问题的原因和解决

    来源:https://help.aliyun.com/knowledge_detail/41739.html RDS MySQL 空间问题的原因和解决 更新时间:2016-07-22 17:20:14 ...

  8. js 常用函数收集(基础)

    (1).判断是否为数值 function isNum(obj){ return !isNaN(parseFloat(obj)) && isFinite(obj); } (2).判断是否 ...

  9. 媒体查询判断ipad和iPhone各版本

    /* 判断ipad */ @media only screen and (min-device-width : 768px) and (max-device-width : 1024px){ /* s ...

  10. [译]学习HTTP协议的请求行

    原文:http://fiddler2.com/blog/blog/2013/02/13/understanding-the-request-line 最近有一位Fiddler用户问我一个问题: 我在使 ...