基本思想:需要水一篇博客,套用了qiuqiu大佬的simplepose代码,使用ncnn框架,做了个动作检测,然后套用了树莓派4b和使用了语音模块播报

一、自己购买树莓派和喇叭,链接参考这篇博客26、友善NanoPi NEO进行目标检测和串口调试语音播报_sxj731533730的博客-CSDN博客_nanopi neo python

然后接线图上一下,串口工具和杜邦线是必不可少的,串口调试工具也是必不可少。

第二步:写代码在树莓中,调用串口和摄像头(摄像头可以使用手机的摄像头或者笔记本的摄像头 直接用ffmpeg拉流推流给树莓派代码),我用的usb摄像头,推拉流摄像头使用手机摄像头当做实际树莓派的输入视频流 参考这篇38、静默活体检测测试及ncnn、mnn部署_sxj731533730的博客-CSDN博客_静默活体检测

#include "ncnn/net.h"#include <algorithm>
#if defined(USE_NCNN_SIMPLEOCV)
#include "simpleocv.h"
#else
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#endif
#include <stdio.h>
#include <vector>
#include <iostream>#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>struct KeyPoint
{cv::Point2f p;float prob;
};
ncnn::Net posenet;
int initial(){posenet.opt.use_vulkan_compute = true;// the simple baseline human pose estimation from gluon-cv// https://gluon-cv.mxnet.io/build/examples_pose/demo_simple_pose.html// mxnet model exported via//      pose_net.hybridize()//      pose_net.export('pose')// then mxnet2ncnn// the ncnn model https://github.com/nihui/ncnn-assets/tree/master/modelsif (posenet.load_param("../model/pose.param"))exit(-1);if (posenet.load_model("../model/pose.bin"))exit(-1);
}
static int detect_posenet(const cv::Mat& bgr, std::vector<KeyPoint>& keypoints)
{int w = bgr.cols;int h = bgr.rows;ncnn::Mat in = ncnn::Mat::from_pixels_resize(bgr.data, ncnn::Mat::PIXEL_BGR2RGB, w, h, 192, 256);// transforms.ToTensor(),// transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)),// R' = (R / 255 - 0.485) / 0.229 = (R - 0.485 * 255) / 0.229 / 255// G' = (G / 255 - 0.456) / 0.224 = (G - 0.456 * 255) / 0.224 / 255// B' = (B / 255 - 0.406) / 0.225 = (B - 0.406 * 255) / 0.225 / 255const float mean_vals[3] = {0.485f * 255.f, 0.456f * 255.f, 0.406f * 255.f};const float norm_vals[3] = {1 / 0.229f / 255.f, 1 / 0.224f / 255.f, 1 / 0.225f / 255.f};in.substract_mean_normalize(mean_vals, norm_vals);ncnn::Extractor ex = posenet.create_extractor();ex.input("data", in);ncnn::Mat out;ex.extract("conv3_fwd", out);// resolve point from heatmapkeypoints.clear();for (int p = 0; p < out.c; p++){const ncnn::Mat m = out.channel(p);float max_prob = 0.f;int max_x = 0;int max_y = 0;for (int y = 0; y < out.h; y++){const float* ptr = m.row(y);for (int x = 0; x < out.w; x++){float prob = ptr[x];if (prob > max_prob){max_prob = prob;max_x = x;max_y = y;}}}KeyPoint keypoint;keypoint.p = cv::Point2f(max_x * w / (float)out.w, max_y * h / (float)out.h);keypoint.prob = max_prob;keypoints.push_back(keypoint);}return 0;
}int sendSerialPort(const char W_BUF[], int length) {int tty_fd = -1;int rv = -1;struct termios options;system("sudo chmod 777 /dev/ttyS0");tty_fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY); //打开串口设备fcntl(tty_fd, F_SETFL, 0);if (tty_fd < 0) {printf("open tty failed:%s\n", strerror(errno));close(tty_fd);return -1;}printf("open devices sucessful!\n");memset(&options, 0, sizeof(options));rv = tcgetattr(tty_fd, &options); //获取原有的串口属性的配置if (rv != 0) {printf("tcgetattr() failed:%s\n", strerror(errno));close(tty_fd);return -1;}options.c_cflag |= (CLOCAL | CREAD); // CREAD 开启串行数据接收,CLOCAL并打开本地连接模式options.c_cflag &= ~CSIZE;// 先使用CSIZE做位屏蔽options.c_cflag |= CS8; //设置8位数据位options.c_cflag &= ~PARENB; //无校验位cfsetispeed(&options, B9600);cfsetospeed(&options, B9600);options.c_cflag &= ~CSTOPB;options.c_cc[VTIME] = 0;options.c_cc[VMIN] = 0;tcflush(tty_fd, TCIFLUSH);if ((tcsetattr(tty_fd, TCSANOW, &options)) != 0) {printf("tcsetattr failed:%s\n", strerror(errno));close(tty_fd);return -1;}std::cout << std::endl << "length= " << length << std::endl;rv = write(tty_fd, W_BUF, length);if(rv<=0) /* 出错了*/{if (errno == EINTR) /* 中断错误 我们继续写*/{close(tty_fd);printf("[SeanSend]error errno==EINTR continue\n");} else if (errno == EAGAIN) /* EAGAIN : Resource temporarily unavailable*/{sleep(1);//等待一秒,希望发送缓冲区能得到释放close(tty_fd);printf("[SeanSend]error errno==EAGAIN continue\n");} else /* 其他错误 没有办法,只好退了*/{printf("[SeanSend]ERROR: errno = %d, strerror = %s \n", errno, strerror(errno));return (-1);}}if (rv < 0) {printf("Write() error:%s\n", strerror(errno));close(tty_fd);return -1;}for (int i = 0; i < length; i++) {std::cout << std::hex << (int) W_BUF[i] << " ";}close(tty_fd);printf("\nWrite() successfully\n");return 0;}static void draw_pose(const cv::Mat& bgr, const std::vector<KeyPoint>& keypoints)
{cv::Mat image = bgr.clone();// draw bonestatic const int joint_pairs[16][2] = {{0, 1}, {1, 3}, {0, 2}, {2, 4}, {5, 6}, {5, 7}, {7, 9}, {6, 8}, {8, 10}, {5, 11}, {6, 12}, {11, 12}, {11, 13}, {12, 14}, {13, 15}, {14, 16}};//    for (int i = 0; i < 16; i++)
//    {
//        const KeyPoint& p1 = keypoints[joint_pairs[i][0]];
//        const KeyPoint& p2 = keypoints[joint_pairs[i][1]];
//
//        if (p1.prob < 0.2f || p2.prob < 0.2f)
//            continue;
//
//        cv::line(image, p1.p, p2.p, cv::Scalar(255, 0, 0), 2);
//
////    }//   cv::line(image, keypoints[joint_pairs[4][0]].p, keypoints[joint_pairs[4][1]].p, cv::Scalar(255, 0, 255), 8);//  cv::line(image, keypoints[joint_pairs[5][0]].p, keypoints[joint_pairs[5][1]].p, cv::Scalar(0, 0, 255), 8);//cv::line(image, keypoints[joint_pairs[6][0]].p, keypoints[joint_pairs[6][1]].p, cv::Scalar(255, 255, 120), 8);//cv::line(image, keypoints[joint_pairs[7][0]].p, keypoints[joint_pairs[7][1]].p, cv::Scalar(0, 255, 255), 8);//cv::line(image, keypoints[joint_pairs[8][0]].p, keypoints[joint_pairs[8][1]].p, cv::Scalar(255, 255, 0), 8);// draw joint
//    for (size_t i = 0; i < keypoints.size(); i++)
//    {
//        const KeyPoint& keypoint = keypoints[i];
//
//        fprintf(stderr, "%.2f %.2f = %.5f\n", keypoint.p.x, keypoint.p.y, keypoint.prob);
//
//        if (keypoint.prob < 0.2f)
//            continue;
//
//        cv::circle(image, keypoint.p, 3, cv::Scalar(0, 255, 0), -1);
//    }const  char data[] = {0xFD,0x00 ,0x07 ,0x01 ,0x01 ,0xB4, 0xF2 ,0xC8, 0xAD ,0xD9 };cv::circle(image, keypoints[5].p, 3, cv::Scalar(255, 255, 255), -1);cv::putText(image, "5", keypoints[5].p, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 1, 8, 0);cv::circle(image, keypoints[6].p, 3, cv::Scalar(0, 255, 0), -1);cv::putText(image, "6", keypoints[6].p, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(0, 255, 255), 1, 8, 0);cv::circle(image, keypoints[8].p, 3, cv::Scalar(0, 255, 0), -1);cv::putText(image, "8", keypoints[8].p, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(0, 255, 255), 1, 8, 0);cv::circle(image, keypoints[7].p, 3, cv::Scalar(0, 255, 0), -1);cv::putText(image, "7", keypoints[7].p, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(0, 255, 255), 1, 8, 0);cv::circle(image, keypoints[9].p, 3, cv::Scalar(0, 255, 0), -1);cv::putText(image, "9", keypoints[9].p, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(0, 255, 255), 1, 8, 0);cv::circle(image, keypoints[10].p, 3, cv::Scalar(0, 255, 0), -1);cv::putText(image, "10", keypoints[10].p, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(0, 255, 255), 1, 8, 0);if(keypoints[9].p.y<keypoints[7].p.y&&keypoints[10].p.y<keypoints[8].p.y){//printf("rise hand \n");int distance0=sqrt( pow(keypoints[9].p.y-keypoints[5].p.y,2)+pow(keypoints[9].p.x-keypoints[5].p.x,2));int distance1=sqrt( pow(keypoints[6].p.y-keypoints[10].p.y,2)+pow(keypoints[6].p.x-keypoints[10].p.x,2));//printf("disntance %d\n",distance);if(distance0>60&&distance1>60){printf("make pose\n");sendSerialPort(data, sizeof(data));//测试}}cv::imshow("image", image);cv::waitKey(1);
}int main(int argc, char** argv)
{cv::VideoCapture capture(0);if (!capture.isOpened()) {std::cout << "open camera error!" << std::endl;return -1;}initial();cv::Mat frame;while (1) {capture >> frame;cv::resize(frame,frame,cv::Size(640,640));std::vector<KeyPoint> keypoints;detect_posenet(frame, keypoints);draw_pose(frame, keypoints);if (frame.empty()) {std::cout << "capture empty frame" << std::endl;continue;}}return 0;
}

