OPENCV_Mat类存取方法(元素访问)
opencv mat 用法

opencv mat 用法OpenCV是一个广泛使用的计算机视觉库,它提供了许多功能和工具,用于图像处理、视频处理、特征提取等任务。
在OpenCV中,Mat 是一个非常重要的数据结构,用于存储和操作图像数据。
在本篇文章中,我们将介绍Mat的基本用法,包括创建、读取、写入和操作图像数据。
一、Mat的创建在使用Mat之前,需要先创建它。
OpenCV提供了多种方法来创建Mat对象,可以根据需要选择合适的方法。
常用的创建Mat的方法包括:1.使用zeros()或ones()函数创建指定尺寸的零矩阵或全矩阵。
2.使用imread()函数从文件中加载图像,并将其存储为Mat对象。
3.使用随机数生成器创建具有一定分布的图像数据。
下面是一个简单的示例代码,演示如何使用imread()函数创建Mat对象:```pythonimportcv2#读取图像并创建Mat对象img=cv2.imread('image.jpg')#显示图像cv2.imshow('Image',img)cv2.waitKey(0)```二、Mat的读取和写入使用imread()函数可以从文件中加载图像数据并将其存储为Mat 对象。
同样地,使用imwrite()函数可以将Mat对象中的数据写入文件。
下面是一个简单的示例代码,演示如何使用imwrite()函数将Mat 对象中的数据写入文件:```pythonimportcv2importnumpyasnp#创建一个随机图像数据data=np.random.randint(0,256,(500,500,3),dtype=np.uint8) #创建Mat对象并设置数据mat=cv2.Mat(500,500,CV_8UC3,data)#显示Mat对象的内容cv2.imshow('Mat',mat)cv2.waitKey(0)#将Mat对象写入文件cv2.imwrite('output.jpg',mat)```三、Mat的数据类型和尺寸Mat对象可以存储不同类型的数据,包括单通道和多通道数据。
OpenCV:Mat元素访问方法、性能、代码复杂度以及安全性分析

OpenCV:Mat元素访问方法、性能、代码复杂度以及安全性分析欢迎转载,尊重原创,所以转载请注明出处:/bendanban/article/details/30527785本文讲述了OpenCV中几种访问矩阵元素的方法,在指定平台上给出性能比较,分析每种矩阵元素访问方法的代码复杂度,易用性。
一、预备设置本文假设你已经正确配置了OpenCV的环境,为方便大家实验,在文中也给出了编译源程序的Makefile,其内容如代码段1所示。
采用如代码段2所示的计时函数,这段代码你可以在我之前的博文中找到,abtic() 可以返回微秒(10^-6秒)级,而且兼容Windows和Linux系统。
本文使用彩色图像做实验,所以矩阵是2维的3通道的。
[plain]view plaincopy = g++2.CPPFLAGS = -O3 `pkg-config --cflags opencv`3.CPPLIB = `pkg-config --libs opencv`4.5.OBJS = test.o6.7.main.exe : $(OBJS)8. $(CC) $(CPPFLAGS) $^ -o $@ $(CPPLIB)9.10.test.o: test.cpp11. $(CC) -c $(CPPFLAGS) $^ -o $@12.13.clean:14. rm -rf *.out main.exe *.o15.16.run:17. ./main.exe文件的内容[cpp]view plaincopy1.#if defined(_WIN32) && defined(_MSC_VER)2.#include <windows.h>3.double abtic() {4.__int64 freq;5.__int64 clock;6. QueryPerformanceFrequency( (LARGE_INTEGER *)&freq );7. QueryPerformanceCounter( (LARGE_INTEGER *)&clock );8.return (double)clock/freq*1000*1000;9.}10.#else11.#include <time.h>12.#include <sys/time.h>13.double abtic() {14.double result = 0.0;15.struct timeval tv;16. gettimeofday( &tv, NULL );17. result = _sec*1000*1000 + _usec;18.return result;19.}20.#endif /* _WIN32 */abtic()的定义二、测试算法文中用于测试的算法:将矩阵中每个元素乘以一个标量,写入一个新的矩阵,每个通道操作独立。
open cv中的Mat详解

通常比矩阵头的尺寸大数个数量级。因此,当在程序中传递图像并创建拷贝时,大的开销 是由矩阵造成的,而不是信息头。OpenCV 是一个图像处理库,囊括了大量的图像处理函数, 为了解决问题通常要使用库中的多个函数,因此在函数中传递图像是家常便饭。同时不要忘 了我们正在讨论的是计算量很大的图像处理算法,因此,除非万不得已,我们不应该拷 贝 大 的图像,因为这会降低程序速度。 二、Mat 的基本操作
如果想建立互不影响的 Mat,是真正的复制操作,需要使用函数 clone()或者 copyTo()。
说到数据的存储,这一直就是一个值得关注的问题,Mat_<uchar>对应的是 CV_8U, Mat_<uchar>对应的是 CV_8U,Mat_<char>对应的是 CV_8S,Mat_<int>对应的是 CV_32S, Mat_<float>对应的是 CV_32F,Mat_<double>对应的是 CV_64F,对应的数据深度如下:
需要注意的是,copy 这样的操作只是 copy 了矩阵的 matrix header 和那个指针,而不是矩 阵的本身,也就意味着两个矩阵的数据指针指向的是同一个地址,需要开发者格外注意。比 如上面这段程序,A、B、C 指向的是同一块数据,他们的 header 不同,但对于 A 的操作 同样也影响着 B、C 的结果。刚刚提高了内存自动释放的问题,那么当我不再使用 A 的时 候就把内存释放了,那时候再操作 B 和 C 岂不是很危险。不用担心,OpenCV 的大神为我 们已经考虑了这个问题,是在最后一个 Mat 不再使用的时候才会释放内存,咱们就放心用 就行了。
在 2001 年刚刚出现的时候,OpenCV 基于 C 语言接口而建。为了在内存(memory) 中存放图像,当时采用名为 IplImage 的 C 语言结构体,时至今日这仍出现在大多数的旧 版教程和教学材料。但这种方法必须接受 C 语言所有的不足,这其中最大的不足要数手动内 存管理,其依据是用户要为开辟和销毁内存负责。虽然对于小型的程序来说手动管理内 一、Mat 简介
opencv中Mat格式的数据访问.at

