hrnet训练的pt模型结合目标检测进行关键点识别的更准确前向推理
本篇在将图像输入hrnet识别之前先进行目标检测来确定识别的位置,让识别更加精准。
本段代码设置了一个区域框BOX,让人走入区域内才开始检测,适用于考核等场景,也可以直接去掉BOX也是一样的效果。若画面背景中有多个行人,还是只取要检测的那个人,同理还是适用考核场景。
为了让检测效果更直观,在一些点位直接使用线连接起来模拟人体骨骼。
import os
import sys
import numpy as np
from mmpose.apis import init_model, inference_topdown
import cv2import torch
sys.path.append("/home/yons/train/code/yolov5")
from models.experimental import attempt_load
from utils.general import non_max_suppression, scale_boxes
from torchvision import transforms# 配置文件路径和检查点文件路径
config_file = '/home/.../pose_td-hm_hrnet-w48_8xb32-210e_PullUp-det/pose_td-hm_hrnet-w48_8xb32-210e_PullUp-det.py'
checkpoint_file = '/home/.../pose_td-hm_hrnet-w48_8xb32-210e_PullUp-det/best_coco_AP_epoch_250.pth'# 初始化姿态估计模型
pose_model = init_model(config_file, checkpoint_file, device='cuda:0')
yolo_model = attempt_load('yolov5x6.pt', device='cuda:0') # 加载训练好的yolov5模型
pose_model.eval()
yolo_model.eval()VIDEO_PATH = 'input.mp4'
BOX = (300, 50, 300, 450) # 区域框的左上角坐标和宽高
OUTPUT_VIDEO_PATH = 'output.mp4'def draw_keypoints(frame, keypoints, box, det_box):# 在帧上绘制关键点# 这里假设关键点是一个 Nx2 的数组,其中 N 是关键点的数量# 并且关键点的坐标是相对于裁剪区域的x, y, w, h = boxfor kp in keypoints:kp_x, kp_y = kpx_rec1 = int(det_box[0] + x)y_rec1 = int(det_box[1] + y)x_rec2 = int(det_box[2] + x)y_rec2 = int(det_box[3] + y)cv2.rectangle(frame, (x_rec1, y_rec1), (x_rec2, y_rec2), (0, 0, 255), 2)x_cir = int(kp_x + det_box[0] + x)y_cir = int(kp_y + det_box[1] + y)cv2.circle(frame, (x_cir, y_cir), 3, (0, 255, 0), -1)lines = [(15, 13), (13, 11), (16, 14), (14, 12), (11, 12), (5, 11), (6, 12), (5, 6),(5, 7), (6, 8), (7, 9), (8, 10), (1, 2), (0, 1), (0, 2), (1, 3), (2, 4), (3, 5), (4, 6)]for line in lines:pt1 = (int(keypoints[line[0]][0] + det_box[0] + x), int(keypoints[line[0]][1] + det_box[1] + y))pt2 = (int(keypoints[line[1]][0] + det_box[0] + x), int(keypoints[line[1]][1] + det_box[1] + y))cv2.line(frame, pt1, pt2, (0, 255, 0), 2)def letterbox(im, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True, stride=32):"""Resizes and pads image to new_shape with stride-multiple constraints, returns resized image, ratio, padding."""shape = im.shape[:2] # current shape [height, width]if isinstance(new_shape, int):new_shape = (new_shape, new_shape)# Scale ratio (new / old)r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])if not scaleup: # only scale down, do not scale up (for better val mAP)r = min(r, 1.0)# Compute paddingratio = r, r # width, height ratiosnew_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh paddingif auto: # minimum rectangledw, dh = np.mod(dw, stride), np.mod(dh, stride) # wh paddingelif scaleFill: # stretchdw, dh = 0.0, 0.0new_unpad = (new_shape[1], new_shape[0])ratio = new_shape[1] / shape[1], new_shape[0] / shape[0] # width, height ratiosdw /= 2 # divide padding into 2 sidesdh /= 2if shape[::-1] != new_unpad: # resizeim = cv2.resize(im, new_unpad, interpolation=cv2.INTER_LINEAR)print(im.shape)top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))left, right = int(round(dw - 0.1)), int(round(dw + 0.1))im = cv2.copyMakeBorder(im, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # add borderreturn im, ratio, (dw, dh)# 处理每一张图像
k = 0
if __name__ == '__main__':# 打开视频cap = cv2.VideoCapture(VIDEO_PATH)# 获取视频的一些属性fps = cap.get(cv2.CAP_PROP_FPS)width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))# 创建 VideoWriter 对象fourcc = cv2.VideoWriter_fourcc(*'mp4v') # 或者使用 'XVID'out = cv2.VideoWriter(OUTPUT_VIDEO_PATH, fourcc, fps, (width, height))while True:# 读取一帧ret, frame = cap.read()if not ret:break# 加载帧x, y, w, h = BOXimg0 = frame[y:y+h, x:x+w, :]img_size = (1280, 1280)stride = max(int(yolo_model.stride.max()), 32)img = letterbox(img0, img_size, stride=stride, auto=True)[0] # padded resizeimg = img.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGBimg = np.ascontiguousarray(img) # contiguous# yolo_model.warmup(imgsz=(1, 3, *img_size)) # warmupimg = torch.from_numpy(img).to('cuda:0')# img = img.half() if yolo_model.fp16 else img.float() # uint8 to fp16/32img = img.float()img /= 255 # 0 - 255 to 0.0 - 1.0if len(img.shape) == 3:img = img[None] # expand for batch dimwith torch.no_grad():pred = yolo_model(img) # Inferencepred = non_max_suppression(pred, 0.25, 0.45, 0) # NMS 0 for person# input()det_box = None# Process predictions# print(pred)for i, det in enumerate(pred): # per image# print(det)if len(det):# Rescale boxes from img_size to img0 sizedet[:, :4] = scale_boxes(img.shape[2:], det[:, :4], img0.shape).round()max_bb = Nonefor x1, y1, x2, y2, conf, cls in reversed(det):if max_bb is None:max_bb = [x1, y1, x2, y2]else:if ((x2 - x1) * (y2 - y1)) > ((max_bb[2] - max_bb[0]) * (max_bb[3] - max_bb[3])):max_bb = [x1, y1, x2, y2]det_box = max_bbfor idx in range(len(det_box)):det_box[idx] = int(det_box[idx])x1, y1, x2, y2 = det_box# print(det_box)img_seg = img0[y1:y2, x1:x2, :]person_results = np.array([[0, 0, x2-x1, y2-y1]])# 推理得到关键点坐标pose_results = inference_topdown(pose_model, img_seg, person_results, bbox_format='xyxy')# 提取关键点坐标并检查是否检测出17个关键点keypoints = []if len(pose_results) > 0 and pose_results[0].pred_instances.keypoints.shape[1] == 17:keypoints = pose_results[0].pred_instances.keypoints[0]draw_keypoints(frame, keypoints, BOX, det_box)# 写入帧out.write(frame)# 显示帧cv2.imshow('frame', frame)if cv2.waitKey(1) & 0xFF == ord('q'):breakcap.release()out.release()cv2.destroyAllWindows()
input.mp4视频如下:
引体向上原始视频
output.mp4视频如下:
引体向上推理结果视频
大概原理是区域框内进行一系列处理后输入进yolo进行目标检测,在多个目标框内选出我们要检测的人物的目标框输入进hrnet得到关键点,关键点从目标框映射回区域框再映射回原图,得到最终结果。
相关文章:
hrnet训练的pt模型结合目标检测进行关键点识别的更准确前向推理
本篇在将图像输入hrnet识别之前先进行目标检测来确定识别的位置,让识别更加精准。 本段代码设置了一个区域框BOX,让人走入区域内才开始检测,适用于考核等场景,也可以直接去掉BOX也是一样的效果。若画面背景中有多个行人࿰…...
Leetcode 3306. Count of Substrings Containing Every Vowel and K Consonants II
Leetcode 3306. Count of Substrings Containing Every Vowel and K Consonants II 1. 解题思路2. 代码实现 题目链接:3306. Count of Substrings Containing Every Vowel and K Consonants II 1. 解题思路 这一题的话思路上就是一个滑动窗口,考察没一…...

