一、知识点
1、在OpenCV中,一切图像皆Mat。
2、对图像像素的读写操作,就是对Mat元素的遍历与访问。
3、对Mat使用数组方式遍历与访问。
(1)、函数声明:
template<typename _Tp> inline
_Tp & Mat::at(int i0, int i1)
(2)、参数说明:
i0: 行索引。 从0开始,应小于image.rows。
i1: 列索引。 从0开始,应小于image.cols。
_Tp: 函数模板的类型参数,表示一个像素的数据类型。
(3)、返回i0行i1列的元素引用,返回值是_Tp &,说明对返回值可读可写,可写会影响原始数据。
(4)、灰度图像的遍历与访问举例:
for (int row = 0; row < h; row++)
{
for (int col = 0; col < w; col++)
{
if (c == 1)
{
//读
int pv = image.at<uchar>(row, col);
//写
image.at<uchar>(row, col) = 255 - pv;
}
}
}
(5)、彩色图像的遍历与访问举例:
for (int row = 0; row < h; row++)
{
for (int col = 0; col < w; col++)
{
if (c == 3)
{
//读
cv::Vec3b bgr = image.at<cv::Vec3b>(row, col);
//写
image.at<cv::Vec3b>(row, col)[0] = 255 - bgr[0];
image.at<cv::Vec3b>(row, col)[1] = 255 - bgr[1];
image.at<cv::Vec3b>(row, col)[2] = 255 - bgr[2];
}
}
}
4、对Mat使用指针方式遍历与访问。
(1)、函数声明:
template<typename _Tp> inline
_Tp * Mat::ptr(int y)
(2)、参数说明:
y: 行索引。 从0开始,应小于image.rows。
_Tp: 函数模板的类型参数,表示返回的指针指向的数据类型,通常是一个像素的数据类型。
(3)、返回y行首个_Tp类型数据的地址,返回值是_Tp *,说明对返回值可读可写,可写会影响原始数据。
(4)、灰度图像的遍历与访问举例:
for (int row = 0; row < h; row++)
{
//返回row行首个元素的地址
uchar * cur_row = image.ptr<uchar>(row);
for (int col = 0; col < w; col++)
{
if (c == 1)
{
int pv = *cur_row;
*cur_row = 255 - pv;
cur_row++;
}
}
}
(5)、彩色图像的遍历与访问举例:
for (int row = 0; row < h; row++)
{
//返回row行首个元素的首个字节地址
uchar * cur_row = image.ptr<uchar>(row);
for (int col = 0; col < w; col++)
{
if (c == 3)
{
int pv1 = *cur_row;
*cur_row = 255 - pv1;
cur_row++;
int pv2 = *cur_row;
*cur_row = 255 - pv2;
cur_row++;
int pv3 = *cur_row;
*cur_row = 255 - pv3;
cur_row++;
}
}
}
5、对Mat使用指针方式遍历与访问2。
(1)、函数声明:
template<typename _Tp> inline
_Tp * Mat::ptr(int i0, int i1)
(2)、参数说明:
i0: 行索引。 从0开始,应小于image.rows。
i1: 列索引。 从0开始,应小于image.cols。
_Tp: 函数模板的类型参数,表示一个像素的数据类型。
(3)、返回i0行i1列的元素地址,返回值是_Tp *,说明对返回值可读可写,可写会影响原始数据。
(4)、灰度图像的遍历与访问举例:
for (int row = 0; row < h; row++)
{
for (int col = 0; col < w; col++)
{
if (c == 1)
{
uchar * pv = image.ptr<uchar>(row, col);
*pv = 255 - *pv;
}
}
}
(5)、彩色图像的遍历与访问举例:
for (int row = 0; row < h; row++)
{
for (int col = 0; col < w; col++)
{
if (c == 3)
{
cv::Vec3b * pv = image.ptr<cv::Vec3b>(row, col);
*pv = cv::Vec3b(255 - (*pv)[0], 255 - (*pv)[1], 255 - (*pv)[2]);
}
}
}
二、示例代码:
#include <iostream>
#include <opencv2/opencv.hpp>
void visit_by_array(cv::Mat & image)
{
int w = image.cols;
int h = image.rows;
int c = image.channels();
for (int row = 0; row < h; row++)
{
for (int col = 0; col < w; col++)
{
//灰度图像
if (c == 1)
{
//读
int pv = image.at<uchar>(row, col);
//写
image.at<uchar>(row, col) = 255 - pv;
}
//彩色图像
else if (c == 3)
{
//读
cv::Vec3b bgr = image.at<cv::Vec3b>(row, col);
//写
image.at<cv::Vec3b>(row, col)[0] = 255 - bgr[0];
image.at<cv::Vec3b>(row, col)[1] = 255 - bgr[1];
image.at<cv::Vec3b>(row, col)[2] = 255 - bgr[2];
}
}
}
}
void visit_by_pointer(cv::Mat & image)
{
int w = image.cols;
int h = image.rows;
int c = image.channels();
for (int row = 0; row < h; row++)
{
uchar * cur_row = image.ptr<uchar>(row);
for (int col = 0; col < w; col++)
{
//灰度图像
if (c == 1)
{
//读
int pv = *cur_row;
//写
*cur_row = 255 - pv;
cur_row++;
}
//彩色图像
else if (c == 3)
{
//读
int pv1 = *cur_row;
//写
*cur_row = 255 - pv1;
cur_row++;
//读
int pv2 = *cur_row;
//写
*cur_row = 255 - pv2;
cur_row++;
//读
int pv3 = *cur_row;
//写
*cur_row = 255 - pv3;
cur_row++;
}
}
}
}
void visit_by_pointer2(cv::Mat & image)
{
int w = image.cols;
int h = image.rows;
int c = image.channels();
for (int row = 0; row < h; row++)
{
for (int col = 0; col < w; col++)
{
if (c == 1)
{
uchar * pv = image.ptr<uchar>(row, col);
*pv = 255 - *pv;
}
else if (c == 3)
{
cv::Vec3b * pv = image.ptr<cv::Vec3b>(row, col);
*pv = cv::Vec3b(255 - (*pv)[0], 255 - (*pv)[1], 255 - (*pv)[2]);
}
}
}
}
int main()
{
//数组方式访问灰度图像
cv::Mat m1 = cv::imread("../images/1.png", cv::IMREAD_GRAYSCALE);
if (m1.empty())
{
std::cout << "load m1 error..." << std::endl;
return -1;
}
cv::imshow("数组方式访问前 m1", m1);
visit_by_array(m1);
cv::imshow("数组方式访问后 m1", m1);
//数组方式访问彩色图像
cv::Mat m2 = cv::imread("../images/1.png", cv::IMREAD_COLOR_BGR);
if (m2.empty())
{
std::cout << "load m2 error..." << std::endl;
return -1;
}
cv::imshow("数组方式访问前 m2", m2);
visit_by_array(m2);
cv::imshow("数组方式访问后 m2", m2);
//指针方式1访问灰度图像
cv::Mat m3 = cv::imread("../images/2.png", cv::IMREAD_GRAYSCALE);
if (m3.empty())
{
std::cout << "load m3 error..." << std::endl;
return -1;
}
cv::imshow("指针方式1访问前 m3", m3);
visit_by_pointer(m3);
cv::imshow("指针方式1访问后 m3", m3);
//指针方式1访问彩色图像
cv::Mat m4 = cv::imread("../images/2.png", cv::IMREAD_COLOR_BGR);
if (m4.empty())
{
std::cout << "load m4 error..." << std::endl;
return -1;
}
cv::imshow("指针方式1访问前 m4", m4);
visit_by_pointer(m4);
cv::imshow("指针方式1访问后 m4", m4);
//指针方式2访问灰度图像
cv::Mat m5 = cv::imread("../images/3.png", cv::IMREAD_GRAYSCALE);
if (m5.empty())
{
std::cout << "load m5 error..." << std::endl;
return -1;
}
cv::imshow("指针方式2访问前 m5", m5);
visit_by_pointer2(m5);
cv::imshow("指针方式2访问后 m5", m5);
//指针方式2访问彩色图像
cv::Mat m6 = cv::imread("../images/3.png", cv::IMREAD_COLOR_BGR);
if (m6.empty())
{
std::cout << "load m6 error..." << std::endl;
return -1;
}
cv::imshow("指针方式2访问前 m6", m6);
visit_by_pointer2(m6);
cv::imshow("指针方式2访问后 m6", m6);
cv::waitKey(0);
return 0;
}