opencv学习笔记之Mat元素访问

8 篇文章 0 订阅

CV::Mat 地址访问

Mat元素访问方法如下

方式一:at<Type>

  • 返回对指定数组元素的引用;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<float>(k+4) and B.at<int>(2*i+1) instead of A.at<float>(0,k+4) and B.at<int>(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<uchar>(y,x).
    • If matrix is of type CV_8S then use Mat.at<schar>(y,x).
    • If matrix is of type CV_16U then use Mat.at<ushort>(y,x).
    • If matrix is of type CV_16S then use Mat.at<short>(y,x).
    • If matrix is of type CV_32S then use Mat.at<int>(y,x).
    • If matrix is of type CV_32F then use Mat.at<float>(y,x).
    • If matrix is of type CV_64F then use Mat.at<double>(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];
        }
    }
enum ImreadModes {
       IMREAD_UNCHANGED            = -1, //!< If set, return the loaded image as is (with alpha channel, otherwise it gets cropped). Ignore EXIF orientation.
       IMREAD_GRAYSCALE            = 0,  //!< If set, always convert image to the single channel grayscale image (codec internal conversion).
       IMREAD_COLOR                = 1,  //!< If set, always convert image to the 3 channel BGR color image.
       IMREAD_ANYDEPTH             = 2,  //!< If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit.
       IMREAD_ANYCOLOR             = 4,  //!< If set, the image is read in any possible color format.
       IMREAD_LOAD_GDAL            = 8,  //!< If set, use the gdal driver for loading the image.
       IMREAD_REDUCED_GRAYSCALE_2  = 16, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/2.
       IMREAD_REDUCED_COLOR_2      = 17, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/2.
       IMREAD_REDUCED_GRAYSCALE_4  = 32, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/4.
       IMREAD_REDUCED_COLOR_4      = 33, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/4.
       IMREAD_REDUCED_GRAYSCALE_8  = 64, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/8.
       IMREAD_REDUCED_COLOR_8      = 65, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/8.
       IMREAD_IGNORE_ORIENTATION   = 128 //!< If set, do not rotate the image according to EXIF's orientation flag.
     };

/*
//use g++ to build
g++ read_mat.cpp -o read -std=c++11 -lopencv_core -lopencv_imgproc -lopencv_highgui
*/

#include<iostream>
#include<string>
#include<stdio.h>

#ifdef _WIN32
#include <io.h> /* _access */
#include<direct.h> /* _mkdir */
#else
#include<unistd.h> /* access */
#include<sys/stat.h> /*mkdir*/
#endif 

#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;

#define ISSHOWAT 1
int main(int argc, char* argv[])
{
	cv::Mat image;
	// Mat imread( const String& filename, int flags = IMREAD_COLOR ); //默认值
	// flags=0 > grayscale 
	// flags=-1 > unchaged 
	image = cv::imread("test.jpg",1);
	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;
}
  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值