opencv中Mat格式的数据访问.atopencv3中图形存储基本为Mat格式,如果我们想获取像素点的灰度值或者RGB值,可以通过image.at<uchar>(i,j)的⽅式轻松获取。
Mat类中的at⽅法对于获取图像矩阵某点的RGB值或者改变某点的值很⽅便,对于单通道的图像,则可以使⽤:image.at<uchar>(i, j)其中有⼀个要注意的地⽅是i对应的是点的y坐标,j对应的是点的x坐标,⽽不是我们习惯的(x,y)来获取或改变该点的值,⽽RGB通道的则可以使⽤:image.at<Vec3b>(i, j)[0]image.at<Vec3b>(i, j)[1]image.at<Vec3b>(i, j)[2]来分别获取B、G、R三个通道的对应的值。
下边的代码实现对图像加椒盐噪声:// created by ning zhang 2018/4/25// The function of this program is to add noise to the image#include <opencv2/opencv.hpp>#include <iostream>using namespace std;using namespace cv;void salt_noise( Mat image, int time );int main ( int argc, char** argv ){Mat image = imread("../lena.jpg",0); //input the gray imageif ( image.empty() ){cout << "Load image error" << endl;return -1;}salt_noise(image, 3000);namedWindow("image", 1);imshow("image", image);waitKey();return 0;}void salt_noise ( Mat image, int time ){for (int k = 0; k < time; k++ ) //time is the number of noise you add{int i = rand() % image.rows;int j = rand() % image.cols;if (image.channels() == 1) //single channel{image.at<uchar>(i,j) = rand() % 255;}else if (image.channels() == 3) //RGB channel{image.at<Vec3b>(i, j)[0] = rand() % 255;image.at<Vec3b>(i, j)[1] = rand() % 255;image.at<Vec3b>(i, j)[2] = rand() % 255;}}}效果图如下所⽰,可以为图⽚增加噪点还有⽐较省时的⽅法使⽤Mat的模板⼦类Mat_<T>,,对于单通道的具体使⽤:Mat_<uchar> img = image;img(i, j) = rand() % 255;对于RGB通道的使⽤:Mat_<Vec3b> img = image;img(i, j)[0] = rand() % 255;img(i, j)[1] = rand() % 255;mg(i, j)[2] = rand() % 255;还可以⽤指针的⽅法遍历每⼀像素:(耗时较⼩)void colorReduce(Mat image, int div = 64){int nrow = image.rows;int ncol = image.cols*image.channels();for (int i = 0; i < nrow; i++){uchar* data = image.ptr<uchar>(i);//get the address of row i;for (int j = 0; j < ncol; j++){data[i] = (data[i] / div)*div ;}}}我们要尤其注意OpenCV坐标系与row&col的关系 (Mat::at(x,y)和Mat::at(Point(x, y))的区别)直接给出对应关系吧row == heigh == Point.ycol == width == Point.xMat::at(Point(x, y)) == Mat::at(y,x)因为还有点的坐标,所以建议在访问时都⽤Mat::at(Point(x, y))这种形式吧,免去了点坐标和⾏列的转换详细说明:1. 坐标体系中的零点坐标为图⽚的左上⾓,X轴为图像矩形的上⾯那条⽔平线;Y轴为图像矩形左边的那条垂直线。
OPENCV对于Mat的理解和操作

