04 图像像素的读写操作
opencv知识点:
- 获取/改变图像的某个像素 - Mat::at
- 图像像素 - 数组遍历
- 图像像素 - 指针遍历
本课所解决的问题:
-
如何获取/改变图像的某个像素?
-
如何利用数组遍历图像像素?
-
如何利用指针遍历图像像素?
1.获取某个像素
我们获取/改变图像的某个像素,要用到Mat::at< >( )
image.at<uchar>(row, col);
/*
获取指定位置的像素值
这里只是at方法的一种演示,一共6种传参方式,具体可查看文档
说明:
at<>中必须标明矩阵的数据类型,一般图像是uchar(8位无符号整型)类型
这里我们采用二维度坐标的方式传参
*/
2.图像像素的数组遍历
为了演示图像像素遍历,我们在遍历的同时进行一个反色处理
程序
main.cpp
#include "opencv2/opencv.hpp"
#include "quickopencv.h"
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
Mat src = imread("C:/Users/LZQ/Desktop/lena.png"); // B, G, R
if (src.empty()) {
printf("could not load image....\n");
return -1;
}
imshow("输入窗口", src);
QuickDemo qd;
qd.pixel_visit_demo(src); //04 <-------------修改的代码(其余不变)
waitKey(0);
destroyAllWindows();
return 0;
}
quickdemo.cpp
#include "quickopencv.h"
#include <opencv2/dnn.hpp>
using namespace cv;
using namespace std;
/*****************************************************************/
void QuickDemo::pixel_visit_demo(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); //pv当前的图像 uchar字节类型
image.at<uchar>(row, col) = 255 - pv; //255-pv 反色
}
/********************************彩色图像*********************************/
if (dims == 3) { // 彩色图像
Vec3b bgr = image.at<Vec3b>(row, col); //(行,列) 可以将Vec3b bgr看为一个数组
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);
}
quickopencv.h
#pragma once
#include <opencv2/opencv.hpp>
using namespace cv;
class QuickDemo { //快速的演示文件 class类
public:
void pixel_visit_demo(Mat& image); //04 <---------------修改的程序
};
案例讲解
//函数定义
void pixel_visit_demo(Mat& image);
//函数实现
void QuickDemo::pixel_visit_demo(Mat& image) {
int h = image.rows;
int w = image.cols;
int dims = image.channels();
/*
灰度图像——通道为1
彩色图像——通道为3
*/
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);
}
如上,我们可以看到,不同通道数的处理方式是不同的
- 对于单通道图像的使用方法:
int pv = image.at<uchar>(row, col);
image.at<uchar>(row, col) = 255 - pv;//对访问的像素进行反色
- 对于RGB三通道图像的使用方法:
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];//对访问的像素进行反色
这里我们解释一下Vec3b是什么
Vec3b可以看作是vector<uchar, 3>。
简单而言就是一个uchar类型的,长度为3的vector向量。
根据通道数的不同,数据类型的不同,就有了很多变化,下面是常用的三种
8U 类型的 RGB 彩色图像可以使用 < Vec3b >
3 通道 float 类型的矩阵可以使用 < Vec3f >
3 通道 int 类型的矩阵可以使用 < Vec3i >
3.图像像素的指针遍历
另一种更快的方式就是指针遍历
通过设置每一行的首地址指针,我们可以实现更快的遍历
quickdemo.cpp
(主函数和头文件保持不变,改变 quickdemo
的 for
循环部分)
void QuickDemo::pixel_visit_demo(Mat& image) {
int w = image.cols; //宽度
int h = image.rows; //高度
int dims = image.channels(); //通道数
以上的部分保持不变。
下面的部分是demo的修改重点。
for(int row = 0; row < h; row++) {
uchar* curren_row = image.ptr<uchar>(row);
//相当于每次获取行的首地址
for (int col = 0; col < w; col++) {
//灰度图像
if (dims == 1) {
*curren_row++ = 255 - *curren_row;
}
//彩色图像
if (dims == 3) {
*curren_row++ = 255 - *curren_row;
*curren_row++ = 255 - *curren_row;
*curren_row++ = 255 - *curren_row;
}
}
}
取完每行的首地址之后
- 对于单通道图像的使用方法:
*curren_row++ = 255 - pv;
- 对于RGB三通道图像的使用方法:
//与数组遍历相比,3通道时执行三次就可以
*curren_row++ = 255 - *curren_row;
*curren_row++ = 255 - *curren_row;
*curren_row++ = 255 - *curren_row;
标签:04,读写操作,int,image,像素,255,col,row
From: https://www.cnblogs.com/L707/p/17045593.html