其中中文生成语音十六进制使用喇叭官方软件拷贝就行,只上个简单图

测试结果

pi@raspberrypi:~/Orienmask_project/build $ ./Orienmask_project
hit box
open devices sucessful!length= 10
fd 0 7 1 1 b4 f2 c8 ad d9
Write() successfully
make pose
open devices sucessful!length= a
fd 0 7 1 1 b4 f2 c8 ad d9
Write() successfully
make pose
open devices sucessful!length= a
fd 0 7 1 1 b4 f2 c8 ad d9
Write() successfully
make pose
open devices sucessful!length= a
fd 0 7 1 1 b4 f2 c8 ad d9
Write() successfully
make pose
open devices sucessful!length= a
fd 0 7 1 1 b4 f2 c8 ad d9
Write() successfully
make pose
open devices sucessful!

关于树莓派的引脚接口定义

pi@raspberrypi:~ $ ls -l /dev/serial*
lrwxrwxrwx 1 root root 5 8月  20 20:15 /dev/serial0 -> ttyS0
lrwxrwxrwx 1 root root 7 8月  20 20:15 /dev/serial1 -> ttyAMA0
pi@raspberrypi:~ $ 

保证

pi@raspberrypi:~ $ sudo gedit /boot/config.txt
#dtoverlay=pi3-disable-bt  #处于注释状态

