手部关键点检测5:c实现手部关键点检测(手部姿势
墨初 知识笔记 134阅读
目录
手部关键点检测4C实现手部关键点检测(手部姿势估计)含源码 可实时检测

1.项目介绍
2.手部关键点检测(手部姿势估计)方法

(1)Top-Down(自上而下)方法
(2)Bottom-Up(自下而上)方法
3.手部关键点检测模型
1 手部关键点检测模型的训练
2 将Pytorch模型转换ONNX模型
3 将ONNX模型转换为TNN模型
4.手部关键点检测C/C部署
1项目结构
2配置开发环境(OpenCVOpenCLbase-utilsTNN)
3部署TNN模型
4CMake配置
5main源码
6源码编译和运行
7Demo测试效果
5.项目源码下载
1.项目介绍
本篇文章是项目《手部关键点检测(手部姿势估计)》系列文章之《C实现手部关键点检测(手部姿势估计)含源码 可实时检测》项目基于Pytorch深度学习框架实现手部关键点检测(手部姿势估计)模型其中手部检测采用YOLOv5模型手部关键点检测是基于开源的HRNet进行改进构建了整套手部关键点检测的训练和测试流程为了方便后续模型工程化和Android平台部署项目支持高精度HRNet检测模型轻量化模型LiteHRNet和Mobilenet模型训练和测试并提供Python/C/Android多个版本
本篇主要分享将Python训练后的手部检测和手部关键点检测模型部署到C/C平台。我们将开发一个简易的、可实时运行的手部关键点检测的C/C Demo。下表格给出HRNet以及轻量化模型LiteHRNet和Mobilenet的计算量和参数量以及其检测精度
模型input-sizeparams(M)GFLOPsAPHRNet-w32192×19228.48M5734.05M0.8570LiteHRNet18192×1921.10M182.15M0.8023Mobilenet-v2192×1922.63M529.25M0.7574先展示一下C/C版本的手部检测以及手部关键点检测(手部姿势估计)效果
Android手部关键点检测(手部姿势估计)APP Demo体验
【尊重原创转载请注明出处】
更多项目《手部关键点检测(手部姿势估计)》系列文章请参考
手部关键点检测1手部关键点(手部姿势估计)数据集(含下载链接) 可实时检测 可实时检测
2.手部关键点检测(手部姿势估计)方法手部关键点检测(手部姿势估计)的方法目前主流的方法主要两种一种是Top-Down自上而下方法另外一种是Bottom-Up自下而上方法
(1)Top-Down(自上而下)方法将手部检测和手部关键点估计分离在图像上首先进行手部目标检测定位手部位置然后crop每一个手部图像再估计每个手部的关键点这类方法往往比较慢但姿态估计准确度较高。目前主流模型主要有CPNHourglassCPMAlpha PoseHRNet等。
(2)Bottom-Up(自下而上)方法先估计图像中所有手部的关键点然后在通过Grouping的方法组合成一个一个手部实例因此这类方法在测试推断的时候往往更快速准确度稍低。典型就是COCO2016年人体关键点检测冠军Open Pose。
通常来说Top-Down具有更高的精度而Bottom-Up具有更快的速度就目前调研而言 Top-Down的方法研究较多精度也比Bottom-Up自下而上方法高。
本项目基于开源的HRNet进行改进关于HRNet项目请参考GitHub
HRNet: 3.手部关键点检测模型 1 手部关键点检测模型的训练
本篇博文主要分享C版本的模型部署不包含Python版本的手部关键点检测以及相关训练代码关于手部关键点检测的训练方法和数据集说明请参考本人另一篇博文《手部关键点检测3Pytorch实现手部关键点检测(手部姿势估计)含训练代码和数据集》手部关键点检测3Pytorch实现手部关键点检测(手部姿势估计)含训练代码和数据集-博客
2 将Pytorch模型转换ONNX模型目前CNN模型有多种部署方式可以采用TNNMNN,NCNN以及TensorRT等部署工具鄙人采用TNN进行C/C端上部署。部署流程可分为四步训练模型->将模型转换ONNX模型->将ONNX模型转换为TNN模型->C/C部署TNN模型。
训练好Pytorch模型后我们需要先将模型转换为ONNX模型以便后续模型部署。
原始项目提供转换脚本你只需要修改model_file为你模型路径即可 convert_torch_to_onnx.py实现将Pytorch模型转换ONNX模型的脚本python libs/convert_tools/convert_torch_to_onnx.py
This code is used to convert the pytorch model into an onnx format model.import osimport torch.onnxfrom pose.inference import PoseEstimationfrom basetrainer.utils.converter import pytorch2onnx def load_model(config_file, model_file, devicecuda:0): pose PoseEstimation(config_file, model_file, devicedevice) model pose.model config pose.config return model, config def convert2onnx(config_file, model_file, devicecuda:0, onnx_typekp): :param model_file: :param input_size: :param device: :param onnx_type: :return: model, config load_model(config_file, model_file, devicedevice) model model.to(device) model.eval() model_name os.path.basename(model_file)[:-len(.pth)] onnx_file os.path.join(os.path.dirname(model_file), model_name .onnx) # dummy_input torch.randn(1, 3, 240, 320).to(cuda) input_size tuple(config.MODEL.IMAGE_SIZE) # w,h input_shape (1, 3, input_size[1], input_size[0]) pytorch2onnx.convert2onnx(model, input_shapeinput_shape, input_names[input], output_names[output], onnx_fileonnx_file, opset_version11) if __name__ __main__: model_file ../../work_space/hand/mobilenet_v2_21_192_192_custom_coco_20230928_065444_0934/model/best_model_153_0.7574.pth config_file ../../work_space/hand/mobilenet_v2_21_192_192_custom_coco_20230928_065444_0934/mobilenetv2_hand_192_192.yaml convert2onnx(config_file, model_file)
3 将ONNX模型转换为TNN模型 目前CNN模型有多种部署方式可以采用TNNMNN,NCNN以及TensorRT等部署工具鄙人采用TNN进行C/C端上部署
TNN转换工具
1将ONNX模型转换为TNN模型请参考TNN官方说明TNN/onnx2tnn.md at master · Tencent/TNN · GitHub2一键转换懒人必备一键转换 Caffe, ONNX, TensorFlow 到 NCNN, MNN, Tengine (可能存在版本问题这个工具转换的TNN模型可能不兼容建议还是自己build源码进行转换2022年9约25日测试可用)
4.手部关键点检测C/C部署项目IDE开发工具使用CLion相关依赖库主要有OpenCVbase-utils以及TNN和OpenCL(可选)其中OpenCV必须安装OpenCL用于模型加速base-utils以及TNN已经配置好无需安装
项目仅在Ubuntu18.04进行测试Windows系统下请自行配置好开发环境。
1项目结构
2配置开发环境(OpenCVOpenCLbase-utilsTNN)项目IDE开发工具使用CLion相关依赖库主要有OpenCVbase-utils以及TNN和OpenCL(可选)其中OpenCV必须安装OpenCL用于模型加速base-utils以及TNN已经配置好无需安装
项目仅在Ubuntu18.04进行测试Windows系统下请自行配置和编译
安装OpenCV图像处理图像处理如读取图片图像裁剪等都需要使用OpenCV库进行处理
安装教程Ubuntu18.04安装opencv和opencv_contrib
OpenCV库使用opencv-4.3.0版本opencv_contrib库暂时未使用可不安装
安装OpenCL模型加速安装教程Ubuntu16.04 安装OpenCV&OpenCL
OpenCL用于模型GPU加速若不使用OpenCL进行模型推理加速纯C推理模型速度会特别特别慢
base-utilsC库GitHub 无需安装项目已经配置了
base_utils是个人开发常用的C库集成了C/C OpenCV等常用的算法
TNN模型推理GitHub 无需安装项目已经配置了
由腾讯优图实验室开源的高性能、轻量级神经网络推理框架同时拥有跨平台、高性能、模型压缩、代码裁剪等众多突出优势。TNN框架在原有Rapidnet、ncnn框架的基础上进一步加强了移动端设备的支持以及性能优化同时借鉴了业界主流开源框架高性能和良好拓展性的特性拓展了对于后台X86, NV GPU的支持。手机端 TNN已经在手机QQ、微视、P图等众多应用中落地服务端TNN作为腾讯云AI基础加速框架已为众多业务落地提供加速支持。
3部署TNN模型项目实现了C/C版本的车牌检测和车牌识别车牌检测模型YOLOv5和车牌识别模型PlateNet模型推理采用TNN部署框架支持多线程CPU和GPU加速推理图像处理采用OpenCV库模型加速采用OpenCL在普通设备即可达到实时处理。
如果你想在这个 Demo部署你自己训练的车牌检测模型YOLOv5和车牌识别模型PlateNet你可将训练好的Pytorch模型转换ONNX 再转换成TNN模型然后把原始的模型替换成你自己的TNN模型即可。
4CMake配置这是CMakeLists.txt其中主要配置OpenCVOpenCLbase-utilsTNN这四个库Windows系统下请自行配置和编译
cmake_minimum_required(VERSION 3.5)project(Detector)add_compile_options(-fPIC) # fix Bug: can not be used when making a shared objectset(CMAKE_CXX_FLAGS -Wall -stdc11 -pthread)#set(CMAKE_CXX_FLAGS_RELEASE -O2 -DNDEBUG)#set(CMAKE_CXX_FLAGS_DEBUG -g)if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) # -DCMAKE_BUILD_TYPEDebug # -DCMAKE_BUILD_TYPERelease message(STATUS No build type selected, default to Release) set(CMAKE_BUILD_TYPE Release CACHE STRING Build type (default Debug) FORCE)endif ()# opencv setfind_package(OpenCV REQUIRED)include_directories(${OpenCV_INCLUDE_DIRS} ./src/)#MESSAGE(STATUS OpenCV_INCLUDE_DIRS ${OpenCV_INCLUDE_DIRS})# base_utilsset(BASE_ROOT 3rdparty/base-utils) # 设置base-utils所在的根目录add_subdirectory(${BASE_ROOT}/base_utils/ base_build) # 添加子目录到build中include_directories(${BASE_ROOT}/base_utils/include)include_directories(${BASE_ROOT}/base_utils/src)MESSAGE(STATUS BASE_ROOT ${BASE_ROOT})# TNN set# Creates and names a library, sets it as either STATIC# or SHARED, and provides the relative paths to its source code.# You can define multiple libraries, and CMake buil ds it for you.# Gradle automatically packages shared libraries with your APK.# build for platform# set(TNN_BUILD_SHARED OFF CACHE BOOL FORCE)if (CMAKE_SYSTEM_NAME MATCHES Android) set(TNN_OPENCL_ENABLE ON CACHE BOOL FORCE) set(TNN_ARM_ENABLE ON CACHE BOOL FORCE) set(TNN_BUILD_SHARED OFF CACHE BOOL FORCE) set(TNN_OPENMP_ENABLE ON CACHE BOOL FORCE) # Multi-Thread #set(TNN_HUAWEI_NPU_ENABLE OFF CACHE BOOL FORCE) add_definitions(-DTNN_OPENCL_ENABLE) # for OpenCL GPU add_definitions(-DTNN_ARM_ENABLE) # for Android CPU add_definitions(-DDEBUG_ANDROID_ON) # for Android Log add_definitions(-DPLATFORM_ANDROID)elseif (CMAKE_SYSTEM_NAME MATCHES Linux) set(TNN_OPENCL_ENABLE ON CACHE BOOL FORCE) set(TNN_CPU_ENABLE ON CACHE BOOL FORCE) set(TNN_X86_ENABLE OFF CACHE BOOL FORCE) set(TNN_QUANTIZATION_ENABLE OFF CACHE BOOL FORCE) set(TNN_OPENMP_ENABLE ON CACHE BOOL FORCE) # Multi-Thread add_definitions(-DTNN_OPENCL_ENABLE) # for OpenCL GPU add_definitions(-DDEBUG_ON) # for WIN/Linux Log add_definitions(-DDEBUG_LOG_ON) # for WIN/Linux Log add_definitions(-DDEBUG_IMSHOW_OFF) # for OpenCV show add_definitions(-DPLATFORM_LINUX)elseif (CMAKE_SYSTEM_NAME MATCHES Windows) set(TNN_OPENCL_ENABLE ON CACHE BOOL FORCE) set(TNN_CPU_ENABLE ON CACHE BOOL FORCE) set(TNN_X86_ENABLE ON CACHE BOOL FORCE) set(TNN_QUANTIZATION_ENABLE OFF CACHE BOOL FORCE) set(TNN_OPENMP_ENABLE ON CACHE BOOL FORCE) # Multi-Thread add_definitions(-DTNN_OPENCL_ENABLE) # for OpenCL GPU add_definitions(-DDEBUG_ON) # for WIN/Linux Log add_definitions(-DDEBUG_LOG_ON) # for WIN/Linux Log add_definitions(-DDEBUG_IMSHOW_OFF) # for OpenCV show add_definitions(-DPLATFORM_WINDOWS)endif ()set(TNN_ROOT 3rdparty/TNN)include_directories(${TNN_ROOT}/include)include_directories(${TNN_ROOT}/third_party/opencl/include)add_subdirectory(${TNN_ROOT}) # 添加外部项目文件夹set(TNN -Wl,--whole-archive TNN -Wl,--no-whole-archive)# set TNN libraryMESSAGE(STATUS TNN_ROOT ${TNN_ROOT})# Detectorinclude_directories(src)set(SRC_LIST src/Interpreter.cpp src/pose_detector.cpp src/object_detection.cpp src/pose_filter.cpp src/yolov5.cpp )add_library(dlcv SHARED ${SRC_LIST})target_link_libraries(dlcv ${OpenCV_LIBS} base_utils)MESSAGE(STATUS DIR_SRCS ${SRC_LIST})add_executable(Detector src/main.cpp)target_link_libraries(Detector dlcv ${TNN} -lpthread)
5main源码 主程序中函数main实现提供了手部关键点检测的使用方法支持图片视频和摄像头测试
test_image_file(); // 测试图片文件 test_video_file(); // 测试视频文件 test_camera(); //测试摄像头//// Created by 390737991qq.com on 2020/6/3.//#include pose_detector.h#include object_detection.h#include yolov5.h#include Types.h#include <iostream>#include <string>#include <vector>#include file_utils.h#include image_utils.husing namespace dl;using namespace vision;using namespace std;const int num_thread 1; // 开启CPU线程数目DeviceType device GPU; // 选择运行设备CPU/GPU// 目标检测SSD或者YOLOv5const float scoreThresh 0.5;const float iouThresh 0.3;//const char *det_model_file (char *) ../data/tnn/ssd/rfb1.0_person_320_320_sim.opt.tnnmodel;//const char *det_proto_file (char *) ../data/tnn/ssd/rfb1.0_person_320_320_sim.opt.tnnproto;//ObjectDetectionParam model_param PERSON_MODEL;//模型参数//ObjectDetection *detector new ObjectDetection(det_model_file, det_proto_file, model_param, num_thread, device);const char *det_model_file (char *) ../data/tnn/yolov5/yolov5s05_320.sim.tnnmodel;const char *det_proto_file (char *) ../data/tnn/yolov5/yolov5s05_320.sim.tnnproto;YOLOv5Param dets_model_param YOLOv5s05_320;//模型参数YOLOv5 *detector new YOLOv5(det_model_file, det_proto_file, dets_model_param, num_thread, device);// 关键点检测const float poseThresh 0.3;const char *pose_model_file (char *) ../data/tnn/pose/litehrnet18_192_192.sim.tnnmodel;const char *pose_proto_file (char *) ../data/tnn/pose/litehrnet18_192_192.sim.tnnproto;PoseParam pose_model_param HAND_PARAM;//模型参数PoseDetector *pose new PoseDetector(pose_model_file, pose_proto_file, pose_model_param, num_thread, device);void test_image_file() { //测试图片的目录 string image_dir ../data/test_image; std::vector<string> image_list get_files_list(image_dir); for (string image_path:image_list) { cv::Mat bgr cv::imread(image_path); if (bgr.empty()) continue; FrameInfo resultInfo; // 进行目标检测 detector->detect(bgr, &resultInfo, scoreThresh, iouThresh); // 进行关键点检测 pose->detect(bgr, &resultInfo, poseThresh); // 可视化代码 pose->visualizeResult(bgr, resultInfo, pose_model_param.skeleton, false, 0); } delete detector; detector nullptr; delete pose; pose nullptr; printf(FINISHED.\n);}/*** * 测试视频文件 * return */int test_video_file() { //测试视频文件 string video_file ../data/video/video-test.mp4; cv::VideoCapture cap; bool ret get_video_capture(video_file, cap); cv::Mat frame; while (ret) { cap >> frame; if (frame.empty()) break; FrameInfo resultInfo; // 进行目标检测 detector->detect(frame, &resultInfo, scoreThresh, iouThresh); // 进行关键点检测 pose->detect(frame, &resultInfo, poseThresh); // 可视化代码 pose->visualizeResult(frame, resultInfo, pose_model_param.skeleton, false, 5); } cap.release(); delete detector; detector nullptr; delete pose; pose nullptr; printf(FINISHED.\n); return 0;}/*** * 测试摄像头 * return */int test_camera() { int camera 0; //摄像头ID号(请修改成自己摄像头ID号) cv::VideoCapture cap; bool ret get_video_capture(camera, cap); cv::Mat frame; while (ret) { cap >> frame; if (frame.empty()) break; FrameInfo resultInfo; // 进行目标检测 detector->detect(frame, &resultInfo, scoreThresh, iouThresh); // 进行关键点检测 pose->detect(frame, &resultInfo, poseThresh); // 可视化代码 pose->visualizeResult(frame, resultInfo, pose_model_param.skeleton, false, 5); } cap.release(); delete detector; detector nullptr; delete pose; pose nullptr; printf(FINISHED.\n); return 0;}/*** * 测试跟踪效果 * return */int test_pose_track() { //测试视频文件 string video_file ../data/video/video-test.mp4; cv::VideoCapture cap; bool ret get_video_capture(video_file, cap); cv::Mat frame; // 指定需要跟踪(滤波)的关键点,目前仅仅支持单目标的关键点跟踪多目标不支持会出现异常 vector<int> filter_id {0}; // 初始化跟踪 pose->initTrack(filter_id, 20, 0.35); while (ret) { cap >> frame; if (frame.empty()) break; FrameInfo resultInfo; // 进行目标检测 detector->detect(frame, &resultInfo, scoreThresh, iouThresh); // 进行关键点检测和跟踪 pose->track(frame, &resultInfo, poseThresh); // 可视化代码 pose->visualizeResult(frame, resultInfo, pose_model_param.skeleton, false, 5); } cap.release(); delete detector; detector nullptr; delete pose; pose nullptr; printf(FINISHED.\n); return 0;}int main() { test_image_file(); // 测试图片文件 test_video_file(); // 测试视频文件 test_camera(); //测试摄像头 return 0;}
6源码编译和运行 编译脚本或者直接bash build.sh
#!/usr/bin/env bashif [ ! -d build/ ];then mkdir buildelse echo exist buildficd buildcmake ..make -j4sleep 1./Detector
如果你要测试CPU运行的性能请修改src/main.cpp DeviceType device CPU;
如果你要测试GPU运行的性能请修改src/main.cpp 需配置好OpenCLDeviceType device GPU;
PS纯CPU C推理模式比较耗时需要几秒的时间而开启OpenCL加速后GPU模式耗时仅需十几毫秒性能极大的提高。
7Demo测试效果C版本与Python版本的结果几乎是一致,下面是手部关键点检测效果展示:
5.项目源码下载
C/C实现手部关键点检测项目源码下载地址C实现手部关键点检测(手部姿势估计)源码下载
整套项目源码内容包含
C/C源码支持YOLOv5手部检测C/C源码提供高精度版本HRNet手部关键点检测C/C源码提供轻量化模型LiteHRNet和Mobilenet-v2手部关键点检测C/C源码支持CPU和GPU开启GPU(OpenCL)可以实时检测和识别纯CPU推理速度很慢模型加速需要配置好OpenCLGPU推理约15ms左右C/C源码Demo支持图片视频摄像头测试项目配置好了base-utils和TNN而OpenCV和OpenCL需要自行编译安装Android手部关键点检测APP Demo体验
如果你需要手部关键点检测的训练代码请参考手部关键点检测3Pytorch实现手部关键点检测(手部姿势估计)含训练代码和数据集