OPENCV对于Mat的理解和操作1,Mat 是⽤来存储图⽚的数据他会把图⽚变成矩阵Mat src;int main(int argc, char** argv){src = imread("F:\\视觉\\opencv\\pic\\MatTest.png");//读图⽚cout << "灰度化后" << endl;cout << src << endl;}矩阵的格式如下图⽚时这样的:⽤dos显⽰是这样的灰度化之后是这样的怎么样是不是看上去有点熟悉没错,灰度化后直接把每个位置的像素的值,组成⼀个矩阵,⽽没有灰度化时是如图⼀所⽰。
2,Mat获取某⼀点坐标的值cout << (int)src.ptr<uchar>(1)[1] << endl;锐化的案例:int cols = (src.cols-1)*src.channels();int rows = src.rows;int channels = src.channels();int offsetx = src.channels();Mat dst1 = Mat::zeros(src.size(), src.type());for (int row = 1; row < (rows - 1); row++){const uchar* previous = src.ptr<uchar>(row - 1);const uchar* current = src.ptr<uchar>(row);const uchar* next = src.ptr<uchar>(row + 1);uchar* output = dst1.ptr<uchar>(row);for (int col = offsetx; col < cols; col++) {output[col] = saturate_cast<uchar>(5 * current[col] - (current[col - offsetx] + current[col + offsetx] + previous[col] + next[col])); }}imshow("锐化转化后", dst1);src.ptr<uchar>(row);是获取第⼏⾏的指针src.ptr<uchar>(1)[1];默认是char类型,所以要转成int类型输出才能看得到,不然会输出Hex码表对于的字符信息。
open cv中的Mat详解

分类: OpenCV2011-12-28 10:33 26348 人阅读 评论(16) 收藏 举报 数据结构 matrixheadernumbers 存储 matlab
我记得开始接触 OpenCV 就是因为一个算法里面需要 2 维动态数组,那时候看 core 这部分 也算是走马观花吧,随着使用的增多,对 Mat 这个结构越来越喜爱,也觉得有必要温故而 知新,于是这次再看看 Mat。
在 2001 年刚刚出现的时候,OpenCV 基于 C 语言接口而建。为了在内存(memory) 中存放图像,当时采用名为 IplImage 的 C 语言结构体,时至今日这仍出现在大多数的旧 版教程和教学材料。但这种方法必须接受 C 语言所有的不足,这其中最大的不足要数手动内 存管理,其依据是用户要为开辟和销毁内存负责。虽然对于小型的程序来说手动管理内 一、Mat 简介
亲,有木有很简单!!!
还有一种快速初始化数据的办法,如下:
[cpp] view plaincopy
1.double m[3][3] = {{a, b, c}, {d, e, f}, {g, h, i}}; 2.Mat M = Mat(3, 3, CV_64F, m).inv();
也可以把原来的 IplImage 格式的图片直接用 Mat(IplImage)的方式转成 Mat 结构,也可 以像 Matlab 一样调用 zeros()、ones()、eye()这样的函数进行初始化。
幸运的是,C++出现了,并且带来类的概念,这给用户带来另外一个选择:自动的内存 管理(不严谨地说)。这是一个好消息,如果 C++完全兼容 C 的话,这个变化不会带来兼容 性问题。为此,OpenCV 在 2.0 版本中引入了一个新的 C++接口,利用自动内存管理给出了解 决问题的新方法。使用这个方法,你不需要纠结在管理内存上,而且你的代码会变得简洁(少 写多得)。但 C++接口唯一的不足是当前许多嵌入式开发系统只支持 C 语言。所以,当目标 不是这种开发平台时,没有必要使用 旧 方法(除非你是自找麻烦的受虐狂码农)。
opencv-访问Mat中每个像素的值

opencv-访问Mat中每个像素的值参考:膜拜⼤佬以下例⼦代码均针对8位单通道灰度图。
1 .ptr和[]操作符Mat最直接的访问⽅法是通过.ptr<>函数得到⼀⾏的指针,并⽤[]操作符访问某⼀列的像素值。
Mat image(rows,cols,CV_8UC1);for (int j=0; j<image.rows; j++){uchar* pdata= image.ptr<uchar>(j);for (int i=0; i<image.cols; i++){uchar data=pdata[i];}}2 .ptr和指针操作除了[]操作符,我们可以使⽤移动指针*++的组合⽅法访问某⼀⾏中所有像素的值。
Mat image(rows,cols,CV_8UC1);for (int j=0; j<image.rows; j++){uchar* pdata= image.ptr<uchar>(j);for (int i=0; i<image.cols; i++){uchar data=*pdata++;}}3 Mat _iterator⽤Mat提供的迭代器代替前⾯的[]操作符或指针,⾎统纯正的官⽅⽅法~1 Mat image(rows,cols,CV_8UC1);23 Mat_<uchar>::iterator it=image.begin<uchar>();4 Mat_<uchar>::iterator itend=image.end<uchar>();56for (;it != itend;++it)7 {8 uchar data=*it;9 }4 图像坐标 atMat image(rows,cols,CV_8UC1);for (int j=0; j<image.rows; j++){for (int i=0; i<image.cols; i++){uchar data=image.at<uchar>(j,i);}}其中,指针*++访问是最快的⽅法;另外迭代器访问虽然安全,但性能远低于指针运算;通过图像坐标(j,i)访问是最慢的。
OpenCV中对Mat的遍历访问与赋值

OpenCV中对Mat的遍历访问与赋值⼀、访问对于Mat的访问有两种⽅式第⼀种,利⽤Mat::at进⾏访问//读取3通道彩⾊图像Mat img = imread("图⽚地址");int px;//读取图像中第⼀⾏第⼀列,Blue通道数据int px = img.at<Vec3b>(0, 0)[0];第⼆种,利⽤Mat的成员ptr指针进⾏访问//读取3通道彩⾊图像Mat img = imread("图⽚地址");//将Mat中的第⼀⾏地址赋予pxVecuchar* pxVec=img.ptr<uchar>(0);//遍历访问Mat中各个像素值int i, j;int px;for (i = 0; i < img.rows; i++){pxvec = img.ptr<uchar>(i);//三通道数据都在第⼀⾏依次排列,按照BGR顺序//依次赋值为1for (j = 0; j < img.cols*img.channels(); j++){px=pxvec[j];//do anything}}⼆、赋值不能⽤Mat::at进⾏赋值,只能⽤ptr对Mat中的像素点进⾏赋值⼀个完整的例⼦如下:#include "stdafx.h"#include <opencv2\core\core.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv2\imgproc\imgproc.hpp>#include <vector>int main(){//对Mat进⾏遍历赋值//初始化Mat数据结构,256*256,三通道8位(256⾊)图像Mat myimg(256,256,CV_8UC3);//取像素数据⾸地址uchar* pxvec = myimg.ptr<uchar>(0);int i, j;for (i = 0; i < myimg.rows; i++){pxvec = myimg.ptr<uchar>(i);//三通道数据都在第⼀⾏依次排列,按照BGR顺序//依次赋值为1for (j = 0; j < myimg.cols*myimg.channels(); j++){pxvec[j] = 1;}}//展⽰图像imshow("abc", myimg); waitKey(10000);}结果如下:。
opencv中Mat使用,很好,顶!

opencv中Mat使用,很好,顶!(一)Mat矩阵中数据指针Mat.data是uchar类型指针,CV_8U 系列可以通过计算指针位置快速地定位矩阵中的任意元素。
二维单通道元素可以用Mat::at(i, j)访问,i是行序号,j是列序号。
但对于多通道的非unsigned char类型矩阵来说,以上方法都不好(注:后来知道可以通过类型转换,用指针访问data数据,见后文)。
可以用Mat::ptr()来获得指向某行元素的指针,在通过行数与通道数计算相应点的指针。
参照OpenCV的Mat::at()函数,写了一个访问二维Mat矩阵的两个简单的小函数,没有边界检查。
1#include <opencv2/core/core.hpp>23template<typename ItemType>4ItemType* getMatPointPtr(cv::Mat & src, int i , int j , int c = 0)5{6ItemType* curRow = src.ptr<ItemType>(i); 7return curRow + j * src.channels() + c; 8}9template<typename ItemType>10ItemType getMatPoint(cv::Mat & src, int i , int j , int c = 0)11{12ItemType* curRow = src.ptr<ItemType>(i);13return *(curRow + j * src.channels() + c);14}OpenCV中的Mat::at()代码有严格的边界检测,Mat::ptr()也有边界检测,但代码中没有检测j是否越界。
以上为推荐使用的情况,下边的不推荐使用。
可以通过转换指针类型,访问非uchar类型的Mat元素。
OpenCV使用FileStorage保存Mat数据

OpenCV使用FileStorage保存Mat数据/************************************************************转自:/mmjwung/article/details/6913540 ************************************************************/在OpenCV2.0以后的版本中,加入了对C++的支持,大大减少了程序代码量,方便了程序编写,也更符合现代编程思想。
在视觉处理过程中,往往需要保存中间数据。
这些数据的数据类型往往并不是整数。
OpenCV的C++接口中,用于保存图像的imwrite只能保存整数数据,且需作为图像格式。
当需要保存浮点数据或XML/YML文件时,OpenCV的C语言接口提供了cvSave函数,但这一函数在C++接口中已经被删除。
取而代之的是FileStorage类。
具体使用方法参照这个例子:矩阵存储[cpp] view plain copy1.Mat mat = Mat::eye(Size(12,12), CV_8UC1);2.FileStorage fs(".\\vocabulary.xml", FileStorage::WRITE);3.fs<<"vocabulary"<<mat;4.fs.release();在另一处,需要加载这个矩阵数据。
代码如下:[cpp] view plain copy1.FileStorage fs(".\\vocabulary.xml", FileStorage::READ);2.Mat mat_vocabulary;3.fs["vocabulary"] >> mat_vocabulary;在存储数据时,fs<<"vocabulary"<<mat将mat矩阵保存在了声明fs对象时制定的xml文件的vocabulary标签下,也可换成其它标签。
Mat数据类型与访问

Mat数据类型与访问Mat数据类型与访问1.opencv数据类型与常⽤类型对应关系 想要准确的访问Mat中元素值,了解opencv中数据类型很重要,他决定了Mat中每个元素所占内存的⼤⼩。
opencv中各种类型定义:#define CV_8U 0 //对应uchar#define CV_8S 1 //对应char#define CV_16U 2 //对应ushort#define CV_16S 3 //对应short#define CV_32S 4 //对应int#define CV_32F 5 //对应float#define CV_64F 6 //对应double#define CV_USRTYPE1 7...#define CV_8UC1 CV_MAKETYPE(CV_8U,1) //0#define CV_8UC2 CV_MAKETYPE(CV_8U,2) //8#define CV_8UC3 CV_MAKETYPE(CV_8U,3) //16#define CV_8UC4 CV_MAKETYPE(CV_8U,4) //32#define CV_8UC(n) CV_MAKETYPE(CV_8U,(n))#define CV_8SC1 CV_MAKETYPE(CV_8S,1) //1#define CV_8SC2 CV_MAKETYPE(CV_8S,2) //9#define CV_8SC3 CV_MAKETYPE(CV_8S,3) //17#define CV_8SC4 CV_MAKETYPE(CV_8S,4) //33#define CV_8SC(n) CV_MAKETYPE(CV_8S,(n))...#define CV_64FC1 CV_MAKETYPE(CV_64F,1) //6#define CV_64FC2 CV_MAKETYPE(CV_64F,2) //14#define CV_64FC3 CV_MAKETYPE(CV_64F,3) //22#define CV_64FC4 CV_MAKETYPE(CV_64F,4) //38#define CV_64FC(n) CV_MAKETYPE(CV_64F,(n))注:CV_MAKETYPE(depth,cn)=(cn-1)*8+depth //定义类型,类型不冲突补充:opencv中数据类型的变化 注意opencv中各个函数所适⽤的Mat矩阵数据类型。
opencv mat类运算

opencv mat类运算OpenCVMat类是一个非常重要的数据结构,可以表示图像、矩阵和向量等,在计算机视觉和图形学领域广泛应用。
本文将介绍Mat类的基本操作,包括创建、访问、赋值、运算等。
1. 创建Mat对象首先,我们可以通过以下两种方式创建一个Mat对象:(1)使用构造函数:Mat(int rows, int cols, int type);(2)使用静态方法:Mat::zeros(int rows, int cols, int type);其中,rows和cols表示矩阵的行数和列数,type表示数据类型和通道数,常用的有CV_8UC1、CV_8UC3、CV_32FC1等。
2. 访问Mat元素访问Mat对象的元素可以使用at()方法或者指针操作符[],例如:Mat img = imread('image.jpg', CV_LOAD_IMAGE_GRAYSCALE); uchar pixel = img.at<uchar>(i, j);或者:uchar* data = img.ptr<uchar>(i);uchar pixel = data[j];3. 赋值操作Mat对象之间可以进行赋值操作,例如:Mat img = imread('image.jpg', CV_LOAD_IMAGE_GRAYSCALE);Mat img2 = img.clone();4. 运算操作Mat对象之间可以进行加、减、乘、除等运算,例如:Mat img1 = imread('image1.jpg', CV_LOAD_IMAGE_GRAYSCALE); Mat img2 = imread('image2.jpg', CV_LOAD_IMAGE_GRAYSCALE); Mat img_add = img1 + img2;Mat img_sub = img1 - img2;Mat img_mul = img1.mul(img2);Mat img_div = img1 / img2;除此之外,还可以进行矩阵转置、矩阵相乘、矩阵求逆、矩阵求特征值等高级运算。
五种Mat元素的访问方法

五种Mat元素的访问方法方法1、使用Mat的成员函数at<>()Mat的成员函数at()是一个模板函数,我们这里用的是二维矩阵,所以我们使用的at()函数的声明如代码段3所示(取自OpenCV的源文件)。
[cpp]view plaincopy1.template<typename _Tp> _Tp& at(int i0, int i1);代码段3 .at()函数的声明代码段4是本文第二部分描述的算法的实现,矩阵元素使用at<>()函数来索引。
[cpp]view plaincopy1.Vec3b pix;2.for (int r = 0; r < im.rows; r++)3.{4.for (int c = 0; c < im.cols; c++)5. {6. pix = im.at<Vec3b>(r,c);7. pix = pix*scale;8. om.at<Vec3b>(r,c) = pix;9. }10.}代码段4. 使用at<>()函数访问矩阵元素注意:使用at函数时,应该知道矩阵元素的类型和通道数,根据矩阵元素类型和通道数来确定at函数传递的类型,代码段4中使用的是Vec3b这个元素类型,他是一个包含3个unsigned char类型向量。
之所以采用这个类型来接受at的返回值,是因为,我们的矩阵im是3通道,类型为unsigned char类型的。
方法2、使用Mat的成员函数ptr<>()此函数也是模板函数,我们将会用到的ptr函数声明如代码段5所示。
此函数返回指定的数据行的首地址。
[cpp]view plaincopy1.template<typename _Tp> _Tp* ptr(int i0=0);代码段5. ptr成员函数的声明使用ptr<>()成员函数完成本文第二部分所述算法的代码如代码段6所示。
OPENCV_Mat类存取方法(元素访问)

OPENCV_Mat类存取方法(元素访问)Opencv----Mat类cv::Matdepth/dims/channels/step/data/elemSizeMat矩阵中数据元素的地址计算公式:addr(M i0,i1,…i m-1) = + [0] * i0 + [1] * i1+ … + [m-1] * i m-1。
其中m = 是指M的维度i.data:Mat对象中的一个指针,指向内存中存放矩阵数据的一块内存(uchar*data).ii.row: 行;col:列;rows:行数;cols:列数。
iii.dims :Mat所代表的矩阵的维度,如3 * 4 的矩阵为2 维,3 * 4 * 5 的为3维. iv.channels:通道,矩阵中的每一个矩阵元素拥有的值的个数,比如说3 * 4 矩阵中一共12 个元素,如果每个元素有三个值,那么就说这个矩阵是 3 通道的,即channels = 3。
常见的是一张彩色图片有红、绿、蓝三个通道。
但是opencv用imread(opencv 读图的函数)读进来的图像,三通道存放顺序为B、G、R。
v.depth:深度,即每一个像素的位数(bits),在opencv的()中得到的是一个0 – 6 的数字,分别代表不同的位数:enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 };可见0和1都代表8位,2和3都代表16位,4和5代表32位,6代表64位;vi.step:是一个数组,定义了矩阵的布局,具体见下面图片分析,另外注意step1 (step / elemSize1),[m-1] 总是等于elemSize,(i)返回的是第i维的步长,因此(m-1)总是等于channels,m是M的维度;这里是解释步长step[k]的,步长也可以看作是与第k维的存储单位,在2维的矩阵中,因为存储是按照行的顺序存储的,整个矩阵存储为一个平面,所以第k=0维的步长也就是单位肯定就是一行所占的字节数;如果是3维的话,第0维是按照面为单位来存储的,第1维是按照行为单位来存储的,第2维是按照元素类型为单位存储的,每个元素类型是基本类型(即uchar,float,short等等)与通道数的乘积...;也就是基本数据类型与通道数组成元素,多个元素组成了行,多行组成了面,多个面组成了3维体,多个3维体组成4维超体。
OpenCV中IplImage,CvMat,Mat基本使用和元素遍历

