个人博客:http://www.chenjianqu.com/

原文链接:http://www.chenjianqu.com/show-104.html

最近某些项目需要用到人体姿势识别。当前有很多著名的人体识别的开源项目,比如CMU的OpenPose,上交的AlphaPose,效果都很好。我昨天试着安装一下AlphaPose,配环境配了一天,终于可以运行Demo的时候,显存溢出。。。因此我换个思路,我的项目不要求实时性,使用API也是可以接受的。发现百度的人体识别这方面的API还不错,QPS限制为2,也能用,于是便有了这篇文章。

本文通过调用百度开放的人体关键点检测API,实现关键点检测并将其在Python的轻量级GUI库Tkinter绘制出来。当然最直接的方法是直接用opencv显示出来,但是我们更多的时候需要进行交互,因此使用Tkinter。

一、百度API获取

若想使用百度的API,需要在百度AI的官网上注册帐号,然后在人体识别功能下创建一个应用,即可得到

APP_ID、API_KEY、SECRET_KEY,这样就可以调用它的API了。调用方式可以参考其API文档https://ai.baidu.com/ai-doc/BODY/0k3cpyxme

若想使用Python调用,首先要安装百度的API接口模块:

pip install baidu-aip

二、人体关键点获取和绘制

可以通过下面的类调用百度API

class BaiduAIP(object):def __init__(self):self.client = AipBodyAnalysis(cfg.APP_ID, cfg.API_KEY, cfg.SECRET_KEY)def bodyAnalysis(self,img_jpg):etval, buffer = cv2.imencode('.jpg', img_jpg)result = self.client.bodyAnalysis(buffer) #内部把buffer转换为base64了return result

然后是绘制关键点和连线和方框的函数:

def draw_line(img,dic,text):color=(0,255,0)thickness=2if(text=='warn'):color=(0,0,255)#nose ---> neckcv2.line(img, (int(dic['nose']['x']),int(dic['nose']['y'])),(int(dic['neck']['x']),int(dic['neck']['y'])), color, thickness)#neck --> left_shouldercv2.line(img, (int(dic['neck']['x']),int(dic['neck']['y'])),(int(dic['left_shoulder']['x']),int(dic['left_shoulder']['y'])), color, thickness)#neck --> right_shouldercv2.line(img, (int(dic['neck']['x']),int(dic['neck']['y'])),(int(dic['right_shoulder']['x']),int(dic['right_shoulder']['y'])), color, thickness)#left_shoulder --> left_elbowcv2.line(img, (int(dic['left_shoulder']['x']),int(dic['left_shoulder']['y'])),(int(dic['left_elbow']['x']),int(dic['left_elbow']['y'])), color, thickness)#left_elbow --> left_wristcv2.line(img, (int(dic['left_elbow']['x']),int(dic['left_elbow']['y'])),(int(dic['left_wrist']['x']),int(dic['left_wrist']['y'])), color, thickness)#right_shoulder --> right_elbowcv2.line(img, (int(dic['right_shoulder']['x']),int(dic['right_shoulder']['y'])),(int(dic['right_elbow']['x']),int(dic['right_elbow']['y'])), color, thickness)#right_elbow --> right_wristcv2.line(img, (int(dic['right_elbow']['x']),int(dic['right_elbow']['y'])),(int(dic['right_wrist']['x']),int(dic['right_wrist']['y'])), color, thickness)#neck --> left_hipcv2.line(img, (int(dic['neck']['x']),int(dic['neck']['y'])),(int(dic['left_hip']['x']),int(dic['left_hip']['y'])), color, thickness)#neck --> right_hipcv2.line(img, (int(dic['neck']['x']),int(dic['neck']['y'])),(int(dic['right_hip']['x']),int(dic['right_hip']['y'])), color, thickness)#left_hip --> left_kneecv2.line(img, (int(dic['left_hip']['x']),int(dic['left_hip']['y'])),(int(dic['left_knee']['x']),int(dic['left_knee']['y'])), color, thickness)#right_hip --> right_kneecv2.line(img, (int(dic['right_hip']['x']),int(dic['right_hip']['y'])),(int(dic['right_knee']['x']),int(dic['right_knee']['y'])), color, thickness)#left_knee --> left_anklecv2.line(img, (int(dic['left_knee']['x']),int(dic['left_knee']['y'])),(int(dic['left_ankle']['x']),int(dic['left_ankle']['y'])), color, thickness)#right_knee --> right_anklecv2.line(img, (int(dic['right_knee']['x']),int(dic['right_knee']['y'])),(int(dic['right_ankle']['x']),int(dic['right_ankle']['y'])), color, thickness)def draw_point(img,dic,text):color=(0,255,0)thickness=2if(text=='warn'):color=(0,0,255)for i in dic:cv2.circle(img,(int(dic[i]['x']),int(dic[i]['y'])),5,color,thickness)def draw_box(img,dic,text):color=(255,0,0)if(text=='warn'):color=(0,0,255)left_top=(int(dic['left']),int(dic['top']))left_bottom=(int(dic['left']),int(dic['top']+dic['height']))right_bottom=(int(dic['left']+dic['width']),int(dic['top']+dic['height']))right_top=(int(dic['left']+dic['width']),int(dic['top']))cv2.line(img, left_top,left_bottom, color, 2)cv2.line(img, left_top,right_top, color, 2)cv2.line(img, right_bottom,left_bottom,color, 2)cv2.line(img, right_bottom,right_top,color, 2)cv2.putText(img, text, (int(dic['left']),int(dic['top'])+20), cv2.FONT_HERSHEY_COMPLEX, 1,color, 1)

