当前位置:   article > 正文

使用OpenCV和YOLOv8制作目标检测器(附源码)

import subprocess import ultralytics from ultralytics import yolo if __name_

2bec3750e364385254348b7dff301fbf.gif

大家好,我是小F~

YOLO(You Only Look Once)是由Joseph Redmon和Ali开发的一种对象检测和图像分割模型

YOLO的第一个版本于2015年发布,由于其高速度和准确性,瞬间得到了广大AI爱好者的喜爱。

0f29dcf06c5f3cdff9d1368391344221.png

Ultralytics YOLOv8则是一款前沿、最先进(SOTA)的模型,基于先前YOLO版本的成功,引入了新功能和改进,进一步提升性能和灵活性。

YOLOv8设计快速、准确且易于使用,使其成为各种物体检测与跟踪、实例分割、图像分类和姿态估计任务的绝佳选择。

15372bc7a7b88d24769bd774f6bc51a8.png

项目地址:

https://github.com/ultralytics/ultralytics

其中官方提供了示例,通过Python代码即可实现YOLOv8对象检测算法模型,使用预训练模型来检测我们的目标。

而且对电脑需求也不高,CPU就能运行代码

今天小F就给大家介绍三个使用YOLOv8制作的检测器,非常实用。

/ 01 /

行人检测器

使用YOLOv8精确检测行人。

并且设定行人计数区域,实现实时计算区域内行人的数量。

af0c662af643b50beb6d16ba1c1b7a1c.png

这项技术可以制作一个,人员密集场所客流量统计监测系统。

非常适合火车站、地铁站、机场等场景,实现客流安全管理。

使用到Python版本即相关Python库。

  1. Python 3.9.7
  2. supervision 0.2.0
  3. ultralytics 8.0.154
  4. torchvision 0.13.0
  5. opencv-contrib-python 4.8.0.74
  6. opencv-python 4.8.0.74

其中OpenCV库大家应该都不陌生。

5caef10359f662de34ecd633dd521d20.png

supervision库是一个可重复使用的计算机视觉工具,帮助处理数据集、检测结果等工作。

可以降低我们学习计算机视觉的难度~

项目地址:

https://github.com/roboflow/supervision

接下来就先看一下全区域的行人检测代码吧!

  1. import numpy as np
  2. import supervision as sv
  3. from ultralytics import YOLO
  4. class CountObject():
  5.     def __init__(self, input_video_path, output_video_path) -> None:
  6.         # 加载YOLOv8模型
  7.         self.model = YOLO('yolov8s.pt')
  8.         # 输入视频, 输出视频
  9.         self.input_video_path = input_video_path
  10.         self.output_video_path = output_video_path
  11.         # 视频信息
  12.         self.video_info = sv.VideoInfo.from_video_path(input_video_path)
  13.         # 检测框属性
  14.         self.box_annotator = sv.BoxAnnotator(thickness=4, text_thickness=4, text_scale=2)
  15.     def process_frame(self, frame: np.ndarray, _) -> np.ndarray:
  16.         # 检测
  17.         results = self.model(frame, imgsz=1280)[0]
  18.         detections = sv.Detections.from_yolov8(results)
  19.         detections = detections[detections.class_id == 0]
  20.         # 绘制检测框
  21.         box_annotator = sv.BoxAnnotator(thickness=4, text_thickness=4, text_scale=2)
  22.         labels = [f"{self.model.names[class_id]} {confidence:0.2f}" for _, confidence, class_id, _ in detections]
  23.         frame = box_annotator.annotate(scene=frame, detections=detections, labels=labels)
  24.         return frame
  25.     def process_video(self):
  26.         # 处理视频
  27.         sv.process_video(source_path=self.input_video_path, target_path=self.output_video_path,
  28.                          callback=self.process_frame)
  29. if __name__ == "__main__":
  30.     obj = CountObject('demo.mp4''single.mp4')
  31.     obj.process_video()

运行代码,结果如下。

e074386d177379fc88877e8d1c513599.gif

发现检测效果还不错,目标的置信度都挺高的。

