利用 OpenCV 库进行实时目标物体检测

发布于:2025-03-16 ⋅ 阅读:(13) ⋅ 点赞:(0)
一、代码概述

此代码利用 OpenCV 库实现了基于特征匹配的实时物体检测系统。通过摄像头捕获实时视频帧,将其与预先加载的参考图像进行特征匹配,从而识别出视频帧中是否存在与参考图像匹配的物体。

二、环境依赖

  • OpenCV:用于图像处理、特征提取和匹配等操作。
  • NumPy:用于数值计算,OpenCV 依赖于 NumPy 进行数组操作。

可以使用以下命令安装所需库:

bash

pip install opencv-python numpy

三、代码详细解释
1. 导入必要的库

python

import cv2
import numpy as np

  • cv2:OpenCV 库,用于计算机视觉任务。
  • np:NumPy 库,用于高效的数值计算。
2. 初始化摄像头

python

cap = cv2.VideoCapture(0)

  • cv2.VideoCapture(0):打开默认的摄像头设备(通常为计算机内置摄像头),用于捕获实时视频帧。
3. 加载所有参考图像

python

reference_images = []
for img_name in ['Black speaker.jpg', 'remote.jpg', 'fan.jpg', 'tempo.jpg']:
    img_path = f'Target_object/{img_name}'
    img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
    if img is None:
        print(f"无法加载图像: {img_path}")
        continue
        
    # 图像预处理
    img = cv2.GaussianBlur(img, (5, 5), 0)
    img = cv2.equalizeHist(img)
    
    # 存储图像信息
    reference_images.append({
        'name': img_name,
        'image': img,
        'kp': None,
        'des': None
    })

  • 遍历指定的参考图像文件名列表,尝试从 Target_object 文件夹中加载图像。
  • cv2.imread:以灰度模式读取图像。
  • cv2.GaussianBlur:对图像进行高斯模糊处理,以减少噪声。
  • cv2.equalizeHist:对图像进行直方图均衡化,增强图像的对比度。
  • 将处理后的图像信息存储在 reference_images 列表中,每个元素是一个字典,包含图像名称、图像数据、关键点和描述符。
4. 初始化 SIFT 特征检测器

python

sift = cv2.SIFT_create(nfeatures=1000)

  • cv2.SIFT_create:创建一个 SIFT(尺度不变特征变换)特征检测器,nfeatures=1000 表示最多检测 1000 个特征点。
5. 提取所有参考图像特征

python

for ref in reference_images:
    ref['kp'], ref['des'] = sift.detectAndCompute(ref['image'], None)

  • 遍历 reference_images 列表,对每个参考图像使用 SIFT 检测器提取关键点(kp)和描述符(des)。
6. 设置匹配阈值

python

MATCH_THRESHOLD = 100

  • MATCH_THRESHOLD:用于判断是否匹配成功的阈值,当匹配的特征点数量超过该阈值时,认为检测到匹配的物体。
7. 主循环:实时物体检测

python

