OpenCV 图像算术运算

OpenCV 图像算术运算 教程(中文)重点讲解 OpenCV 中用于图像的算术运算,包括像素级加、减、乘、除、位运算,以及图像融合、亮度/对比度调整等操作。这些功能主要基于 core 模块,结合 NumPy 数组操作。本教程提供清晰的 Python 代码示例、解释和注意事项,适合初学者快速上手。假设你已安装 OpenCV(opencv-python)。


一、图像算术运算概述

  • 图像表示:OpenCV 中图像是 NumPy 数组,形状为 (height, width, channels),默认使用 BGR 格式,数据类型通常为 uint8(0-255)。
  • 算术运算
  • 像素级运算:加、减、乘、除,直接操作像素值。
  • 位运算:与、或、非、异或,用于掩码和逻辑操作。
  • 图像融合:加权求和,调整图像混合比例。
  • 亮度/对比度调整:线性变换改变图像外观。
  • 关键函数
  • cv2.add, cv2.subtract, cv2.multiply, cv2.divide:像素级算术运算。
  • cv2.bitwise_and, cv2.bitwise_or, cv2.bitwise_not, cv2.bitwise_xor:位运算。
  • cv2.addWeighted:图像加权融合。

二、核心算术运算与代码示例

以下按功能分类,逐一讲解并提供 Python 示例代码。

2.1 像素级加法

使用 cv2.add 或 NumPy 加法进行图像像素相加。

示例:图像加法

import cv2
import numpy as np

# 读取两张图像(需相同尺寸)
img1 = cv2.imread('lena.jpg')
img2 = cv2.imread('opencv_logo.jpg')  # 替换为你的图像路径
if img1 is None or img2 is None:
    print("错误:无法加载图像")
    exit()

# 调整 img2 尺寸与 img1 一致
img2 = cv2.resize(img2, (img1.shape[1], img1.shape[0]))

# OpenCV 加法
add_cv = cv2.add(img1, img2)  # 限制在 [0, 255]

# NumPy 加法
add_np = img1 + img2  # 模 256 运算,可能溢出

# 显示结果
cv2.imshow('原始图像1', img1)
cv2.imshow('原始图像2', img2)
cv2.imshow('OpenCV 加法', add_cv)
cv2.imshow('NumPy 加法', add_np)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 保存结果
cv2.imwrite('add_cv.jpg', add_cv)
cv2.imwrite('add_np.jpg', add_np)

说明

  • cv2.add:将像素值相加,超出 255 时截断为 255(饱和运算)。
  • NumPy 加法 (+):模 256 运算,可能导致溢出(如 255 + 1 = 0)。
  • 图像需尺寸和通道数一致。

2.2 像素级减法

使用 cv2.subtract 进行图像像素相减。

示例:图像减法

import cv2

img1 = cv2.imread('lena.jpg')
img2 = cv2.imread('opencv_logo.jpg')
if img1 is None or img2 is None:
    print("错误:无法加载图像")
    exit()

# 调整尺寸
img2 = cv2.resize(img2, (img1.shape[1], img1.shape[0]))

# OpenCV 减法
subtract = cv2.subtract(img1, img2)  # 限制在 [0, 255]

# 显示结果
cv2.imshow('原始图像1', img1)
cv2.imshow('原始图像2', img2)
cv2.imshow('减法', subtract)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 保存结果
cv2.imwrite('subtract.jpg', subtract)

说明

  • cv2.subtract:像素值相减,小于 0 时截断为 0。
  • 适合提取图像差异(如背景减除)。

2.3 像素级乘法与除法

使用 cv2.multiplycv2.divide 进行像素乘除运算。

示例:乘法与除法

import cv2
import numpy as np

img = cv2.imread('lena.jpg')
if img is None:
    print("错误:无法加载图像")
    exit()

# 创建一个标量图像
scalar = np.ones_like(img) * 50  # 每个像素值为 50

# 乘法(增强亮度)
multiply = cv2.multiply(img, scalar / 255.0)  # 缩放避免溢出

# 除法(降低亮度)
divide = cv2.divide(img, scalar / 25.0)

# 显示结果
cv2.imshow('原始图像', img)
cv2.imshow('乘法', multiply)
cv2.imshow('除法', divide)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 保存结果
cv2.imwrite('multiply.jpg', multiply)
cv2.imwrite('divide.jpg', divide)

说明

  • cv2.multiply:像素值相乘,适合增强亮度。
  • cv2.divide:像素值相除,适合降低亮度。
  • 输入需归一化(如 / 255.0),避免溢出。

2.4 位运算

位运算(如与、或、非、异或)用于掩码操作或图像合成。

示例:位运算与掩码

import cv2
import numpy as np

# 读取图像
img = cv2.imread('lena.jpg')
if img is None:
    print("错误:无法加载图像")
    exit()

