两图像间的像素操作
两幅图像的比较运算max()和min()
max()和min()函数原型:
void max(InputArray src1,
InputArray src2,
OutputArray dst
)
void min(InoutArray src1,
InputArray src2,
OutputArray dst
)
- src1:第一个图像矩阵,可以是任意通道数的矩阵
- src2:第二个图像矩阵,尺寸以及数据类型需要与src1一致
- dst:保留对应位置较大(较小)灰度值后的图像矩阵,尺寸、通道数和数据类型与src1一致
这两种函数功能就是比较每一个像素的大小,按要求保留较大值或较小值,最后生成新图像
例如max()函数,第一幅图像(x,y)像素值为100,第二幅图像(x,y)像素值为10,那么输出图像(x,y)像素值为100
示例:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
float a[12] = {1,2,3.3,4,5,9,5,7,8.2,9,10,2};
float b[12] = {1,2.2,3,1,3,10,6,7,8,9.3,10,1};
Mat imga = Mat(3,4,CV_32FC1,a);
Mat imgb = Mat(3,4,CV_32FC1,b);
Mat imgas = Mat(2,3,CV_32FC2,a);
Mat imgbs = Mat(2,3,CV_32FC2,b);
//对两个单通道矩阵进行比较
Mat myMax,myMin;
max(imga,imgb,myMax);
min(imga,imgb,myMin);
//对两个多通道矩阵进行比较
Mat myMaxs,myMins;
max(imgas,imgbs,myMaxs);
min(imgas,imgbs,myMins);
//对两个彩色图像进行比较
Mat img0 = imread("E:\\CLion\\opencv_xin\\SG\\SG_1.jpg");
Mat img1 = imread("E:\\CLion\\opencv_xin\\SG\\SG_0.jpg");
if(img0.empty()||img1.empty())
{
cout << "error" << endl;
return -1;
}
Mat comMin,comMax;
max(img0,img1,comMax);
min(img0,img1,comMin);
imshow("comMin",comMin);
imshow("comMax",comMax);
//与掩模进行比较运算
Mat src1 = Mat::zeros(Size(img0.rows,img0.cols),CV_8UC3);
Rect rect(180,0,300,300);
src1(rect) = Scalar(255,255,255); //生成一个低通300*300的掩模
Mat comsrc1,comsrc2;
min(img0,src1,comsrc1);
imshow("comsrc1",comsrc1);
Mat src2 = Mat(img0.rows,img0.cols,CV_8UC3,Scalar(0,0,255)); //生成一个显示红色通道的低通掩模
min(img0,src2,comsrc2);
imshow("comsrc2",comsrc2);
//对两幅灰度图像进行比较运算
Mat img0G,img1G,comMinG,comMaxG;
cvtColor(img0,img0G,COLOR_BGR2GRAY);
cvtColor(img1,img1G,COLOR_BGR2GRAY);
max(img0G,img1G,comMaxG);
min(img0G,img1G,comMinG);
imshow("comMinG",comMinG);
imshow("comMaxG",comMaxG);
waitKey(0);
return 0;
}
注意:尺寸、通道数和数据类型要一致
两幅图像的逻辑运算
OpenCV4对两个图像像素之间的“与” “或” ”异或“ 以及”非“运算分别提供了
bitwise_and()、bitwise_or()、bitwise_xor()和bitwwise_not()函数
与运算(&)
参加运算的两个数据,按二进制位进行“与”运算
运算规则:0&0=0; 0&1=0; 1&0=0; 1&1=1; 即:两位同时为“1”,结果才为“1”,否则为0
例如:3&5 即 0000 0011 & 0000 0101 = 0000 0001 因此,3&5的值为1
或运算(|)
参加运算的两个对象,按二进制位进行“或”运算
运算规则:0|0=0; 0|1=1; 1|0=1; 1|1=1; 即 :参加运算的两个对象只要有一个为1,其值为1 例如: 3|5 可写算式如下: 0000 0011 | 0000 0101 = 0000 0111(十进制为7)因此,3|5的值为7
异或运算(^)
参加运算的两个数据,按二进制位进行“异或”运算
运算规则:0^0=0; 0^1=1; 1^0=1; 1^1=0; 即:参加运算的两个对象,如果两个相应位为“异”(值不同),则该位结果为1,否则为0 例如:9^5可写成算式如下: 00001001 ^ 00000101 = 00001100 (十进制为12)因此,9^5的值为12
非运算(~)
参加运算的两个数据,按二进制位进行“非”运算
即:"非"运算符号表示为~,运算法则为按位取反,也就是遇1取0,遇0取1,即 ~1 = 0 , ~0 = 1
例如:5可以写成:00000101 = 1111010(十进制为250)因此,~5的值为250
OpenCV4中像素逻辑运算函数原型:
//像素求"与"运算
void bitwise_and(InputArray src1,
InputArray src2,
OutputArray dst,
InputArray mask = noArray()
)
//像素求"或"运算
void bitwise_or(InputArray src1,
InputArray src2,
OutputArray dst,
InputArray mask = noArray()
)
//像素求"异或"运算
void bitwise_xor(InputArray src1,
InputArray src2,
OutputArray dst,
InputArray mask = noArray()
)
//像素求"非"运算
void bitwise_not(InputArray src,
OutputArray dst,
InputArray mask = noArray()
)
- src1:第一个图像矩阵,可以是多通道图像数据
- src2:第二个图像矩阵,尺寸以及数据类型需要与src1一致
- dst:逻辑运算输出结果,尺寸以及数据类型需要与src1一致
- mask:用于设置图像或矩阵中的逻辑运算的范围
在进行逻辑运算时,一定要保证两个图像矩阵之间的尺寸、数据类型和通道数相同,多个通道进行逻辑运算时不同通道是独立进行
示例:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat img = imread("E:\\CLion\\opencv_xin\\SG\\SG_1.jpg");
if (img.empty())
{
cout << "Error" << endl;
return -1;
}
//创建两个黑白图像
Mat img0 = Mat::zeros(200,200,CV_8UC1);
Mat img1 = Mat::zeros(200,200,CV_8UC1);
Rect rect0(50,50,100,100);
img0(rect0) = Scalar(255);
Rect rect1(100,100,100,100);
img1(rect1) = Scalar(255);
imshow("img0",img0);
imshow("img1",img1);
//进行逻辑运算
Mat myAnd,myOr,myXor,myNot,imgNot;
bitwise_and(img0,img1,myAnd);
bitwise_or(img0,img1,myOr);
bitwise_xor(img0,img1,myXor);
bitwise_not(img0,myNot);
bitwise_not(img,imgNot);
imshow("myAnd",myAnd);
imshow("myXor",myXor);
imshow("myOr",myOr);
imshow("myNot",myNot);
imshow("img",img);
imshow("imgNot",imgNot);
waitKey();
return 0;
}
\
图像二值化threshold()和adaptiveThreshold()
只有黑色和白色的图像,这种“非黑即白”图像像素的灰度值无论这种什么数据类型种豆只有最大值和最小值两种取值
因此称为二值图像。二值图像色彩种类少,可以进行高度的压缩,节省储存空间,将非二值图像经过计算变成二值图像的过程称为
图像的二值化,OpenCV4提供了threshold()和adaptiveThreshold()用于实现图像的二值化
threshold()函数原型:
double threshold(InputArray src,
OutputArray dst,
double thresh,
double maxval,
int type
)
src:待二值化的图像,图像只能是CV_8U和CV_32F两种数据类型。
对于图像通道数目的要求与选择的二值化方法有关
- dst:二值化后的图像,与输入图像具有相同的尺寸、数据类型和通道数
- thresh:二值化的阈值
- maxval:二值化过程的最大值,只在THRESH_BINARY和THRESH_BINARY_INV两种二值化方法中才使用
- type:选择图像二值化方法的标志
该函数是众多二值化方法的集成,所有的方法都实现了一个功能,就是给定一个阈值,计算所有像素灰度值与这个阈值关系
二值化方法可选择的标志及含义
| 标志参数 | 简记 | 作用 |
|---|---|---|
| THRESH_BINARY | 0 | 灰度值大于阈值的为最大值,其他值为0 |
| THRESH_BINARY_INV | 1 | 灰度值大于阈值的为0,其他值为最大值 |
| THRESH_TRUNC | 2 | 灰度值大于阈值的为阈值,其他值不变 |
| THRESH_TOZERO | 3 | 灰度值大于阈值的不变,其他值为0 |
| THRESH_TOZERO_INV | 4 | 灰度值大于阈值的为0,其他值不变 |
| THRESH_OTSU | 8 | 大津法自动寻求全局阈值 |
| THRESH_TRIANGLE | 16 | 三角法自动寻求全局阈值 |
1.THRESH_BINARY和THRESH_BINARY_INV
这两个标志是相反的二值化方法,THRESH_BINARY是将灰度值与阈值(第三个参数thresh)进行比较,如果灰度值大于阈值,
将灰度值改为函数中第四个参数maxval的值,否则将灰度值改为0
THRESH_BINARY_INV与其相反,如果灰度值大于阈值,就将灰度值改为0,否则将灰度值改为maxval的值
2.THRESH_TRUNC
这个标志相当于重新给图像的灰度值设定一个新的最大值,将大于新的最大值的灰度值全部重新设置为新的最大值
逻辑为将灰度值与阈值thresh进行比较,如果灰度值大于thresh,则将灰度值改为thresh,否则保持灰度值不变
3.THRESH_TOZERO和THRESH_TOZERO_INV
这两种标志是相反的阈值比较方法,THRESH_TOZERO表示将灰度值与阈值比较,如果灰度值大于阈值,则保持不变,否则改为0
THRESH_BINARY_INV是将灰度值与阈值进行比较,如果灰度值小于或等于thresh,则保持不变,否则改为0
4.THRESH_OTSU和THRESH_TRIANGLE
这两种标志表示利用大津法和三角形法结合图像灰度值分布特性获取二值化的阈值,并将阈值以函数返回值的形式给出
因此,使用这两个标志时,第三个参数thresh将由系统自动给出
注意:OpenCV4对这两种标志只支持输入CV_8UC1类型图像
在实际情况中,由于光照不均匀以及阴影的存在,全局只有一个阈值会使得阴影处的白色区域也会被函数二值化成黑色
adaptiveThreshold()函数提供了两种局部自适应阈值的二值化方法
adaptiveThreshold()函数函数原型:
void adaptiveThreshold(InputArray src,
OutputArray dst,
double maxvalue,
int adaptiveMethod,
int thresholdType,
double C
)
- src:待二值化的图像,图像只能是CV_8U数据类型。
- dst:二值化后的图像,与输入图像具有相同的尺寸、数据类型和通道数
- maxValue:二值化的最大值
- adaptiveMethod:自适应确定阈值的方法,分为均值法ADAPTIVE_THRESH_MEAE_C和高斯法ADAPTIVE_THRESH_GAUSSIAN_C
- thresholdType:选择二值化方法的标志,只能是THRESH_BINARY和THRESH_BINARY_INV
- blockSize:自适应确定阈值的像素领域大小,一般是3、5、7的奇数
- C:从平均值或者加权平均值中减去的常数,可以为正,也可以为负
LUT
如果需要与多个阈值进行比较,就需要用到显示查找表(Look-Up-Table,LUT)
简单说,LUT就是一个像素值灰度值的映射表,以像素灰度值作为索引,以灰度值映射后的数值作为表中的内容
例如,由一个长度为5的存放字符的数组[a,b,c,d,e],LUT就是通过这个数组将0映射为a,将1映射成b,依次类推
其映射关系为P[0] = a、P[1] = b
LUT()函数原型:
void LUT(InputArray src,
InputArray lut,
OutputArray dst
)
- src:输入图像矩阵,数据类型只能是CV_8U
- lut:256个像素灰度值的查找表,尺寸与src相同,数据类型与lut相同
该函数第一个参数数据类型要求必须是CV_8U类型,单、但可以是多通道的图像矩阵