OpenCV基础笔记
1. OpenCV简介
OpenCV (Open Source Computer Vision Library) 是一个开源的计算机视觉和机器学习软件库。它包含了超过2500个优化的算法,用于人脸识别、物体识别、跟踪运动、提取3D模型等。
特点
- 跨平台:支持Windows、Linux、macOS、iOS、Android
- 多语言支持:C++、Python、Java等
- 高性能:使用优化的C/C++编写
- 丰富的功能:图像处理、计算机视觉、机器学习
2. 安装OpenCV
Python环境安装
# 安装基础版本
pip install opencv-python
# 安装包含额外功能的版本(推荐)
pip install opencv-contrib-python
# 验证安装
python -c "import cv2; print(cv2.__version__)"
依赖库安装
# 常用的配套库
pip install numpy matplotlib pillow
3. 基本概念
图像表示
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 图像是一个多维数组
# 灰度图像:2D数组 (height, width)
# 彩色图像:3D数组 (height, width, channels)
# BGR顺序:蓝色、绿色、红色
# 创建一个简单的图像
img = np.zeros((300, 300, 3), dtype=np.uint8)
print(f"图像形状: {img.shape}")
print(f"图像数据类型: {img.dtype}")
坐标系统
# OpenCV坐标系统
# 原点(0,0)在左上角
# x轴向右递增,y轴向下递增
# 访问像素:img[y, x] 或 img[row, col]
# 获取图像尺寸
height, width = img.shape[:2]
print(f"图像尺寸: {width} x {height}")
4. 图像读取和显示
读取图像
# 读取彩色图像
img_color = cv2.imread('image.jpg', cv2.IMREAD_COLOR)
# 读取灰度图像
img_gray = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)
# 读取原始图像(包括alpha通道)
img_unchanged = cv2.imread('image.png', cv2.IMREAD_UNCHANGED)
# 检查图像是否成功读取
if img_color is None:
print("无法读取图像")
else:
print("图像读取成功")
显示图像
# 使用OpenCV显示图像
cv2.imshow('Original Image', img_color)
cv2.waitKey(0) # 等待按键
cv2.destroyAllWindows() # 关闭所有窗口
# 使用matplotlib显示图像(推荐用于Jupyter)
def show_image(img, title="Image", cmap=None):
"""显示图像的辅助函数"""
plt.figure(figsize=(10, 6))
if len(img.shape) == 3:
# BGR转RGB用于matplotlib显示
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img_rgb)
else:
plt.imshow(img, cmap='gray' if cmap is None else cmap)
plt.title(title)
plt.axis('off')
plt.show()
# 显示图像
show_image(img_color, "彩色图像")
show_image(img_gray, "灰度图像")
保存图像
# 保存图像
cv2.imwrite('output.jpg', img_color)
cv2.imwrite('output_gray.png', img_gray)
# 指定压缩质量(JPEG)
cv2.imwrite('output_compressed.jpg', img_color, [cv2.IMWRITE_JPEG_QUALITY, 90])
# 保存PNG(无损压缩)
cv2.imwrite('output.png', img_color, [cv2.IMWRITE_PNG_COMPRESSION, 9])
5. 基本图像操作
图像属性
# 获取图像基本信息
print(f"图像形状: {img_color.shape}")
print(f"图像大小: {img_color.size}")
print(f"数据类型: {img_color.dtype}")
print(f"通道数: {len(img_color.shape)}")
# 分离颜色通道
b, g, r = cv2.split(img_color)
print(f"蓝色通道形状: {b.shape}")
# 合并颜色通道
merged = cv2.merge([b, g, r])
图像裁剪和复制
# 图像裁剪(ROI - Region of Interest)
roi = img_color[100:300, 50:250] # [y1:y2, x1:x2]
show_image(roi, "裁剪区域")
# 图像复制
img_copy = img_color.copy()
# 在图像上放置ROI
img_color[0:200, 0:200] = roi
像素操作
# 访问像素值
pixel = img_color[100, 50] # 获取(50,100)位置的像素值
print(f"像素值: {pixel}")
# 修改像素值
img_color[100, 50] = [255, 0, 0] # 设置为蓝色
# 访问单个通道的像素
blue_value = img_color[100, 50, 0]
green_value = img_color[100, 50, 1]
red_value = img_color[100, 50, 2]
6. 颜色空间转换
常用颜色空间
# BGR到RGB
img_rgb = cv2.cvtColor(img_color, cv2.COLOR_BGR2RGB)
# BGR到灰度
img_gray = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)
# BGR到HSV(色调、饱和度、亮度)
img_hsv = cv2.cvtColor(img_color, cv2.COLOR_BGR2HSV)
# BGR到LAB
img_lab = cv2.cvtColor(img_color, cv2.COLOR_BGR2LAB)
# 显示不同颜色空间
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
axes[0,0].imshow(cv2.cvtColor(img_color, cv2.COLOR_BGR2RGB))
axes[0,0].set_title('原始图像 (RGB)')
axes[0,1].imshow(img_gray, cmap='gray')
axes[0,1].set_title('灰度图像')
axes[1,0].imshow(img_hsv)
axes[1,0].set_title('HSV图像')
axes[1,1].imshow(img_lab)
axes[1,1].set_title('LAB图像')
for ax in axes.flat:
ax.axis('off')
plt.tight_layout()
plt.show()
HSV颜色空间的应用
# HSV在颜色检测中的应用
def detect_color_range(img, lower_bound, upper_bound):
"""检测特定颜色范围"""
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, lower_bound, upper_bound)
result = cv2.bitwise_and(img, img, mask=mask)
return mask, result
# 检测蓝色物体
lower_blue = np.array([100, 50, 50])
upper_blue = np.array([130, 255, 255])
blue_mask, blue_objects = detect_color_range(img_color, lower_blue, upper_blue)
# 显示结果
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
axes[0].imshow(cv2.cvtColor(img_color, cv2.COLOR_BGR2RGB))
axes[0].set_title('原始图像')
axes[1].imshow(blue_mask, cmap='gray')
axes[1].set_title('蓝色掩膜')
axes[2].imshow(cv2.cvtColor(blue_objects, cv2.COLOR_BGR2RGB))
axes[2].set_title('蓝色物体')
for ax in axes.flat:
ax.axis('off')
plt.show()
7. 基本图像处理
图像缩放
# 图像缩放
def resize_image(img, scale_percent=50):
"""按百分比缩放图像"""
width = int(img.shape[1] * scale_percent / 100)
height = int(img.shape[0] * scale_percent / 100)
return cv2.resize(img, (width, height), interpolation=cv2.INTER_AREA)
# 不同的插值方法
img_resized_area = cv2.resize(img_color, (300, 200), interpolation=cv2.INTER_AREA)
img_resized_linear = cv2.resize(img_color, (300, 200), interpolation=cv2.INTER_LINEAR)
img_resized_cubic = cv2.resize(img_color, (300, 200), interpolation=cv2.INTER_CUBIC)
# 固定尺寸缩放
img_fixed = cv2.resize(img_color, (640, 480))
图像旋转
# 图像旋转
def rotate_image(img, angle, center=None, scale=1.0):
"""旋转图像"""
height, width = img.shape[:2]
if center is None:
center = (width // 2, height // 2)
# 获取旋转矩阵
rotation_matrix = cv2.getRotationMatrix2D(center, angle, scale)
# 应用旋转
rotated = cv2.warpAffine(img, rotation_matrix, (width, height))
return rotated
# 旋转示例
img_rotated_45 = rotate_image(img_color, 45)
img_rotated_90 = rotate_image(img_color, 90)
img_rotated_180 = rotate_image(img_color, 180)
# 显示旋转结果
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
axes[0,0].imshow(cv2.cvtColor(img_color, cv2.COLOR_BGR2RGB))
axes[0,0].set_title('原始图像')
axes[0,1].imshow(cv2.cvtColor(img_rotated_45, cv2.COLOR_BGR2RGB))
axes[0,1].set_title('旋转45度')
axes[1,0].imshow(cv2.cvtColor(img_rotated_90, cv2.COLOR_BGR2RGB))
axes[1,0].set_title('旋转90度')
axes[1,1].imshow(cv2.cvtColor(img_rotated_180, cv2.COLOR_BGR2RGB))
axes[1,1].set_title('旋转180度')
for ax in axes.flat:
ax.axis('off')
plt.tight_layout()
plt.show()
图像翻转
# 图像翻转
img_flip_horizontal = cv2.flip(img_color, 1) # 水平翻转
img_flip_vertical = cv2.flip(img_color, 0) # 垂直翻转
img_flip_both = cv2.flip(img_color, -1) # 同时翻转
# 显示翻转结果
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
axes[0,0].imshow(cv2.cvtColor(img_color, cv2.COLOR_BGR2RGB))
axes[0,0].set_title('原始图像')
axes[0,1].imshow(cv2.cvtColor(img_flip_horizontal, cv2.COLOR_BGR2RGB))
axes[0,1].set_title('水平翻转')
axes[1,0].imshow(cv2.cvtColor(img_flip_vertical, cv2.COLOR_BGR2RGB))
axes[1,0].set_title('垂直翻转')
axes[1,1].imshow(cv2.cvtColor(img_flip_both, cv2.COLOR_BGR2RGB))
axes[1,1].set_title('同时翻转')
for ax in axes.flat:
ax.axis('off')
plt.tight_layout()
plt.show()
8. 图像滤波
噪声去除
# 添加噪声(用于演示)
def add_noise(img, noise_type='gaussian'):
"""添加噪声到图像"""
if noise_type == 'gaussian':
noise = np.random.normal(0, 25, img.shape).astype(np.uint8)
noisy = cv2.add(img, noise)
elif noise_type == 'salt_pepper':
noisy = img.copy()
# 盐噪声
salt = np.random.random(img.shape[:2]) < 0.01
noisy[salt] = 255
# 胡椒噪声
pepper = np.random.random(img.shape[:2]) < 0.01
noisy[pepper] = 0
return noisy
# 创建带噪声的图像
noisy_img = add_noise(img_color, 'gaussian')
# 高斯滤波
gaussian_filtered = cv2.GaussianBlur(noisy_img, (15, 15), 0)
# 中值滤波
median_filtered = cv2.medianBlur(noisy_img, 15)
# 双边滤波
bilateral_filtered = cv2.bilateralFilter(noisy_img, 15, 80, 80)
# 显示滤波结果
fig, axes = plt.subplots(2, 2, figsize=(15, 10))
axes[0,0].imshow(cv2.cvtColor(noisy_img, cv2.COLOR_BGR2RGB))
axes[0,0].set_title('带噪声图像')
axes[0,1].imshow(cv2.cvtColor(gaussian_filtered, cv2.COLOR_BGR2RGB))
axes[0,1].set_title('高斯滤波')
axes[1,0].imshow(cv2.cvtColor(median_filtered, cv2.COLOR_BGR2RGB))
axes[1,0].set_title('中值滤波')
axes[1,1].imshow(cv2.cvtColor(bilateral_filtered, cv2.COLOR_BGR2RGB))
axes[1,1].set_title('双边滤波')
for ax in axes.flat:
ax.axis('off')
plt.tight_layout()
plt.show()
锐化滤波
# 创建锐化核
sharpening_kernel = np.array([[-1, -1, -1],
[-1, 9, -1],
[-1, -1, -1]])
# 应用锐化滤波
sharpened = cv2.filter2D(img_color, -1, sharpening_kernel)
# Unsharp Mask锐化
def unsharp_mask(img, sigma=1.0, strength=1.5):
"""Unsharp Mask锐化"""
blurred = cv2.GaussianBlur(img, (0, 0), sigma)
sharpened = cv2.addWeighted(img, 1.0 + strength, blurred, -strength, 0)
return sharpened
unsharp_result = unsharp_mask(img_color)
# 显示锐化结果
fig, axes = plt.subplots(1, 3, figsize=(18, 6))
axes[0].imshow(cv2.cvtColor(img_color, cv2.COLOR_BGR2RGB))
axes[0].set_title('原始图像')
axes[1].imshow(cv2.cvtColor(sharpened, cv2.COLOR_BGR2RGB))
axes[1].set_title('卷积核锐化')
axes[2].imshow(cv2.cvtColor(unsharp_result, cv2.COLOR_BGR2RGB))
axes[2].set_title('Unsharp Mask锐化')
for ax in axes.flat:
ax.axis('off')
plt.tight_layout()
plt.show()
9. 边缘检测
Canny边缘检测
# Canny边缘检测
def canny_edge_detection(img, low_threshold=50, high_threshold=150):
"""Canny边缘检测"""
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 高斯模糊
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
# Canny边缘检测
edges = cv2.Canny(blurred, low_threshold, high_threshold)
return edges
# 不同阈值的Canny检测
edges_50_150 = canny_edge_detection(img_color, 50, 150)
edges_100_200 = canny_edge_detection(img_color, 100, 200)
edges_150_250 = canny_edge_detection(img_color, 150, 250)
# 显示边缘检测结果
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
axes[0,0].imshow(cv2.cvtColor(img_color, cv2.COLOR_BGR2RGB))
axes[0,0].set_title('原始图像')
axes[0,1].imshow(edges_50_150, cmap='gray')
axes[0,1].set_title('Canny (50, 150)')
axes[1,0].imshow(edges_100_200, cmap='gray')
axes[1,0].set_title('Canny (100, 200)')
axes[1,1].imshow(edges_150_250, cmap='gray')
axes[1,1].set_title('Canny (150, 250)')
for ax in axes.flat:
ax.axis('off')
plt.tight_layout()
plt.show()
其他边缘检测算法
# Sobel边缘检测
gray = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)
sobel_x = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
sobel_y = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)
sobel_combined = np.sqrt(sobel_x**2 + sobel_y**2)
# Laplacian边缘检测
laplacian = cv2.Laplacian(gray, cv2.CV_64F)
# Scharr边缘检测
scharr_x = cv2.Scharr(gray, cv2.CV_64F, 1, 0)
scharr_y = cv2.Scharr(gray, cv2.CV_64F, 0, 1)
scharr_combined = np.sqrt(scharr_x**2 + scharr_y**2)
# 显示不同边缘检测算法的结果
fig, axes = plt.subplots(2, 3, figsize=(18, 12))
axes[0,0].imshow(gray, cmap='gray')
axes[0,0].set_title('原始灰度图像')
axes[0,1].imshow(np.abs(sobel_x), cmap='gray')
axes[0,1].set_title('Sobel X')
axes[0,2].imshow(np.abs(sobel_y), cmap='gray')
axes[0,2].set_title('Sobel Y')
axes[1,0].imshow(sobel_combined, cmap='gray')
axes[1,0].set_title('Sobel Combined')
axes[1,1].imshow(np.abs(laplacian), cmap='gray')
axes[1,1].set_title('Laplacian')
axes[1,2].imshow(scharr_combined, cmap='gray')
axes[1,2].set_title('Scharr Combined')
for ax in axes.flat:
ax.axis('off')
plt.tight_layout()
plt.show()
10. 图像阈值处理
简单阈值
# 简单阈值处理
gray = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)
# 不同类型的阈值处理
ret1, thresh1 = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
ret2, thresh2 = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV)
ret3, thresh3 = cv2.threshold(gray, 127, 255, cv2.THRESH_TRUNC)
ret4, thresh4 = cv2.threshold(gray, 127, 255, cv2.THRESH_TOZERO)
ret5, thresh5 = cv2.threshold(gray, 127, 255, cv2.THRESH_TOZERO_INV)
# 显示阈值处理结果
fig, axes = plt.subplots(2, 3, figsize=(18, 12))
axes[0,0].imshow(gray, cmap='gray')
axes[0,0].set_title('原始灰度图像')
axes[0,1].imshow(thresh1, cmap='gray')
axes[0,1].set_title('THRESH_BINARY')
axes[0,2].imshow(thresh2, cmap='gray')
axes[0,2].set_title('THRESH_BINARY_INV')
axes[1,0].imshow(thresh3, cmap='gray')
axes[1,0].set_title('THRESH_TRUNC')
axes[1,1].imshow(thresh4, cmap='gray')
axes[1,1].set_title('THRESH_TOZERO')
axes[1,2].imshow(thresh5, cmap='gray')
axes[1,2].set_title('THRESH_TOZERO_INV')
for ax in axes.flat:
ax.axis('off')
plt.tight_layout()
plt.show()
自适应阈值
# 自适应阈值处理
adaptive_mean = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C,
cv2.THRESH_BINARY, 11, 2)
adaptive_gaussian = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 11, 2)
# Otsu阈值
ret_otsu, thresh_otsu = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 显示自适应阈值结果
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
axes[0,0].imshow(gray, cmap='gray')
axes[0,0].set_title('原始灰度图像')
axes[0,1].imshow(adaptive_mean, cmap='gray')
axes[0,1].set_title('自适应阈值(均值)')
axes[1,0].imshow(adaptive_gaussian, cmap='gray')
axes[1,0].set_title('自适应阈值(高斯)')
axes[1,1].imshow(thresh_otsu, cmap='gray')
axes[1,1].set_title(f'Otsu阈值 (阈值={ret_otsu:.2f})')
for ax in axes.flat:
ax.axis('off')
plt.tight_layout()
plt.show()
11. 形态学操作
基本形态学操作
# 创建形态学核
kernel = np.ones((5, 5), np.uint8)
# 获取二值图像
_, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 形态学操作
erosion = cv2.erode(binary, kernel, iterations=1) # 腐蚀
dilation = cv2.dilate(binary, kernel, iterations=1) # 膨胀
opening = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel) # 开运算
closing = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel) # 闭运算
gradient = cv2.morphologyEx(binary, cv2.MORPH_GRADIENT, kernel) # 梯度
tophat = cv2.morphologyEx(binary, cv2.MORPH_TOPHAT, kernel) # 顶帽
blackhat = cv2.morphologyEx(binary, cv2.MORPH_BLACKHAT, kernel) # 黑帽
# 显示形态学操作结果
operations = [
(binary, '原始二值图像'),
(erosion, '腐蚀'),
(dilation, '膨胀'),
(opening, '开运算'),
(closing, '闭运算'),
(gradient, '梯度'),
(tophat, '顶帽'),
(blackhat, '黑帽')
]
fig, axes = plt.subplots(2, 4, figsize=(20, 10))
axes = axes.flatten()
for i, (img, title) in enumerate(operations):
axes[i].imshow(img, cmap='gray')
axes[i].set_title(title)
axes[i].axis('off')
plt.tight_layout()
plt.show()
12. 实践练习
练习1:图像增强工具
class ImageEnhancer:
"""图像增强工具类"""
def __init__(self, image_path):
self.original = cv2.imread(image_path)
if self.original is None:
raise ValueError(f"无法读取图像: {image_path}")
self.current = self.original.copy()
def adjust_brightness(self, value):
"""调整亮度"""
self.current = cv2.convertScaleAbs(self.current, alpha=1, beta=value)
return self
def adjust_contrast(self, alpha):
"""调整对比度"""
self.current = cv2.convertScaleAbs(self.current, alpha=alpha, beta=0)
return self
def adjust_gamma(self, gamma):
"""调整伽马值"""
inv_gamma = 1.0 / gamma
table = np.array([((i / 255.0) ** inv_gamma) * 255
for i in np.arange(0, 256)]).astype("uint8")
self.current = cv2.LUT(self.current, table)
return self
def apply_gaussian_blur(self, kernel_size):
"""应用高斯模糊"""
self.current = cv2.GaussianBlur(self.current, (kernel_size, kernel_size), 0)
return self
def apply_sharpen(self, strength=1.0):
"""应用锐化"""
kernel = np.array([[-1, -1, -1],
[-1, 9, -1],
[-1, -1, -1]]) * strength
self.current = cv2.filter2D(self.current, -1, kernel)
return self
def reset(self):
"""重置到原始图像"""
self.current = self.original.copy()
return self
def show_comparison(self):
"""显示原始图像和处理后的图像对比"""
fig, axes = plt.subplots(1, 2, figsize=(15, 6))
axes[0].imshow(cv2.cvtColor(self.original, cv2.COLOR_BGR2RGB))
axes[0].set_title('原始图像')
axes[0].axis('off')
axes[1].imshow(cv2.cvtColor(self.current, cv2.COLOR_BGR2RGB))
axes[1].set_title('处理后图像')
axes[1].axis('off')
plt.tight_layout()
plt.show()
# 使用示例
# enhancer = ImageEnhancer('your_image.jpg')
# enhancer.adjust_brightness(30).adjust_contrast(1.2).apply_sharpen(0.5).show_comparison()
练习2:颜色检测器
class ColorDetector:
"""颜色检测器"""
def __init__(self):
self.color_ranges = {
'red': [(np.array([0, 50, 50]), np.array([10, 255, 255])),
(np.array([170, 50, 50]), np.array([180, 255, 255]))],
'green': [(np.array([40, 50, 50]), np.array([80, 255, 255]))],
'blue': [(np.array([100, 50, 50]), np.array([130, 255, 255]))],
'yellow': [(np.array([20, 50, 50]), np.array([30, 255, 255]))],
'orange': [(np.array([10, 50, 50]), np.array([20, 255, 255]))],
'purple': [(np.array([130, 50, 50]), np.array([170, 255, 255]))]
}
def detect_color(self, img, color_name):
"""检测特定颜色"""
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
if color_name not in self.color_ranges:
raise ValueError(f"不支持的颜色: {color_name}")
mask = np.zeros(hsv.shape[:2], dtype=np.uint8)
for lower, upper in self.color_ranges[color_name]:
mask += cv2.inRange(hsv, lower, upper)
# 形态学操作去除噪声
kernel = np.ones((3, 3), np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
# 应用掩膜
result = cv2.bitwise_and(img, img, mask=mask)
return mask, result
def detect_all_colors(self, img):
"""检测所有预定义的颜色"""
results = {}
for color_name in self.color_ranges.keys():
mask, result = self.detect_color(img, color_name)
results[color_name] = (mask, result)
return results
def visualize_detection(self, img, color_name):
"""可视化颜色检测结果"""
mask, result = self.detect_color(img, color_name)
fig, axes = plt.subplots(1, 3, figsize=(18, 6))
axes[0].imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
axes[0].set_title('原始图像')
axes[0].axis('off')
axes[1].imshow(mask, cmap='gray')
axes[1].set_title(f'{color_name.title()}颜色掩膜')
axes[1].axis('off')
axes[2].imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
axes[2].set_title(f'检测到的{color_name.title()}颜色')
axes[2].axis('off')
plt.tight_layout()
plt.show()
# 使用示例
# detector = ColorDetector()
# detector.visualize_detection(img_color, 'blue')
练习3:简单的物体计数
def count_objects(img, min_area=100):
"""计算图像中的物体数量"""
# 转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 高斯模糊
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
# 二值化
_, thresh = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 形态学操作
kernel = np.ones((3, 3), np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
# 寻找轮廓
contours, _ = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 过滤小轮廓
valid_contours = [cnt for cnt in contours if cv2.contourArea(cnt) > min_area]
# 绘制轮廓
result = img.copy()
cv2.drawContours(result, valid_contours, -1, (0, 255, 0), 2)
# 添加编号
for i, cnt in enumerate(valid_contours):
M = cv2.moments(cnt)
if M["m00"] != 0:
cx = int(M["m10"] / M["m00"])
cy = int(M["m01"] / M["m00"])
cv2.putText(result, str(i+1), (cx, cy), cv2.FONT_HERSHEY_SIMPLEX,
0.7, (255, 0, 0), 2)
return len(valid_contours), result, thresh
# 使用示例
# count, result_img, binary_img = count_objects(img_color)
# print(f"检测到 {count} 个物体")
总结
OpenCV基础知识包括:
核心概念
- 图像表示:多维数组、坐标系统、像素操作
- 颜色空间:BGR、RGB、HSV、灰度等转换
- 基本操作:读取、显示、保存、裁剪、缩放
图像处理
- 滤波:高斯滤波、中值滤波、双边滤波
- 边缘检测:Canny、Sobel、Laplacian算子
- 阈值处理:简单阈值、自适应阈值、Otsu方法
形态学操作
- 基本操作:腐蚀、膨胀、开运算、闭运算
- 应用场景:噪声去除、形状分析、图像分割
实践要点
- 理解图像结构:熟悉numpy数组操作
- 选择合适的颜色空间:根据任务需求选择
- 参数调优:通过实验找到最佳参数
- 组合技术:将多种技术结合解决复杂问题
这些基础知识为进一步学习计算机视觉和图像处理奠定了坚实的基础。