opencv里,Mat图像的像素访问跟IplImage类型有所不同。
IplImage类型与Mfc图像处理相似。像素指针加上内存位移即可表示图像像素。
在mfc中:
for(i=0;i<m_imgHeight;i++){
for(j=0;j<m_imgWidth;j++){
if(*(m_pImgData+i*lineByte+j)<threshold)
*(m_pImgDataOut+i*lineByte+j)=0;
else
*(m_pImgDataOut+i*lineByte+j)=255;
}
}
Mat本质上是由两个数据部分组成的类: (包含信息有矩阵的大小,用于存储的方法,矩阵存储的地址等) 的矩阵头和一个指针。 指针指向包含了像素值的矩阵(可根据选择用于存储的方法采用任何维度存储数据)。矩阵头部的大小是恒定的。然而,矩阵本身的大小因图像的不同而不同,通常是较大的数量级。因此,当你在您的程序中传递图像并在有些时候创建图像副本您需要花费很大的代价生成图像矩阵本身,而不是图像的头部。
这样在opencv里,Mat的每个对象具有其自己的头,但可能他们通过让他们矩阵指针指向同一地址的两个实例之间共享该矩阵。此外,拷贝运算符将只能复制矩阵头部,也还将复制指向矩阵的指针,但不复制矩阵本身。
1.Mat A, C; //仅创建了头部
2.A = imread(argv[1], CV_LOAD_IMAGE_COLOR); //在此我们知道使用的方法(分配矩阵)
3.Mat B(A); //使用拷贝构造函数
4.C = A; //赋值运算符
上文中的所有对象,使用同一个数据矩阵。他们的头不同,但是其中任何一个对矩阵进行修改,都会将影响所有其他的矩阵。
单通道灰度图数据存放格式:
多通道的图像中,每列并列存放通道数量的子列,如RGB三通道彩色图:
注意通道的顺序反转了:BGR
两种访问Mat图像像素的方法
通常情况内存足够大的话图像的每一行是连续存放的,也就是在内存上图像的所有数据存放成一行,这中情况在访问时可以提供很大方便。可以用 isContinuous() 函数来判断图像数组是否为连续的。第一:遍历图像先行后列,每行定义一个指针,然后在内存上直接连续访问。
Mat binImage = imread("test.jpg", 0);
int rows = binImage.rows - 1;
int cols = binImage.cols - 1;
for (int i = 0; i < rows; i++)
{ uchar* data= binImage.ptr<uchar>(i); //像素的指针
for (int j = 0; j < cols; j++)
{
if (data[j] >50)
data[j]=0;
else
data[j]=255;
}
}
还有:
uchar* p=binImage.data;
for(int i=0;i<rows*cols;i++)
{
if (*p>100)
*p=0;
else
*p=255;
*p++;
}
若是RGB彩色图像
Mat& ScanImageAndReduceC(Mat& I, const uchar* const table)
{
// accept only char type matrices
CV_Assert(I.depth() != sizeof(uchar));
int channels = I.channels();
int nRows = I.rows ;
int nCols = I.cols* channels;
if (I.isContinuous())
{
nCols *= nRows;
nRows = 1;
}
int i,j;
uchar* p;
for( i = 0; i < nRows; ++i)
{
p = I.ptr<uchar>(i);
for ( j = 0; j < nCols; ++j)
{
p[j] = table[p[j]];
}
}
return I;
}
第二种 先列后行,定义指向整个图像的指针。
cv::Mat imbottom;
int channle = imbottom.channels();
uchar *datar = imbottom.data; //
/*
//对于单通道图像可以直接这样访问
for(unsigned int i=0; i<imbottom.cols*imbottom.rows; i++)
*datar++ = 0; // 可以
*/
//对于三通道图像,bgr就是一列
for(int j = 0;j<imbottom.cols*channle;j=j++)
{
for (int i=0,q =0;i < imbottom.rows;i++)
{
datar[i*imbottom.step+j] = 0; //
}
}
先列后行方法在上下图像拼接中会用到。平时因为习惯问题还是少用。
Mat矩阵初始化
//用一个一维数组来初始化矩阵
void InitMat(Mat& m,float* num)
{
for(int i=0;i<m.rows;i++)
for(int j=0;j<m.cols;j++)
m.at<float>(i,j)=*(num+i*m.rows+j);
}
主程序:
int main()
{
//Mat矩阵中的初始化,可以利用Mat::at()来完成
float m0[]={ 1,2,3,
6,5,4,
7,8,9 };
Mat M0(3,3,CV_32F);
InitMat(M0,m0);
}