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;
}

可以看到有两个小狗叠加在一起,如下图所示:

Blog_OpenCV_Learnl_32.png


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;
}

可以看到相减后变暗了很多,如下图所示:

Blog_OpenCV_Learnl_33.png


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 会变亮。效果图如下图所示:

Blog_OpenCV_Learnl_34.png


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 会变暗。效果图如下图所示:

Blog_OpenCV_Learnl_35.png


二、图像位运算

位运算是对图像的每个像素进行二进制位操作。

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;
}

效果图如下图所示:

Blog_OpenCV_Learnl_36.png


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;
}

效果图如下图所示:

Blog_OpenCV_Learnl_37.png


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;
}

效果图如下图所示:

Blog_OpenCV_Learnl_38.png


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;
}

效果图如下图所示:

Blog_OpenCV_Learnl_39.png


三、图像混合

图像混合是将两幅图像按照一定的权重进行线性组合,生成一幅新的图像。在 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;
}

可以看到两个图像合成到一起了,如下图所示:

Blog_OpenCV_Learnl_40.png


四、注意事项

  • 数据类型一致
    参与运算的图像必须具有相同的尺寸、通道数和数据类型(如 CV_8UC3)。

  • 饱和操作
    add()subtract() 会限制结果在有效范围内(如 0~255)。即像素值相加、相加、相乘、相除后的像素如果超过 255 或小于 0,OpenCV 会自动将其截断为 255 或 0。

  • 掩膜的作用
    位运算和 copyTo() 可通过掩膜控制操作区域。

五、应用场景

  • 加法:图像叠加(水印)、光照增强。
  • 减法:背景消除、运动检测。
  • 位运算:ROI 提取、二值图像处理。
  • 融合:图像合成、透明度效果。

posted @ 2025-08-11 17:02  fengMisaka  阅读(17)  评论(0)    收藏  举报