在计算机视觉项目开发中很多开发者都会遇到这样的困境想要快速上手图像处理却被复杂的算法原理和繁琐的环境配置劝退网上资料零散不成体系难以形成完整的知识框架。本文将以 OpenCV 这一经典计算机视觉库为核心系统讲解从环境搭建到图像分割、目标检测、特征提取等核心技术的完整实战路径涵盖基础概念、代码示例、常见问题及优化方案帮助零基础开发者快速入门并应用到实际项目中。1. OpenCV 基础概念与环境搭建1.1 OpenCV 简介与应用场景OpenCVOpen Source Computer Vision Library是一个开源的计算机视觉和机器学习软件库包含超过2500种优化算法广泛应用于图像处理、视频分析、物体检测、人脸识别、运动跟踪等领域。其核心优势在于跨平台支持 Windows、Linux、macOS、Android、iOS、多语言接口C、Python、Java以及丰富的预训练模型。典型应用场景包括工业检测产品缺陷检测、尺寸测量医疗影像病灶分割、细胞计数安防监控移动目标检测、人脸识别自动驾驶车道线检测、交通标志识别AR/VR图像跟踪、手势识别1.2 环境安装与配置本文以 Python 3.8 和 OpenCV 4.x 为例演示安装过程。推荐使用 Anaconda 管理 Python 环境避免依赖冲突。方法一pip 安装推荐# 安装基础包 pip install opencv-python # 安装完整版包含 contrib 模块 pip install opencv-contrib-python # 安装指定版本 pip install opencv-python4.5.5.64方法二conda 安装conda install -c conda-forge opencv验证安装import cv2 print(cv2.__version__) # 测试基础功能 img cv2.imread(test.jpg) if img is not None: print(图像加载成功) else: print(请准备测试图像)1.3 基础图像操作掌握图像的基本读写和显示是 OpenCV 入门的第一步。import cv2 import numpy as np # 读取图像第二个参数可选cv2.IMREAD_COLOR、cv2.IMREAD_GRAYSCALE、cv2.IMREAD_UNCHANGED img cv2.imread(image.jpg, cv2.IMREAD_COLOR) # 显示图像 cv2.imshow(Original Image, img) cv2.waitKey(0) # 等待按键 cv2.destroyAllWindows() # 关闭所有窗口 # 保存图像 cv2.imwrite(output.jpg, img) # 获取图像属性 print(f图像尺寸: {img.shape}) # (高度, 宽度, 通道数) print(f图像数据类型: {img.dtype}) print(f图像大小: {img.size} 像素)2. 图像滤波与增强技术2.1 图像滤波基础图像滤波主要用于消除噪声、平滑图像、增强特征等。OpenCV 提供了多种线性滤波和非线性滤波方法。均值滤波import cv2 import numpy as np # 生成带噪声的图像 img cv2.imread(image.jpg) noise np.random.normal(0, 25, img.shape).astype(np.uint8) noisy_img cv2.add(img, noise) # 应用均值滤波 blur cv2.blur(noisy_img, (5, 5)) # 5x5 卷积核 # 显示结果对比 cv2.imshow(Noisy Image, noisy_img) cv2.imshow(Blurred Image, blur) cv2.waitKey(0)高斯滤波# 高斯滤波更注重中心像素边缘保留更好 gaussian_blur cv2.GaussianBlur(noisy_img, (5, 5), 0) # 中值滤波对椒盐噪声效果显著 median_blur cv2.medianBlur(noisy_img, 5) # 双边滤波保边去噪 bilateral_blur cv2.bilateralFilter(noisy_img, 9, 75, 75)2.2 图像增强技术图像增强旨在改善图像视觉效果或便于后续处理。直方图均衡化# 转换为灰度图 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 全局直方图均衡化 equ cv2.equalizeHist(gray) # 自适应直方图均衡化 clahe cv2.createCLAHE(clipLimit2.0, tileGridSize(8,8)) clahe_img clahe.apply(gray) # 对比显示 cv2.imshow(Original Gray, gray) cv2.imshow(Global Equalization, equ) cv2.imshow(Adaptive Equalization, clahe_img) cv2.waitKey(0)伽马校正def gamma_correction(image, gamma1.0): # 构建伽马校正查找表 inv_gamma 1.0 / gamma table np.array([((i / 255.0) ** inv_gamma) * 255 for i in np.arange(0, 256)]).astype(uint8) return cv2.LUT(image, table) # 应用不同伽马值 gamma_08 gamma_correction(img, 0.8) # 变亮 gamma_12 gamma_correction(img, 1.2) # 变暗3. 边缘检测技术详解3.1 边缘检测原理边缘检测是识别图像中亮度明显变化的点这些点通常对应物体的边界。常见的边缘检测算法基于一阶或二阶导数。Sobel 算子import cv2 import numpy as np # 读取图像并转为灰度 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Sobel 边缘检测 sobelx cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize5) # x方向 sobely cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize5) # y方向 sobel_combined cv2.magnitude(sobelx, sobely) # 转换为8位无符号整数 sobel_combined np.uint8(np.absolute(sobel_combined)) cv2.imshow(Sobel Edge Detection, sobel_combined) cv2.waitKey(0)Canny 边缘检测Canny 边缘检测是实际项目中最常用的方法包含噪声去除、梯度计算、非极大值抑制和双阈值检测四个步骤。# Canny 边缘检测 edges cv2.Canny(gray, threshold150, threshold2150) # 参数调优建议 def auto_canny(image, sigma0.33): # 计算图像中像素强度的中位数 v np.median(image) # 根据中位数设置上下阈值 lower int(max(0, (1.0 - sigma) * v)) upper int(min(255, (1.0 sigma) * v)) return cv2.Canny(image, lower, upper) auto_edges auto_canny(gray) cv2.imshow(Canny Edges, edges) cv2.imshow(Auto Canny, auto_edges) cv2.waitKey(0)3.2 边缘检测优化技巧在实际应用中边缘检测需要根据具体场景进行调整。多尺度边缘检测# 不同尺度下的边缘检测 scales [1.0, 1.5, 2.0] edge_results [] for scale in scales: # 调整图像尺寸 width int(gray.shape[1] * scale) height int(gray.shape[0] * scale) resized cv2.resize(gray, (width, height)) # 边缘检测 edges cv2.Canny(resized, 50, 150) edge_results.append(edges) # 显示多尺度结果 for i, edges in enumerate(edge_results): cv2.imshow(fScale {scales[i]}, edges) cv2.waitKey(0)4. 图像特征提取方法4.1 传统特征提取算法在深度学习流行之前传统特征提取方法在计算机视觉中占据重要地位。HOG方向梯度直方图特征from skimage.feature import hog from skimage import exposure import matplotlib.pyplot as plt # 计算 HOG 特征 features, hog_image hog(gray, orientations9, pixels_per_cell(8, 8), cells_per_block(2, 2), visualizeTrue, block_normL2-Hys) # 增强 HOG 图像显示效果 hog_image_rescaled exposure.rescale_intensity(hog_image, in_range(0, 10)) # 显示原图和 HG 特征图 plt.figure(figsize(12, 6)) plt.subplot(121), plt.imshow(gray, cmapgray) plt.title(Original Image), plt.axis(off) plt.subplot(122), plt.imshow(hog_image_rescaled, cmapgray) plt.title(HOG Features), plt.axis(off) plt.show() print(fHOG 特征维度: {features.shape})SIFT 特征# 初始化 SIFT 检测器 sift cv2.SIFT_create() # 检测关键点和计算描述符 keypoints, descriptors sift.detectAndCompute(gray, None) # 绘制关键点 img_with_keypoints cv2.drawKeypoints(img, keypoints, None, flagscv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) cv2.imshow(SIFT Keypoints, img_with_keypoints) cv2.waitKey(0) print(f检测到 {len(keypoints)} 个关键点) print(f描述符形状: {descriptors.shape})4.2 特征匹配应用特征提取后常用于图像匹配、目标识别等任务。特征匹配示例# 读取两张图像 img1 cv2.imread(image1.jpg, cv2.IMREAD_GRAYSCALE) img2 cv2.imread(image2.jpg, cv2.IMREAD_GRAYSCALE) # 检测 ORB 特征 orb cv2.ORB_create() kp1, des1 orb.detectAndCompute(img1, None) kp2, des2 orb.detectAndCompute(img2, None) # 创建 BFMatcher 对象 bf cv2.BFMatcher(cv2.NORM_HAMMING, crossCheckTrue) # 特征匹配 matches bf.match(des1, des2) # 按距离排序 matches sorted(matches, keylambda x: x.distance) # 绘制最佳匹配 img_matches cv2.drawMatches(img1, kp1, img2, kp2, matches[:50], None, flags2) cv2.imshow(Feature Matches, img_matches) cv2.waitKey(0)5. 图像分割技术实战5.1 基于阈值的分割阈值分割是最简单直接的分割方法适用于背景和前景对比明显的场景。全局阈值分割# 转换为灰度图 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 简单阈值分割 ret, thresh1 cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 自适应阈值分割 thresh2 cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2) thresh3 cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2) # 显示结果 cv2.imshow(Original, gray) cv2.imshow(Global Threshold, thresh1) cv2.imshow(Adaptive Mean, thresh2) cv2.imshow(Adaptive Gaussian, thresh3) cv2.waitKey(0)Otsu 阈值法# Otsu 自动阈值确定 ret, otsu_thresh cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY cv2.THRESH_OTSU) print(fOtsu 方法确定的最佳阈值: {ret}) # 显示直方图和阈值 plt.figure(figsize(10, 4)) plt.subplot(121) plt.hist(gray.ravel(), 256, [0, 256]) plt.axvline(xret, colorr, linestyle--, labelfThreshold: {ret}) plt.legend() plt.title(Grayscale Histogram) plt.subplot(122) plt.imshow(otsu_thresh, cmapgray) plt.title(Otsu Thresholding) plt.show()5.2 基于边缘的分割结合边缘检测结果进行图像分割。边缘连接与轮廓检测# 边缘检测 edges cv2.Canny(gray, 50, 150) # 形态学操作连接边缘 kernel np.ones((3, 3), np.uint8) closed_edges cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel) # 查找轮廓 contours, hierarchy cv2.findContours(closed_edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 绘制轮廓 contour_img img.copy() cv2.drawContours(contour_img, contours, -1, (0, 255, 0), 2) cv2.imshow(Edges, edges) cv2.imshow(Closed Edges, closed_edges) cv2.imshow(Contours, contour_img) cv2.waitKey(0) print(f检测到 {len(contours)} 个轮廓)5.3 分水岭算法分水岭算法适用于重叠物体的分割。# 读取图像并转为灰度 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化 ret, thresh cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV cv2.THRESH_OTSU) # 噪声去除 kernel np.ones((3, 3), np.uint8) opening cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations2) # 确定背景区域 sure_bg cv2.dilate(opening, kernel, iterations3) # 确定前景区域 dist_transform cv2.distanceTransform(opening, cv2.DIST_L2, 5) ret, sure_fg cv2.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0) # 找到未知区域 sure_fg np.uint8(sure_fg) unknown cv2.subtract(sure_bg, sure_fg) # 标记连通组件 ret, markers cv2.connectedComponents(sure_fg) markers markers 1 markers[unknown 255] 0 # 应用分水岭算法 markers cv2.watershed(img, markers) img[markers -1] [255, 0, 0] # 标记边界为红色 cv2.imshow(Watershed Segmentation, img) cv2.waitKey(0)6. 目标检测实战应用6.1 基于传统方法的目标检测在深度学习之前传统方法如 Haar 级联分类器被广泛使用。人脸检测示例# 加载预训练的人脸检测器 face_cascade cv2.CascadeClassifier(cv2.data.haarcascades haarcascade_frontalface_default.xml) # 检测人脸 faces face_cascade.detectMultiScale(gray, scaleFactor1.1, minNeighbors5, minSize(30, 30)) # 绘制检测框 for (x, y, w, h) in faces: cv2.rectangle(img, (x, y), (xw, yh), (255, 0, 0), 2) cv2.imshow(Face Detection, img) cv2.waitKey(0) print(f检测到 {len(faces)} 张人脸)6.2 基于深度学习的目标检测OpenCV 支持多种深度学习框架的模型。YOLO 目标检测# 加载 YOLO 模型 net cv2.dnn.readNet(yolov3.weights, yolov3.cfg) # 加载类别名称 with open(coco.names, r) as f: classes [line.strip() for line in f.readlines()] # 获取输出层名称 layer_names net.getLayerNames() output_layers [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()] # 准备输入图像 blob cv2.dnn.blobFromImage(img, 0.00392, (416, 416), (0, 0, 0), True, cropFalse) net.setInput(blob) outs net.forward(output_layers) # 解析检测结果 class_ids [] confidences [] boxes [] for out in outs: for detection in out: scores detection[5:] class_id np.argmax(scores) confidence scores[class_id] if confidence 0.5: # 置信度阈值 # 边界框坐标 center_x int(detection[0] * width) center_y int(detection[1] * height) w int(detection[2] * width) h int(detection[3] * height) # 矩形框的左上角坐标 x int(center_x - w / 2) y int(center_y - h / 2) boxes.append([x, y, w, h]) confidences.append(float(confidence)) class_ids.append(class_id) # 非极大值抑制 indexes cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4) # 绘制检测结果 font cv2.FONT_HERSHEY_PLAIN for i in range(len(boxes)): if i in indexes: x, y, w, h boxes[i] label str(classes[class_ids[i]]) confidence confidences[i] color (0, 255, 0) cv2.rectangle(img, (x, y), (x w, y h), color, 2) cv2.putText(img, f{label} {confidence:.2f}, (x, y - 10), font, 1, color, 2) cv2.imshow(YOLO Detection, img) cv2.waitKey(0)7. 人脸识别系统搭建7.1 人脸检测与特征点定位# 使用 DNN 模块进行人脸检测 model_file opencv_face_detector_uint8.pb config_file opencv_face_detector.pbtxt net cv2.dnn.readNetFromTensorflow(model_file, config_file) # 人脸检测 blob cv2.dnn.blobFromImage(img, 1.0, (300, 300), [104, 117, 123]) net.setInput(blob) detections net.forward() # 处理检测结果 for i in range(detections.shape[2]): confidence detections[0, 0, i, 2] if confidence 0.5: x1 int(detections[0, 0, i, 3] * img.shape[1]) y1 int(detections[0, 0, i, 4] * img.shape[0]) x2 int(detections[0, 0, i, 5] * img.shape[1]) y2 int(detections[0, 0, i, 6] * img.shape[0]) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) # 添加置信度文本 text f{confidence:.2f} cv2.putText(img, text, (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2) cv2.imshow(Face Detection DNN, img) cv2.waitKey(0)7.2 人脸识别完整流程import os import numpy as np # 人脸识别器训练 def train_face_recognizer(data_path): faces [] labels [] # 遍历数据集 for person_name in os.listdir(data_path): person_path os.path.join(data_path, person_name) label int(person_name.split(_)[0]) # 假设目录名为1_name格式 for image_name in os.listdir(person_path): image_path os.path.join(person_path, image_name) image cv2.imread(image_path, cv2.IMREAD_GRAYSCALE) # 人脸检测 face_cascade cv2.CascadeClassifier(cv2.data.haarcascades haarcascade_frontalface_default.xml) faces_rect face_cascade.detectMultiScale(image, scaleFactor1.1, minNeighbors5) for (x, y, w, h) in faces_rect: face_roi image[y:yh, x:xw] faces.append(face_roi) labels.append(label) # 创建识别器并训练 recognizer cv2.face.LBPHFaceRecognizer_create() recognizer.train(faces, np.array(labels)) return recognizer # 使用训练好的模型进行识别 def recognize_face(recognizer, test_image): gray cv2.cvtColor(test_image, cv2.COLOR_BGR2GRAY) # 人脸检测 face_cascade cv2.CascadeClassifier(cv2.data.haarcascades haarcascade_frontalface_default.xml) faces face_cascade.detectMultiScale(gray, 1.1, 5) for (x, y, w, h) in faces: face_roi gray[y:yh, x:xw] # 预测 label, confidence recognizer.predict(face_roi) # 绘制结果 cv2.rectangle(test_image, (x, y), (xw, yh), (0, 255, 0), 2) text fPerson {label} ({confidence:.2f}) cv2.putText(test_image, text, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2) return test_image8. 性能优化与工程实践8.1 OpenCV 性能优化技巧在实际项目中性能优化至关重要。图像处理优化import time # 测量执行时间 start_time time.time() # 批量处理优化 def batch_process_images(image_paths): results [] for path in image_paths: img cv2.imread(path) if img is not None: # 使用更高效的函数 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) blurred cv2.GaussianBlur(gray, (3, 3), 0) edges cv2.Canny(blurred, 50, 150) results.append(edges) return results # 使用多线程处理 from concurrent.futures import ThreadPoolExecutor def parallel_process_images(image_paths, max_workers4): with ThreadPoolExecutor(max_workersmax_workers) as executor: results list(executor.map(process_single_image, image_paths)) return results def process_single_image(path): img cv2.imread(path) if img is not None: gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) return cv2.Canny(gray, 50, 150) return None end_time time.time() print(f处理时间: {end_time - start_time:.2f} 秒)8.2 内存管理与资源释放# 正确的资源管理 def safe_image_processing(image_path): img None try: img cv2.imread(image_path) if img is not None: # 处理图像 processed process_image(img) return processed else: print(f无法读取图像: {image_path}) return None except Exception as e: print(f处理图像时出错: {e}) return None finally: # 确保资源释放 if img in locals(): del img cv2.destroyAllWindows() def process_image(img): # 图像处理逻辑 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) return cv2.GaussianBlur(gray, (5, 5), 0)9. 常见问题与解决方案9.1 环境配置问题问题1ModuleNotFoundError: No module named cv2原因OpenCV 未正确安装或环境路径问题解决方案# 重新安装 pip uninstall opencv-python pip install opencv-python # 或者尝试 pip install opencv-python-headless问题2CUDA 相关错误原因GPU 版本配置问题解决方案# 检查 CUDA 支持 print(cv2.cuda.getCudaEnabledDeviceCount()) # 如果没有 GPU使用 CPU 版本 cv2.setUseOptimized(True) cv2.setNumThreads(4)9.2 图像处理常见问题问题3图像读取返回 None原因文件路径错误、格式不支持或文件损坏解决方案import os # 检查文件是否存在 if os.path.exists(image.jpg): img cv2.imread(image.jpg) if img is None: print(文件可能损坏或格式不支持) # 尝试其他格式 img cv2.imread(image.png) else: print(文件不存在)问题4内存不足错误原因处理大图像或批量处理时内存溢出解决方案# 调整图像尺寸 def resize_image(img, max_dimension1024): height, width img.shape[:2] if max(height, width) max_dimension: scale max_dimension / max(height, width) new_size (int(width * scale), int(height * scale)) return cv2.resize(img, new_size) return img # 使用生成器处理大文件 def image_generator(image_paths, batch_size10): for i in range(0, len(image_paths), batch_size): batch_paths image_paths[i:ibatch_size] batch_images [] for path in batch_paths: img cv2.imread(path) if img is not None: batch_images.append(img) yield batch_images10. 项目实战综合应用案例10.1 文档扫描仪实现结合边缘检测、透视变换等技术实现文档扫描功能。def document_scanner(image_path): # 读取图像 img cv2.imread(image_path) original img.copy() # 预处理 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) blurred cv2.GaussianBlur(gray, (5, 5), 0) edged cv2.Canny(blurred, 75, 200) # 查找轮廓 contours, _ cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) contours sorted(contours, keycv2.contourArea, reverseTrue)[:5] # 寻找文档轮廓 screen_cnt None for c in contours: peri cv2.arcLength(c, True) approx cv2.approxPolyDP(c, 0.02 * peri, True) if len(approx) 4: screen_cnt approx break if screen_cnt is not None: # 透视变换 warped four_point_transform(original, screen_cnt.reshape(4, 2)) # 二值化 warped_gray cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY) _, thresh cv2.threshold(warped_gray, 0, 255, cv2.THRESH_BINARY cv2.THRESH_OTSU) return warped, thresh else: print(未找到文档轮廓) return None, None def four_point_transform(image, pts): # 获取坐标点并排序 rect order_points(pts) (tl, tr, br, bl) rect # 计算新图像宽度 widthA np.sqrt(((br[0] - bl[0]) ** 2) ((br[1] - bl[1]) ** 2)) widthB np.sqrt(((tr[0] - tl[0]) ** 2) ((tr[1] - tl[1]) ** 2)) maxWidth max(int(widthA), int(widthB)) # 计算新图像高度 heightA np.sqrt(((tr[0] - br[0]) ** 2) ((tr[1] - br[1]) ** 2)) heightB np.sqrt(((tl[0] - bl[0]) ** 2) ((tl[1] - bl[1]) ** 2)) maxHeight max(int(heightA), int(heightB)) # 构建变换矩阵 dst np.array([ [0, 0], [maxWidth - 1, 0], [maxWidth - 1, maxHeight - 1], [0, maxHeight - 1]], dtypefloat32) # 应用透视变换 M cv2.getPerspectiveTransform(rect, dst) warped cv2.warpPerspective(image, M, (maxWidth, maxHeight)) return warped def order_points(pts): # 初始化坐标点 rect np.zeros((4, 2), dtypefloat32) # 左上角点有最小的xy和右下角点有最大的xy和 s pts.sum(axis1) rect[0] pts[np.argmin(s)] rect[2] pts[np.argmax(s)] # 计算点之间的差值右上角点有最小的x-y差左下角点有最大的x-y差 diff np.diff(pts, axis1) rect[1] pts[np.argmin(diff)] rect[3] pts[np.argmax(diff)] return rect10.2 实时视频处理系统实现实时视频流的目标检测和跟踪。import cv2 import numpy as np def real_time_object_detection(): # 初始化摄像头 cap cv2.VideoCapture(0) # 设置摄像头参数 cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) cap.set(cv2.CAP_PROP_FPS, 30) # 加载目标检测模型 net cv2.dnn.readNet(yolov3-tiny.weights, yolov3-tiny.cfg) while True: ret, frame cap.read() if not ret: break # 目标检测 blob cv2.dnn.blobFromImage(frame, 1/255.0, (416, 416), swapRBTrue, cropFalse) net.setInput(blob) outputs net.forward(net.getUnconnectedOutLayersNames()) # 处理检测结果 boxes, confidences, class_ids process_detections(outputs, frame.shape) # 非极大值抑制 indices cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4) if len(indices) 0: for i in indices.flatten(): x, y, w, h boxes[i] cv2.rectangle(frame, (x, y), (x w, y h), (0, 255, 0), 2) cv2.putText(frame, fObject {confidences[i]:.2f}, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2) # 显示帧率 cv2.putText(frame, fFPS: {int(cap.get(cv2.CAP_PROP_FPS))}, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) cv2.imshow(Real-time Detection, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows() def process_detections(outputs, shape): height, width shape[:2] boxes [] confidences [] class_ids [] for output in outputs: for detection in output: scores detection[5:] class_id np.argmax(scores) confidence scores[class_id] if confidence 0.5: center_x int(detection[0] * width) center_y int(detection[1] * height) w int