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.multiply 和 cv2.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') # 替换为你的图像路径
四、注意事项
- 图像尺寸:
- 算术运算要求输入图像尺寸和通道数一致,否则需调整(如
cv2.resize)。
- 数据类型:
- 默认
uint8(0-255),溢出时cv2函数使用饱和运算,NumPy 使用模运算。 - 使用浮点运算时,需归一化(如
/ 255.0)并转换回uint8。
- 错误处理:
- 检查
imread返回值,防止图像加载失败。 - 确保掩码与图像格式匹配。
- 性能优化:
- 避免逐像素操作,使用 OpenCV 或 NumPy 的矢量化函数。
- 大图像处理时,考虑 ROI 减少计算量。
- 颜色格式:
- OpenCV 使用 BGR,需注意与 RGB 的转换。
五、资源
- 官方文档:https://docs.opencv.org/master/d5/df1/group__imgproc.html
- Python 教程:https://opencv-python-tutroals.readthedocs.io/
- 社区:在 X 平台搜索
#opencv获取最新讨论。
如果你需要更深入的算术运算示例(如高级掩码操作、批量处理)或 C++ 实现代码,请告诉我,我可以提供详细的解决方案或针对特定任务的优化!