找回密码
 会员注册
查看: 19|回复: 0

使用Python和OpenCV进行实时目标检测的详解

[复制链接]

2万

主题

0

回帖

6万

积分

超级版主

积分
65034
发表于 2024-9-10 20:30:53 | 显示全部楼层 |阅读模式
使用到的模型文件我已经上传了,但是不知道能否通过审核,无法通过审核的话,就只能靠大家自己发挥实力了,^_^目录简介代码介绍代码拆解讲解1.首先,让我们导入需要用到的库:2.然后,设置两个阈值:conf_threshold和nms_threshold,以及图片的宽度和高度:3.接下来,我们加载预训练的YOLOv3模型,并加载识别的类名:4.然后,我们创建一个颜色列表,以在最后的目标检测结果中为不同的类别绘制不同的颜色:5.下一步,我们定义两个函数fetch_frame和process_frame6.在主循环中,我们使用ThreadPoolExecutor实现了并行处理读取帧和模型推理的操作。7.退出程序总体代码效果展示​编辑使用GPU说明如何操作1.在读取模型时启用CUDA:2.其它代码不需要做太多修改:总结     简介        这段程序是一个Python脚本,它使用了OpenCV库和预训练的YOLOv3模型来实现实时视频流的目标检测。它首先从摄像头捕获视频流,并使用线程池处理每一帧图像。在每一帧中,程序都会检测和识别不同的对象,并用不同的颜色显示结果。使用了非极大值抑制技术删除重复的检测框,并利用了并发处理技术以提高性能。最后,他还显示了每秒处理的帧数(FPS)。我们可以通过按'q'键来结束程序。这个程序展示了一种有效的使用深度学习模型进行实时视觉任务的方法。        代码介绍        这段代码是使用OpenCV和Python编写的,主要用于实时视频流处理和目标检测。代码的核心是使用训练好的YOLOv3模型来识别和定位视频帧中的对象。下面是对整个流程的详细解释:导入库:首先,导入所需的库,包括cv2(OpenCV),numpy(用于科学计算),time(时间管理),以及concurrent.futures(用于并发执行)。初始化参数:设置检测参数,包括置信度阈值(用于过滤掉那些置信度低于阈值的检测结果),非极大值抑制(NMS)阈值(用于去除重复的检测框),以及输入图像的宽和高。加载模型和类别:通过使用cv2.dnn.readNet加载预训练的YOLOv3模型,并从coco.names文件中加载可以识别的类名列表。颜色列表:为每个可识别的类别创建一个随机颜色列表,这用于在检测到的对象周围绘制彩色的边界框。视频捕获:打开摄像头进行视频流的捕获。多线程处理:初始化ThreadPoolExecutor以并发执行多个任务。这里定义了两个函数fetch_frame和process_frame。fetch_frame用于从视频流中获取一帧图像,而process_frame则用于处理图像并执行目标检测。目标检测流程:转换输入帧:将输入帧转换为模型所需要的格式(blob),包括缩放、颜色空间转换等。执行检测:调用神经网络模型执行前向传播,获取检测结果。过滤结果:根据置信度阈值和NMS阈值过滤掉一部分检测结果,消除低置信度以及重复的检测框。绘制边界框和类别标签:在原图上绘制检测到的对象的边界框,并显示类别名称和置信度。显示结果:在屏幕上实时显示处理后的视频帧,并计算显示FPS(每秒帧数)。程序退出:等待我们按q键退出,并在退出前释放资源,包括摄像头和窗口。        这段代码的设计利用了异步处理技术(通过ThreadPoolExecutor)来提高处理视频流的效率,使得帧的捕获和处理能够并行执行,从而尽可能提高FPS。    为什么这样做,主要是我的电脑没有独立GPU,所以,呃,只能动点这中方法了,但是说实话并没有什么实质性的提升,难受了。代码拆解讲解        我们将使用预训练的YOLOv3模型进行目标检测,并使用Python的concurrent.futures库来并行处理视频帧的读取和模型推理,以优化程序的执行速度。    感谢YOLO,虽然现在已经发展到v8了,但是我们这里使用v3还是足够了。1.首先,让我们导入需要用到的库:importcv2importnumpyasnpimporttimefromconcurrent.futuresimportThreadPoolExecutor2.然后,设置两个阈值:conf_threshold和nms_threshold,以及图片的宽度和高度:conf_threshold=0.5nms_threshold=0.4Width=416Height=416'运行运行3.接下来,我们加载预训练的YOLOv3模型,并加载识别的类名:net=cv2.dnn.readNet('../needFiles/yolov3.weights','../needFiles/yolov3.cfg')withopen('../needFiles/coco.names','r')asf:classes=f.read().strip().split('\n')4.然后,我们创建一个颜色列表,以在最后的目标检测结果中为不同的类别绘制不同的颜色:color_list=np.random.uniform(0,255,size=(len(classes),3))5.下一步,我们定义两个函数fetch_frame和process_frame        fetch_frame用于从视频对象读取一帧;而process_frame则将读取到的帧输入到YOLOv3模型中,然后处理获得的输出结果,并在帧上绘制物体检测结果:deffetch_frame(cap):...defprocess_frame(frame):...'运行运行6.在主循环中,我们使用ThreadPoolExecutor实现了并行处理读取帧和模型推理的操作。        这样可以使读取下一帧的操作和模型推理操作同时进行,从而显著地加快了处理速度:executor=ThreadPoolExecutor(max_workers=2)frame_future=executor.submit(fetch_frame,cap)whileTrue:...ret,frame,height,width,channels=frame_future.result()frame_future=executor.submit(fetch_frame,cap)processed_frame=executor.submit(process_frame,frame).result()...7.退出程序        在这段代码的最后,如果你按下q键退出主循环,视频读取对象将会被释放,所有的窗口也将被销毁:ifcv2.waitKey(1)&0xFF==ord('q'):break...cap.release()cv2.destroyAllWindows()总体代码#导入必要的库importcv2importnumpyasnpimporttimefromconcurrent.futuresimportThreadPoolExecutor#设置置信度阈值和非极大值抑制(NMS)阈值conf_threshold=0.5nms_threshold=0.4Width=416Height=416#加载预训练的YOLOv3模型net=cv2.dnn.readNet('../needFiles/yolov3.weights','../needFiles/yolov3.cfg')#加载可识别的类名withopen('../needFiles/coco.names','r')asf:classes=f.read().strip().split('\n')#为不同的类别创建一个颜色列表color_list=np.random.uniform(0,255,size=(len(classes),3))#打开摄像头进行视频帧的捕获cap=cv2.VideoCapture(0)#初始化一个ThreadPoolExecutor用于多线程处理executor=ThreadPoolExecutor(max_workers=2)#定义fetch_frame函数,从视频流中获取视频帧deffetch_frame(cap):ret,frame=cap.read()#读取一帧图像height,width,channels=frame.shape#获取图像的尺寸和通道信息returnret,frame,height,width,channels#定义process_frame函数,处理每帧图像并进行目标检测defprocess_frame(frame):#将帧转换为模型的输入格式blob=cv2.dnn.blobFromImage(frame,1/255.0,(416,416),swapRB=True,crop=False)net.setInput(blob)output_layers=net.getUnconnectedOutLayersNames()#获取输出层的名字layer_outputs=net.forward(output_layers)#进行前向传播,获取检测结果boxes=[]#用于存储检测到的边界框confidences=[]#用于存储边界框的置信度class_ids=[]#用于存储边界框的类别ID#循环每个输出层的检测结果foroutputinlayer_outputs:fordetectioninoutput:scores=detection[5:]#获取类别的得分class_id=np.argmax(scores)#获取得分最高的类别IDconfidence=scores[class_id]#获取得分最高的置信度#过滤低置信度的检测结果ifconfidence>conf_threshold: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)#将边界框的位置、尺寸、置信度和类别ID添加到列表中boxes.append([x,y,w,h])confidences.append(float(confidence))class_ids.append(class_id)#使用非极大值抑制去除重叠的边界框indices=cv2.dnn.NMSBoxes(boxes,confidences,conf_threshold,nms_threshold)#在原图上绘制边界框和类别标签foriinindices.flatten():box=boxes[i]x=box[0]y=box[1]w=box[2]h=box[3]label=str(classes[class_ids[i]])color=color_list[class_ids[i]]cv2.rectangle(frame,(x,y),(x+w,y+h),color,2)cv2.putText(frame,label,(x,y-10),cv2.FONT_HERSHEY_SIMPLEX,0.5,color,2)returnframe#在进入循环前,先读取一帧以开始异步处理frame_future=executor.submit(fetch_frame,cap)#主循环whileTrue:start=time.time()#记录开始处理的时间点#获取当前帧和相应信息ret,frame,height,width,channels=frame_future.result()#异步读取下一帧frame_future=executor.submit(fetch_frame,cap)#如果当前帧读取成功,则继续处理ifret:#使用线程池异步处理当前帧processed_frame=executor.submit(process_frame,frame).result()#计算FPSend=time.time()fps=1/(end-start)#在处理好的帧上显示FPScv2.putText(processed_frame,"FPS:"+str(round(fps,2)),(10,30),cv2.FONT_HERSHEY_SIMPLEX,0.6,(0,255,0),2)#显示处理好的帧cv2.imshow('frame',processed_frame)#如果我们按下‘q’键,退出循环ifcv2.waitKey(1)&0xFF==ord('q'):breakelse:break#如果帧没有被成功读取,退出循环#释放视频捕获对象和销毁所有OpenCV窗口cap.release()cv2.destroyAllWindows()效果展示        这个效果还是不错的哈,就是这个硬件性能跟不上,要是有独显就好了。 使用GPU说明    当然了,为了在大学时期狠狠的奖励自己四年游戏,很多同学应该都是购买的游戏本,那么恭喜你,你的硬件非常的完美,那么这里你可以看一下。如何操作        如果你想利用GPU加速你的目标检测代码,主要更改会集中在如何让OpenCV利用你的GPU。不幸的是,OpenCV的 dnn 模块默认使用CPU进行计算。想要使用GPU,首要条件是你需要有一个支持CUDA的NVIDIAGPU。        从OpenCV4.2版本开始,dnn 模块添加了对CUDA的支持,但实现这一点需要确保你的OpenCV是用CUDA支持构建的。如果你自己编译OpenCV,确保在编译时启用了CUDA支持。以下是如何更改你的代码以利用CUDA的基本步骤:1.在读取模型时启用CUDA:替换代码中的 readNet 调用,使用 readNetFromDarknet 并添加代码来设置网络的首选后端和目标为CUDA。#加载预训练的YOLOv3模型net=cv2.dnn.readNetFromDarknet('../needFiles/yolov3.cfg','../needFiles/yolov3.weights')#启用CUDAnet.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)2.其它代码不需要做太多修改:        使用CUDA优化后,主要是模型推理过程(即net.forward()的调用)会更快。数据准备和后处理(例如非极大值抑制)的代码不需要太多修改,因为它们仍然在CPU上执行。        这些改动仅在你已有OpenCV版本支持CUDA,并且你的系统拥有合适的NVIDIAGPU时有效。如果你的环境满足这些条件,这样的更改可以显著加快模型推理的速度,尤其是在进行视频流处理时。        最后,你一定要确定你的环境(包括NVIDIA驱动程序和CUDAToolkit)被正确设置以支持GPU加速。如果你对如何编译支持CUDA的OpenCV或如何配置你的系统环境有任何疑问,我建议查阅OpenCV官方文档和NVIDIA的CUDA安装指导,因为我真的没有仔细研究过。总结             希望这篇博客对你有所帮助。最后我想说,虽然NVIDIA对我们的学习有帮助,但是我还是想说。AMDyes!!!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-29 13:33 , Processed in 0.838141 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表