opencv学习笔记之Mat元素访问

CV::Mat 地址访问

Mat元素访问方法如下

  • Mat类中的at成员函数方法访问;

    • 优点:直观,易于理解;
    • 缺点:访问速度慢
  • 地址指针访问:访问速度快

  • 参考地址:https://docs.opencv.org/3.4.1/d3/d63/classcv_1_1Mat.html

方式一:at

  • 返回对指定数组元素的引用;Returns a reference to the specified array element.
	//declare
    template<typename _Tp >
			_Tp& cv::Mat::at(int i0 = 0)
  • example: A is a 1 x N floating-point matrix and B is an M x 1 integer matrix, you can simply write A.at(k+4) and B.at(2*i+1) instead of A.at(0,k+4) and B.at(2*i+1,0), respectively.
   cv::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);//赋值
  • Keep in mind that the size identifier used in the at operator cannot be chosen at random. It depends on the image from which you are trying to retrieve the data. The table below gives a better insight in this:
    • If matrix is of type CV_8U then use Mat.at(y,x).
    • If matrix is of type CV_8S then use Mat.at(y,x).
    • If matrix is of type CV_16U then use Mat.at(y,x).
    • If matrix is of type CV_16S then use Mat.at(y,x).
    • If matrix is of type CV_32S then use Mat.at(y,x).
    • If matrix is of type CV_32F then use Mat.at(y,x).
    • If matrix is of type CV_64F then use Mat.at(y,x).
  • 优点:直观好理解
  • 缺点:访问速度相对慢

方式二:指针pointer

  • 二维图像Mat类型常见的多个属性:
    • data uchar型的指针。Mat类分为了两个部分:矩阵头和指向矩阵数据部分的指针,data就是指向矩阵数据的指针;
    • dims 矩阵的维度,例如5*6矩阵是二维矩阵,则dims=2,三维矩阵dims=3;
    • channels 矩阵元素拥有的通道数;
    • type 表示Mat中元素的类型以及矩阵的通道个数,它是一系列的预定义的常量,其命名规则为CV_(位数)+(数据类型)+(通道数);CV_16UC2表示的是元素类型是一个16位的无符号整数,通道数为2
    • depth表示矩阵中元素的一个通道的数据类型;
    • elemSize表示矩阵一个元素占用的字节数;type是CV_16SC3,那么elemSize = 3 * 16 / 8 = 6 bytes
    • elemSize1表示矩阵元素一个通道占用的字节数;
    • step表示是一个数组,定义了矩阵的布局
    • 矩阵 (M) 中数据元素的地址: a d d r ( M i 0 , i 1 , … i m − 1 ) = M . d a t a + M . s t e p [ 0 ] ∗ i 0 + M . s t e p [ 1 ] ∗ i 1 + … + M . s t e p [ m − 1 ] ∗ i m − 1 addr(M_{i_0,i_1,…i_{m-1}}) = M.data + M.step[0] * i_0+ M.step[1] * i_1 + … + M.step[m-1] * i_{m-1} addr(Mi0,i1,im1)=M.data+M.step[0]i0+M.step[1]i1++M.step[m1]im1(其中 m = M.dims M的维度)
  • 代码如下
	cv::Mat src(100, 100, CV_64F); //初始化
    int width = src.cols;
    int height = src.rows;
    int step = src.step;
    const float* sptr = (float*)src.data;
    step /= sizeof(*sptr);

    for (int i = 0; i < height; i++)
    {
        const float* sptrCurr = sptr + i * step;
        for (int j = 0; j < width; j++)
        {
            float pt = sptrCurr[j];
        }
    }
/*
//use g++ to build
g++ read_mat.cpp -o read -std=c++11 -lopencv_core -lopencv_imgproc -lopencv_highgui
*/

#include
#include
#include

#ifdef _WIN32
#include  /* _access */
#include /* _mkdir */
#else
#include /* access */
#include /*mkdir*/
#endif 

#include
using namespace cv;
using namespace std;

#define ISSHOWAT 1
int main(int argc, char* argv[])
{
	cv::Mat image;
	image = cv::imread("test.jpg");
	if (image.empty()){
		printf("input image read error.\n");
	}
	
	int width = image.cols;//宽
	int height = image.rows;//高
//如果定义了宏等于1,则使用at访问,否则使用地址指针访问
#if ISSHOWAT
  	Vec3b tmp;
	cv::Mat new_image = cv::Mat::zeros(image.size(), image.type());
	for (int r = 0; r < height; r++){
		for (int c = 0; c < width; c++)
		{
			tmp = image.at<Vec3b>(r, c);
			tmp = tmp*1.0;
			new_image.at<Vec3b>(r, c) = tmp;
		}
	}
	cv::imshow("new_image", new_image);
	cv::waitKey(0);
#else
	int step = image.step; //每一行包含的字节数
	//cout << image.type() << endl; //CV_8UC3
	//cout << "image.step "<< image.step << endl; //
    
	//定义指向矩阵数据的内存地址的指针,首先得知道数据元素的类型,
    //正常的rgb的图像类型为CV_8UC3,灰度图为CV_8UC1
	const uchar* imgPtr = (uchar*)image.data; 
	cout << sizeof(*imgPtr) << endl;//输出单一通道的字节数=1,默认与image.elemSize1()相等
	step /= sizeof(*imgPtr);//每一行总的通道单元数
    
	// 每个元素大小,单位是字节 例type是CV_16SC3,那么elemSize = 3 * 16 / 8 = 6 bytes
	cout << "elemSize:" << image.elemSize() << endl;// 8*3/8=3
	// 每个通道大小,单位是字节
	cout << "elemSize1:" << image.elemSize1() << endl;//1
	//创建文件对象,保存图片的值
	errno_t err;
	FILE *fp;
	if ((err = fopen_s(&fp, "result.txt", "w")) != 0)
		printf("The file 'result.txt' was not opened\n");
	else
		printf("The file 'result.txt' was opened\n");
	
	//FILE *fp = fopen("result.txt", "w");
	//if (fp == NULL){ printf("error.\n"); }
    
    cv::Mat same = cv::Mat::zeros(image.size(),CV_8UC3);
	for (int i = 0; i < height; i++)
	{
		const uchar* imgPtrCur = imgPtr + i*step;//指向矩阵数据第i行的内存地址
		for (int j = 0; j < width; j++)
		{
			uchar b = imgPtrCur[j * 3 + 0];
			uchar g = imgPtrCur[j * 3 + 1];
			uchar r = imgPtrCur[j * 3 + 2];
			same.at<Vec3b>(i, j)[0] = b;
			same.at<Vec3b>(i, j)[1] = g;
			same.at<Vec3b>(i, j)[2] = r;
			fprintf(fp, " %d ", imgPtrCur[j]);
		}		
		fprintf(fp,"\n");
	}
	
	fclose(fp);
	
	cv::imwrite("same.png", same);
#endif
	getchar();
	return 0;
}
  • 参考博客地址
    • https://blog.csdn.net/bendanban/article/details/30527785
    • https://blog.csdn.net/xiaowei_cqu/article/details/19839019

你可能感兴趣的:(C++,opencv)