while True:
    # 读取摄像头帧
    ret, frame = cap.read()
    if not ret:
        break
        
    # 转换为灰度图像并进行预处理
    gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    gray_frame = cv2.GaussianBlur(gray_frame, (5, 5), 0)
    gray_frame = cv2.equalizeHist(gray_frame)
    
    # 提取当前帧特征
    kp2, des2 = sift.detectAndCompute(gray_frame, None)
    
    # 特征匹配
    if des2 is not None:
        # 使用FLANN匹配器
        FLANN_INDEX_KDTREE = 1
        index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
        search_params = dict(checks=100)
        flann = cv2.FlannBasedMatcher(index_params, search_params)
        
        # 遍历所有参考图像
        for ref in reference_images:
            if ref['des'] is None:
                continue
                
            try:
                matches = flann.knnMatch(ref['des'], des2, k=2)
                
                # 检查是否有足够匹配对
                if len(matches) < 1 or len(matches[0]) < 2:
                    continue
                    
                # 应用比率测试
                good_matches = [m for m,n in matches if m.distance < 0.7*n.distance]
                
                # 如果匹配点超过阈值
                if len(good_matches) > MATCH_THRESHOLD:
                    print(f"检测到匹配物体: {ref['name']}")
                    cv2.putText(frame, f"Match: {ref['name']}", (50, 50), 
                               cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
                    
                    # 可视化匹配结果
                    match_img = cv2.drawMatches(ref['image'], ref['kp'],
                                              frame, kp2,
                                              good_matches[:50], None,
                                              flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
                    cv2.imshow('Matches', match_img)
                    break
                    
            except Exception as e:
                print(f"匹配错误: {str(e)}")
                continue
    
    # 显示结果
    cv2.imshow('Object Detection', frame)
    
    # 按q退出
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

  • cap.read():从摄像头读取一帧图像。
  • cv2.cvtColor:将彩色图像转换为灰度图像。
  • sift.detectAndCompute:对当前帧提取关键点和描述符。
  • cv2.FlannBasedMatcher:使用 FLANN(快速最近邻搜索库)匹配器进行特征匹配。
  • flann.knnMatch:对参考图像的描述符和当前帧的描述符进行 k 近邻匹配,k=2 表示为每个查询描述符找到两个最近邻。
  • 应用比率测试(m.distance < 0.7*n.distance)筛选出好的匹配点。
  • 如果好的匹配点数量超过 MATCH_THRESHOLD,则认为检测到匹配的物体,在帧上绘制匹配信息并显示匹配结果图像。
  • cv2.imshow:显示当前帧和匹配结果图像。
  • cv2.waitKey(1) & 0xFF == ord('q'):等待用户按下 q 键退出循环。
8. 释放资源

python

cap.release()
cv2.destroyAllWindows()

  • cap.release():释放摄像头资源。
  • cv2.destroyAllWindows():关闭所有 OpenCV 窗口。
四、注意事项

  • 确保 Target_object 文件夹存在,并且包含指定的参考图像文件。
  • SIFT 算法在 OpenCV 4.x 版本中需要额外安装 opencv-contrib-python 库,因为它属于非免费的专利算法。
  • 特征匹配的准确性受光照、物体姿态、遮挡等因素的影响,可以根据实际情况调整匹配阈值和预处理步骤。

完整代码:

import cv2
import numpy as np

# 初始化摄像头
cap = cv2.VideoCapture(0)

# 加载所有参考图像
reference_images = []
for img_name in ['Black speaker.jpg', 'remote.jpg', 'fan.jpg', 'tempo.jpg']:
    img_path = f'Target_object/{img_name}'
    img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
    if img is None:
        print(f"无法加载图像: {img_path}")
        continue
        
    # 图像预处理
    img = cv2.GaussianBlur(img, (5, 5), 0)
    img = cv2.equalizeHist(img)
    
    # 存储图像信息
    reference_images.append({
        'name': img_name,
        'image': img,
        'kp': None,
        'des': None
    })

# 初始化SIFT特征检测器
sift = cv2.SIFT_create(nfeatures=1000)

# 提取所有参考图像特征
for ref in reference_images:
    ref['kp'], ref['des'] = sift.detectAndCompute(ref['image'], None)

# 设置匹配阈值
MATCH_THRESHOLD = 100

while True:
    # 读取摄像头帧
    ret, frame = cap.read()
    if not ret:
        break
        
    # 转换为灰度图像并进行预处理
    gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    gray_frame = cv2.GaussianBlur(gray_frame, (5, 5), 0)
    gray_frame = cv2.equalizeHist(gray_frame)
    
    # 提取当前帧特征
    kp2, des2 = sift.detectAndCompute(gray_frame, None)
    
    # 特征匹配
    # 在特征匹配部分添加调试信息
    if des2 is not None:
        for ref in reference_images:
            if ref['des'] is None:
                continue
            try:
                matches = flann.knnMatch(ref['des'], des2, k=2)
                print(f"参考图像 {ref['name']} 的匹配点数量: {len(matches)}")
                if len(matches) < 1 or len(matches[0]) < 2:
                    continue
                good_matches = [m for m,n in matches if m.distance < 0.7*n.distance]
                print(f"参考图像 {ref['name']} 的良好匹配点数量: {len(good_matches)}")
                if len(good_matches) > MATCH_THRESHOLD:
                    print(f"检测到匹配物体: {ref['name']}")
                    cv2.putText(frame, f"Match: {ref['name']}", (50, 50), 
                            cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
                    match_img = cv2.drawMatches(ref['image'], ref['kp'], frame, kp2, good_matches[:50], None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
                    cv2.imshow('Matches', match_img)
                    break
            except Exception as e:
                print(f"匹配错误: {str(e)}")
                continue
        # 使用FLANN匹配器
        FLANN_INDEX_KDTREE = 1
        index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
        search_params = dict(checks=100)
        flann = cv2.FlannBasedMatcher(index_params, search_params)
        
        # 遍历所有参考图像
        for ref in reference_images:
            if ref['des'] is None:
                continue
                
            try:
                matches = flann.knnMatch(ref['des'], des2, k=2)
                
                # 检查是否有足够匹配对
                if len(matches) < 1 or len(matches[0]) < 2:
                    continue
                    
                # 应用比率测试
                good_matches = [m for m,n in matches if m.distance < 0.7*n.distance]
                
                # 如果匹配点超过阈值
                if len(good_matches) > MATCH_THRESHOLD:
                    print(f"检测到匹配物体: {ref['name']}")
                    cv2.putText(frame, f"Match: {ref['name']}", (50, 50), 
                               cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
                    
                    # 可视化匹配结果
                    match_img = cv2.drawMatches(ref['image'], ref['kp'],
                                              frame, kp2,
                                              good_matches[:50], None,
                                              flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
                    cv2.imshow('Matches', match_img)
                    break
                    
            except Exception as e:
                print(f"匹配错误: {str(e)}")
                continue
    
    # 显示结果
    cv2.imshow('Object Detection', frame)
    
    # 按q退出
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# 释放资源
cap.release()
cv2.destroyAllWindows()