OpenCV中IplImage,CvMat,Mat基本使用和元素遍历OpenCV中IplImage, CvMat, Mat 基本使用和元素遍历opencv中常见的与图像操作有关的数据容器有Mat,cvMat和IplImage,这三种类型都可以代表和显示图像。
在OpenCV的文档中说明Mat类型通过C++面向对象的方法实现的,可以进行Matlab风格的矩阵操作,IplImage类型和CvMat类型用C语言实现的,两者之间存在着类似于面向对象中的继承关系。
•IplImage一、先上OpenCV中的图像信息头,该结构体的定义如下:[cpp]view plaincopy1.typedef struct _IplImage2.{3.int nSize; /* IplImage大小 */4.int ID; /* 版本 (=0)*/5.int nChannels; /* 大多数OPENCV函数支持1,2,3 或 4 个通道 */6.int alphaChannel; /* 被OpenCV忽略 */7.int depth; /* 像素的位深度: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U,8.IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_ DEPTH_64F 可支持 */9.10.char colorModel[4]; /* 被OpenCV忽略 */11.char channelSeq[4]; /* 被OpenCV忽略 */12.int dataOrder; /* 0 - 交叉存取颜色通道, 1 - 分开的颜色通道. cvCreateImage只能创建交叉存取图像 */13.int origin; /* 0 - 顶—左结构,1 - 底—左结构 (Windows bitmaps 风格) */14.int align; /* 图像行排列 (4 or 8). OpenCV 忽略它,使用 widthStep 代替 */15.16.int width; /* 图像宽像素数 */17.int height; /* 图像高像素数*/18.19.struct _IplROI *roi; /* 图像感兴趣区域. 当该值非空只对该区域进行处理 */20.struct _IplImage *maskROI; /* 在 OpenCV中必须置NULL */21.void *imageId; /* 同上*/22.struct _IplTileInfo *tileInfo; /*同上*/23.24.int imageSize; /* 图像数据大小(在交叉存取格式下imageSize=image->height*image->widthStep),单位字节*/25.char *imageData; /* 指向排列的图像数据 */26.int widthStep; /* 排列的图像行大小,以字节为单位 */27.int BorderMode[4]; /* 边际结束模式, 被OpenCV忽略 */28.int BorderConst[4]; /* 同上 */29.30.char *imageDataOrigin; /* 指针指向一个不同的图像数据结构(不是必须排列的),是为了纠正图像内存分配准备的 */31.} IplImage;特别说明:(1)dataOrder这个可以取两个不同的值(0/1),其中交叉存取颜色通道:指颜色数据排列会是BGRBGR....分开颜色通道:几个颜色通道就分几个颜色平面存储。
opencv mat 运算符 操作 详解

