目录
概述
访问图像像素值是图像处理的基本操作。OpenCV提供了很多访问方式,比较常用的三种方式:
(1) 通过指针访问 (逐通道)
(2) 通过迭代器访问 (逐像素)
(3) 动态地址计算,通过at()函数实现(逐像素)
方法比较:
(1)用指针访问像素,速度最快;但在彩色图像处理中,如果要单独对某一个颜色分量处理,则需要通过数学公式计算,不是很直观;
(2)推荐用通过迭代器访问像素,速度快,而且提取BGR某一颜色分量很方便。
(3)at()函数适用于随机访问某个具体的像素点(已知该像素点行、列坐标),不建议用at()函数遍历整个图。
1、指针访问
指针逐通道访问
//方式1:指针操作(逐通道访问)
void Handle_Ptr()
{
uchar* p;
//彩图
for (int i = 0; i < src.rows; i++)
{
p = src.ptr<uchar>(i); //指向每一行首地址
for (int j = 0; j < src.cols * src.channels(); j++)
{
p[j] = 255 - p[j]; //反差处理
}
}
//灰度图
for (int i = 0; i < src_gray.rows; i++)
{
p = src_gray.ptr<uchar>(i); //指向每一行首地址
for (int j = 0; j < src_gray.cols; j++)
{
p[j] = 255 - p[j]; //反差处理
}
}
}
2、迭代器访问
迭代器逐像素访问
//方式2:迭代器操作(逐像素访问)
void Iterator()
{
//彩色图
//获取迭代器
Mat_<Vec3b>::iterator it1 = src.begin<Vec3b>(); //初始位置的迭代器
Mat_<Vec3b>::iterator itend1 = src.end<Vec3b>(); //终止位置的迭代器
//彩色图逐像素操作
for ( ; it1 != itend1; it1++) //逐像素
{
(*it1)[0] = 255 - (*it1)[0]; //逐通道
(*it1)[1] = 255 - (*it1)[1]; //逐通道
(*it1)[2] = 255 - (*it1)[2]; //逐通道
}
//灰度图
//获取迭代器
Mat_<uchar>::iterator it2 = src_gray.begin<uchar>(); //初始位置的迭代器
Mat_<uchar>::iterator itend2 = src_gray.end<uchar>(); //终止位置的迭代器
//灰度图逐像素操作
for (; it2 != itend2; it2++)
{
(*it2) = 255 - (*it2);
}
}
3、at()函数访问
at()函数逐像素访问
//方式3:at()函数操作(逐像素访问)
void At()
{
//彩色图
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++) //逐像素
{
src.at<Vec3b>(i, j)[0] = 255 - (int)src.at<Vec3b>(i, j)[0]; //逐通道
src.at<Vec3b>(i, j)[1] = 255 - (int)src.at<Vec3b>(i, j)[1]; //逐通道
src.at<Vec3b>(i, j)[2] = 255 - (int)src.at<Vec3b>(i, j)[2]; //逐通道
}
}
//灰度图
for (int i = 0; i < src_gray.rows; i++)
{
for (int j = 0; j < src_gray.cols; j++)
{
src_gray.at<uchar>(i, j) = 255 - (int)src_gray.at<uchar>(i, j);
}
}
}
总代码
//图像像素的三种访问方式(指针、迭代器、at()函数)
//指针:逐通道访问 迭代器:逐像素访问 at()函数:逐通道访问
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
Mat src, src_gray;
//图像初始化
void Image_Init()
{
src = imread("Resource/test.jpg"); //读取
if (src.empty())
{
printf("could not load the picture...");
}
cvtColor(src, src_gray, COLOR_RGB2GRAY);
}
//方式1:指针操作(逐通道访问)
void Handle_Ptr()
{
uchar* p;
//彩图
for (int i = 0; i < src.rows; i++)
{
p = src.ptr<uchar>(i); //指向每一行首地址
for (int j = 0; j < src.cols * src.channels(); j++)
{
p[j] = 255 - p[j]; //反差处理(逐通道)
}
}
//灰度图
for (int i = 0; i < src_gray.rows; i++)
{
p = src_gray.ptr<uchar>(i); //指向每一行首地址
for (int j = 0; j < src_gray.cols; j++)
{
p[j] = 255 - p[j]; //反差处理(逐通道)
}
}
}
//方式2:迭代器操作(逐像素访问)
void Iterator()
{
//彩色图
//获取迭代器
Mat_<Vec3b>::iterator it1 = src.begin<Vec3b>(); //初始位置的迭代器
Mat_<Vec3b>::iterator itend1 = src.end<Vec3b>(); //终止位置的迭代器
//彩色图逐像素操作
for ( ; it1 != itend1; it1++) //逐像素
{
(*it1)[0] = 255 - (*it1)[0]; //逐通道
(*it1)[1] = 255 - (*it1)[1]; //逐通道
(*it1)[2] = 255 - (*it1)[2]; //逐通道
}
//灰度图
//获取迭代器
Mat_<uchar>::iterator it2 = src_gray.begin<uchar>(); //初始位置的迭代器
Mat_<uchar>::iterator itend2 = src_gray.end<uchar>(); //终止位置的迭代器
//灰度图逐像素操作
for (; it2 != itend2; it2++)
{
(*it2) = 255 - (*it2);
}
}
//方式3:at()函数操作(逐像素访问)
void At()
{
//彩色图
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++) //逐像素
{
src.at<Vec3b>(i, j)[0] = 255 - (int)src.at<Vec3b>(i, j)[0]; //逐通道
src.at<Vec3b>(i, j)[1] = 255 - (int)src.at<Vec3b>(i, j)[1]; //逐通道
src.at<Vec3b>(i, j)[2] = 255 - (int)src.at<Vec3b>(i, j)[2]; //逐通道
}
}
//灰度图
for (int i = 0; i < src_gray.rows; i++)
{
for (int j = 0; j < src_gray.cols; j++)
{
src_gray.at<uchar>(i, j) = 255 - (int)src_gray.at<uchar>(i, j);
}
}
}
//显示图像
void Image_Show()
{
imshow("彩图", src);
imshow("灰度图", src_gray);
}
int main()
{
Image_Init(); //图像初始化
//Handle_Ptr(); //1、指针操作
//Iterator(); //2、迭代器操作
At(); //3、at()函数操作
Image_Show(); //显示图像
waitKey(0);
return 0;
}
效果
参考资料
https://blog.youkuaiyun.com/zhu_hongji/article/details/81333200