一、线性混合操作
void cv::addWeighted ( InputArray src1,
double alpha,
InputArray src2,
double beta,
double gamma,
OutputArray dst,
int dtype = -1
)
- 计算两个数组的加权和
- 这两个数组的加权和的关系可有下式表示
dst(I)=saturate(src1(I)∗alpha+src2(I)∗beta+gamma) 用数学的方式表示 dst(I)=saturate(src1(I)∗α+src2(I)∗β+γ)
其中I是一个多维数组索引。在计算多维数组索引的情况下,每一个通道值都是单独计算的。这个函数可以用矩阵表达式代替dst = src1*alpha+src2*beta+gamma
α,β是两图在新图中所占的比例,一般的α+β=1,当然也可以不等于1。
γ为一个增益变量,作用是可以提高或减小整体的亮度。 - 最后一个参数
dtype
的作用是指定输出数组的类型;当两个输入数组是相同的depth时,dtype被设置成-1,也就是输出数组的类型与src1.depth()
相等。 - 相似的函数:
add, subtract, scaleAdd, Mat::convertTo - nots:
- 输出数组的深度不能是
CV_32S
,如果是的话,你可能得到不正确的结果。 - 两个输入数组的类型必须相同。但是类型相同,主要就是说通道数相同;经过如下情况亦可
第一种情况
cvtColor(src2, src2, COLOR_BGR2GRAY);
cvtColor(src2, src2, COLOR_GRAY2BGR);
//得到的src2能够使用
第二种情况
src4.convertTo(src2, CV_16UC3);
//src4亦可使用
用处:视频字幕上可以看成是这样操作的
使用方法
//【1】API方式:
//addWeighted(src1, 2, src2, 2, -60, dst);
//【2】表达式方式
//dst = src1*2 + src1*2 - 60;
//【3】遍历图像的方式
Mat_<Vec3b> src1_data = src1;
Mat_<Vec3b> src2_data = src2;
Mat_<Vec3b> dst_data = dst;
for (int i = 0; i < src1.rows; i++)
{
for (int j = 0; j < src1.cols; j++)
{
dst_data(i, j)[0] = saturate_cast<uchar>(src1_data(i, j)[0] * 2 -src2_data(i, j)[0] * 2- 60);
dst_data(i, j)[1] = saturate_cast<uchar>(src1_data(i, j)[1] * 2 -src2_data(i, j)[0] * 2- 60);
dst_data(i, j)[2] = saturate_cast<uchar>(sr1c_data(i, j)[2] * 2 -src2_data(i, j)[0] * 2- 60);
}
}
程序文件
二、调整图像的亮度与对比度
图像变换可以分为两类操作:
- 像素变换-点操作
- 邻域操作-区域
线性混合、调整图像的亮度与对比度属于像素变换。卷积操作,图形操作属于邻域操作;
调整图像的亮度与对比度原理:
dst(I)=saturate(src1(I)∗alpha+gamma)
用数学的方式表示
dst(I)=saturate(src1(I)∗α+γ)
γ是增益变量同同上边的。
β=0
这个暂时不知道它有没有独有的API,但是可以通过上面线性混合的API得到两种,只需要把两个输入图像中的一个图像的比例设置为0,或者传入一个所有像素值为0的空图像,即可。
当然可以用矩阵的运算
dst = src1*alpha+src2*0+gamma
使用方法
//【1】API方式:
addWeighted(src1, 2, src2, 0, -60, dst);
//【2】表达式方式
dst = src1*2 + 60;
//【3】遍历图像的方式
Mat_<Vec3b> src_data = src1;
Mat_<Vec3b> dst_data = dst;
//Mat_<Vec3b> dst1_data = dst1;
for (int i = 0; i < src1.rows; i++)
{
for (int j = 0; j < src1.cols; j++)
{
dst_data(i, j)[0] = saturate_cast<uchar>(src_data(i, j)[0] * 2 - 60);
dst_data(i, j)[1] = saturate_cast<uchar>(src_data(i, j)[1] * 2 - 60);
dst_data(i, j)[2] = saturate_cast<uchar>(src_data(i, j)[2] * 2 - 60);
//这种方式是错误的,寻找错误方法见程序文件
/* 比如说点(50,300)的值为26,经过下式计算应该得-8,经过saturate计算的为0,没有经过saturate转换的确成了228*/
/*dst1_data(i, j)[0] = (uchar)(src_data(i, j)[0] * 1.2 - 60);
dst1_data(i, j)[1] = (uchar)(src_data(i, j)[1] * 1.2 - 60);
dst1_data(i, j)[2] = (uchar)(src_data(i, j)[2] * 1.2 - 60);*/
}
}
程序文件
注意:
这种对点的操作都需要把计算结果的值经过saturate_cast转换,不然容易溢出,得到不是想得到的值。