测试一下:

if __name__ == '__main__':baiduapi = BaiduAIP()img = cv2.imread('/media/chen/chen/Photo/others/littleCookies.jpg')d=baiduapi.bodyAnalysis(img)print("api time= "+str(t2-t1))print(d["person_num"])print(d["log_id"])persion=d["person_info"]for p in persion:draw_line(img,p['body_parts'],'ok')draw_point(img,p['body_parts'],'ok')draw_box(img,p['location'],'beauty')cv2.imwrite("image1.jpg",img)

结果:

三、tkinter界面开发

先定义窗口和组件:

IMG_HEIGT=352*2
IMG_WIDTH=640*2
#根窗口
window = tk.Tk()#显示变量
num_people = StringVar()
num_people.set('当前人数:0')
num_desertion = StringVar()
num_desertion.set('开小差:0')#UI绘制
window.title("智能课堂管理")
sw = window.winfo_screenwidth()#获取屏幕宽
sh = window.winfo_screenheight()#获取屏幕高#设置窗口大小和位置
wx = IMG_WIDTH+100
wh = IMG_HEIGT+100
window.geometry("%dx%d+%d+%d" %(wx,wh,(sw-wx)/2,(sh-wh)/2-100))#窗口至指定位置#顶部是信息栏
fm1 = Frame(window)
Label(fm1, text="总人数:20").pack(side='left')
label_num = Label(fm1, textvariable=num_people).pack(side='left')
label_num = Label(fm1, textvariable=num_desertion).pack(side='left')
fm1.pack(side='top', padx=10)#左侧是操作栏
fm2 = Frame(window)
fm2.pack(side='left', padx=10)canvas1 = tk.Canvas(window,bg="#c4c2c2",height=IMG_HEIGT,width=IMG_WIDTH)#绘制画布
canvas1.pack(side="left")job=ImgProcThread()bt_start = tk.Button(fm2,text="启动",height=2,width=15,command=job.start).pack(side="top")
bt_pause = tk.Button(fm2,text="暂停",height=2,width=15,command=job.pause).pack(side="top")
bt_resume = tk.Button(fm2,text="恢复",height=2,width=15,command=job.resume).pack(side="top")
bt_stop = tk.Button(fm2,text="结束线程",height=2,width=15,command=job.stop).pack(side="top")
bt_quit = tk.Button(fm2,text="退出程序",height=2,width=15,command=window.quit).pack(side="top")window.mainloop()

