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. Git的使用

    1.从Git服务器上获取项目   2.提交我的修改项目 3.发布新版本 4.修复bug

  2. host 文件

    艾玛,果然一个破的小问题也能纠结好久!不过终于过去了... 1. 机器上的host文件目录一般是  /etc/hosts 主要可能会涉及一些网站的安全访问,把网站加入hosts也就意味着 加入了白名单 ...

  3. 怪物AI之发现玩家(视觉范围发现系列)

    在网上找到一些资料参考,然后写写自己的想法. 这里感谢MOMO等大神. 我们用玩家检测怪物的方法来测,这样比较试用与弱联网游戏,每次在同步玩家的时候来判断玩家与怪物的位置. 这里给出两个处理方式: 1 ...

  4. 5G为何采纳华为力挺的Polar码?一个通信工程师的大实话

    Polar码被采纳为5G eMBB场景的控制信道编码,这两天连续被这条消息刷屏,连吃瓜群众都直呼好爽. 然而,随着媒体报道的持续发酵,真相在口口相传中变了形,不乏夸大不实之嫌,小编终于坐不住了,也想吐 ...

  5. 使用safari对webview进行调试

    在web开发的过程中,抓包.调试页面样式.查看请求头是很常用的技巧.其实在iOS开发中,这些技巧也能用(无论是模拟器还是真机),不过我们需要用到mac自带的浏览器Safari.所以,本文将讲解如何使用 ...

  6. CSS书写规范、命名规范、网易CSS框架NEC

    网易CSS框架NEC:http://nec.netease.com/ NEC框架的CSS规范:  CSS规范 - 分类方法 CSS规范 - 命名规则 CSS规范 - 代码格式 CSS规范 - 优化方案 ...

  7. Linux C fcntl()函数详解

    fcntl系统调用 功能描述:根据文件描述词来操作文件的特性. 用法: int fcntl(int fd, int cmd);  int fcntl(int fd, int cmd, long arg ...

  8. PF_INET 和 AF_INET 的区别

    在写网络程序的时候,建立TCP socket: sock = socket(PF_INET, SOCK_STREAM, 0); 然后再绑定本地地址或连接远程地址时需要初始化sockaddr_in结构, ...

  9. Windows下memcached.exe的安装与配置

    D:\PHP\Memcached\memcached.exe -d install D:\PHP\Memcached\memcached.exe –m  1024  -d start 假设安装在:D: ...

  10. 相同根域名下跨域共享session的解决方案

    https://code.msdn.microsoft.com/CSASPNETShareSessionBetween-021daa39