以下是 OpenCV 核心模块教程 的介绍文章,涵盖图像基础操作、像素处理、算术运算、性能优化等核心功能。由于内容比较多,分为三篇文章进行描述,本文是第一部分。
目录
- 图像的基础操作
- 图像的算术运算
- 性能优化与测量
- 颜色空间转换
- 图像阈值处理
- 几何变换
1. 图像的基础操作
核心功能
- 访问像素值:读取和修改像素。
- 裁剪感兴趣区域(ROI):提取图像局部区域。
- 通道拆分与合并:处理多通道图像。
代码示例
import cv2
img = cv2.imread("image.jpg")
# 访问像素值(BGR格式)
pixel = img[100, 100] # 返回 [B, G, R] 值
print("Pixel at (100,100):", pixel)
# 修改像素值
img[100:150, 100:150] = [255, 0, 0] # 将区域设为蓝色
# 裁剪ROI(例如提取左上角200x200区域)
roi = img[0:200, 0:200]
# 拆分通道
b, g, r = cv2.split(img)
# 合并通道
merged = cv2.merge([b, g, r])
cv2.imshow("Operations", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
2. 图像的算术运算
核心函数
- 加法:
cv2.add()
(饱和运算)或+
(取模运算)。 - 混合:
cv2.addWeighted()
实现加权混合。
代码示例
import cv2
import numpy as np
def validate_image(image, name="image"):
"""输入图像基础验证"""
if image is None:
raise ValueError(f"❌ {name} 加载失败,请检查文件路径")
if image.dtype != np.uint8:
raise TypeError(f"⚠️ {name} 数据类型应为np.uint8,当前类型为 {image.dtype}")
def add_images(img1, img2):
"""安全图像加法
参数要求:
- 两张图像必须同尺寸同通道
"""
validate_image(img1, "img1")
validate_image(img2, "img2")
if img1.shape != img2.shape:
raise ValueError(f"🚫 图像尺寸不匹配\n img1: {img1.shape}\n img2: {img2.shape}")
return cv2.add(img1, img2)
def blend_images(img1, img2, alpha=0.7, beta=0.3, gamma=0):
"""带权重检查的图像混合"""
validate_image(img1, "img1")
validate_image(img2, "img2")
if not (0 <= alpha <= 1 and 0 <= beta <= 1):
raise ValueError(f"📊 权重系数应在[0,1]之间\n alpha={alpha}, beta={beta}")
if img1.shape != img2.shape:
raise ValueError(f"🚫 图像尺寸不匹配\n img1: {img1.shape}\n img2: {img2.shape}")
return cv2.addWeighted(img1, alpha, img2, beta, gamma)
def bitwise_operation(img, mask_path):
"""安全的位运算操作
要求:
- mask必须是单通道二值图
"""
mask = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE)
validate_image(mask, "mask")
if mask.ndim != 2:
raise ValueError(f"🎭 mask必须为单通道灰度图,当前通道数: {mask.ndim}")
_, binary_mask = cv2.threshold(mask, 1, 255, cv2.THRESH_BINARY)
return cv2.bitwise_and(img, img, mask=binary_mask)
try:
# 示例调用
img1 = cv2.imread("img1.png") # BGR三通道图像
img2 = cv2.imread("img2.jpeg")
# 图像加法
added_img = add_images(img1, img2)
# 图像混合
blended_img = blend_images(img1, img2)
# 位与操作(演示自动二值化)
and_result = bitwise_operation(img1, "mask.png")
# 显示结果(可选)
cv2.imshow("Added", added_img)
cv2.imshow("Blended", blended_img)
cv2.imshow("Bitwise AND", and_result)
cv2.waitKey(0)
except Exception as e:
print(f"❌ 处理失败: {str(e)}")
exit(1)
finally:
cv2.destroyAllWindows()
3. 性能优化与测量
核心方法
- 测量执行时间:使用
cv2.getTickCount()
和cv2.getTickFrequency()
。 - 优化技巧:避免使用 Python 循环,优先使用 OpenCV 内置函数。
代码示例
import cv2
import numpy as np
class PerfAnalyzer:
"""OpenCV 性能分析与优化工具箱"""
def __init__(self, content:str):
self.tick_freq = cv2.getTickFrequency()
self.content = content
def __enter__(self):
"""上下文管理器入口"""
self.start = cv2.getTickCount()
return self
def __exit__(self, *args):
"""上下文管理器出口"""
self.elapsed = (cv2.getTickCount() - self.start) / self.tick_freq
print(f"⏱️ {self.content}耗时: {self.elapsed:.4f}s")
def validate_image(image):
"""图像有效性检查"""
if image is None:
raise ValueError("图像加载失败")
if not isinstance(image, np.ndarray):
raise TypeError("需传入NumPy数组")
def optimized_gaussian_blur(img, ksize=(5, 5)):
"""优化版高斯模糊(使用OpenCV内置加速)"""
validate_image(img)
return cv2.GaussianBlur(img, ksize, 0)
def unoptimized_box_filter(img, ksize=5):
"""未优化盒式滤波(Python循环实现)"""
validate_image(img)
h, w = img.shape[:2]
dst = np.zeros_like(img)
offset = ksize // 2
for y in range(offset, h - offset):
for x in range(offset, w - offset):
roi = img[y - offset:y + offset + 1, x - offset:x + offset + 1]
dst[y, x] = np.mean(roi, axis=(0, 1))
return dst
def demo_optimizations(img_path):
"""全流程优化示范"""
try:
# 读取测试图像
img = cv2.imread(img_path)
validate_image(img)
print("\n=== 性能对比实验 ===")
# 实验1:OpenCV内置高斯模糊
with PerfAnalyzer("OpenCV内置高斯模糊") as t:
blur_cv = optimized_gaussian_blur(img)
cv2.imshow("OpenCV Gaussian", blur_cv)
# 实验2:Python实现的盒式模糊
with PerfAnalyzer("Python实现的盒式模糊") as t:
blur_py = unoptimized_box_filter(img)
cv2.imshow("Python Box Filter", blur_py)
# 实验3:内存预分配优化
with PerfAnalyzer("内存预分配优化") as t:
optimized = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
optimized = cv2.Canny(optimized, 100, 200)
# 实验4:多步骤合并(避免中间内存分配)
with PerfAnalyzer("多步骤合并(避免中间内存分配)") as t:
optimized = cv2.Canny(
cv2.cvtColor(img, cv2.COLOR_BGR2GRAY),
100, 200
)
cv2.waitKey(0)
except Exception as e:
print(f"错误: {str(e)}")
finally:
cv2.destroyAllWindows()
if __name__ == "__main__":
demo_optimizations("img1.png")
输出的测试报告如下:
=== 性能对比实验 ===
⏱️ OpenCV内置高斯模糊耗时: 0.0035s
⏱️ Python实现的盒式模糊耗时: 2.4692s
⏱️ 内存预分配优化耗时: 0.0041s
⏱️ 多步骤合并(避免中间内存分配)耗时: 0.0040s
从输入的评测结果可以看出优化的效果
4. 颜色空间转换
📚 颜色空间基础
颜色空间 | 组成要素 | 典型用途 | 范围说明 |
---|---|---|---|
BGR | 蓝(B)、绿(G)、红®通道 | OpenCV默认图像存储格式 | 每个通道0-255(uint8) |
灰度 | 单通道亮度值 | 简化计算(如边缘检测) | 0(黑)-255(白) |
HSV | 色相(H)、饱和度(S)、明度(V) | 色彩阈值分割 | H:0-180, S/V:0-255(OpenCV) |
LAB | 亮度(L)、a轴(绿红)、b轴(蓝黄) | 色差分析、肤色检测 | L:0-100, a/b:-127-127 |
📌关键差异:
- HSV的H通道在OpenCV中范围是0-180(而非常规0-360),因使用uint8数据类型压缩存储
- LAB颜色空间接近人类视觉感知特性,常用于复杂光照下的颜色分析
BGR ↔ 灰度转换原理
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
转换算法 | 公式 | 适用场景 |
---|---|---|
加权平均法 | Gray = 0.114*B + 0.587*G + 0.299*R | 符合人眼敏感度(默认) |
简单平均法 | Gray = (B + G + R) / 3 | 快速处理但精度较低 |
取单通道 | 直接取B/G/R通道数据 | 特定场景预处理 |
BGR ↔ HSV转换详解
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
HSV颜色模型参数范围
分量 | OpenCV范围 | 物理意义 |
---|---|---|
H | 0-179 | 色相(色彩基色) |
S | 0-255 | 饱和度(色彩浓淡) |
V | 0-255 | 明度(亮度) |
注意:常规HSV模型H范围为0-360°,但OpenCV用8位存储时压缩到0-179
🚀 演示代码,提取黄色
import cv2
import numpy as np
def extract_yellow_object(image_path):
# 读取图像(支持jpg/png等格式)
img = cv2.imread(image_path)
if img is None:
print("错误:无法读取图像文件,请检查路径是否正确")
return
# 转换为HSV颜色空间
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 定义黄色范围(H:20-30, S:100-255, V:100-255)
lower_yellow = np.array([20, 100, 100])
upper_yellow = np.array([30, 255, 255])
# 创建二值化掩膜
mask = cv2.inRange(hsv, lower_yellow, upper_yellow)
# 形态学处理(消除噪声)
kernel = np.ones((5, 5), np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) # 闭运算填充小孔
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) # 开运算消除小噪点
# 提取黄色区域
result = cv2.bitwise_and(img, img, mask=mask)
# 可视化显示
cv2.imshow('Original', img)
cv2.imshow('Mask', mask)
cv2.imshow('Result', result)
# 按ESC退出
while True:
if cv2.waitKey(1) == 27:
break
cv2.destroyAllWindows()
if __name__ == "__main__":
# 使用示例(替换为你的图片路径)
extract_yellow_object("yello_test.png")
🔧 参数调试建议
HSV范围获取技巧:
下面的代码可以通过滑块演示HSV的取值范围
# 实时调节工具代码(可在另一个脚本运行)
def hsv_tuner():
cv2.namedWindow("HSV Tuner")
cv2.createTrackbar("H min", "HSV Tuner", 0, 180, lambda x: None)
cv2.createTrackbar("H max", "HSV Tuner", 180, 180, lambda x: None)
cv2.createTrackbar("S min", "HSV Tuner", 0, 255, lambda x: None)
cv2.createTrackbar("V min", "HSV Tuner", 0, 255, lambda x: None)
while True:
img = cv2.imread("test_image.jpg")
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h_min = cv2.getTrackbarPos("H min", "HSV Tuner")
h_max = cv2.getTrackbarPos("H max", "HSV Tuner")
s_min = cv2.getTrackbarPos("S min", "HSV Tuner")
v_min = cv2.getTrackbarPos("V min", "HSV Tuner")
lower = np.array([h_min, s_min, v_min])
upper = np.array([h_max, 255, 255])
mask = cv2.inRange(hsv, lower, upper)
res = cv2.bitwise_and(img, img, mask=mask)
cv2.imshow("Mask", cv2.hconcat([img, res]))
if cv2.waitKey(1) == 27:
break
5. 图像阈值处理
核心函数
cv2.threshold()
:全局阈值处理。cv2.adaptiveThreshold()
:自适应阈值。
代码示例
import cv2
import numpy as np
def threshold_demo(image_path):
# 读取图像并转换为灰度图
img = cv2.imread(image_path)
if img is None:
print("错误:图像文件读取失败,请检查路径")
return
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 全局阈值处理
ret1, thresh_global = cv2.threshold(
gray,
127, # 初始阈值
255, # 最大值
cv2.THRESH_BINARY + cv2.THRESH_OTSU # 使用大津算法自动确定阈值
)
# 自适应阈值处理
thresh_adaptive = cv2.adaptiveThreshold(
gray,
255, # 输出最大值
cv2.ADAPTIVE_THRESH_GAUSSIAN_C, # 自适应方法
cv2.THRESH_BINARY, # 阈值类型
21, # 邻域大小(必须奇数)
10 # 常数C(从平均值减去的值)
)
# 可视化结果
cv2.imshow('Original', img)
cv2.imshow('Gray', gray)
cv2.imshow('Global Threshold (OTSU)', thresh_global)
cv2.imshow('Adaptive Threshold', thresh_adaptive)
# 退出机制
while True:
key = cv2.waitKey(1)
if key == 27: # ESC退出
break
cv2.destroyAllWindows()
if __name__ == "__main__":
# 使用示例(替换为你的图片路径)
threshold_demo("yello_test.png")
6. 几何变换
核心功能
- 缩放:
cv2.resize()
- 旋转:
cv2.getRotationMatrix2D()
+cv2.warpAffine()
- 仿射变换:
cv2.getAffineTransform()
- 透视变换:
cv2.getPerspectiveTransform()
代码示例(旋转图像)
import cv2
import numpy as np
def validate_image(image):
"""图像有效性检查"""
if image is None:
raise ValueError("🔴 图像加载失败,请确认路径是否正确")
if image.dtype != np.uint8:
image = image.astype(np.uint8)
if not isinstance(image, np.ndarray):
raise TypeError("🟡 需传入NumPy数组类型的图像")
def visualize_transform(original, transformed, title="对比视图"):
"""改进版可视化工具,自动处理尺寸差异"""
# 统一图像高度(通过底部填充黑色区域)
h_orig, w_orig = original.shape[:2]
h_trans, w_trans = transformed.shape[:2]
# 计算最大高度
max_height = max(h_orig, h_trans)
# 对高度不足的图像进行底部填充
if h_orig < max_height:
original = cv2.copyMakeBorder(original,
0, max_height - h_orig,
0, 0,
cv2.BORDER_CONSTANT,
value=(0, 0, 0))
if h_trans < max_height:
transformed = cv2.copyMakeBorder(transformed,
0, max_height - h_trans,
0, 0,
cv2.BORDER_CONSTANT,
value=(0, 0, 0))
# 执行拼接操作
combined = cv2.hconcat([original, transformed])
# 添加对比标注
cv2.putText(combined, "Original -> Transformed", (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
cv2.imshow(title, combined)
cv2.waitKey(500)
def geometric_transform_demo(img_path):
"""几何变换综合演示"""
try:
img = cv2.imread(img_path)
validate_image(img)
h, w = img.shape[:2]
print("=== 几何变换测试启动 ===")
# ------------------------
# 1. 图像缩放(保持长宽比)
# ------------------------
scale_factor = 0.6
# 确保输出尺寸为整数
new_width = int(w * scale_factor)
new_height = int(h * scale_factor)
scaled = cv2.resize(img, (new_width, new_height),
interpolation=cv2.INTER_AREA)
print(f"缩放比例: {scale_factor} | 缩放后尺寸: {scaled.shape[1]}x{scaled.shape[0]}")
visualize_transform(img, scaled, "缩放对比")
# ------------------------
# 2. 旋转变换(可调参数)
# ------------------------
angle = 45
# 参数验证:防止输入异常角度
if not -360 <= angle <= 360:
raise ValueError(f"⚙️ 非法旋转角度值 {angle}°,应在[-360, 360]范围内")
# 计算旋转矩阵(旋转中心/角度/缩放因子)
rotation_matrix = cv2.getRotationMatrix2D((w // 2, h // 2), angle, 1.0)
# 边缘处理:保留完整旋转内容
rotated = cv2.warpAffine(img, rotation_matrix, (w, h),
flags=cv2.INTER_LINEAR,
borderMode=cv2.BORDER_CONSTANT,
borderValue=(255, 255, 255))
print(f"旋转矩阵:\n{rotation_matrix}")
visualize_transform(img, rotated, f"旋转 {angle}°")
# ------------------------
# 3. 仿射变换(三点定位)
# ------------------------
# 源点(原始图像三角形)
src_pts = np.float32([[50, 50], [200, 50], [50, 200]])
# 目标点(变换后位置)
dst_pts = np.float32([[10, 100], [200, 50], [100, 250]])
affine_matrix = cv2.getAffineTransform(src_pts, dst_pts)
print(f"仿射矩阵:\n{affine_matrix}")
# 绘制标记点用于验证变换准确性
marked_img = img.copy()
for pt in src_pts:
cv2.circle(marked_img, tuple(pt.astype(int)), 5, (0, 0, 255), -1)
affine_output = cv2.warpAffine(marked_img, affine_matrix, (w, h))
visualize_transform(marked_img, affine_output, "仿射变换")
# ------------------------
# 4. 透视变换(四点定位)
# ------------------------
# 源点(书本的四角坐标示例)
src_quad = np.float32([[0, 0], [w, 0], [w, h], [0, h]])
# 目标点(投影后的四边形)
dst_quad = np.float32([[50, 50], [w - 50, 100], [w - 100, h - 50], [50, h - 50]])
perspective_matrix = cv2.getPerspectiveTransform(src_quad, dst_quad)
print(f"透视矩阵:\n{perspective_matrix}")
warped = cv2.warpPerspective(img, perspective_matrix, (w, h),
flags=cv2.INTER_LANCZOS4)
visualize_transform(img, warped, "透视变换")
cv2.waitKey(0)
except Exception as e:
print(f"❌ 处理失败: {str(e)}")
finally:
cv2.destroyAllWindows()
if __name__ == "__main__":
# 参数配置区(可修改数值实时验证效果)
TEST_IMAGE_PATH = "yello_test.png" # 替换为你的测试图片路径
geometric_transform_demo(TEST_IMAGE_PATH)
总结
OpenCV 核心模块提供了图像处理的底层能力,涵盖:
- 基础操作:像素访问、ROI、通道处理。
- 数学运算:加减乘除、位运算、混合。
- 图像增强:滤波、阈值、形态学操作。
- 高级分析:边缘检测、轮廓提取、直方图均衡化。
通过灵活组合这些功能,可实现图像增强、目标检测、特征提取等复杂任务。
转载自CSDN-专业IT技术社区
版权声明:本文为博主原创文章,遵循 CC 4.0 BY 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/desert_fish1976/article/details/147193389