基于openpose的引体向上的识别计数统计项目(3)CPoseRender类设计与实现

本文主要是介绍基于openpose的引体向上的识别计数统计项目(3)CPoseRender类设计与实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

CPoseRender 主要是为了简化openpose中的调用方式进行简化重写,只需要opencv的参数即可使用。

1、CPoseRender 声明

#pragma once#include "opencv2/core.hpp"#include "CPoseClassify.h"#include "Keypoints.h"namespace Utils {
// fastmath, taken from op
//
// Use op::round/max/min for basic types (int, char, long, float, double, etc). Never with classes!
// `std::` alternatives uses 'const T&' instead of 'const T' as argument.
// E.g., std::round is really slow (~300 ms vs ~10 ms when I individually apply it to each element of a whole
// image array// VERY IMPORTANT: These fast functions does NOT work for negative integer numbers.
// E.g., positiveIntRound(-180.f) = -179.// Round functions
// Signed
template<typename T>
inline char positiveCharRound(const T a)
{return char(a + 0.5f);
}template<typename T>
inline signed char positiveSCharRound(const T a)
{return (signed char)(a + 0.5f);
}template<typename T>
inline int positiveIntRound(const T a)
{return int(a + 0.5f);
}template<typename T>
inline long positiveLongRound(const T a)
{return long(a + 0.5f);
}template<typename T>
inline long long positiveLongLongRound(const T a)
{return (long long)(a + 0.5f);
}// Unsigned
template<typename T>
inline unsigned char uCharRound(const T a)
{return (unsigned char)(a + 0.5f);
}template<typename T>
inline unsigned int uIntRound(const T a)
{return (unsigned int)(a + 0.5f);
}template<typename T>
inline unsigned long ulongRound(const T a)
{return (unsigned long)(a + 0.5f);
}template<typename T>
inline unsigned long long uLongLongRound(const T a)
{return (unsigned long long)(a + 0.5f);
}// Max/min functions
template<typename T>
inline T fastMax(const T a, const T b)
{return (a > b ? a : b);
}template<typename T>
inline T fastMin(const T a, const T b)
{return (a < b ? a : b);
}template<class T>
inline T fastTruncate(T value, T min = 0, T max = 1)
{return fastMin(max, fastMax(min, value));
}
//
} // namespace Utilsclass CPoseRender
{
public:CPoseRender(PoseModel poseModel);~CPoseRender();void rendPose(cv::Mat& frame, const cv::Mat& poseData, float renderThreshold = 0.05);private:const PoseModel poseModel;
};

2、CPoseRender 实现

