像素操作
本文了解单通道图像与三通道图像的像素操作,包括指针访问和非指针访问。
指针访问
单通道指针访问
定义一个uchar指针指向第row行元素,将第row行元素视为数组,按索引访问。
height = gray_src2.rows;
width = gray_src2.cols;
for (int row = 0; row < height; row++)
{
uchar* current = gray_src2.ptr<uchar>(row);
for (int col = 0; col < width; col++)
{
int gray = current[col];
current[col] = saturate_cast < uchar>(255 - gray);
}
}
三通道指针访问
三通道指针访问需要注意的是当uchar指针指向row行时,row行的数组长度应该是cols x channels 即列数 × 通道数(看<LearnOpenCV(2)>)。这里的访问也是按索引访问,只不过是内循环的范围定义不同。
height = color_src2.rows;
width = color_src2.cols*color_src2.channels();//内循环范围定义不同
for (int row = 0; row < height; row++)
{
uchar* current = color_src2.ptr<uchar>(row);
for (int col = 0; col < width; col++)
{
current[col] = 255 - current[col];
}
}
非指针
使用Mat.at<type>(row,col)访问。
单通道非指针访问
int height = gray_src1.rows;
int width = gray_src2.cols;
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
int gray = gray_src1.at<uchar>(row, col);
gray_src1.at<uchar>(row, col) = 255 - gray;//单通道的数据类型是uchar
}
}
三通道非指针访问
height = color_src1.rows;
width = color_src1.cols;
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
int b = color_src1.at<Vec3b>(row, col)[0];//Vec3b对应的是bgr的uchar类型 还有Vec3f 是对应float类型
int g = color_src1.at<Vec3b>(row, col)[1];//可以看出3通道的访问中,非指针是要简洁一些,另外指针访问也不怎么安全
int r = color_src1.at<Vec3b>(row, col)[2];
color_src1.at<Vec3b>(row, col)[0] = 255 - b;
color_src1.at<Vec3b>(row, col)[1] = 255 - g;
color_src1.at<Vec3b>(row, col)[2] = 255 - r;
}
}
另外的函数
这个与上面的取反操作相同
// 取反函数 bitwise_not
Mat bitwise = src.clone();
bitwise_not(src, bitwise);
代码
//通过单通道与三通道的图像反转了解图像像素的取值与赋值,
#include<opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main() {
Mat src, gray_src1,gray_src2,color_src1,color_src2;
src = imread("girl4.jpg");
// 单通道像素操作 //
cvtColor(src, gray_src1, COLOR_BGR2GRAY);
gray_src2 = gray_src1.clone();
//单通道非指针访问
int height = gray_src1.rows;
int width = gray_src2.cols;
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
int gray = gray_src1.at<uchar>(row, col);
gray_src1.at<uchar>(row, col) = 255 - gray;
}
}
//单通道指针访问
height = gray_src2.rows;
width = gray_src2.cols;
for (int row = 0; row < height; row++)
{
uchar* current = gray_src2.ptr<uchar>(row);
for (int col = 0; col < width; col++)
{
int gray = current[col];
current[col] = saturate_cast < uchar>(255 - gray);
}
}
//三通道像素操作//
color_src1 = src.clone();
color_src2 = src.clone();
//三通道非指针访问
height = color_src1.rows;
width = color_src1.cols;
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
int b = color_src1.at<Vec3b>(row, col)[0];//Vec3b对应的是bgr的uchar类型 还有Vec3f 是对应float类型
int g = color_src1.at<Vec3b>(row, col)[1];
int r = color_src1.at<Vec3b>(row, col)[2];
color_src1.at<Vec3b>(row, col)[0] = 255 - b;
color_src1.at<Vec3b>(row, col)[1] = 255 - g;
color_src1.at<Vec3b>(row, col)[2] = 255 - r;
}
}
//三通道指针访问
height = color_src2.rows;
width = color_src2.cols*color_src2.channels();//内循环范围定义不同
for (int row = 0; row < height; row++)
{
uchar* current = color_src2.ptr<uchar>(row);
for (int col = 0; col < width; col++)
{
current[col] = 255 - current[col];
}
}
gray_src1, gray_src2, color_src1, color_src2;
imshow("src", src);
imshow("gray_src1", gray_src1);
imshow("gray_src2", gray_src2);
imshow("color_src1", color_src1);
imshow("color_src2", color_src2);
// 取反函数 bitwise_not//
Mat bitwise = src.clone();
bitwise_not(src, bitwise);
imshow("bitwise", bitwise);
waitKey(0);
return 0;
}
本文含有隐藏内容,请 开通VIP 后查看