image.at
在OpenCV中,使用Mat对象表示图像数据,在使用at
方法时,需要确保使用正确的数据类型(如uchar或Vec3b),这取决于图像的通道数和数据深度。
单通道图像
对于单通道图像(如灰度图像),每个像素值由一个字节表示,范围是0到255。可以使用uchar
类型来访问和修改像素值:
// 访问位于(y, x)的像素值
uchar pixelValue = image.at<uchar>(y, x);
// 修改位于(y, x)的像素值
image.at<uchar>(y, x) = newValue;
多通道图像
对于多通道图像(如RGB彩色图像),每个像素由多个值组成(在RGB图像中是3个值,分别对应红、绿、蓝通道)。要访问这种图像的像素,可以使用Vec3b类型,这是一个包含3个uchar
值的向量,对应于一个像素的所有通道:
// 访问位于(y, x)的像素的所有通道
Vec3b pixelValue = image.at<Vec3b>(y, x);
// 访问特定通道(例如蓝色通道)
uchar blueValue = pixelValue[0];
// 修改位于(y, x)的像素的红色通道值
image.at<Vec3b>(y, x)[2] = newValue; // 对于RGB图像,索引2通常对应红色通道
应用示例1-没有用到指针
quick_opencv.h
#include<opencv2\opencv.hpp>
using namespace cv;
class QuickDemo{
public:
void pixel_visit_demo_nopointer(Mat &image);//图像像素读写
};
QuickDemo.cpp
#include<quick_opencv.h>
//图像像素读写
void QuickDemo::pixel_visit_demo_nopointer(Mat &image) {
int w = image.cols;
int h = image.rows;
int dims = image.channels();
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
if (dims == 1) {
int pv = image.at<uchar>(row, col);
image.at<uchar>(row, col) = 255 - pv;
}
if (dims == 3) {
Vec3b bgr = image.at<Vec3b>(row, col);
image.at<Vec3b>(row, col)[0] = 255 - bgr[0];
image.at<Vec3b>(row, col)[1] = 255 - bgr[1];
image.at<Vec3b>(row, col)[2] = 255 - bgr[2];
}
}
}
imshow("像素读写演示结果", image);
}
主函数main.cpp
#include<opencv2/opencv.hpp>
#include<quick_opencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
//读取并显示图像,如果imread返回的Mat对象(src)是空的,打印错误消息并退出程序。
Mat src = imread("C:/Users/Desktop/opencv-0/win.png");//B G R 蓝绿红
if (src.empty())
{
printf("could not find the image...\n");
return -1;
}
namedWindow("输入窗口", WINDOW_FREERATIO);//创建一个可以自由调整比例的窗口
imshow("输入窗口", src);
//创建QuickDemo类的实例qd
QuickDemo qd;
//像素读写
qd.pixel_visit_demo_nopointer(src);
//等待用户输入并清理资源
waitKey(0);
destroyAllWindows();
return 0;
}
可以利用image.ptr结合指针对上述代码进行优化,优化结果会简洁代码并且提高运行速度。
image.ptr
在OpenCV中,cv::Mat类的ptr方法用于获取指向图像数据某一行的指针。通过这个指针,可以直接访问和修改图像数据。这种方法比使用at方法访问单个像素值更快,特别是在需要遍历图像所有像素或进行大量像素级操作时。但是,使用指针访问数据需要更加小心,以避免越界访问和其他内存错误。
uchar* ptr = image.ptr<uchar>(y);
y
是图像中行的索引(行号)。
<uchar>
指定了数据的类型。对于单通道的灰度图像,可以使用uchar
(无符号字符)。对于多通道图像,可能需要使用不同的类型,例如Vec3b
对于一个3通道的BGR图像。
获取了指针后,可以通过指针运算来访问或修改像素值。例如,修改第y行第x列像素的值:
ptr[x] = newValue; // 对于灰度图像
Vec3b* ptr = image.ptr<Vec3b>(y);// 对于多通道图像
ptr[x] = Vec3b(blue, green, red); // 设置像素值
或者直接访问和修改特定通道的值:
ptr[x][0] = newBlue; // 修改蓝色通道的值
ptr[x][1] = newGreen; // 修改绿色通道的值
ptr[x][2] = newRed; // 修改红色通道的值
应用示例2-用到指针
quick_opencv.h
#include<opencv2\opencv.hpp>
using namespace cv;
class QuickDemo{
public:
void pixel_visit_demo_usepointer(Mat &image);//图像像素读写
};
QuickDemo.cpp
#include<quick_opencv.h>
//图像像素读写
void QuickDemo::pixel_visit_demo_usepointer(Mat &image) {
int w = image.cols;
int h = image.rows;
int dims = image.channels();
for (int row = 0; row < h; row++) {
uchar* current_row= image.ptr<uchar>(row);
for (int col = 0; col < w; col++) {
if (dims == 1) {
int pv = *current_row;
*current_row++ = 255 - *current_row;
}
if (dims == 3) {
*current_row++ = 255 - *current_row;
*current_row++ = 255 - *current_row;
*current_row++ = 255 - *current_row;
}
}
}
imshow("像素读写演示结果", image);
}
主函数main.cpp
#include<opencv2/opencv.hpp>
#include<quick_opencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
//读取并显示图像,如果imread返回的Mat对象(src)是空的,打印错误消息并退出程序。
Mat src = imread("C:/Users/Desktop/opencv-0/win.png");//B G R 蓝绿红
if (src.empty())
{
printf("could not find the image...\n");
return -1;
}
namedWindow("输入窗口", WINDOW_FREERATIO);//创建一个可以自由调整比例的窗口
imshow("输入窗口", src);
//创建QuickDemo类的实例qd
QuickDemo qd;
//像素读写
qd.pixel_visit_demo_usepointer(src);
//等待用户输入并清理资源
waitKey(0);
destroyAllWindows();
return 0;
}