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. Kafka 分布式环境搭建

    这篇文章将介绍如何搭建kafka环境,我们会从单机版开始,然后逐渐往分布式扩展.单机版的搭建官网上就有,比较容易实现,这里我就简单介绍下即可,而分布式的搭建官网却没有描述,我们最终的目的还是用分布式来 ...

  2. 回归树|GBDT|Gradient Boosting|Gradient Boosting Classifier

    已经好久没写了,正好最近需要做分享所以上来写两篇,这篇是关于决策树的,下一篇是填之前SVM的坑的. 参考文献: http://stats.stackexchange.com/questions/545 ...

  3. Unity Development with VS Code

    https://code.visualstudio.com/Docs/runtimes/unity

  4. python 模块基础介绍

    从逻辑上组织代码,将一些有联系,完成特定功能相关的代码组织在一起,这些自我包含并且有组织的代码片段就是模块,将其他模块中属性附加到你的模块的操作叫做导入. 那些一个或多个.py文件组成的代码集合就称为 ...

  5. C# GUID转换成16位字符串或19位数字并确保唯一

    /// <summary> /// 根据GUID获取16位的唯一字符串 /// </summary> /// <param name=\"guid\" ...

  6. Spring系列之AOP

    一.什么是AOPAOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引 ...

  7. Npoi导入导出Excel操作

    之前公司的一个物流商系统需要实现对订单的批量导入和导出,翻阅了一些资料,最后考虑使用NPOI实现这个需求. 在winform上面实现excel操作:http://www.cnblogs.com/Cal ...

  8. 安装 Ruby, Rails 运行环境 常见的错误

    安装部署ruby on rails 的环境时并不是想的那么顺利 这个是我遇到的问题及解决的方式 参考安装博客: (1) https://ruby-china.org/wiki/install_ruby ...

  9. tyvj1148 小船弯弯

    描述 童年的我们,充满了新奇的想法.这天,小朋友们用彩虹画笔在云霞上绘制了世界上最美丽的图画.那描绘的是一条大河波浪宽,风吹稻花香两岸的情景.欣赏着自己的作品,小朋友们别提多开心了.这时,Q小朋友对C ...

  10. 【bzoj3450】Tyvj1952 Easy

    题目描述 某一天WJMZBMR在打osu~~~但是他太弱逼了,有些地方完全靠运气:(我们来简化一下这个游戏的规则有n次点击要做,成功了就是o,失败了就是x,分数是按comb计算的,连续a个comb就有 ...