|  |  | @ -0,0 +1,182 @@ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | # yolov4-tiny目标检测 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | import cv2 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | import numpy as np | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | from myFunction import drawButton | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | #(1)导入yolov4-tiny网络模型结构 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | # 传入模型结构.cfg文件,模型权重参数.weight文件 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | net = cv2.dnn.readNet('dnn_model\yolov4-tiny.cfg', 'dnn_model\yolov4-tiny.weights') | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | # 定义一个目标检测模型,将模型传进去 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | model = cv2.dnn_DetectionModel(net) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | ''' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 设置模型的输入 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | size:将输入的图像缩放至指定大小。size越大检测效果越好,但是检测速度越慢 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | scale:像素值的缩放大小。在opencv中每个像素值的范围在0-255之间,而在神经网络中每个像素值在0-1之间 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | ''' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | model.setInputParams(size=(416, 416), scale=1/255) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | #(2)获取分类文本的信息 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | classes = []  # 存放每个分类的名称 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | with open('dnn_model\classes.txt') as file_obj: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     # 获取文本中的每一行 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     for class_name in file_obj.readlines(): | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         # 删除文本中的换行符、空格等 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         class_name = class_name.strip() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         # 将每个分类名保存到列表中 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         classes.append(class_name) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | #(3)视频捕获 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | filepath = 'F:\\yolov4-tiny\\1.mp4' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | cap = cv2.VideoCapture(filepath)   | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | #(4)创建鼠事件 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | # 创建按钮,默认停用 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | button_class = False | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | button_index = None  # 存放哪个按键被点亮了 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | # 定义鼠标回调函数 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | def click_button(event, x, y, flags, params): | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     # 调用外部变量 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     global button_class | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     global button_index | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     # 设置事鼠标件event为点击鼠标左键 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     if event == cv2.EVENT_LBUTTONDOWN: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |          | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         # 检查鼠标的坐标是否在矩形框按键内部,index代表第几个按钮 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         # 遍历每个矩形框,每个框包含四个角的坐标 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         for index, pt in enumerate(np.array(buttonList)):  # 要转换成numpy类型   | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |              | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             # 如果设为True,计算鼠标左键距离矩形框的距离 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             is_inside = cv2.pointPolygonTest(pt, (x,y), False) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |              | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             if is_inside > 0:  # 鼠标在矩形框内部 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                  | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 print(f'click in the No.{index+1}', (x,y)) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                  | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 # 如果鼠标点击位置在矩形框内部,并且上一次没点击 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 if button_class == False: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     # 激活按钮 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     button_class = True | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     # 激活哪个分类的检测框 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     button_index = index | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                      | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |              | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             # 如果鼠标点击位置不在矩形框内部 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             else: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                   button_class = False | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                  | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | #(5)创建窗口 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | cv2.namedWindow('Image')  # 窗口名和显示图像的窗口名相同 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | # 设置鼠标回调,窗口名和上面相同,自定义回调函数 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | cv2.setMouseCallback('Image', click_button) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | # 创建按钮 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | usenames = ['all', 'person', 'car', 'bus', 'truck'] | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | button = drawButton(usenames) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | #(6)定义检测框绘制函数 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | colorline = (0,255,0)  # 角点线段颜色 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | angerline = 13  # 角点线段长度 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | def drawbbx(img, x, y, w, h, predName, score): | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     # 检测框 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     cv2.rectangle(img, (x, y), (x+w, y+h), (255,255,0), 1) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     # 角点美化 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     cv2.line(img, (x,y), (x+angerline,y), colorline, 2) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     cv2.line(img, (x,y), (x,y+angerline), colorline, 2)     | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     cv2.line(img, (x+w,y), (x+w,y+angerline), colorline, 2) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     cv2.line(img, (x+w,y), (x+w-angerline,y), colorline, 2) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     cv2.line(img, (x,y+h), (x,y+h-angerline), colorline, 2) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     cv2.line(img, (x,y+h), (x+angerline,y+h), colorline, 2) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     cv2.line(img, (x+w,y+h), (x+w,y+h-angerline), colorline, 2)     | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     cv2.line(img, (x+w,y+h), (x+w-angerline,y+h), colorline, 2) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     # 显示预测的类别 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     cv2.putText(img, predName, (x,y+h+20), cv2.FONT_HERSHEY_COMPLEX, 1, (0,255,0), 2) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     # 显示预测概率 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     cv2.putText(img, str(int(score*100))+'%', (x,y-5), cv2.FONT_HERSHEY_COMPLEX, 1, (0,255,255), 2) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | #(6)对每一帧视频图像处理 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | while True: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     # 返回是否读取成功ret和读取的帧图像frame | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ret, frame = cap.read() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     # 图像比较大把它缩小一点 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     frame = cv2.resize(frame, (1280,720)) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     # 视频比较短,循环播放 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     if cap.get(cv2.CAP_PROP_POS_FRAMES) == cap.get(cv2.CAP_PROP_FRAME_COUNT): | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |          | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         # 如果当前帧==总帧数,那就重置当前帧为0 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         cap.set(cv2.CAP_PROP_POS_FRAMES, 0) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     # 目标检测 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ''' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     返回值 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     classids:检测得到的类别 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     score:检测得到的目标的概率 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     bbox:检测框的85项信息 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     参数 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     confThreshold:目标检测最小置信度 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     nmsThreshold:非极大值抑制的自定义参数 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ''' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     classids, scores, bboxes = model.detect(frame, 0.5, 0.3) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     # 在画面上创建按钮 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     button.drawRec_many(frame) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     # 获取所有矩形框的四个角的坐标 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     buttonList = button.recList   | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     #(7)显示检测结果 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     # 遍历所有的检测框信息,把它们绘制出来 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     for class_id, score, bbox in zip(classids, scores, bboxes): | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |          | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         # 获取检测框的左上角坐标和宽高 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         x, y, w, h = bbox | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |          | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         # 获取检测框对应的分类名 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         class_name = classes[class_id] | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |          | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |          | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         # 遍历四个按键的名称 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         for index, name in enumerate(usenames): | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |          | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             # 设置检测条件,只有检测到的类别是person并且鼠标点击位置在矩形框内 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             if class_name == name and index == button_index: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |              | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 # 绘制class_name类别的检测框 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 drawbbx(frame, x, y, w, h, class_name, score)                 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |              | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             elif name == 'all' and index == button_index: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                  | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 # 绘制所有类别的检测框 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 drawbbx(frame, x, y, w, h, class_name, score) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     # 显示图像 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     cv2.imshow('Image', frame)  #窗口名,图像变量 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     if cv2.waitKey(30) & 0xFF==27:  #每帧滞留1毫秒后消失 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         break | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | # 释放视频资源 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | cap.release() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | cv2.destroyAllWindows() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 |