ImgProcThread是什么?由于tkiner中没有提供直接播放视频的组件,因此我们使用cavas显示图片,并将关键点检测和图片检测放到另一个线程。但是由于Python自带的线程类功能功能不足,因此需要自己实现线程阻塞、结束等功能,如下:

class ImgProcThread(threading.Thread):def __init__(self, *args, **kwargs):super(ImgProcThread, self).__init__(*args, **kwargs)self.__flag = threading.Event()     # 用于暂停线程的标识self.__flag.set()       # 设置为Trueself.__running = threading.Event()      # 用于停止线程的标识self.__running.set()      # 将running设置为Truedef run(self):capture = cv2.VideoCapture('/media/chen/chen/Photo/others/1.mp4')while self.__running.isSet() and capture.isOpened():self.__flag.wait()      # 为True时立即返回, 为False时阻塞直到内部的标识位为True后返回passdef pause(self):self.__flag.clear()     # 设置为False, 让线程阻塞def resume(self):self.__flag.set()    # 设置为True, 让线程停止阻塞def stop(self):self.__flag.set()       # 将线程从暂停状态恢复, 如何已经暂停的话self.__running.clear()        # 设置为Fals

四、总程序

本程序是根据我自己的需求来写的,因此会有一些在别人看起来蜜汁操作的代码,大家可以略过。

    config.py

APP_ID="***"
API_KEY="***"
SECRET_KEY="***"

aip_bodyanalysis.py

