OpenCv Mat操作总结

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 指针高效访问

// 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.);

}

 

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;

}

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

{

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

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

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

}

 

4 二维单通道数据访问

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);

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)