Mat
Mat一般是二维向量,如果是灰度图,一般存放
<uchar>类型;如果是RGB彩色图,存放
<Vec3b>类型。
单通道灰度图数据格式:
多通道的图像中,每列并列存放通道数量的子列,如RGB三通道彩色图:
注意通道的顺序反转了:BGR。通常情况内存足够大的话图像的每一行是连续存放的,也就是在内存上图像的所有数据存放成一行,这中情况在访问时可以提供很大方便。可以用
isContinuous()函数来判断图像数组是否为连续的。
1.用指针访问元素
Mat imgs = imread("1.jpg", 1);
if (imgs.empty())
{
cout << "fail to read image" << endl;
return -1;
}
Mat img1 = imgs.clone();
int div = 64;
/* 方法1:用指针访问 */
//多通道访问法1
int rows = img1.rows;
int cols = img1.cols;
for (int i = 0; i < rows; i++)
{
//uchar* p = img1.ptr<uchar>(i); //获取第i行的首地址
for (int j = 0; j < cols; j++)
{
//在这里操作具体元素
uchar *p = img1.ptr<uchar>(i, j);
p[0] = p[0] / div*div + div / 2;
p[1] = p[1] / div*div + div / 2;
p[2] = p[2] / div*div + div / 2;
}
}
imshow("lean", img1);
//多通道访问法2
Mat img3 = imgs.clone();
int channels = img3.channels(); //获取通道数
int rows3 = img3.rows;
int cols3 = img3.cols* channels; //注意,是列数*通道数
for (int i = 0; i < rows3; i++)
{
uchar* p = img3.ptr<uchar>(i); //获取第i行的首地址
for (int j = 0; j < cols3; j++)
{
//在这里操作具体元素
p[j] = p[j] / div*div + div / 2;
p[j + 1] = p[j + 1] / div*div + div / 2;
p[j + 2] = p[j + 2] / div*div + div / 2;
}
}
imshow("lean3", img3);
//单通道图像
Mat img2 = imgs.clone();
cvtColor(img2, img2, COLOR_BGR2GRAY);
for (int i = 0; i < img2.rows; i++)
{
uchar* p = img2.ptr<uchar>(i); //获取第i行的首地址
for (int j = 0; j < img2.cols; j++)
{
//在这里操作具体元素
//p[j] = p[j] / div*div + div / 2;
p[j] = p[j];
}
}
imshow("lean2", img2);
waitKey(0);
2.用迭代器访问元素
Mat img = imread("lena.jpg",1); //载入灰度图
Mat img1 = img.clone();
int div = 64;
/* 方法2:用迭代器访问 */
/******************多通道的可以这么写***************/
Mat_<Vec3b>::iterator it = img1.begin<Vec3b>(); //获取起始迭代器
Mat_<Vec3b>::iterator it_end = img1.end<Vec3b>(); //获取结束迭代器
for (; it != it_end; it++)
{
//在这里分别访问每个通道的元素
(*it)[0] = (*it)[0] / div*div + div / 2;
(*it)[1] = (*it)[1] / div*div + div / 2;
(*it)[1] = (*it)[1] / div*div + div / 2;
}
imshow("lean", img1);
/******************单通道的可以这么写***************/
Mat img2;
cvtColor(img, img2, COLOR_RGB2GRAY); //转化为单通道灰度图
Mat_<uchar>::iterator it2 = img2.begin<uchar>(); //获取起始迭代器
Mat_<uchar>::iterator it_end2 = img2.end<uchar>(); //获取结束迭代器
for (; it2 != it_end2; it2++)
{
//在这里分别访问每个通道的元素
*it2 = *it2 / div*div + div / 2;
}
imshow("lena2", img2);
waitKey(0);
若要从图像的第二行开始,程序该怎么修改? 我们可以用
image.begin<cv::Vec3b>()+image.cols
初始化cv::Mat迭代器。 获得集合结束位置的方法也类似, 只是改用end方法。 但是, 用end方法得到的迭代器已经超出了集合范围, 因此必须在结束位置停止迭代过程。 结束的迭代器也能使用数学计算, 例如, 如果你想在最后一行前就结束迭代, 可使用
image.end<cv::Vec3b>()-image.cols
3.动态地址+at()访问元素
Mat img = imread("lena.jpg",1);
Mat img1 = img.clone();
int div = 64;
/* 方法3:用at访问 */
/****************访问多通道元素*********************/
int rows = img1.rows;
int cols = img1.cols;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
//在这里访问每个通道的元素,注意,成员函数at(int y,int x)的参数
img1.at<Vec3b>(i,j)[0] = img1.at<Vec3b>(i, j)[0] / div*div + div / 2;
img1.at<Vec3b>(i, j)[1] = img1.at<Vec3b>(i, j)[1] / div*div + div / 2;
img1.at<Vec3b>(i, j)[2] = img1.at<Vec3b>(i, j)[2] / div*div + div / 2;
}
}
imshow("lena", img1);
/****************访问单通道元素*********************/
Mat img2;
cvtColor(img, img2, COLOR_RGB2GRAY);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
//在这里访问每个通道的元素,注意,成员函数at(int y,int x)的参数
img2.at<uchar>(i, j) = img2.at<uchar>(i, j) / div*div + div / 2;
}
}
imshow("lena2", img2);
waitKey(0);
Iplimage
/*访问多通道元素*/
IplImage* img = cvCreateImage(cvSize(640, 480), IPL_DEPTH_8U, 3);
uchar* data = (uchar *)img->imageData;
int step = img->widthStep / sizeof(uchar);
int channels = img->nChannels;
uchar b, g, r;
for (int i = 0; i < img->height; i++)
{
for (int j = 0; j < img->width; j++)
{
//获得元素的值
b = data[i*step + j*channels + 0];
g = data[i*step + j*channels + 1];
r = data[i*step + j*channels + 2];
//修改元素的值
data[i*step + j*channels + 0] = 255;
}
}
cvShowImage("img", img);
/*访问单通道元素*/
IplImage* img2 = cvCreateImage(cvSize(640, 480), IPL_DEPTH_8U, 1);
uchar* data2 = (uchar *)img2->imageData;
int step2 = img2->widthStep / sizeof(uchar);
uchar v;
for (int i = 0; i < img2->height; i++)
{
for (int j = 0; j < img2->width; j++)
{
//获得元素的值
v = data2[i*step2 + j];
//修改元素的值
data2[i*step2 + j] = 255;
}
}
cvShowImage("img2", img2);
waitKey(0);
参考:
1.https://blog.csdn.net/xiaowei_cqu/article/details/7557063
2.http://www.cnblogs.com/skyfsm/p/7082914.html
3.https://blog.csdn.net/xiaowei_cqu/article/details/7557063