yolo v8 人体关键点检测的本地及接口应用

YOLOV8

YOLOv8 是一款前沿、最先进(SOTA)的模型,基于先前 YOLO 版本的成功,引入了新功能和改进,进一步提升性能和灵活性。YOLOv8 设计快速、准确且易于使用,使其成为各种物体检测与跟踪、实例分割、图像分类和姿态估计任务的绝佳选择。

模型尺寸
(像素)
mAPval
50-95
速度
CPU ONNX
(ms)
速度
A100 TensorRT
(ms)
参数
(M)
FLOPs
(B)
YOLOv8n64037.380.40.993.28.7
YOLOv8s64044.9128.41.2011.228.6
YOLOv8m64050.2234.71.8325.978.9
YOLOv8l64052.9375.22.3943.7165.2
YOLOv8x64053.9479.13.53

环境

需要Python>=3.8环境中安装ultralytics

pip install ultralytics

也可以直接拉取项目进行代码测试:

git clone https://github.com/ultralytics/ultralytics

命令

YOLOv8 可以在命令行界面(CLI)中直接使用,只需安装完成环境以后输入 yolo 命令:

yolo predict model='模型路径 'source='图片路径'

也可以在 Python 环境中直接使用,并接受与上述 CLI 示例中相同的参数:

# 导入ultralytics包
from ultralytics import YOLO

# 加载模型
model = YOLO("yolov8n.pt")  # 加载预训练模型(建议用于训练)

# 使用模型
results = model("图片路径")  # 对图像进行预测

模型

也可以根据自己的需要进行训练模型
可以参考COCO数据集准备相应的文件以及yml配置,这里不做阐述。

使用

本次使用python的flask框架对yolov8做一些实践方面的应用。
先上代码:

import base64
import json
import cv2
from ultralytics import YOLO
import numpy as np
from flask_cors import CORS
from flask import Flask, request, Response
import logging

# 加载YOLOv8模型
model = None
# 加载本地摄像头
camera = cv2.VideoCapture(0)


# 初始化
def create_app():
    global model
    app = Flask(__name__)
    logger = logging.getLogger(__name__)
    logger.info('加载app成功')
    CORS(app)
    # 初始化模型
    model = YOLO(model="./model/yolov8n-pose.pt")
    print('模型加载成功')
    # 加载路由和其它初始化过程
    # 载入测试图片
    test_img = cv2.imread('./model/wbb.jpg')
    print('加载初始化图片')
    # 模型预测
    results = model(test_img)
    print('进行初始预测')
    frame = results[0].plot()
    print('初始化预测成功')
    print("结果" + str(type(frame)))
    return app


# 创建应用
app = create_app()