参考:

树莓派教程 - 1.5 树莓派GPIO库wiringPi 使用硬件串口ttyAMA0与ttyS0_Mark_md的博客-CSDN博客_ttyama0

34、树莓派进行人体姿态检测并进行语音播报相关推荐

  1. 加盟依图科技后,颜水成首篇顶会论文提出“高效多人体姿态检测SPM”

    唐木 发自 天龙寺  量子位 出品 | 公众号 QbitAI 颜水成团队研究实力依然强劲. 从360到依图,颜水成依然保持着高质量的学术输出. 最近提出的单阶段高效人体姿态检测模型SPM就是最好的例证 ...

  2. python 人体检测技术_tensorflow入门教程(四十三)人体姿态检测(一)

    # #作者:韦访 #博客:https://blog.csdn.net/rookie_wei #微信:1007895847 #添加微信的备注一下是CSDN的 #欢迎大家一起学习 # ------韦访 2 ...

  3. tensorflow入门教程(四十四)人体姿态检测(二)

    # #作者:韦访 #博客:https://blog.csdn.net/rookie_wei #微信:1007895847 #添加微信的备注一下是CSDN的 #欢迎大家一起学习 # ------韦访 2 ...

  4. MATLAB基于视频的人体姿态检测

    基于视频的人体姿态检测 设计目的和要求 1.根据已知要求分析视频监控中行人站立和躺卧姿态检测的处理流程,确定视频监中行人的检测设计的方法,画出流程图,编写实现程序,并进行调试,录制实验视频,验证检测方 ...

  5. 轻量级openpose人体姿态检测

    1.去github下载轻量级openpose人体姿态检测项目:https://github.com/Daniil-Osokin/lightweight-human-pose-estimation.py ...

  6. ​MATLAB差影法人体姿态检测系统

    ​MATLAB差影法人体姿态检测系统 1.应用背景 运动目标的定位跟踪,检测识别,运动分析在图像压缩.运动分析.交通检测,智能监控等方面有主要的应用. 首先,在图像压缩中,运动目标检测技术可以在背景区 ...

  7. 项目开源!基于PaddleDetection打造实时人体姿态检测的多关节控制皮影机器人

    本文已在[飞桨PaddlePaddle]公众号平台发布,详情请戳链接:项目开源!基于PaddleDetection打造实时人体姿态检测的多关节控制皮影机器人 皮影戏是一种以兽皮或纸板做成的人物剪影以表 ...

  8. 百度AI 实现人体姿态检测

    最近在搞人脸识别,Yolo,Dlib,单纯向量法都玩了一遍,效果还可以. 昨天由老师给我发了一个百度AI的链接,我就玩开了上面的一个demo,叫做人体姿态检测出,这个名词名副其实,其背后的数学原理和论 ...

  9. 人体姿态检测 通过Opencv+Openpose实现

    通过一个偶然机会,我了解到了人体姿态解算,在学习K210之余,我便想着通过opencv实现这个功能,查找了很多资料,发现可以利用opencv+openpose实现,接着我又开始找一些资料,在pycha ...