算法笔记(五)——分治
文章目录 算法笔记(五)——分治快排颜色分类排序数组数组中的第K个最大元素库存管理 III 归并排序数组交易逆序对的总数计算右侧小于当前元素的个数翻转对 算法笔记(五)——分治 分治算法字面上的解释是“分而治之”,就…...

多级侧边菜单(递归)
需要编写两个文件 aside-menu.vue 和 menu-item.vue menu-item.vue <script setup> defineOptions({name: MenuItem}) defineProps({menuList: Array}) </script><template><template v-for"menu of menuList"><!-- 如果当前有子菜单&a…...

JavaScript break与continue语句
break语句和continue语句都具有跳转作用,可以让代码不按既有的顺序执行。 break break语句用于跳出代码块或循环 for(i0;i<100;i){if(i5){break;}console.log(i);} continue continue语句用于应即终止本轮循环,返回循环结构的头部,开始下一轮循环。…...
算法【从递归入手一维动态规划】
动态规划:用空间代替重复计算,包含一整套原理和技巧的总和。后面会有非常多的文章介绍动态规划。 有些递归在展开计算时,总是重复调用同一个子问题的解,这种重复调用的递归变成动态规划很有收益。如果每次展开都是不同的解&#…...

Linux中的进程间通信之共享内存
共享内存 共享内存示意图 共享内存数据结构 struct shmid_ds {struct ipc_perm shm_perm; /* operation perms */int shm_segsz; /* size of segment (bytes) */__kernel_time_t shm_atime; /* last attach time */__kernel_time_t shm_dtime; /* last detach time */__kerne…...
第18周 3-过滤器
过滤器(Filter)概念总结 什么是过滤器 过滤器(Filter)是Java Web应用中用于统一拦截和处理请求的组件,类似于现实生活中的空气净化器或安检。它通过对请求进行前置处理,确保请求符合特定要求。 过滤器的…...

Linux之进程概念
作者主页: 作者主页 本篇博客专栏:Linux专栏 创作时间 :2024年9月28日 基本概念: 进程说白了其实就是一个程序的执行实例,正在执行的程序。 在内核层面来说,就是一个担当分配资源(CPU时间…...

小程序-使用npm包
目录 Vant Weapp 安装 Vant 组件库 使用 Vant 组件 定制全局主题样式 API Promise化 1. 基于回调函数的异步 API 的缺点 2. 什么是 API Promise 化 3. 实现 API Promise 化 4.调用 Promise 化之后的异步 API 小程序对 npm 的支持与限制 目前,小程序中已经…...

【springboot】整合沙箱支付
目录 1. 配置沙箱应用环境2. 配置springboot项目1. 引入依赖2. 配置文件注册下载ngrok 3. 创建支付宝支付服务类4. 支付界面模板5. 控制类实现支付6. 测试 1. 配置沙箱应用环境 使用支付宝账号登录到开放平台控制台。 使用支付宝登录后,看到以下页面,下…...

技术速递|Python in Visual Studio Code 2024年9月发布
排版:Alan Wang 我们很高兴地宣布将于 2024 年 9 月发布适用于 Visual Studio Code 的 Python 和 Jupyter 扩展! 此版本包括以下公告: Django 单元测试支持使用 Pylance 从 inlay 提示转到定义 如果您有兴趣,可以在我们的 Pyth…...

数据结构-3.5.队列的顺序实现
一.队列的顺序实现,初始化操作以及判断队列是否为空: 1.图解: 2.代码: #include<stdio.h> #define MaxSize 10 //定义一个队列最多存储的元素个数 typedef struct {int data[MaxSize]; //用静态数组存放队列元素int f…...
preconnect 预解析
preconnect 是一种浏览器优化技术,用于告诉浏览器提前与指定的域名建立连接,包括DNS解析、TCP握手和TLS协商(如果适用)。这样做可以减少客户端在请求资源时所需的往返时间(RTT),从而提高页面加载…...

Leecode热题100-283.移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0]示例 2: 输入: nums [0] 输出: […...

如何高效使用Prompt与AI大模型对话
一、如何与人工智能对话 在人工智能的世界里,提示词(Prompt)就像是一把钥匙,能够解锁AI智能助手的潜力,帮助你更高效地获取信息、解决问题。但如何正确使用这把钥匙,却是一门艺术。本文将带你了解提示词的…...

Java 之深入理解 String、StringBuilder、StringBuffer
前言 由于发现 String、StringBuilder、StringBuffer 面试的时候会经常问到,这里就顺便总结一下:本文重点会以这三个字符串类的性能、线程安全、存储结构这三个方面进行分析 ✨上期回顾:Java 哈希表 ✨目录 前言 String 介绍 String 的不可变…...

vue3项目执行pnpm update后还原package.json文件后运行报错
项目场景: vue官方版本已更新到vue3.5,项目中还在使用vue3.4,因此想要更新项目vue版本。 问题描述 执行了 pnpm update 命令,一键更新了所有包,更新完成后项目不能正常运行。为了还原项目代码,先删除 nod…...

蓝桥杯【物联网】零基础到国奖之路:十七. 扩展模块之单路ADC和NE555
蓝桥杯【物联网】零基础到国奖之路:十七. 扩展模块之单路ADC和NE555 第一节 硬件解读第二节 CubeMx配置第三节 代码1,脉冲部分代码2,ADC部分代码 第一节 …...
SolveigMM Video Splitter方便快捷视频分割合并软件 V3.6.1309.3-供大家学习研究参考
视频分割功能(Splitter)支持各种编码格式的AVI(DivX、DV、MJPEG、XVID、MPEG-4)、WMV、ASF(DivX、MJPEG、XVID、MPEG-4、WM Video 7/9)F、MPEG(*.mpg、*.mpeg、*.mpv、*.m2v、*.vob)文件、也支持受损的WMV、ASF格式的分割。视频合并功能(Joiner)则支持AVI、WMV/ASF、WMA、MP3、…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式
简介 在我的 QT/C 开发工作中,合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式:工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...
加密通信 + 行为分析:运营商行业安全防御体系重构
在数字经济蓬勃发展的时代,运营商作为信息通信网络的核心枢纽,承载着海量用户数据与关键业务传输,其安全防御体系的可靠性直接关乎国家安全、社会稳定与企业发展。随着网络攻击手段的不断升级,传统安全防护体系逐渐暴露出局限性&a…...
Java中栈的多种实现类详解
Java中栈的多种实现类详解:Stack、LinkedList与ArrayDeque全方位对比 前言一、Stack类——Java最早的栈实现1.1 Stack类简介1.2 常用方法1.3 优缺点分析 二、LinkedList类——灵活的双端链表2.1 LinkedList类简介2.2 常用方法2.3 优缺点分析 三、ArrayDeque类——高…...
基于 HTTP 的单向流式通信协议SSE详解
SSE(Server-Sent Events)详解 🧠 什么是 SSE? SSE(Server-Sent Events) 是 HTML5 标准中定义的一种通信机制,它允许服务器主动将事件推送给客户端(浏览器)。与传统的 H…...