CV::Mat 地址访问
Mat元素访问方法如下
-
Mat类中的
at
成员函数方法访问;- 优点:直观,易于理解;
- 缺点:访问速度慢
-
地址指针访问:访问速度快
-
参考地址:https://docs.opencv.org/3.4.1/d3/d63/classcv_1_1Mat.html
方式一: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)
andB.at<int>(2*i+1)
instead ofA.at<float>(0,k+4)
andB.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 useMat.at<uchar>(y,x)
. - If matrix is of type
CV_8S
then useMat.at<schar>(y,x)
. - If matrix is of type
CV_16U
then useMat.at<ushort>(y,x)
. - If matrix is of type
CV_16S
then useMat.at<short>(y,x)
. - If matrix is of type
CV_32S
then useMat.at<int>(y,x)
. - If matrix is of type
CV_32F
then useMat.at<float>(y,x)
. - If matrix is of type
CV_64F
then useMat.at<double>(y,x)
.
- If matrix is of type
- 优点:直观好理解
- 缺点:访问速度相对慢
方式二:指针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,…im−1)=M.data+M.step[0]∗i0+M.step[1]∗i1+…+M.step[m−1]∗im−1(其中 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;
}