最新文章

  1. 2014 Super Training #8 C An Easy Game --DP
  2. springboot redis
  3. cx_oracle windows缺少100 dll,Windows10无法运行QQ提示缺少MSVCR100.dll的解决方案
  4. Vmware ESX server CPU掩码导致的挂起
  5. UA MATH571B 试验设计V 2K析因设计简介
  6. jdk紧急漏洞,XMLDecoder反序列化攻击
  7. Oracle 11g新特性:Result Cache
  8. oracle行迁移实验,Oracle 行迁移 amp; 行链接的检测与消除
  9. 年近八旬教授曾一次性捐款8000多万,今获省杰出贡献奖!
  10. ftp服务器复制粘贴文件夹,ftp服务器复制粘贴文件夹
  11. webso员ket php,客戶端和PHP後端通信:Sokets,Stream,TCP/UDP?
  12. java 注解加载配置文件_Spring的Java配置方式和读取properties配置文件
  13. leetcode16 3-Sum
  14. [PeterDLax著泛函分析习题参考解答]第4章 Hahn-Bananch 定理的应用
  15. shiro的详细讲解
  16. FATF发布数字资产反洗钱指南
  17. 申万一级行业指数是什么?
  18. 如何将网站转化为桌面应用
  19. Vue+Vuex+Axios+ECharts 画一个动态更新的中国地图
  20. const violate

热门文章

  1. VS Code 杀死 IDEA?!
  2. 雷火神山直播超两亿,Web播放器事件监听是怎么实现的?
  3. JTAG(四) 边界扫描测试技术
  4. Value '0000-00-00 00:00:00' can not be represented as java.sql.Timestamp
  5. hbase shell assign
  6. Redash 可视化BI系统部署安装及简单使用
  7. Linux内核学习(五):linux kernel源码结构以及makefile分析
  8. 全国计算机等级考试vb试卷,2002年9月全国计算机等级考试二级VB试卷(含答案)...
  9. 中忻嘉业科技:怎样来提升抖音账号的等级
  10. linux去掉文件空行,linux下删除文件中空行的多种方法 互联网技术圈 互联网技术圈...