#include "CPoseRender.h"#include <vector>
#include <array>//#include "openpose/utilities/fastMath.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"namespace {#define POSE_BODY_25_PAIRS_RENDER \1,8,   1,2,   1,5,   2,3,   3,4,   5,6,   6,7,   8,9,   9,10,  10,11, 8,12,  12,13, 13,14,  1,0,   0,15, 15,17,  0,16, 16,18,   14,19,19,20,14,21, 11,22,22,23,11,24
#define POSE_BODY_25_SCALES_RENDER 1
#define POSE_BODY_25_COLORS_RENDER \255.f,     0.f,    85.f, \255.f,     0.f,     0.f, \255.f,    85.f,     0.f, \255.f,   170.f,     0.f, \255.f,   255.f,     0.f, \170.f,   255.f,     0.f, \85.f,   255.f,     0.f, \0.f,   255.f,     0.f, \255.f,     0.f,     0.f, \0.f,   255.f,    85.f, \0.f,   255.f,   170.f, \0.f,   255.f,   255.f, \0.f,   170.f,   255.f, \0.f,    85.f,   255.f, \0.f,     0.f,   255.f, \255.f,     0.f,   170.f, \170.f,     0.f,   255.f, \255.f,     0.f,   255.f, \85.f,     0.f,   255.f, \0.f,     0.f,   255.f, \0.f,     0.f,   255.f, \0.f,     0.f,   255.f, \0.f,   255.f,   255.f, \0.f,   255.f,   255.f, \0.f,   255.f,   255.fconst std::array<std::vector<unsigned int>, (int)PoseModel::Size> POSE_BODY_PART_PAIRS_RENDER{std::vector<unsigned int>{POSE_BODY_25_PAIRS_RENDER},       // BODY_25
};const std::array<std::vector<unsigned int>, (int)PoseModel::Size> POSE_BODY_PART_PAIRS{// BODY_25std::vector<unsigned int>{1,8, 1,2, 1,5, 2,3, 3,4, 5,6, 6,7, 8,9, 9,10, 10,11, 8,12, 12,13, 13,14, 1,0,  0,15, 15,17, 0,16, 16,18,  2,17, 5,18,  14,19,19,20,14,21, 11,22,22,23,11,24}
};const std::array<std::vector<float>, (int)PoseModel::Size> POSE_SCALES{std::vector<float>{POSE_BODY_25_SCALES_RENDER},       // BODY_25
};const std::array<std::vector<float>, (int)PoseModel::Size> POSE_COLORS{std::vector<float>{POSE_BODY_25_COLORS_RENDER},       // BODY_25
};void renderOpenPoseKeypoints(cv::Mat & frame, const cv::Mat & poseData, PoseModel poseModel, const float threshold)
{const auto thicknessCircleRatio = 1.f / 75.f;const auto thicknessLineRatioWRTCircle = 0.75f;const auto& pairs = POSE_BODY_PART_PAIRS_RENDER.at((int)poseModel);const auto& poseScales = POSE_SCALES.at((int)poseModel);const auto& colors = POSE_COLORS.at((int)(int)poseModel);//-------------------------------------------------------------------------const auto width = frame.size[1];const auto height = frame.size[0];const auto area = width * height;// Parametersconst auto lineType = 8;const auto shift = 0;const auto numberColors = colors.size();const auto numberScales = poseScales.size();const auto thresholdRectangle = float(0.1);const auto numberKeypoints = poseData.cols; //keypoints.getSize(1);// Keypointsfor(auto person = 0; person < poseData.rows; person++) {const auto personRectangle = Utils::getKeypointsRectangle(poseData, person, thresholdRectangle);if(personRectangle.area() > 0) {const auto ratioAreas = Utils::fastMin(float(1), Utils::fastMax(personRectangle.width / (float)width, personRectangle.height / (float)height));// Size-dependent variablesconst auto thicknessRatio = Utils::fastMax(Utils::positiveIntRound(std::sqrt(area)* thicknessCircleRatio * ratioAreas), 2);// Negative thickness in cv::circle means that a filled circle is to be drawn.const auto thicknessCircle = Utils::fastMax(1, (ratioAreas > float(0.05) ? thicknessRatio : -1));const auto thicknessLine = Utils::fastMax(1, Utils::positiveIntRound(thicknessRatio * thicknessLineRatioWRTCircle));const auto radius = thicknessRatio / 2;// Draw linesfor(auto pair = 0u; pair < pairs.size(); pair += 2) {const auto index1 = (person * numberKeypoints + pairs[pair]) * poseData.channels();const auto index2 = (person * numberKeypoints + pairs[pair + 1]) * poseData.channels();if(poseData.at<float>(index1 + 2) > threshold && poseData.at<float>(index2 + 2) > threshold) {const auto thicknessLineScaled = Utils::positiveIntRound(thicknessLine * poseScales[pairs[pair + 1] % numberScales]);const auto colorIndex = pairs[pair + 1] * 3; // Before: colorIndex = pair/2*3;const cv::Scalar color{colors[(colorIndex + 2) % numberColors],colors[(colorIndex + 1) % numberColors],colors[colorIndex % numberColors]};const cv::Point keypoint1{Utils::positiveIntRound(poseData.at<float>(index1)), Utils::positiveIntRound(poseData.at<float>(index1+1))};const cv::Point keypoint2{Utils::positiveIntRound(poseData.at<float>(index2)), Utils::positiveIntRound(poseData.at<float>(index2 + 1))};cv::line(frame, keypoint1, keypoint2, color, thicknessLineScaled, lineType, shift);}}// Draw circlesfor(auto part = 0; part < numberKeypoints; part++) {const auto faceIndex = (person * numberKeypoints + part) * frame.channels();if(poseData.at<float>(faceIndex + 2) > threshold) {const auto radiusScaled = Utils::positiveIntRound(radius * poseScales[part % numberScales]);const auto thicknessCircleScaled = Utils::positiveIntRound(thicknessCircle * poseScales[part % numberScales]);const auto colorIndex = part * 3;const cv::Scalar color{colors[(colorIndex + 2) % numberColors],colors[(colorIndex + 1) % numberColors],colors[colorIndex % numberColors]};const cv::Point center{Utils::positiveIntRound(poseData.at<float>(faceIndex)),Utils::positiveIntRound(poseData.at<float>(faceIndex + 1))};cv::circle(frame, center, radiusScaled, color, thicknessCircleScaled, lineType, shift);}}}}
}} // namespaceCPoseRender::CPoseRender(PoseModel poseModel):poseModel(poseModel)
{
}CPoseRender::~CPoseRender()
{
}void CPoseRender::rendPose(cv::Mat & frame, const cv::Mat & poseData, float renderThreshold)
{if(frame.empty() || poseData.empty())return;renderOpenPoseKeypoints(frame, poseData, poseModel, renderThreshold);
}