进行区域划分,编写算法,判断不同区域内的人员数量。

  1. import numpy as np
  2. import supervision as sv
  3. from ultralytics import YOLO
  4. class CountObject():
  5.     def __init__(self, input_video_path, output_video_path) -> None:
  6.         # 加载YOLOv8模型
  7.         self.model = YOLO('yolov8s.pt')
  8.         # 设置颜色
  9.         self.colors = sv.ColorPalette.default()
  10.         # 输入视频, 输出视频
  11.         self.input_video_path = input_video_path
  12.         self.output_video_path = output_video_path
  13.         # 多边形区域
  14.         self.polygons = [
  15.             np.array([
  16.                 [540985],
  17.                 [1620985],
  18.                 [21601920],
  19.                 [16202855],
  20.                 [5402855],
  21.                 [01920]
  22.             ], np.int32),
  23.             np.array([
  24.                 [01920],
  25.                 [540985],
  26.                 [00]
  27.             ], np.int32),
  28.             np.array([
  29.                 [1620985],
  30.                 [21601920],
  31.                 [21600]
  32.             ], np.int32),
  33.             np.array([
  34.                 [540985],
  35.                 [00],
  36.                 [21600],
  37.                 [1620985]
  38.             ], np.int32),
  39.             np.array([
  40.                 [01920],
  41.                 [03840],
  42.                 [5402855]
  43.             ], np.int32),
  44.             np.array([
  45.                 [21601920],
  46.                 [16202855],
  47.                 [21603840]
  48.             ], np.int32),
  49.             np.array([
  50.                 [16202855],
  51.                 [5402855],
  52.                 [03840],
  53.                 [21603840]
  54.             ], np.int32)
  55.         ]
  56.         # 视频信息
  57.         self.video_info = sv.VideoInfo.from_video_path(input_video_path)
  58.         # 多边形区域
  59.         self.zones = [
  60.             sv.PolygonZone(
  61.                 polygon=polygon,
  62.                 frame_resolution_wh=self.video_info.resolution_wh
  63.             )
  64.             for polygon
  65.             in self.polygons
  66.         ]
  67.         # 区域计数数量标识属性
  68.         self.zone_annotators = [
  69.             sv.PolygonZoneAnnotator(
  70.                 zone=zone,
  71.                 color=self.colors.by_idx(index),
  72.                 thickness=6,
  73.                 text_thickness=8,
  74.                 text_scale=4
  75.             )
  76.             for index, zone
  77.             in enumerate(self.zones)
  78.         ]
  79.         # 检测框绘制属性
  80.         self.box_annotators = [
  81.             sv.BoxAnnotator(
  82.                 color=self.colors.by_idx(index),
  83.                 thickness=4,
  84.                 text_thickness=4,
  85.                 text_scale=2
  86.             )
  87.             for index
  88.             in range(len(self.polygons))
  89.         ]
  90.     def process_frame(self, frame: np.ndarray, i) -> np.ndarray:
  91.         # 检测
  92.         results = self.model(frame, imgsz=1280)[0]
  93.         detections = sv.Detections.from_yolov8(results)
  94.         detections = detections[(detections.class_id == 0) & (detections.confidence > 0.5)]
  95.         # 绘制区域、区域数量、检测框
  96.         for zone, zone_annotator, box_annotator in zip(self.zones, self.zone_annotators, self.box_annotators):
  97.             mask = zone.trigger(detections=detections)
  98.             detections_filtered = detections[mask]
  99.             frame = box_annotator.annotate(scene=frame, detections=detections_filtered, skip_label=True)
  100.             frame = zone_annotator.annotate(scene=frame)
  101.         return frame
  102.     def process_video(self):
  103.         # 处理视频
  104.         sv.process_video(source_path=self.input_video_path, target_path=self.output_video_path,
  105.                          callback=self.process_frame)
  106. if __name__ == "__main__":
  107.     obj = CountObject('demo.mp4''multiple.mp4')
  108.     obj.process_video()

运行代码,结果如下。

ad8c4938f7d20c19e2f8403650d05786.gif

这样每个区域的行人就计算展示出来了。

/ 02 /

小狗检测器

小狗检测器,防止小狗跳到沙发上,留下一团毛~

非常适合想要训练宠物,或者保护家具的宠物主人。

2585d3d704af8471756431c0ca0e47a8.png

实现实时检测小狗,并且在小狗爬上沙发后触发报警。

其中报警推送可以设置成微信or短信,也是可以实现的。