from aip import AipBodyAnalysis
import sys
if('/opt/ros/kinetic/lib/python2.7/dist-packages' in sys.path):sys.path.remove('/opt/ros/kinetic/lib/python2.7/dist-packages')
import cv2
import os
import  config  as cfg
import base64
import timedef pose_analyse(img,dic):nose=(int(dic['nose']['x']),int(dic['nose']['y']))neck=(int(dic['neck']['x']),int(dic['neck']['y']))if(neck[1]<=nose[1]):return 'warn'return 'ok'def draw_line(img,dic,text):color=(0,255,0)thickness=2if(text=='warn'):color=(0,0,255)#nose ---> neckcv2.line(img, (int(dic['nose']['x']),int(dic['nose']['y'])),(int(dic['neck']['x']),int(dic['neck']['y'])), color, thickness)#neck --> left_shouldercv2.line(img, (int(dic['neck']['x']),int(dic['neck']['y'])),(int(dic['left_shoulder']['x']),int(dic['left_shoulder']['y'])), color, thickness)#neck --> right_shouldercv2.line(img, (int(dic['neck']['x']),int(dic['neck']['y'])),(int(dic['right_shoulder']['x']),int(dic['right_shoulder']['y'])), color, thickness)#left_shoulder --> left_elbowcv2.line(img, (int(dic['left_shoulder']['x']),int(dic['left_shoulder']['y'])),(int(dic['left_elbow']['x']),int(dic['left_elbow']['y'])), color, thickness)#left_elbow --> left_wristcv2.line(img, (int(dic['left_elbow']['x']),int(dic['left_elbow']['y'])),(int(dic['left_wrist']['x']),int(dic['left_wrist']['y'])), color, thickness)#right_shoulder --> right_elbowcv2.line(img, (int(dic['right_shoulder']['x']),int(dic['right_shoulder']['y'])),(int(dic['right_elbow']['x']),int(dic['right_elbow']['y'])), color, thickness)#right_elbow --> right_wristcv2.line(img, (int(dic['right_elbow']['x']),int(dic['right_elbow']['y'])),(int(dic['right_wrist']['x']),int(dic['right_wrist']['y'])), color, thickness)#neck --> left_hipcv2.line(img, (int(dic['neck']['x']),int(dic['neck']['y'])),(int(dic['left_hip']['x']),int(dic['left_hip']['y'])), color, thickness)#neck --> right_hipcv2.line(img, (int(dic['neck']['x']),int(dic['neck']['y'])),(int(dic['right_hip']['x']),int(dic['right_hip']['y'])), color, thickness)#left_hip --> left_kneecv2.line(img, (int(dic['left_hip']['x']),int(dic['left_hip']['y'])),(int(dic['left_knee']['x']),int(dic['left_knee']['y'])), color, thickness)#right_hip --> right_kneecv2.line(img, (int(dic['right_hip']['x']),int(dic['right_hip']['y'])),(int(dic['right_knee']['x']),int(dic['right_knee']['y'])), color, thickness)#left_knee --> left_anklecv2.line(img, (int(dic['left_knee']['x']),int(dic['left_knee']['y'])),(int(dic['left_ankle']['x']),int(dic['left_ankle']['y'])), color, thickness)#right_knee --> right_anklecv2.line(img, (int(dic['right_knee']['x']),int(dic['right_knee']['y'])),(int(dic['right_ankle']['x']),int(dic['right_ankle']['y'])), color, thickness)def draw_point(img,dic,text):color=(0,255,0)thickness=2if(text=='warn'):color=(0,0,255)for i in dic:cv2.circle(img,(int(dic[i]['x']),int(dic[i]['y'])),5,color,thickness)def draw_box(img,dic,text):color=(255,0,0)if(text=='warn'):color=(0,0,255)left_top=(int(dic['left']),int(dic['top']))left_bottom=(int(dic['left']),int(dic['top']+dic['height']))right_bottom=(int(dic['left']+dic['width']),int(dic['top']+dic['height']))right_top=(int(dic['left']+dic['width']),int(dic['top']))cv2.line(img, left_top,left_bottom, color, 2)cv2.line(img, left_top,right_top, color, 2)cv2.line(img, right_bottom,left_bottom,color, 2)cv2.line(img, right_bottom,right_top,color, 2)cv2.putText(img, text, (int(dic['left']),int(dic['top'])+20), cv2.FONT_HERSHEY_COMPLEX, 1,color, 1)class BaiduAIP(object):def __init__(self):self.client = AipBodyAnalysis(cfg.APP_ID, cfg.API_KEY, cfg.SECRET_KEY)def bodyAnalysis(self,img_jpg):etval, buffer = cv2.imencode('.jpg', img_jpg)result = self.client.bodyAnalysis(buffer) #内部把buffer转换为base64了return resultif __name__ == '__main__':baiduapi = BaiduAIP()img = cv2.imread('/media/chen/chen/Photo/others/littleCookies.jpg')t1=time.time()d=baiduapi.bodyAnalysis(img)t2=time.time()print("api time= "+str(t2-t1))print(d["person_num"])print(d["log_id"])persion=d["person_info"]for p in persion:draw_line(img,p['body_parts'],'ok')draw_point(img,p['body_parts'],'ok')draw_box(img,p['location'],'beauty')t3=time.time()print("draw time= "+str(t3-t2))cv2.imwrite("image1.jpg",img)

 tkinter_body.py

