OpenCV入门(14):图像处理之算术运算
在图像处理中,算术运算和位运算是非常基础且重要的操作。下面将详细介绍如何使用 OpenCV 进行图像的加法、减法、乘法、除法、位运算以及图像混合操作。
一、基础运算
1.1 图像加法
图像加法是将两幅图像的对应像素值相加,生成一幅新的图像。在 OpenCV 中,可以使用 cv::add() 函数来实现图像加法。
#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
// 读取图像
cv::Mat srcImage = cv::imread("./dog.jpg");
if (srcImage.empty()) {
std::cout << "Could not read the image.";
return -1;
}
// 显示原图像
cv::imshow("Src Image", srcImage);
// 定义平移矩阵
int xOffset = 50;
int yOffset = 0;
Mat tranMat = Mat::zeros(2, 3, CV_32FC1);
tranMat.at<float>(0, 0) = 1;
tranMat.at<float>(0, 2) = xOffset; // 水平平移量
tranMat.at<float>(1, 1) = 1;
tranMat.at<float>(1, 2) = yOffset; // 垂直平移量
// 根据平移矩阵进行仿射变换
Mat dstImage;
Size dstSize = srcImage.size(); // 输出图像的大小
warpAffine(srcImage, dstImage, tranMat, dstSize);
// 显示平移后的目标图像
cv::imshow("Dst Image", dstImage);
// 图像运算
cv::Mat resultImage;
cv::add(srcImage, dstImage, resultImage);
// 显示图像算数运算后的图像
cv::imshow("Result Image", resultImage);
// 等待用户按键后退出
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
可以看到有两个小狗叠加在一起,如下图所示:

1.2 图像减法
图像减法是将两幅图像的对应像素值相减,生成一幅新的图像。在 OpenCV 中,可以使用 cv::subtract() 函数来实现图像减法。
#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
// 读取图像
cv::Mat srcImage = cv::imread("./dog.jpg");
if (srcImage.empty()) {
std::cout << "Could not read the image.";
return -1;
}
// 显示原图像
cv::imshow("Src Image", srcImage);
// 创建空白图像
Mat dstImage = Mat::zeros(Size(srcImage.size().width,srcImage.size().height), CV_8UC3); // 8uc1无符号8位,通道1
dstImage = Scalar(100, 100, 100); // 赋值 B G R
// 显示目标图像
cv::imshow("Dst Image", dstImage);
// 图像运算
cv::Mat resultImage;
cv::subtract(srcImage, dstImage, resultImage);
// 显示图像算数运算后的图像
cv::imshow("Result Image", resultImage);
// 等待用户按键后退出
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
可以看到相减后变暗了很多,如下图所示:

1.3 图像乘法
图像乘法是将两幅图像的对应像素值相乘,生成一幅新的图像。在 OpenCV 中,可以使用 cv::multiply() 函数来实现图像乘法。
#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
// 读取图像
cv::Mat srcImage = cv::imread("./dog.jpg");
if (srcImage.empty()) {
std::cout << "Could not read the image.";
return -1;
}
// 显示原图像
cv::imshow("Src Image", srcImage);
// 图像运算(变暗)
cv::Mat resultImage1;
cv::multiply(srcImage, cv::Scalar(0.7, 0.7, 0.7), resultImage1);
// 显示图像算数运算后的图像
cv::imshow("Result Image1", resultImage1);
// 图像运算(变亮)
cv::Mat resultImage2;
cv::multiply(srcImage, cv::Scalar(1.2, 1.2, 1.2), resultImage2);
// 显示图像算数运算后的图像
cv::imshow("Result Image2", resultImage2);
// 等待用户按键后退出
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
可以看到像素乘以 0.7 会变暗,而乘以 1.2 会变亮。效果图如下图所示:

1.4 图像加法
图像除法是将两幅图像的对应像素值相除,生成一幅新的图像。在 OpenCV 中,可以使用 cv::divide() 函数来实现图像除法。
#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
// 读取图像
cv::Mat srcImage = cv::imread("./dog.jpg");
if (srcImage.empty()) {
std::cout << "Could not read the image.";
return -1;
}
// 显示原图像
cv::imshow("Src Image", srcImage);
// 图像运算
cv::Mat resultImage;
cv::divide(srcImage, cv::Scalar(2, 2, 2), resultImage);
// 显示图像算数运算后的图像
cv::imshow("Result Image1", resultImage);
// 等待用户按键后退出
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
可以看到像素除以 2 会变暗。效果图如下图所示:

二、图像位运算
位运算是对图像的每个像素进行二进制位操作。
OpenCV 提供了 cv::bitwise_and()、cv::bitwise_or()、cv::bitwise_not() 和 cv::bitwise_xor() 函数来实现图像的位运算。
| 函数 | 功能 | 应用场景 |
|---|---|---|
cv::bitwise_and() |
按位与操作 | 掩码操作、图像分割 |
cv::bitwise_or() |
按位或操作 | 图像叠加 |
cv::bitwise_not() |
按位取反操作 | 图像反色 |
cv::bitwise_xor() |
按位异或操作 | 图像差异检测 |
2.1 位与运算 (AND)
位与运算是对两幅图像的每个像素进行按位与操作。
原图同时 AND 纯白和纯黑图片 的示例:
#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
// 读取图像
cv::Mat srcImage = cv::imread("./dog.jpg");
if (srcImage.empty()) {
std::cout << "Could not read the image.";
return -1;
}
// 显示原图像
cv::imshow("Src Image", srcImage);
// 原图像 AND 纯白图像
cv::Mat resultImage1;
cv::bitwise_and(srcImage, cv::Scalar(255, 255, 255), resultImage1);
// 显示图像算数运算后的图像
cv::imshow("Result Image AND White", resultImage1);
// 原图像 AND 纯黑图像
cv::Mat resultImage2;
cv::bitwise_and(srcImage, cv::Scalar(0, 0, 0), resultImage2);
// 显示图像算数运算后的图像
cv::imshow("Result Image AND Black", resultImage2);
// 等待用户按键后退出
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
效果图如下图所示:

2.2 位或运算 (OR)
位或运算是对两幅图像的每个像素进行按位或操作。
原图同时 OR 纯白和纯黑图片 的示例:
#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
// 读取图像
cv::Mat srcImage = cv::imread("./dog.jpg");
if (srcImage.empty()) {
std::cout << "Could not read the image.";
return -1;
}
// 显示原图像
cv::imshow("Src Image", srcImage);
// 原图像 OR 纯白图像
cv::Mat resultImage1;
cv::bitwise_or(srcImage, cv::Scalar(255, 255, 255), resultImage1);
// 显示图像算数运算后的图像
cv::imshow("Result Image OR White", resultImage1);
// 原图像 OR 纯黑图像
cv::Mat resultImage2;
cv::bitwise_or(srcImage, cv::Scalar(0, 0, 0), resultImage2);
// 显示图像算数运算后的图像
cv::imshow("Result Image OR Black", resultImage2);
// 等待用户按键后退出
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
效果图如下图所示:

2.3 位非运算 (NOT)
位非运算是对图像的每个像素进行按位取反操作。
#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
// 读取图像
cv::Mat srcImage = cv::imread("./dog.jpg");
if (srcImage.empty()) {
std::cout << "Could not read the image.";
return -1;
}
// 显示原图像
cv::imshow("Src Image", srcImage);
// 原图像 NOT
cv::Mat resultImage;
cv::bitwise_not(srcImage, resultImage);
// 显示图像算数运算后的图像
cv::imshow("Result Image NOT", resultImage);
// 等待用户按键后退出
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
效果图如下图所示:

2.4 位异或运算 (XOR)
位异或运算是对两幅图像的每个像素进行按位异或操作。
#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
// 读取图像
cv::Mat srcImage = cv::imread("./dog.jpg");
if (srcImage.empty()) {
std::cout << "Could not read the image.";
return -1;
}
// 显示原图像
cv::imshow("Src Image", srcImage);
// 原图像 XOR 纯白图像
cv::Mat resultImage1;
cv::bitwise_xor(srcImage, cv::Scalar(255, 255, 255), resultImage1);
// 显示图像算数运算后的图像
cv::imshow("Result Image XOR White", resultImage1);
// 原图像 XOR 纯黑图像
cv::Mat resultImage2;
cv::bitwise_xor(srcImage, cv::Scalar(0, 0, 0), resultImage2);
// 显示图像算数运算后的图像
cv::imshow("Result Image XOR Black", resultImage2);
// 等待用户按键后退出
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
效果图如下图所示:

三、图像混合
图像混合是将两幅图像按照一定的权重进行线性组合,生成一幅新的图像。在 OpenCV 中,可以使用 cv::addWeighted() 函数来实现图像混合。
函数原型为:
void addWeighted(InputArray src1, double alpha, InputArray src2,
double beta, double gamma, OutputArray dst, int dtype = -1);
参数说明:
alpha:第一幅图像的权重。beta:第二幅图像的权重。gamma:可选的标量值,通常设置为 0。
公式:
result = img1 * alpha + img2 * beta + gamma
示例如下:
#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
// 读取图像1
cv::Mat srcImage1 = cv::imread("./star.png");
// 显示图像1
cv::imshow("Src Image1", srcImage1);
// 读取图像2
cv::Mat srcImage2 = cv::imread("./man.png");
// 显示图像2
cv::imshow("Src Image2", srcImage2);
// 混合参数
double alpha = 0.5;
double beta;
double inputValue = 0.5; // 改变此值可以得到不同的效果
// 混合图像
if (inputValue >= 0.0 && inputValue <= 1.0)
alpha = inputValue;
beta = (1.0 - alpha);
cv::Mat resultImage;
addWeighted(srcImage1, alpha, srcImage2, beta, 0.0, resultImage);
// 显示结果图像
cv::imshow("Result Image", resultImage);
// 等待用户按键后退出
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
可以看到两个图像合成到一起了,如下图所示:

四、注意事项
-
数据类型一致:
参与运算的图像必须具有相同的尺寸、通道数和数据类型(如CV_8UC3)。 -
饱和操作:
add()和subtract()会限制结果在有效范围内(如 0~255)。即像素值相加、相加、相乘、相除后的像素如果超过 255 或小于 0,OpenCV 会自动将其截断为 255 或 0。 -
掩膜的作用:
位运算和copyTo()可通过掩膜控制操作区域。
五、应用场景
- 加法:图像叠加(水印)、光照增强。
- 减法:背景消除、运动检测。
- 位运算:ROI 提取、二值图像处理。
- 融合:图像合成、透明度效果。

浙公网安备 33010602011771号