具体代码如下。

  1. import io
  2. import os
  3. import cv2
  4. import telebot
  5. import threading
  6. import numpy as np
  7. from PIL import Image
  8. import pygame as pygame
  9. from ultralytics import YOLO
  10. from datetime import datetime, timedelta
  11. # 设置报警机器人, 可以使用微信替代
  12. # telegram_key = ""
  13. # chat_id = ""
  14. # bot = telebot.TeleBot(telegram_key)
  15. # shared_frame = None
  16. # 发消息
  17. # def send_message(chat_id, message):
  18. #     bot.send_message(chat_id, message)
  19. #
  20. # 发图片
  21. # def send_photo(chat_id, frame):
  22. #     img_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
  23. #     img = Image.fromarray(img_rgb)
  24. #
  25. #     bio = io.BytesIO()
  26. #     bio.name = 'image.jpeg'
  27. #     img.save(bio, 'JPEG')
  28. #     bio.seek(0)
  29. #
  30. #     bot.send_photo(chat_id, bio)
  31. # 监听
  32. # def telegram_listener():
  33. #     @bot.message_handler(func=lambda messageTrue)
  34. #     def echo_all(message):
  35. #         if message.text == "update":
  36. #             global shared_frame
  37. #             if shared_frame is not None:
  38. #                 send_photo(chat_id, shared_frame)
  39. #     bot.polling()
  40. # 报警机器人
  41. # telegram_thread = threading.Thread(target=telegram_listener)
  42. # telegram_thread.start()
  43. # 时间计算
  44. last_sent_time = datetime.now() - timedelta(seconds=15)
  45. # 加载模型
  46. model = YOLO("yolov8n.pt")
  47. # 检测类别
  48. classes = [
  49.     'person''bicycle''car''motorcycle''airplane''bus''train''truck',
  50.     'boat''traffic light''fire hydrant''stop sign''parking meter''bench',
  51.     'bird''cat''dog''horse''sheep''cow''elephant''bear''zebra',
  52.     'giraffe''backpack''umbrella''handbag''tie''suitcase''frisbee''skis',
  53.     'snowboard''sports ball''kite''baseball bat''baseball glove''skateboard',
  54.     'surfboard''tennis racket''bottle''wine glass''cup''fork''knife''spoon',
  55.     'bowl''banana''apple''sandwich''orange''broccoli''carrot''hot dog',
  56.     'pizza''donut''cake''chair''couch''potted plant''bed''dining table',
  57.     'toilet''tv''laptop''mouse''remote''keyboard''cell phone''microwave',
  58.     'oven''toaster''sink''refrigerator''book''clock''vase''scissors',
  59.     'teddy bear''hair drier''toothbrush'
  60. ]
  61. # 初始化pygame, 加载报警音乐
  62. pygame.init()
  63. pygame.mixer.init()
  64. alarm_played = False
  65. pygame.mixer.music.load(os.path.abspath('alarm.mp3'))
  66. COLORS = np.random.uniform(0255, size=(len(classes), 3))
  67. # 加载视频
  68. cap = cv2.VideoCapture('test_video1.mp4')
  69. fps_camera = cap.get(cv2.CAP_PROP_FPS)
  70. target_fps = 10
  71. n = int(fps_camera / target_fps)
  72. frame_counter, not_detected = 00
  73. while True:
  74.     ret, frame = cap.read()
  75.     if not ret:
  76.         break
  77.     shared_frame = frame
  78.     if frame_counter % n == 0:
  79.         # 检测
  80.         outs = model(frame, task='detect', iou=0.2, conf=0.3, show=True, save_conf=True, classes=[15165759],
  81.                      boxes=True)
  82.         # 算法部分, 计算狗和沙发的位置情况, 并且触发报警
  83.         pred_classes = [classes[int(i.item())] for i in outs[0].boxes.cls]
  84.         pred_bbox = [i.tolist() for i in outs[0].boxes.xywh]
  85.         length = len(pred_classes)
  86.         dog_boxes = []
  87.         couch_boxes = []
  88.         dog_flag, couch_bed_flag = 00
  89.         for i in range(length):
  90.             if pred_classes[i] in ['dog''cat']:
  91.                 dog_boxes.append((round(pred_bbox[i][0]), round(pred_bbox[i][1]),
  92.                                   round(pred_bbox[i][0] + pred_bbox[i][2]), round(pred_bbox[i][1] + pred_bbox[i][3])))
  93.                 dog_flag = 1
  94.             if pred_classes[i] in ['couch''bed']:
  95.                 couch_boxes.append((round(pred_bbox[i][0]), round(pred_bbox[i][1]),
  96.                                     round(pred_bbox[i][0] + pred_bbox[i][2]), round(pred_bbox[i][1] + pred_bbox[i][3])))
  97.                 couch_bed_flag = 1
  98.         if alarm_played and (not dog_flag or not couch_bed_flag):
  99.             dog_boxes = [(0000)]
  100.             couch_boxes = [(0000)]
  101.         else:
  102.             for dog_box in dog_boxes:
  103.                 for couch_box in couch_boxes:
  104.                     if dog_box[3] < (couch_box[3] - ((couch_box[3] - couch_box[1]) * 0.5)) and (
  105.                             (couch_box[0] < dog_box[0] < couch_box[2]) or (
  106.                             couch_box[0] < dog_box[2] < couch_box[2])) and dog_flag and couch_bed_flag:
  107.                         not_detected = 0
  108.                         if not alarm_played:
  109.                             # 发送消息
  110.                             # if datetime.now() - last_sent_time >= timedelta(seconds=15):
  111.                             #     send_message(chat_id, "Dog has detected on couch!")
  112.                             #     last_sent_time = datetime.now()
  113.                             #     send_photo(chat_id, frame)
  114.                             pygame.mixer.music.play(-1)  # play in a loop
  115.                             alarm_played = True
  116.                     else:
  117.                         if alarm_played:
  118.                             not_detected += 1
  119.                             if not_detected > 10:
  120.                                 not_detected = 0
  121.                                 pygame.mixer.music.stop()
  122.                                 alarm_played = False
  123.     couch_bed_flag = 0
  124.     dog_flag = 0
  125.     dog_boxes = [(0000)]
  126.     couch_boxes = [(0000)]
  127.     frame_counter += 1
  128.     if cv2.waitKey(1) & 0xFF == ord('q'):
  129.         break
  130. cap.release()
  131. cv2.destroyAllWindows()

