opencv图像像素读写操作
常用类型介绍
-
uchar类型
typedef unsigned uint; typedef signed char schar; typedef unsigned char uchar; typedef unsigned short ushort;
-
Vec系列
Vec+数字+字母: C++STL vector容器类似
-
数字: Vec 的长度
-
字母: 类型
-
b: uchar
-
s:short
-
w: ushort
-
i: int
-
f:float
-
d:double
-
-
typedef Vec<uchar, 2> Vec2b; typedef Vec<uchar, 3> Vec3b; typedef Vec<uchar, 4> Vec4b; typedef Vec<short, 2> Vec2s; typedef Vec<short, 3> Vec3s; typedef Vec<short, 4> Vec4s; typedef Vec<ushort, 2> Vec2w; typedef Vec<ushort, 3> Vec3w; typedef Vec<ushort, 4> Vec4w; typedef Vec<int, 2> Vec2i; typedef Vec<int, 3> Vec3i; typedef Vec<int, 4> Vec4i; typedef Vec<int, 6> Vec6i; typedef Vec<int, 8> Vec8i; typedef Vec<float, 2> Vec2f; typedef Vec<float, 3> Vec3f; typedef Vec<float, 4> Vec4f; typedef Vec<float, 6> Vec6f; typedef Vec<double, 2> Vec2d; typedef Vec<double, 3> Vec3d; typedef Vec<double, 4> Vec4d; typedef Vec<double, 6> Vec6d;
图像的像素读写
数组方式读写
注意:①at方法的使用,是Mat中的模板函数,需要实例化,<uchar>(unsigned char---->8个位都是用来存储相关的像素信息),然后传入x,y坐标即可。
其返回值是引用类型,所以才有了下面的负片处理
②Mat中channels()方法获取图片的通道数,是一维的(黑白)还是三维的(rgb)
③注意dims=3的情况,如何接收pixel值的?--->Vec3b类型的容器接收。
int dims = img.channels(); //得到图片通道数
for (int i = 0; i < img.rows; i++)
{
for (int j = 0; j < img.cols; j++)
{
if (dims == 1)
{
//单通道图像像素点获取
int pixel = img.at<uchar>(i, j);
img.at<uchar>(i, j) = 255 - pixel; //负片处理
}
if (dims == 3)
{
//三通道图像像素点获取
Vec3b bgr = img.at<Vec3b>(i, j);
//负片处理
img.at<Vec3b>(i, j)[0] = 255 - bgr[0];
img.at<Vec3b>(i, j)[1] = 255 - bgr[1];
img.at<Vec3b>(i, j)[2] = 255 - bgr[2];
}
}
}
指针方式读写
注意:Mat中的成员函数ptr用uchar实例化之后,传入要获取的行数,即可。
//二维数组-->一级指针访问二维数组方式
int dims = img.channels();
for (int i = 0; i < img.rows; i++)
{
//Mat中有一个ptr成员函数,获取当前i行的指针
uchar* current_row = img.ptr<uchar>(i);
for (int j = 0; j < img.cols; j++)
{
if (dims == 1)
{
int pixel = *current_row; //current_row[j];
*current_row++ = 255 - pixel; //做一个横向移动
}
if (dims == 3)
{
Vec3b bgr = img.at<Vec3b>(i, j);
*current_row++ = 255 - *current_row;
*current_row++ = 255 - *current_row;
*current_row++ = 255 - *current_row;
}
}
}
注意:*p++中*和++的运算优先级相同,自右向左的运算顺序,
所以先++(指针的指向先发生改变)
完整案例
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
class ImgVisitPixel
{
public:
ImgVisitPixel(int type = IMREAD_UNCHANGED) :img(imread("mm.jpg",type)) {}
void Show(string wName)
{
imshow(wName, img);
moveWindow(wName, 600, 300);
waitKey(0);
}
void Visit_By_Array();
void Visit_By_Point();
protected:
Mat img;
};
void ImgVisitPixel::Visit_By_Array()
{
int dims = img.channels(); //得到图片通道数
for (int i = 0; i < img.rows; i++)
{
for (int j = 0; j < img.cols; j++)
{
if (dims == 1)
{
//单通道图像像素点获取
int pixel = img.at<uchar>(i, j);
img.at<uchar>(i, j) = 255 - pixel; //负片处理
}
if (dims == 3)
{
//三通道图像像素点获取
Vec3b bgr = img.at<Vec3b>(i, j);
//负片处理
img.at<Vec3b>(i, j)[0] = 255 - bgr[0];
img.at<Vec3b>(i, j)[1] = 255 - bgr[1];
img.at<Vec3b>(i, j)[2] = 255 - bgr[2];
}
}
}
}
void ImgVisitPixel::Visit_By_Point()
{
int dims = img.channels();
for (int i = 0; i < img.rows; i++)
{
//Mat中有一个ptr成员函数,获取当前i行的指针
uchar* current_row = img.ptr<uchar>(i);
for (int j = 0; j < img.cols; j++)
{
if (dims == 1)
{
int pixel = *current_row; //current_row[j];
*current_row++ = 255 - pixel; //做一个横向移动
}
if (dims == 3)
{
Vec3b bgr = img.at<Vec3b>(i, j);
*current_row++ = 255 - *current_row;
*current_row++ = 255 - *current_row;
*current_row++ = 255 - *current_row;
}
}
}
}
int main()
{
ImgVisitPixel* pImg = new ImgVisitPixel;
pImg->Show("原图");
pImg->Visit_By_Array();
pImg->Show("第一次负片操作");
pImg->Visit_By_Point();
pImg->Show("第二次负片操作");
return 0;
}
像素读写注意点
在读取到像素点的时候,做一些算数运算,一定要注意颜色范围问题,小心溢出,针对溢出,opencv提供一个转换防止溢出
saturate_cast<要转换的类型>(要转换的数据)
-
小于0 等于0
-
大于255 直接等于255
img.at<Vec3b>(i, j)[0] =saturate_cast<uchar>(bgr[0]+100);
img.at<Vec3b>(i, j)[1] = saturate_cast<uchar>(bgr[1] + 100);
img.at<Vec3b>(i, j)[2] = saturate_cast<uchar>(bgr[2] + 100);
opencv图像像素运算
注意:参与算术运算图像的数据类型、通道数目、大小必须相同!!!
算术运算
加法:add
void add(InputArray src1, InputArray src2, OutputArray dst,InputArray mask = noArray(), int dtype = -1);
/*******************************************************************
* src1: 输入图1
* src2: 输入图2
* dst: 输出图
* mask: 遮罩像素 可有可无
* dtype: 输出图深度 可有可无
*********************************************************************/
减法:subtract
void subtract(InputArray src1,InputArray src2,OutputArray dst,InputArray mask = noArray(),int dtype = -1);
/*******************************************************************
* src1: 输入图1
* src2: 输入图2
* dst: 输出图
* mask: 遮罩像素 可有可无
* dtype: 输出图深度 可有可无
*********************************************************************/
乘法:multiply
void multiply(InputArray src1, InputArray src2,OutputArray dst, double scale = 1, int dtype = -1);
/*******************************************************************
* src1: 输入图1
* src2: 输入图2
* dst: 输出图
* scale: 缩放因子,即在src1*src2的基础上再乘scale
* dtype: 输出图深度 可有可无
*********************************************************************/
除法:divide
void divide(InputArray src1, InputArray src2, OutputArray dst,double scale = 1, int dtype = -1);
/*******************************************************************
* src1: 输入图1
* src2: 输入图2
* dst: 输出图
* scale: 缩放因子,即在src1*src2的基础上再乘scale
* dtype: 输出图深度 可有可无
*********************************************************************/
混合运算:addWeighted
dst = α · img1 + β · img2 + γ
void addWeighted(InputArray s1,double a,InputArray s2,double b,double gamma,OutputArray d,int dtype = -1);
/*******************************************************************
* s1: 输入图1
* a: 输入图占比 α
* s2: 输入图2
* b: 输入图2占比 β
* gamma: 附加值,结果基础上再加+gamma γ
* dst: 输出图
* dtype: 输出图深度 可有可无
*********************************************************************/
综合代码
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
class ImgOpreations
{
public:
ImgOpreations() :img1(imread("mm.jpg")), img2(imread("text.jpg"))
{
result = Mat::zeros(img1.size(), img2.type()); //存储的图像一定要初始化
}
void testAdd(string wName="Add")
{
add(img1, img2, result);
imshow(wName, result);
waitKey(0);
}
void testSub(string wName="Sub")
{
subtract(img1, img2, result);
imshow(wName, result);
waitKey(0);
}
void testMul(string wName="Mul")
{
multiply(img1, img2, result);
imshow(wName, result);
waitKey(0);
}
void testDivide(string wName = "Div")
{
divide(img1, img2, result);
imshow(wName, result);
waitKey(0);
}
//dst = α · img1 + β · img2 + γ
void testAddWeighted(string wName = "AddWeighted")
{
addWeighted(img1, 0.6, img2, 0.4, 0, result);
imshow(wName, result);
waitKey(0);
}
protected:
Mat img1;
Mat img2;
Mat result;
};
int main()
{
ImgOpreations* pImg = new ImgOpreations;
pImg->testAdd();
pImg->testSub();
pImg->testMul();
pImg->testDivide();
pImg->testAddWeighted();
return 0;
}
位运算
位与
void bitwise_and(InputArray src1, InputArray src2,,OutputArray dst, InputArray mask = noArray());
/*******************************************************************
* src1: 输入图1
* src2: 输入图2
* dst: 输出图
* mask: 遮罩像素 可有可无
*********************************************************************/
位或
void bitwise_or(InputArray src1, InputArray src2, OutputArray dst, InputArray mask = noArray());
/*******************************************************************
* src1: 输入图1
* src2: 输入图2
* dst: 输出图
* mask: 遮罩像素 可有可无
*********************************************************************/
非运算
void bitwise_not(InputArray src, OutputArray dst,InputArray mask = noArray());
/*******************************************************************
* src1: 输入图1
* dst: 输出图
* mask: 遮罩像素 可有可无
*********************************************************************/
异或运算
void bitwise_xor(InputArray src1, InputArray src2,OutputArray dst, InputArray mask = noArray());
/*******************************************************************
* src1: 输入图1
* src2: 输入图2
* dst: 输出图
* mask: 遮罩像素 可有可无
*********************************************************************/
综合代码:图像位运算用图片
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
class BitWise
{
public:
BitWise() :img1(imread("mm.jpg")), img2(imread("text.jpg")) {}
void Show()
{
imshow("mm", img1);
imshow("text", img2);
}
void BitOpreations()
{
Mat myand, myor, myxor, mynot;
bitwise_and(img1, img2, myand);
bitwise_or(img1, img2, myor);
bitwise_not(img1, mynot);
bitwise_xor(img1, img2, myxor);
imshow("and", myand);
imshow("or", myor);
imshow("xor", myxor);
imshow("not", mynot);
waitKey(0);
}
protected:
Mat img1;
Mat img2;
};
int main()
{
BitWise* pImg = new BitWise;
pImg->Show();
pImg->BitOpreations();
return 0;
}
图像位运算用自绘图图形
注意:
①函数Scalar的使用,传入一个参数就是单通道,三个参数就是RGB
②注意构造函数的写法,在Mat类型的img中利用Rect函数进行绘制。
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
class BitWise
{
public:
BitWise() :img1(Mat(200,200,CV_8UC1)), img2(Mat(200,200,CV_8UC1))
{
//Rect绘制矩形(左上角坐标 和绘制矩形宽度和高度)
img1(Rect(50, 50, 100, 100)) = Scalar(255);
img2(Rect(100, 100, 100, 100)) = Scalar(255);
}
void Show()
{
imshow("mm", img1);
imshow("text", img2);
waitKey(0);
}
void BitOpreations()
{
Mat myand, myor, myxor, mynot;
bitwise_and(img1, img2, myand);
bitwise_or(img1, img2, myor);
bitwise_not(img1, mynot);
bitwise_xor(img1, img2, myxor);
imshow("and", myand);
imshow("or", myor);
imshow("xor", myxor);
imshow("not", mynot);
waitKey(0);
}
protected:
Mat img1;
Mat img2;
};
int main()
{
BitWise* pImg = new BitWise;
pImg->Show();
pImg->BitOpreations();
return 0;
}