# 创建掩码(圆形区域)
mask = np.zeros_like(img)
center = (img.shape[1]//2, img.shape[0]//2)
cv2.circle(mask, center, 100, (255, 255, 255), -1)

# 位与运算(保留圆形区域)
bitwise_and = cv2.bitwise_and(img, mask)

# 位或运算(与另一图像结合)
img2 = np.zeros_like(img)
img2[:] = [0, 0, 255]  # 纯红色图像
bitwise_or = cv2.bitwise_or(img, img2)

# 位非运算
bitwise_not = cv2.bitwise_not(img)

# 显示结果
cv2.imshow('原始图像', img)
cv2.imshow('掩码', mask)
cv2.imshow('位与', bitwise_and)
cv2.imshow('位或', bitwise_or)
cv2.imshow('位非', bitwise_not)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 保存结果
cv2.imwrite('bitwise_and.jpg', bitwise_and)
cv2.imwrite('bitwise_or.jpg', bitwise_or)
cv2.imwrite('bitwise_not.jpg', bitwise_not)

说明

  • bitwise_and:保留掩码区域的图像内容。
  • bitwise_or:合并两张图像的像素。
  • bitwise_not:像素值取反(255 – pixel)。

2.5 图像融合

使用 cv2.addWeighted 实现两张图像的加权融合。

示例:图像融合

import cv2

img1 = cv2.imread('lena.jpg')
img2 = cv2.imread('opencv_logo.jpg')
if img1 is None or img2 is None:
    print("错误:无法加载图像")
    exit()

# 调整尺寸
img2 = cv2.resize(img2, (img1.shape[1], img1.shape[0]))

# 加权融合
alpha = 0.7  # img1 权重
beta = 0.3   # img2 权重
gamma = 0.0  # 标量加法
blended = cv2.addWeighted(img1, alpha, img2, beta, gamma)

# 显示结果
cv2.imshow('原始图像1', img1)
cv2.imshow('原始图像2', img2)
cv2.imshow('融合图像', blended)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 保存结果
cv2.imwrite('blended.jpg', blended)

说明

  • addWeighted:计算 dst = src1*alpha + src2*beta + gamma
  • 权重和通常为 1(alpha + beta = 1),但可调整。

2.6 亮度和对比度调整

通过线性变换调整图像亮度和对比度:new_pixel = alpha * pixel + beta

示例:亮度与对比度调整

import cv2
import numpy as np

img = cv2.imread('lena.jpg')
if img is None:
    print("错误:无法加载图像")
    exit()

# 增加亮度(beta > 0)
bright = cv2.convertScaleAbs(img, alpha=1.0, beta=50)

# 增加对比度(alpha > 1)
contrast = cv2.convertScaleAbs(img, alpha=1.5, beta=0)

# 显示结果
cv2.imshow('原始图像', img)
cv2.imshow('高亮度', bright)
cv2.imshow('高对比度', contrast)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 保存结果
cv2.imwrite('bright.jpg', bright)
cv2.imwrite('contrast.jpg', contrast)

说明

  • convertScaleAbs:计算 dst = abs(alpha * src + beta),确保输出为 uint8
  • alpha:控制对比度(>1 增强,<1 减弱)。
  • beta:控制亮度(正值增加,负值减少)。

三、综合示例:图像算术处理流水线

结合多种算术运算:

import cv2
import numpy as np

def arithmetic_pipeline(image_path1, image_path2):
    """图像算术运算流水线"""
    # 读取图像
    img1 = cv2.imread(image_path1)
    img2 = cv2.imread(image_path2)
    if img1 is None or img2 is None:
        print("错误:无法加载图像")
        return

    # 调整尺寸
    img2 = cv2.resize(img2, (img1.shape[1], img1.shape[0]))

    # 1. 加法
    add = cv2.add(img1, img2)

    # 2. 图像融合
    blended = cv2.addWeighted(img1, 0.7, img2, 0.3, 0.0)

    # 3. 亮度调整
    bright = cv2.convertScaleAbs(img1, alpha=1.0, beta=50)

    # 4. 创建掩码并进行位运算
    mask = np.zeros_like(img1)
    center = (img1.shape[1]//2, img1.shape[0]//2)
    cv2.circle(mask, center, 100, (255, 255, 255), -1)
    masked = cv2.bitwise_and(img1, mask)

    # 显示结果
    cv2.imshow('原始图像1', img1)
    cv2.imshow('原始图像2', img2)
    cv2.imshow('加法', add)
    cv2.imshow('融合', blended)
    cv2.imshow('高亮度', bright)
    cv2.imshow('掩码区域', masked)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    # 保存结果
    cv2.imwrite('add.jpg', add)
    cv2.imwrite('blended.jpg', blended)
    cv2.imwrite('bright.jpg', bright)
    cv2.imwrite('masked.jpg', masked)

# 使用示例
arithmetic_pipeline('lena.jpg', 'opencv_logo.jpg')  # 替换为你的图像路径

四、注意事项

  1. 图像尺寸
  • 算术运算要求输入图像尺寸和通道数一致,否则需调整(如 cv2.resize)。
  1. 数据类型
  • 默认 uint8(0-255),溢出时 cv2 函数使用饱和运算,NumPy 使用模运算。
  • 使用浮点运算时,需归一化(如 / 255.0)并转换回 uint8
  1. 错误处理
  • 检查 imread 返回值,防止图像加载失败。
  • 确保掩码与图像格式匹配。
  1. 性能优化
  • 避免逐像素操作,使用 OpenCV 或 NumPy 的矢量化函数。
  • 大图像处理时,考虑 ROI 减少计算量。
  1. 颜色格式
  • OpenCV 使用 BGR,需注意与 RGB 的转换。

五、资源

  • 官方文档:https://docs.opencv.org/master/d5/df1/group__imgproc.html
  • Python 教程:https://opencv-python-tutroals.readthedocs.io/
  • 社区:在 X 平台搜索 #opencv 获取最新讨论。

如果你需要更深入的算术运算示例(如高级掩码操作、批量处理)或 C++ 实现代码,请告诉我,我可以提供详细的解决方案或针对特定任务的优化!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注