# 本机摄像头调用
def gen_frames():
    while True:
        success, frame = camera.read()
        if not success:
            break
        else:
            # YOLOv8预测
            results = model(frame)
            # 绘制预测结果
            frame = results[0].plot()
            # Encode as a jpeg image and return
            ret, buffer = cv2.imencode('.jpg', frame)
            frame = buffer.tobytes()
            yield (b'--frame\r\n'
                   b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')


# 网络接口
@app.route('/receive_image', methods=['POST'])
def receive_image():
    # 从request中获取参数
    data = request.data.decode('utf-8')
    json_data = json.loads(data)
    str_image = json_data.get("imgData")
    img = base64.b64decode(str_image)
    img_np = np.frombuffer(img, dtype='uint8')
    new_img_np = cv2.imdecode(img_np, 1)
    # YOLOv8预测
    results = model(new_img_np)
    # # 绘制预测结果
    print("预测结果"+str(type(results[0])))
    frame = results[0].plot()
    ret, buffer = cv2.imencode('.jpg', frame)
    frame = buffer.tobytes()

    return Response(frame,
                    mimetype='multipart/x-mixed-replace; boundary=frame')


# 本机测试接口
@app.route('/video_feed')
def video_feed():
    return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')


if __name__ == "__main__":
    app.run(debug=True)

  1. create_app函数:
    • 初始化Flask应用,加载模型,进行一次测试预测
    • 打印初始化日志,用于调试
    • 返回构造好的Flask应用实例
  2. gen_frames函数:
    • 从本地摄像头读取视频流
    • 使用YOLOv8模型对每帧图像进行预测
    • 将预测结果画框,编码为JPEG格式
    • 生成视频流响应返回给前端显示
  3. receive_image接口:
    • 接收前端base64编码的图像
    • 解码图像,交给YOLOv8模型预测
    • 将预测结果画框,编码为JPEG格式
    • 返回图像响应给前端显示
  4. video_feed接口:
    • 调用gen_frames函数获取本地摄像头视频流
    • 将视频流通过Response返回给前端显示

在没写前端的情况下,通过接口/video_feed在网页中进行测试结果如图:
在这里插入图片描述
但是这里调用的是本机摄像头,只能通过本地部署才能实现效果,所以,我们需要远程部署的一个接口.
主要就是拿到不同设备上的视频帧的数据流,这里使用web端的网页部署,代码如下:

index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link type="text/css" rel="styleSheet"  href="./css/index.css" />
    <script src="./js/jquery-3.6.1.min.js"></script>
    <script src="./js/vue.js"></script>
    <title>主页面</title>
</head>
<body>
    <div id="app">
        <div class="content">
            <div class="v1">原视频</div>            
            <video id="video" autoplay></video>
            <div class="res">
                <div class="v2">识别结果</div>  
                <img id="resVideo" width=640 height=480 :src="src" crossOrigin="anonymous"></img>
                <div class="slider">
                    <input type="range" min="100" max="2000" v-model="speed" value="1000"><br/>
                    <span>调节帧率,当前:{{speed}}</span>
                </div>
            </div>
        </div>
    </div>
    
    <script src="./js/index.js"></script>
</body>
</html> 
:root {
  --primary-color: #3f51b5;
  --bg-color: #f5f5f5;
  --box-shadow: 0 5px 10px rgba(0,0,0,0.1);
}

body {
  background: var(--bg-color);
  font-family: 'Open Sans', sans-serif;
}

.content {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
  display: flex;
  text-align: center;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 20px;
}

.v1, 
.v2 {
  font-size: 1.2rem;
  font-weight: 500;
  margin-bottom: 10px;
}

#video {
  flex: 1 1 500px;
  width: 55%;
  border-radius: 10px;
  box-shadow: var(--box-shadow);
}

.res {
  flex: 1 1 500px;
  text-align: center;
}

#resVideo {
  max-width: 100%;
  border-radius: 10px;
  box-shadow: var(--box-shadow);
  transition: all 0.3s;
}

#resVideo:hover {
  transform: scale(1.05);
}

.slider {
  margin-top: 20px;
  text-align: left;
}

.slider input {
  width: 100%;
  padding: 10px;
} 

.slider span {
  font-size: 0.9rem;
  color: #666;
}


/* 平板 */
@media (max-width: 1024px) {

  .content {
    gap: 10px;
  }

  #video,
  .res {
    flex: 1 1 auto;
  }

}

/* 手机 */
@media (max-width: 768px) {

  .content {
    flex-direction: column;
  }
  
  #video,
  .res {
    width: 100%;
  }
  #resVideo{
    max-height: 23em;
  }

}

js
var vm = new Vue({
  el:"#app",
  /*Model:数据*/
  data:{
    imgBlob:{},
    speed:2000,
    src:""
  },
  
  created() {
    this.camera()
  },
  methods: {
    startTimeout(){
      setTimeout(()=>{
         // 创建canvas元素
         const canvas = document.createElement('canvas')  
         canvas.width = 320
         canvas.height = 240
         const context = canvas.getContext('2d')
         // 绘制视频帧到canvas
         context.drawImage(video, 0, 0, 320, 240) 
         // 获取图像数据
         var imgData = canvas.toDataURL("image/jpg");
         imgData = imgData.replace(/^data:image\/(png|jpg);base64,/,"")
        
         var myHeaders = new Headers();
         myHeaders.append("Accept", "*/*");
         var requestOptions = {
           method: 'POST',
           headers: myHeaders,
           body: JSON.stringify({"imgData": imgData})
         };

         fetch("https://localhost:5000/receive_image", requestOptions)
           .then(response => response.blob())
           .then(blob  => {
             const url = URL.createObjectURL(blob);
             this.src = url;
           })
           .catch(error => console.log('error', error));
           this.startTimeout()
      },this.speed)
    },
    camera(){
      navigator.mediaDevices.getUserMedia({ video: true })
      .then(stream => {
        // 视频元素显示流
        const video = document.getElementById('video')
        video.srcObject = stream

        this.startTimeout();
      })
      .catch(error => {
        console.error('访问用户媒体设备失败:', error)
      })
    }
  },
});