运行代码,结果如下。

使用预训练模型获取小狗和沙发的目标框,并且计算两者的关系,以此来触发报警。

/ 03 /

车辆检测器

这是一个交通监控系统的项目。

使用OpenCV和YOLOv8实现如下功能,实时车辆检测、车辆跟踪、实时车速检测,以及检测车辆是否超速。

跟踪代码如下,赋予每个目标唯一ID,避免重复计算。

  1. import math
  2. class Tracker:
  3.     def __init__(self):
  4.         # 存储目标的中心位置
  5.         self.center_points = {}
  6.         # ID计数
  7.         # 每当检测到一个新的目标id时, 计数将增加1
  8.         self.id_count = 0
  9.     def update(self, objects_rect):
  10.         # 目标的方框和ID
  11.         objects_bbs_ids = []
  12.         # 获取新目标的中心点
  13.         for rect in objects_rect:
  14.             x, y, w, h = rect
  15.             cx = (x + x + w) // 2
  16.             cy = (y + y + h) // 2
  17.             # 看看这个目标是否已经被检测到过
  18.             same_object_detected = False
  19.             for id, pt in self.center_points.items():
  20.                 dist = math.hypot(cx - pt[0], cy - pt[1])
  21.                 if dist < 35:
  22.                     self.center_points[id] = (cx, cy)
  23.                     # print(self.center_points)
  24.                     objects_bbs_ids.append([x, y, w, h, id])
  25.                     same_object_detected = True
  26.                     break
  27.             # 检测到新目标,分配ID给新目标
  28.             if same_object_detected is False:
  29.                 self.center_points[self.id_count] = (cx, cy)
  30.                 objects_bbs_ids.append([x, y, w, h, self.id_count])
  31.                 self.id_count += 1
  32.         # 按中心点清理字典, 删除不再使用的ID
  33.         new_center_points = {}
  34.         for obj_bb_id in objects_bbs_ids:
  35.             _, _, _, _, object_id = obj_bb_id
  36.             center = self.center_points[object_id]
  37.             new_center_points[object_id] = center
  38.         # 更新字典, 删除未使用的ID
  39.         self.center_points = new_center_points.copy()
  40.         return objects_bbs_ids

这是检测代码,速度计算那部分代码有点小粗糙。