在 OpenCV 中,cv::Mat类型是表示矩阵(图像)的核心数据结构。
它支持各种矩阵运算和操作,可以进行像素级别的图像处理和计算。
以下是一些常见的cv::Mat运算符和操作的详解:
创建cv::Mat对象:
1.创建空白矩阵:
2.通过数据创建矩阵:
3.复制矩阵:
基本运算:
1.矩阵加法:
2.矩阵减法:
3.矩阵乘法:
4.标量乘法:
逐元素运算:
1.逐元素加法:
2.逐元素减法:
3.逐元素乘法:
4.逐元素除法:
转置和翻转:
1.矩阵转置:
2.水平翻转:
3.垂直翻转:
其他操作:
1.矩阵元素访问:
2.改变矩阵大小:
3.提取子矩阵:
4.通道拆分与合并:
这些是一些常见的cv::Mat运算符和操作的示例。
OpenCV 提供了丰富的功能,允许进行更复杂的图像处理和计算。
具体的操作和运算可以根据具体需求进行查阅OpenCV 文档。
OPENCV的MAT类详解

类Mat导言OpenCV c + + n 维稠密数组类类CV_EXPORTS Mat{public:/ / … …很多的方法....../*!包括几位字段:-神奇的签名-连续性标志-深度(Note:应该是位深)-通道数*/int flags;(Note :目前还不知道flags做什么用的).};Mat类表示一个n 维的密集数值单通道或多通道数组。
它可以用于存储实数或复数值的向量和矩阵、灰度或彩色图像、体素、向量场、点云、张量、直方图(尽管较高维的直方图存储在SparseMat可能更好)。
M 数组的数据布局是由阵列[]定义的,使元素的地址(i0,。
,其中0<= i k < [k],可以计算为:addr( Mi0 ;:::; = + [ 0]*i0 + [ 1] *i1+ .…+ [ M:dims- 1] i M:dims- 12维的数组的情况下根据上述公式被减至:addr( M i,j)= + [ 0]*i+ [ 1] *j请注意,[i] > =[i+1] (事实上,[i] > =[i+1]*[i+1])。
这意味着2维矩阵是按行存储的,3 维矩阵是由平面存储,以此类推。
[] 是最小的而且总是等于元素大小()。
因此,Mat中的数据布局完全兼容OpenCV 中CvMat、IplImage、CvMatND类型。
它也和标准工具包和SDK,如Numpy(ndarray),Win32(独立设备位图)等主流的密集数组类型相兼容,也就是说,与任何使用步进(或步长)来计算像素位置的阵列相兼容。
由于这种兼容性,使用户分配的数据创建Mat头以及用OpenCV函数实时处理该头成为可能。
有很多不同的方法,创建一个Mat的对象。
下面列出了最常见的选项:使用create(nrows,ncols,type)方法或类似的Mat(nrows,ncols,type [,fillValue])构造函数。
一个新的指定了大小和类型的数组被分配。
pencv中mat的数学运算和基本操作

pencv中mat的数学运算和基本操作在OpenCV中,Mat是一个多维数组,被广泛用于图像处理和计算机视觉领域。
Mat类提供了各种数学运算和基本操作,用于处理图像的像素值、形状和数据类型等。
1.创建和初始化Mat对象:Mat可以通过多种方法进行创建和初始化。
常见的方法包括:-使用默认构造函数创建一个空的Mat对象:Mat()-使用指定的行数、列数和数据类型创建一个Mat对象:Mat(int rows, int cols, int type)-复制一个已有的Mat对象:Mat(Mat m)-从数组、向量或指针初始化Mat对象:Mat(int rows, int cols, int type, void* data)2.访问和修改元素:可以使用at()方法或操作符()来访问和修改Mat对象的元素。
at()方法具有边界检查,而操作符()没有。
例如:-获取指定位置的像素值:int value = mat.at<int>(row, col);-修改指定位置的像素值:mat.at<int>(row, col) = newValue;3.像素值的常见运算:Mat对象可以进行各种常见的数学运算,包括像素值的加法、减法、乘法和除法。
这些运算可以对整个图像进行,也可以对指定区域进行。
例如:-对整个图像进行像素值加法:mat1 = mat1 + mat2;-对指定区域进行像素值减法:mat1(Rect(x, y, width, height)) -= Scalar(b, g, r);4.形状和尺寸操作:Mat对象提供了各种方法来获取和修改图像的形状和尺寸。
常见的方法包括:-获取图像的行数和列数:int rows = mat.rows; int cols = mat.cols;-获取图像的尺寸:Size size = mat.size();-修改图像的尺寸:mat.resize(height, width);-转置图像:mat = mat.t();5.通道操作:对于多通道的图像,Mat对象还提供了通道的操作方法。
OpenCV学习笔记(2):Mat矩阵的初始化和元素访问

OpenCV学习笔记(2):Mat矩阵的初始化和元素访问在研究Mat矩阵的初始化的时候,发现其不能像Matx轻量级矩阵那样,直接利⽤数组来进⾏初始化,⽽是利⽤⼀个内部的变量类型:Scalar来进⾏初始化的。
参考⼿册中的构造函数如下所⽰:(1) Mat::Mat()(2) Mat::Mat(int rows, int cols, int type)(3) Mat::Mat(Size size, int type)(4) Mat::Mat(int rows, int cols, int type, const Scalar& s)(5) Mat::Mat(Size size, int type, const Scalar& s)(6) Mat::Mat(const Mat& m)(7) Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP)(8) Mat::Mat(Size size, int type, void* data, size_t step=AUTO_STEP)(9) Mat::Mat(const Mat& m, const Range& rowRange, const Range& colRange)(10) Mat::Mat(const Mat& m, const Rect& roi)(11) Mat::Mat(const CvMat* m, bool copyData=false)(12) Mat::Mat(const IplImage* img, bool copyData=false)(13) template<typename T, int n> explicit Mat::Mat(const Vec<T, n>& vec, bool copyData=true)(14) template<typename T, int m, int n> explicit Mat::Mat(const Matx<T, m, n>& vec, bool copyData=true)(15) template<typename T> explicit Mat::Mat(const vector<T>& vec, bool copyData=false)(16) Mat::Mat(const MatExpr& expr)(17) Mat::Mat(int ndims, const int* sizes, int type)(18) Mat::Mat(int ndims, const int* sizes, int type, const Scalar& s)(19) Mat::Mat(int ndims, const int* sizes, int type, void* data, const size_t* steps=0)(20) Mat::Mat(const Mat& m, const Range* ranges)似乎这样的矩阵让我们⽤起来感觉很不顺⼿,不过接着往下读参考⼿册,你会发现这样⼀个例⼦: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);通过这个例⼦,我们尝试来给Mat类型初始化。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Opencv----Mat类∙cv::Mat∙depth/dims/channels/step/data/elemSizeMat矩阵中数据元素的地址计算公式:addr(M i0,i1,…i m-1) = M.data + M.step[0] * i0 + M.step[1] * i1+ … + M.step[m-1] * i m-1。
其中m = M.dims 是指M的维度i.data:Mat对象中的一个指针,指向内存中存放矩阵数据的一块内存(uchar*data).ii.row: 行;col:列;rows:行数;cols:列数。
iii.dims :Mat所代表的矩阵的维度,如3 * 4 的矩阵为2 维,3 * 4 * 5 的为3维. iv.channels:通道,矩阵中的每一个矩阵元素拥有的值的个数,比如说3 * 4 矩阵中一共12 个元素,如果每个元素有三个值,那么就说这个矩阵是3 通道的,即channels = 3。
常见的是一张彩色图片有红、绿、蓝三个通道。
但是opencv用imread(opencv读图的函数)读进来的图像,三通道存放顺序为B、G、R。
v.depth:深度,即每一个像素的位数(bits),在opencv的Mat.depth()中得到的是一个0 –6 的数字,分别代表不同的位数:enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 };可见0和1都代表8位,2和3都代表16位,4和5代表32位,6代表64位;vi.step:是一个数组,定义了矩阵的布局,具体见下面图片分析,另外注意step1(step / elemSize1),M.step[m-1] 总是等于elemSize,M.step1(i)返回的是第i 维的步长,因此M.step1(m-1)总是等于channels,m是M的维度;这里是解释步长step[k]的,步长也可以看作是与第k维的存储单位,在2维的矩阵中,因为存储是按照行的顺序存储的,整个矩阵存储为一个平面,所以第k=0维的步长也就是单位肯定就是一行所占的字节数;如果是3维的话,第0维是按照面为单位来存储的,第1维是按照行为单位来存储的,第2维是按照元素类型为单位存储的,每个元素类型是基本类型(即uchar,float,short等等)与通道数的乘积...;也就是基本数据类型与通道数组成元素,多个元素组成了行,多行组成了面,多个面组成了3维体,多个3维体组成4维超体。
以此类推,如此看来某一维的步长应该等于高一维的步长step*低一维的大小size 。
vii.elemSize : 矩阵中每一个元素的数据大小,如果是n通道,就是(n*数据类型)。
如果Mat中的数据的数据类型是CV_8U 那么elemSize = 1,CV_8UC3 那么elemSize = 3,CV_16UC2 那么elemSize = 4;记住另外有个elemSize1 表示的是矩阵中数据类型的大小,即elemSize / channels 的大小。
图片分析1:考虑二维情况(stored row by row)按行存储上面是一个3 X 4 的矩阵,假设其数据类型为CV_8U,也就是单通道的uchar 类型∙这是一个二维矩阵,那么维度为2 (M.dims == 2);∙M.rows == 3; M.cols == 4;∙sizeof(uchar) = 1,那么每一个数据元素大小为1 (M.elemSize() == 1, M.elemSize1() == 1);∙CV_8U 得到M.depth() == 0, M.channels() == 1;∙因为是二维矩阵,那么step 数组只有两个值,step[0] 和step[1] 分别代表一行的数据大小和一个元素的数据大小,则M.step[0] == 4, M.step[1] == 1;∙M.step1(0) == M.cols = 4; M.step1(1) == 1;假设上面的矩阵数据类型是CV_8UC3,也就是三通道∙M.dims == 2;M.channels() == 3;M.depth() == 0;∙M.elemSize() == 3 (每一个元素包含3个uchar值)M.elemSize1() == 1 (elemSize / channels)∙M.step[0] == M.cols * M.elemSize() == 12, M.step[1] == M.channels() *M.elemSize1() == M.elemSize() == 3;∙M.step(0) == M.cols * M.channels() == 12 ; M.step(1) == M.channels() == 3;图片分析2:考虑三维情况(stored plane by plane)按面存储上面是一个3 X 4 X 6 的矩阵,假设其数据类型为CV_16SC4,也就是short 类型∙M.dims == 3 ; M.channels() == 4 ; M.elemSize1() == sizeof(short) == 2 ;∙M.rows == M.cols == –1;∙M.elemSize() == M.elemSize1() * M.channels() == M.step[M.dims-1] == M.step[2] == 2 * 4 == 8;∙M.step[0] == 4 * 6 * M.elemSize() == 192;∙M.step[1] == 6 * M.elemSize() == 48;∙M.step[2] == M.elemSize() == 8;∙M.step1(0) == M.step[0] / M.elemSize() == 48 / 2 == 96 (第一维度(即面的元素个数) * 通道数);∙M.step1(1) == M.step[1] / M.elemSize() == 12 / 2 == 24(第二维度(即行的元素个数/列宽) * 通道数);∙M.step1(2) == M.step[2] / M.elemSize() == M.channels() == 4(第三维度(即元素) * 通道数);End以上为Mat的存放形式以下为Mat的一些操作方法具体使用方法Fn 1 :利用step。
Code 1:int main(){//新建一个uchar类型的单通道矩阵(grayscale image 灰度图)Mat m(400, 400, CV_8U, Scalar(0));for (int col = 0; col < 400; col++){for (int row = 195; row < 205; row++){//获取第[row,col]个像素点的地址并用 * 符号解析*(m.data + m.step[0] * row + m.step[1] * col) = 255;}}imshow("canvas", m);cvWaitKey();return 0;}Output 1 :Code1只是演示了单通道的情况,对于多通道的例子,请看Code2 然后再看Code3。
Fn 2 :使用Mat::at 函数∙原型template<typename _Tp> inline _Tp& Mat::at(…) //其中参数有多个,也就是说at 函数有多个重载∙返回值为Mat 类型, Mat 有个索引的重载,也就是[] 符号的重载,用这个重载可以定位多通道数据,具体示例可以看下面代码。
下面的代码把红色通道值大于128的颜色的置为白色,左边为原图,右边为处理过后的图。
Code 2 :int main(){Mat img = imread("lena.jpg");imshow("Lena Original", img);for (int row = 0; row < img.rows; row++){for (int col = 0; col < img.cols; col++){/* 注意 Mat::at 函数是个模板函数, 需要指明参数类型, 因为这张图是具有红蓝绿三通道的图,所以它的参数类型可以传递一个 Vec3b, 这是一个存放 3 个 uchar 数据的Vec(向量). 这里提供了索引重载, [2]表示的是返回第三个通道, 在这里是 Red 通道, 第一个通道(Blue)用[0]返回 */if(img.at<Vec3b>(row, col)[2] > 128)img.at<Vec3b>(row, col) = Vec3b(255, 255, 255);}}imshow("Lena Modified", img);cvWaitKey();return 0;}Output 2 :Code 3 :这段代码用的是Fn1 的方式,效果和Code 2 等价,不过是处理三通道数据而已:int main(){Mat img = imread("lena.jpg");imshow("Lena Original", img);for (int row = 0; row < img.rows; row++){for (int col = 0; col < img.cols; col++){//主要是这里的代码if(*(img.data + img.step[0] * row + img.step[1] * col + img.elemSize1() * 2) > 128){//[row, col]像素的第 1 通道地址被 * 解析(blue通道)*(img.data + img.step[0] * row + img.step[1] * col) = 255;//[row, col]像素的第 2 通道地址被 * 解析(green通道), 关于elemSize1函数的更多描述请见 Fn1 里所列的博文链接*(img.data + img.step[0] * row + img.step[1] * col +img.elemSize1()) = 255;//[row, col]像素的第 3 通道地址被 * 解析(red通道)*(img.data + img.step[0] * row + img.step[1] * col +img.elemSize1() * 2) = 255;}}}imshow("Lena Modified", img);cvWaitKey();return 0;}Output 3 = Output 2Fn 3 :使用Mat 的一个模板子类Mat_<typename _Tp> 的( ) 符号重载定位一个像素Code 4 :int main(){Mat m(400, 400, CV_8UC3, Scalar(255, 255, 255));// m2 是 Mat_<Vec3b> 类型的, 因为 m 中元素的类型是 CV_8UC3, 可以用 Vec3b 存储 3 个通道的值// 注意 Mat_<CV_8UC3> 这种写法是错误的, 因为 CV_8UC3 只是一个宏定义// #define CV_8UC3 CV_MAKETYPE(CV_8U, 3)Mat_<Vec3b> m2 = m;// for 循环画一个红色的实心圆for (int y = 0; y < m.rows; y++){for (int x = 0; x < m.rows; x++){if (pow(double(x-200), 2) + pow(double(y-200), 2) - 10000.0 < 0.00000000001){// Mat_ 模板类实现了对()的重载, 可以定位到一个像素m2(x, y) = Vec3b(0, 0, 255);}}}imshow("Image", m);cvWaitKey();return 0;}Output 4 :[ 看上去怎么有点不爽]Fn 4 :使用Mat::ptr 模板函数Code 5 :int main(){Mat m(400, 400, CV_8UC3, Scalar(226, 46, 166)); imshow("Before", m);for (int row = 0; row < m.rows; row++){if (row % 5 == 0){// data 是 uchar* 类型的, m.ptr<uchar>(row) 返回第 row 行数据的首地址// 需要注意的是该行数据是按顺序存放的,也就是对于一个 3 通道的 Mat, 一个像素有// 有 3 个通道值, [B,G,R][B,G,R][B,G,R]... 所以一行长度为:// sizeof(uchar) * m.cols * m.channels() 个字节uchar* data = m.ptr<uchar>(row);for (int col = 0; col < m.cols; col++){data[col * 3] = 102; //第row行的第col个像素点的第一个通道值 Blue data[col * 3 + 1] = 217; // Greendata[col * 3 + 2] = 239; // Red}}}imshow("After", m);cout << (int)m.at<Vec3b>(0, 0)[0] << ','; //利用 Fn 1 介绍的方法输出一下像素值到控制台cout << (int)m.at<Vec3b>(0, 0)[1] << ',';cout << (int)m.at<Vec3b>(0, 0)[2] << endl;cvWaitKey();return 0;}Output 5 :End :Author : Ggicci谢谢阅读,有误希望指正!--OpenCV初学者。