主要流程如下:

  1. 获取摄像头视频流,显示在页面的 元素中。
  2. 每隔一段时间(由 data 中的 speed 控制间隔),从视频流中截取一帧图像,绘制到 canvas 中。
  3. 将 canvas 图像数据转成 base64 格式,发送到后端 /receive_image 接口。
  4. 接收后端返回的预测结果图片,设置到 src 数据中展示出来。
  5. 创建一个递归的定时器,不停重复上述过程,从而实现摄像头实时预测效果。
  6. 通过设置 speed 的值可以控制截图预测的频率。

关键在于:

  • 获取和显示视频流
  • 截图并编码为 base64 格式
  • 递归调用来不断发送截图预测
  • 展示后端返回的预测结果

效果如下:
在这里插入图片描述
也可以在不同设备进行测试:
在这里插入图片描述

这样可以实现一个伪全平台的检测功能。

这里主要通过settimeout对调用接口的速率进行控制
setTimeout在这个场景中的作用是设置一个定时器,以一定的时间间隔(由speed控制)重复执行一个函数。
具体用法:

  1. setTimeout接受两个参数,第一个参数是一个函数,第二个参数是时间间隔,单位是毫秒。
  2. 在setTimeout内部的函数中,包含了截取视频帧、编码为base64、发送到后端、展示结果等一系列操作。
  3. 最关键的是,在这个函数的最后又调用了setTimeout,并传入了这个同一个函数。这就创建了一个递归的定时器。
  4. 每次定时器执行结束,就会再设置一个定时器,周而复始地重复执行这个函数。
  5. 这样就可以周期性地截取视频帧并预测,实现实时效果。
  6. 通过修改speed的值可以控制每次定时器的时间间隔,来调整预测的频率。

这是利用 JavaScript 的 setTimeout 来周期性执行某个操作的用法。可以很好地配合其他逻辑来实现需要定时或周期执行的功能。

然后传输至后端的/receive_image
前端发送base64编码图像 -> 后端解码为OpenCV矩阵 -> YOLOv8预测 -> 绘图 -> 编码为jpg -> 返回预测结果图

  1. 接收到前端通过POST方法发送来的JSON数据
  2. 从JSON中提取出key为imgData的值,这是base64编码后的图像数据
  3. 使用base64.b64decode()对其解码,转换为字节数据
  4. 使用np.frombuffer()将上一步得到的字节数据转换为Numpy数组
  5. 使用cv2.imdecode()对数组进行解码,还原为OpenCV图像矩阵
  6. 将得到的图像矩阵传给YOLOv8模型的forward方法,进行预测
  7. 从预测结果中取出第一个检测框,使用plot()方法在图像上绘制出来
  8. 使用cv2.imencode()来编码处理后的图像,转为jpg格式
  9. 将编码后的jpg图像数据包装到Response对象中返回给前端

对yolov8的总结

  1. YOLOv8是一个目标检测模型,可以对图像进行多类别目标的识别和定位。
  2. 该项目需要对摄像头视频流进行人体姿态预测,YOLOv8可以满足这个需求。
  3. 在后端代码中,加载了YOLOv8的模型文件,并初始化了模型对象。
  4. 在receive_image接口中,将前端发送来的图像输入到YOLOv8模型中进行预测。
  5. YOLOv8模型会输出检测到的人体目标框以及类别等信息。
  6. 从YOLOv8输出中取出需要的预测框位置信息,在图像上进行绘图标注。
  7. 这样就完成了对视频图像的人体检测和 LOCALIZATION。
  8. 最终编码后的预测结果图像返回给前端展示。

如需模型文件可访问该项目git地址:https://gitee.com/taritaris/yolov8-as-human-detection/blob/master/model/yolov8n-pose.pt

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lanlnan抱抱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值