最好是能有相机标定这一过程,这样速度才会准确。

  1. import cv2
  2. import time
  3. import numpy as np
  4. from tracker import *
  5. import pandas as pd
  6. from ultralytics import YOLO
  7. # 加载模型
  8. model = YOLO('yolov8s.pt')
  9. def RGB(event, x, y, flags, param):
  10.     if event == cv2.EVENT_MOUSEMOVE:
  11.         colorsBGR = [x, y]
  12.         print(colorsBGR)
  13. cv2.namedWindow('RGB')
  14. cv2.setMouseCallback('RGB', RGB)
  15. cap = cv2.VideoCapture('Vid1.mp4')
  16. my_file = open("coco.txt""r")
  17. data = my_file.read()
  18. class_list = data.split("\n")
  19. print(class_list)
  20. count = 0
  21. speed = {}
  22. area = [(225335), (803335), (962408), (57408)]
  23. area_c = set()
  24. # 跟踪算法
  25. tracker = Tracker()
  26. speed_limit = 62
  27. while True:
  28.     ret, frame = cap.read()
  29.     if not ret:
  30.         break
  31.     count += 1
  32.     if count % 3 != 0:
  33.         continue
  34.     frame = cv2.resize(frame, (1020500))
  35.     results = model.predict(frame)
  36.     # print(results)
  37.     a = results[0].boxes.boxes
  38.     px = pd.DataFrame(a).astype("float")
  39.     # print(px)
  40.     list = []
  41.     # 使用YOLOv8的检测结果, 进行算法设计
  42.     for index, row in px.iterrows():
  43.         # print(row)
  44.         x1 = int(row[0])
  45.         y1 = int(row[1])
  46.         x2 = int(row[2])
  47.         y2 = int(row[3])
  48.         d = int(row[5])
  49.         c = class_list[d]
  50.         if 'car' in c:
  51.             list.append([x1, y1, x2, y2])
  52.     bbox_id = tracker.update(list)
  53.     for bbox in bbox_id:
  54.         x3, y3, x4, y4, id = bbox
  55.         cx = int(x3+x4)//2
  56.         cy = int(y3+y4)//2
  57.         results = cv2.pointPolygonTest(
  58.             np.array(area, np.int32), ((cx, cy)), False)
  59.         if results >= 0:
  60.             cv2.circle(frame, (cx, cy), 4, (00255), -1)
  61.             cv2.putText(frame, str(id), (x3, y3), cv2.FONT_HERSHEY_COMPLEX,
  62.                         0.8, (0255255), 2, cv2.LINE_AA)
  63.             cv2.rectangle(frame, (x3, y3), (x4, y4), (00255), 2)
  64.             area_c.add(id)
  65.             now = time.time()
  66.             if id not in speed:
  67.                 speed[id] = now
  68.             else:
  69.                 try:
  70.                     prev_time = speed[id]
  71.                     speed[id] = now
  72.                     dist = 2
  73.                     a_speed_ms = dist / (now - prev_time)
  74.                     a_speed_kh = a_speed_ms * 3.6
  75.                     cv2.putText(frame, str(int(a_speed_kh))+'Km/h', (x4, y4),
  76.                                 cv2.FONT_HERSHEY_COMPLEX, 0.8, (0255255), 2, cv2.LINE_AA)
  77.                     speed[id] = now
  78.                 except ZeroDivisionError:
  79.                     pass
  80.                 # 检查速度是否超过速度限制
  81.                 # if a_speed_kh >= speed_limit:
  82.                 #     # Display a warning message
  83.                 #     cv2.putText(frame, "Speed limit violated!", (440115),
  84.                 #                 cv2.FONT_HERSHEY_TRIPLEX, 0.8, (2550255), 2, cv2.LINE_AA)
  85.                 #     # Display the message for 3 seconds
  86.                 #     start_time = time.time()
  87.                 #     while time.time() - start_time < 3:
  88.                 #         cv2.imshow("RGB", frame)
  89.                 #         if cv2.waitKey(1) & 0xFF == 27:
  90.                 #             break
  91.     cv2.polylines(frame, [np.array(area, np.int32)], True, (02550), 2)
  92.     cnt = len(area_c)
  93.     cv2.putText(frame, ('Vehicle-Count:-')+str(cnt), (45250),
  94.                 cv2.FONT_HERSHEY_TRIPLEX, 1, (1020255), 2, cv2.LINE_AA)
  95.     cv2.imshow("RGB", frame)
  96.     if cv2.waitKey(1) & 0xFF == 27:
  97.         break
  98. # 刷新,释放资源
  99. cap.release()
  100. cv2.destroyAllWindows()

运行代码,结果如下。

06a0ba9aff849ee75138e3b16602bddc.gif

发现效果还不错~

/ 04 /

总结

以上操作,就是三个使用YOLOv8实现的计算机视觉项目

当然我们还可以通过预训练模型实现其它功能。

如果预训练模型的检测效果在你要使用的场景不太好,那就是需要加加数据了~

相关文件及代码都已上传,公众号回复【YOLO】即可获取。

万水千山总是情,点个 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/422652
推荐阅读
相关标签