这篇关于基于openpose的引体向上的识别计数统计项目(3)CPoseRender类设计与实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/788470

相关文章

Springboot处理跨域的实现方式(附Demo)

《Springboot处理跨域的实现方式(附Demo)》:本文主要介绍Springboot处理跨域的实现方式(附Demo),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录Springboot处理跨域的方式1. 基本知识2. @CrossOrigin3. 全局跨域设置4.

Spring Boot 3.4.3 基于 Spring WebFlux 实现 SSE 功能(代码示例)

《SpringBoot3.4.3基于SpringWebFlux实现SSE功能(代码示例)》SpringBoot3.4.3结合SpringWebFlux实现SSE功能,为实时数据推送提供... 目录1. SSE 简介1.1 什么是 SSE?1.2 SSE 的优点1.3 适用场景2. Spring WebFlu

基于SpringBoot实现文件秒传功能

《基于SpringBoot实现文件秒传功能》在开发Web应用时,文件上传是一个常见需求,然而,当用户需要上传大文件或相同文件多次时,会造成带宽浪费和服务器存储冗余,此时可以使用文件秒传技术通过识别重复... 目录前言文件秒传原理代码实现1. 创建项目基础结构2. 创建上传存储代码3. 创建Result类4.

SpringBoot日志配置SLF4J和Logback的方法实现

《SpringBoot日志配置SLF4J和Logback的方法实现》日志记录是不可或缺的一部分,本文主要介绍了SpringBoot日志配置SLF4J和Logback的方法实现,文中通过示例代码介绍的非... 目录一、前言二、案例一:初识日志三、案例二:使用Lombok输出日志四、案例三:配置Logback一

Python如何使用__slots__实现节省内存和性能优化

《Python如何使用__slots__实现节省内存和性能优化》你有想过,一个小小的__slots__能让你的Python类内存消耗直接减半吗,没错,今天咱们要聊的就是这个让人眼前一亮的技巧,感兴趣的... 目录背景:内存吃得满满的类__slots__:你的内存管理小助手举个大概的例子:看看效果如何?1.

Python+PyQt5实现多屏幕协同播放功能

《Python+PyQt5实现多屏幕协同播放功能》在现代会议展示、数字广告、展览展示等场景中,多屏幕协同播放已成为刚需,下面我们就来看看如何利用Python和PyQt5开发一套功能强大的跨屏播控系统吧... 目录一、项目概述:突破传统播放限制二、核心技术解析2.1 多屏管理机制2.2 播放引擎设计2.3 专

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

一文教你如何将maven项目转成web项目

《一文教你如何将maven项目转成web项目》在软件开发过程中,有时我们需要将一个普通的Maven项目转换为Web项目,以便能够部署到Web容器中运行,本文将详细介绍如何通过简单的步骤完成这一转换过程... 目录准备工作步骤一:修改​​pom.XML​​1.1 添加​​packaging​​标签1.2 添加

idea中创建新类时自动添加注释的实现

《idea中创建新类时自动添加注释的实现》在每次使用idea创建一个新类时,过了一段时间发现看不懂这个类是用来干嘛的,为了解决这个问题,我们可以设置在创建一个新类时自动添加注释,帮助我们理解这个类的用... 目录前言:详细操作:步骤一:点击上方的 文件(File),点击&nbmyHIgsp;设置(Setti

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.