OpenCV cv::Mat之(三)算术操作
在计算机视觉领域,OpenCV的算术运算是图像处理的基础操作。通过简单的加减乘除,我们可以实现亮度调整、对比度增强、图像融合等多种效果。下面将介绍OpenCV 4.x中C++接口的核心运算方法。
1、算术符号计算
1.1和标量Scalar计算
使用 “+ - /” 符号可以对Mat对象直接进行操作。注意不支持乘法操作,需要使用后面的核心算术函数
#include "stdio.h"
#include "opencv2/opencv.hpp"
#include <iostream>
using namespace cv;
int main()
{
//-------------------------------------------------------------------------------------
Mat image(3, 4, CV_8UC3);
//直接赋值
image = Scalar(120, 120, 120);//B G R
//除法运算
image = image/Scalar(2, 3, 5);
std::cout << "CV_8UC3:" << std::endl;
std::cout << image << std::endl;
cv::waitKey(0);
destroyAllWindows();
return 0;
}
注意:计算过程是对BGR3个通道分别除以对应的值“2,3,5”。加法和减法也是一样。
1.2 Mat和Mat计算
Mat image(3, 4, CV_8UC3);
Mat image1(3, 4, CV_8UC3);
image1= Scalar(120, 120, 120);
image = Scalar(120, 120, 120);
image = image/ image1;
注意:两个Mat进行计算需要保证行列通道数一致。
2、核心算术函数计算
2.1 基础运算函数
// 图像加法(饱和运算)
void add(InputArray src1, InputArray src2, OutputArray dst);
// 图像减法
void subtract(InputArray src1, InputArray src2, OutputArray dst);
// 像素乘法(支持缩放因子)
void multiply(InputArray src1, InputArray src2, OutputArray dst, double scale=1);
// 像素除法
void divide(InputArray src1, InputArray src2, OutputArray dst, double scale=1);
2.2 运算特性对比
运算类型 | 溢出处理 | 执行速度 | 典型应用场景 |
---|---|---|---|
加法 | 饱和截断(0-255) | 快 | 亮度增强 |
减法 | 模运算 | 较快 | 背景差分 |
乘法 | 可能溢出需缩放 | 中等 | 对比度调整 |
除法 | 向下取整 | 较慢 | 颜色空间归一化 |
2.3 标量运算示例
cv::Mat srcImage=cv::imread("E:/image/lena.png");
Mat result1, result2;
// 亮度增强:每个像素值+80
add(srcImage, Scalar(80, 80, 80),result1);
// 对比度降低:每个像素值×0.7
multiply(srcImage, Scalar(0.7, 0.7, 0.7), result2);
add(srcImage, srcImage2, result3);
imshow("原图", srcImage);
imshow("add", result1);
imshow("multiply", result2);
cv::waitKey(0);
destroyAllWindows();
运行结果看到相加后图像亮度增加
注意:因uint8类型数值溢出,一些运算需先转换为浮点类型。参考代码
Mat img_float;
img.convertTo(img_float, CV_32F,1.0/255);//限制在0~1之间
2.3 图像运算
Mat和Mat数据进行运算,需要保证大小一致,这里使用了resize函数进行调整。
cv::Mat srcImage=cv::imread("E:/image/lena.png");
cv::Mat srcImage2 = imread("E:/image/Opencv-logo.png",COLOR_BGR2GRAY);
//减法降低亮度
//subtract(srcImage2, Scalar(100, 100, 100), srcImage2);
//调整大小
resize(srcImage2, srcImage2, Size(srcImage.rows, srcImage.cols));
//加法运算
Mat result1;
add(srcImage, srcImage2, result1);
//乘法运算比例因子抑制过饱和
Mat result2;
multiply(srcImage, srcImage2, result2,0.02);
//减法
Mat result3;
subtract(srcImage, srcImage2, result3);
Mat result4;
//除法
divide(srcImage, srcImage2, result4);
//imshow("srcImage", srcImage);
//imshow("srcImage2", srcImage2);
imshow("add", result1);
imshow("multiply", result2);
imshow("subtract", result3);
imshow("divide", result4);
cv::waitKey(0);
destroyAllWindows();
2.4 运算应用之图像融合
函数addWeighted可以实现权重融合,也可以使用multiply和add进行
// 线性混合:result1= 0.3*srcImage+ 0.7*srcImage2
addWeighted(srcImage, 0.7, srcImage2, 0.3, 0, result1);
//使用multiply 和add
multiply(srcImage, Scalar(0.7, 0.7, 0.7), result1);
multiply(srcImage2, Scalar(0.3, 0.3, 0.3), result2);
add(result1, result2, result3);
融合效果就好像加了水印