import sys
if('/opt/ros/kinetic/lib/python2.7/dist-packages' in sys.path):sys.path.remove('/opt/ros/kinetic/lib/python2.7/dist-packages')
import cv2
import tkinter as tk
from tkinter import *#文件控件
from PIL import Image, ImageTk#图像控件
import threading#多线程
from aip_bodyanalysis import *
import timeIMG_HEIGT=352*2
IMG_WIDTH=640*2aip=BaiduAIP()
is_run=True#申请线程锁
lock=threading.Lock()#根窗口
window = tk.Tk()#显示变量
num_people = StringVar()
num_people.set('当前人数:0')
num_desertion = StringVar()
num_desertion.set('不正常:0')#UI绘制
window.title("测试")
sw = window.winfo_screenwidth()#获取屏幕宽
sh = window.winfo_screenheight()#获取屏幕高#设置窗口大小和位置
wx = IMG_WIDTH+100
wh = IMG_HEIGT+100
window.geometry("%dx%d+%d+%d" %(wx,wh,(sw-wx)/2,(sh-wh)/2-100))#窗口至指定位置#顶部是信息栏
fm1 = Frame(window)
Label(fm1, text="总人数:20").pack(side='left')
label_num = Label(fm1, textvariable=num_people).pack(side='left')
label_num = Label(fm1, textvariable=num_desertion).pack(side='left')
fm1.pack(side='top', padx=10)#左侧是操作栏
fm2 = Frame(window)
fm2.pack(side='left', padx=10)
canvas1 = tk.Canvas(window,bg="#c4c2c2",height=IMG_HEIGT,width=IMG_WIDTH)#绘制画布
canvas1.pack(side="left")def getResult(img):d=aip.bodyAnalysis(img)if("person_info" not in d):returnpersion=d["person_info"]#获取人数num=len(persion)num_people.set( "当前人数:"+str(num))#绘制人体姿势for p in persion:status=pose_analyse(img,p['body_parts'])draw_line(img,p['body_parts'],status)draw_point(img,p['body_parts'],status)draw_box(img,p['location'],status)def cc():capture = cv2.VideoCapture('/media/chen/chen/Photo/others/1.mp4')#capture = cv2.VideoCapture(0)while capture.isOpened():t0=time.time()_, frame = capture.read()#清除缓存for i in range(15):_, frame = capture.read()getResult(frame)frame = cv2.flip(frame, 1)#翻转 0:上下颠倒 大于0水平颠倒cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)img = Image.fromarray(cv2image)image_file=ImageTk.PhotoImage(img)canvas1.create_image(0,0,anchor="nw",image=image_file)print(time.time()-t0)print("ending")class ImgProcThread(threading.Thread):def __init__(self, *args, **kwargs):super(ImgProcThread, self).__init__(*args, **kwargs)self.__flag = threading.Event()     # 用于暂停线程的标识self.__flag.set()       # 设置为Trueself.__running = threading.Event()      # 用于停止线程的标识self.__running.set()      # 将running设置为Truedef run(self):capture = cv2.VideoCapture('/media/chen/chen/Photo/others/1.mp4')while self.__running.isSet() and capture.isOpened():self.__flag.wait()      # 为True时立即返回, 为False时阻塞直到内部的标识位为True后返回t0=time.time()_, frame = capture.read()for i in range(15):_, frame = capture.read()frame = cv2.resize(frame,(IMG_WIDTH,IMG_HEIGT), interpolation=cv2.INTER_NEAREST)getResult(frame)#frame = cv2.flip(frame, 1)#翻转 0:上下颠倒 大于0水平颠倒cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)img = Image.fromarray(cv2image)image_file=ImageTk.PhotoImage(img)canvas1.create_image(0,0,anchor="nw",image=image_file)print(time.time()-t0)def pause(self):self.__flag.clear()     # 设置为False, 让线程阻塞def resume(self):self.__flag.set()    # 设置为True, 让线程停止阻塞def stop(self):self.__flag.set()       # 将线程从暂停状态恢复, 如何已经暂停的话self.__running.clear()        # 设置为Falsdef video_demo():t=threading.Thread(target=cc)t.start()job=ImgProcThread()bt_start = tk.Button(fm2,text="启动",height=2,width=15,command=job.start).pack(side="top")
bt_pause = tk.Button(fm2,text="暂停",height=2,width=15,command=job.pause).pack(side="top")
bt_resume = tk.Button(fm2,text="恢复",height=2,width=15,command=job.resume).pack(side="top")
bt_stop = tk.Button(fm2,text="结束线程",height=2,width=15,command=job.stop).pack(side="top")
bt_quit = tk.Button(fm2,text="退出程序",height=2,width=15,command=window.quit).pack(side="top")window.mainloop()

代码执行结果:

基于Tkinter和百度Aip的人体关键点检测相关推荐

  1. 基于百度AL平台人体检测实现人体关键点检测代码

    本文通过OpenCV模块调用摄像头,利用百度开放的人体关键点检测API,实现了实时对人体的关键点检测. 一.百度API获取 使用百度的API,首先要在百度AI的官网上注册帐号,然后在人体关键点识别功能 ...

  2. VideoPose3D:基于视频的3D人体关键点检测

    1. 概述 Dario Pavllo等人于2019年提出了VideoPose3D模型,旨在把输入视频转换成人体各关键点相对于根关节的相对三维位置.为了实现这一目的,作者采取的是两步走的策略.首先要利用 ...

  3. 基于深度学习目标检测和人体关键点检测的不健康坐姿检测

    基于深度学习目标检测和人体关键点检测的不健康坐姿检测 代码下载链接:下载地址 0.实验结果

  4. 基于MindStudio的3D人体关键点检测

    3D人体关键点检测 1 任务介绍 人体关键点检测插件基于 MindX SDK 开发,在昇腾芯片上进行人体关键点和骨架检测,将检测结果可视化并保存.输入一幅图像,可以检测得到图像中所有行人的关键点并连接 ...

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

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

  6. OpenMMLab-AI实战营第二期——2-1.人体关键点检测与MMPose

    文章目录 1. 人体姿态估计的介绍和应用 2-1. 2D姿态估计概述 2.1 任务描述 2.2 基于回归 2.3 基于热力图 2.3.1 从数据标注生成热力图(高斯函数) 2.3.2 使用热力图训练模 ...

  7. 人体姿态估计(人体关键点检测)2D Pose训练代码和Android源码

    人体姿态估计(人体关键点检测)2D Pose训练代码和Android源码 目录 人体姿态估计(人体关键点检测)2D Pose训练代码和Android源码 1.人体姿态估计2D Pose方法 2.人体姿 ...

  8. Pytorch+Python实现人体关键点检测

    用Python+Pytorch工程代码对人体进行关键点检测和骨架提取,并实现可视化. 使用背景: 物体检测为许多视觉任务提供动力,如实例分割.姿态估计.跟踪和动作识别.它在监控.自动驾驶和视觉答疑中有 ...

  9. OpenMMLab AI实战营第二期|人体关键点检测与MMPose学习笔记

    OpenMMLab AI实战营第二期|人体关键点检测与MMPose学习笔记 文章目录 OpenMMLab AI实战营第二期|人体关键点检测与MMPose学习笔记 一.前言 1.1 人体姿态概述 1.2 ...

最新文章

  1. CentOS7 php7.0 升级到php7.3
  2. SPOJ 694 不同子串个数
  3. am335x 配置 GPIO 为可输入也可输出
  4. java高级考试题_JAVA高级考试题
  5. 11gR2集群件任务角色分离(Job Role Separation)简介
  6. Linux内存管理--基本概念【转】
  7. paip.sql2008 客户端软件绿色版V319
  8. LintCode Memcache
  9. iOS 15 真机调试包 DeviceSupport
  10. UOS/Deepin 常用文本代码编辑器推荐及安装
  11. 字符串前面添加u,r,b的含义
  12. 【重构-改善代码】笔记
  13. JAVA根据PDF文件生成图片
  14. unity中使用手柄控制角色移动
  15. pip install 安装加速(修改为国内源)
  16. blueprint 实例
  17. matlab多元决策问题,matlab 贝叶斯决策对二维二分类问题的实现
  18. [FPGA系列] 扩展知识 --- QPSK调制解调器
  19. 狭隘型性格分析,如何改变狭隘型性格?
  20. SpringBoot整合emqx(MQTT)解决循坏依赖

热门文章

  1. MySQL安装叫重启,如何重启MySQL,正确启动MySQL
  2. 2018年软工第一次作业
  3. hdu 1231 最大连续子序列 ,1003 Max Sum;
  4. One-hot encoding 独热编码
  5. 算法与数据结构实验题 6.4 Summary
  6. 缓存2 动态缓存 memcached
  7. bzoj2208 [Jsoi2010]连通数
  8. How to manage the certificates in the PC
  9. JavaScript函数调用规则
  10. 人类视觉计算理论经典著作,豆瓣评分9.7,中文版惊鸿面世!