基于mediapipe的姿态识别和简单行为识别——前端界面的设计

一、wxpython介绍

  wxpython是python制作前端界面使用比较简单的一个工具。常被用于一些基础界面的生成,其中包含按键、滑钮、文本块等多种实用组件,是一个极易上手的前端工具。

1、文本

2、文本框(状态栏)

wx.Textctrl()

3、按键

wx.Button()

4、滑钮

二、Mediapipe与wxpython的有效结合

1、运行效果

  代码运行后的效果如下:左边是图像框,用来显示图像;
  右边是状态栏,用来打开文件和执行检测过程。
在这里插入图片描述
  打开文件之后,会在图像框的位置显示图片,如下图所示:

在这里插入图片描述
  点击“检测关键点”之后,就可以检测到人体的关键点了。
在这里插入图片描述

2、代码讲解

  接下来我们来具体说一下代码是如何实现的。

(1)关键点检测函数

  在之前的mediapipe讲解中,已经把关键点检测和检测行为识别的功能实现了。那么我们可以把它封装成一个函数,专供wxpython前端界面的按键调用使用。
  这里封装得到的函数如下:

def pre_image(image_path):
    print(image_path)
    #image = cv2.imread(image_path)
    image = cv2.imdecode(np.fromfile(image_path, dtype=np.uint8), -1)
    img = image.copy()
    frame = process_frame(img)
    return frame
    # 先不显示

  cv2.imdecode()的使用是因为包含中文路径的图片无法使用cv2.imread()打开。
  process_frame()函数的功能是将原图片输入,将检测好的关键点图片输出。
以下是process_frame()函数的全部内容:

def process_frame(img):
    start_time = time.time()
    h, w = img.shape[0], img.shape[1]               # 高和宽
    # 调整字体
    tl = round(0.005 * (img.shape[0] + img.shape[1]) / 2) + 1
    tf = max(tl-1, 1)
    # BRG-->RGB
    img_RGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    # 将RGB图像输入模型,获取 关键点 预测结果
    results = pose.process(img_RGB)
    keypoints = ['' for i in range(33)]
    if results.pose_landmarks:
        mp_drawing.draw_landmarks(img, results.pose_landmarks, mp_pose.POSE_CONNECTIONS)
        for i in range(33):
            cx = int(results.pose_landmarks.landmark[i].x * w)
            cy = int(results.pose_landmarks.landmark[i].y * h)
            keypoints[i] = (cx, cy)                                 # 得到最终的33个关键点
    else:
        print("NO PERSON")
        struction = "NO PERSON"
        img = cv2.putText(img, struction, (25, 100), cv2.FONT_HERSHEY_SIMPLEX, 1.25, (255, 255, 0),
                          6)
    end_time = time.time()
    process_time = end_time - start_time            # 图片关键点预测时间
    fps = 1 / process_time                          # 帧率
    colors = [[random.randint(0,255) for _ in range(3)] for _ in range(33)]
    radius = [random.randint(8,15) for _ in range(33)]
    for i in range(33):
        cx, cy = keypoints[i]
        #if i in range(33):
        img = cv2.circle(img, (cx, cy), radius[i], colors[i], -1)
    '''str_pose = get_pos(keypoints)            #获取姿态
    cv2.putText(img, "POSE-{}".format(str_pose), (12, 100), cv2.FONT_HERSHEY_TRIPLEX,
                tl / 3, (255, 0, 0), thickness=tf)'''
    cv2.putText(img, "FPS-{}".format(str(int(fps))), (12, 100), cv2.FONT_HERSHEY_SIMPLEX,
                tl/3, (255, 255, 0),thickness=tf)
    return img

  这个函数其实在之前的讲解中也出现过。
  有了这两个函数,就可以将其与按键绑定,实现回调使用。

扫描二维码关注公众号,回复: 16812020 查看本文章

(2)wxpython的具体操作

  主体框架部分其实在wxpython中,wxpython将所有想要实现的功能串联了起来。

在这里我定义了一个类,专门用于放置前端的代码调用。
以下是加了注释的wxpython代码:

class mediapipeApp(wx.App):
    def __init__(self):
    	'''UI界面的设计'''
        wx.App.__init__(self)
        self.frame = wx.Frame(None, title="Mediapipe_UI")
        self.panel = wx.Panel(self.frame)
        # -------------------------
        # 新建控件位置变量
        # -------------------------
        VERTICAL = wx.BoxSizer(wx.VERTICAL)
        HORIZONTAL = wx.BoxSizer(wx.HORIZONTAL)
        # ------------------------------------
        # 新建控件
        # ------------------------------------
        # 图片框
        image = wx.EmptyImage(500,500)
        self.image = wx.StaticBitmap(self.panel, wx.ID_ANY,   # 设置图片控件
                                       wx.BitmapFromImage(image))
        self.opare = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, "操作栏"),
                                       wx.VERTICAL)
        # 图片操作栏
        self.image_op = wx.StaticBoxSizer(wx.StaticBox(self.opare.GetStaticBox(), wx.ID_ANY, "图片操作栏"),
                                       wx.VERTICAL)
        grider = wx.GridSizer(0, 2, 0, 9)
        btn_open = wx.Button(self.image_op.GetStaticBox(), label="打开文件")
        btn_points = wx.Button(self.image_op.GetStaticBox(), label="检测关键点")
        btn_pose = wx.Button(self.image_op.GetStaticBox(), label="检测姿态")
        # 状态栏,文本输入框
        self.sympol = wx.StaticBoxSizer(wx.StaticBox(self.opare.GetStaticBox(), wx.ID_ANY, "状态栏"),
                                          wx.HORIZONTAL)
        self.text_ctrl = wx.TextCtrl(self.sympol.GetStaticBox(), size=(200,300))

        # -----------------------------------
        #   设置控件 : 按钮、文本输入框等
        # -----------------------------------
        btn_open.Bind(wx.EVT_BUTTON, self.openfile)
        btn_points.Bind(wx.EVT_BUTTON, self.points)
        # ------------------------------------
        # 控件分布
        # ------------------------------------
        grider.Add(btn_open, 0, wx.ALL|wx.EXPAND, 5)
        grider.Add(btn_points, 0, wx.ALL|wx.EXPAND, 5)
        grider.Add(btn_pose, 0, wx.ALL|wx.EXPAND, 5)
        self.opare.Add(self.image_op, 0, wx.ALL|wx.EXPAND, 5)
        self.opare.Add(self.sympol, 0, wx.ALL|wx.EXPAND, 5)
        self.image_op.Add(grider, 0, wx.ALL|wx.EXPAND, 5)
        self.sympol.Add(self.text_ctrl, 0, wx.ALL|wx.EXPAND, 5)
        HORIZONTAL.Add(self.image, 0, wx.ALL|wx.EXPAND, 5)
        HORIZONTAL.Add(self.opare, 0, wx.ALL|wx.EXPAND, 5)
        VERTICAL.Add(HORIZONTAL)
        # ------------------------------------
        # 最终设置
        # ------------------------------------
        self.panel.SetSizer(VERTICAL)
        self.panel.Layout()
        HORIZONTAL.Fit(self.frame)
        self.frame.Show()
        self.PhotoMaxSize = 500
        self.filepath = ""
    def points(self, event):
    	'''检测关键点函数'''
    	# 如果路径是空的,那么就在状态栏中报错
        if self.filepath == "":
            struction = "错误,请先导入原始图片"
            self.text_ctrl.SetValue(struction)
            self.text_ctrl.GetValue()
        # 如果路径不为空,则执行检测操作,并把检测过后的图片显示在图片框中
        else:
            # 返回的image是cv2格式
            image = pre_image(self.filepath)
            image = cv2.resize(image, (500,500))
            image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
            pic = wx.Bitmap.FromBuffer(image.shape[1], image.shape[0], image)
            self.image.SetBitmap(pic)
            self.panel.Refresh()


    def openfile(self, event):
    	'''打开文件函数:点击打开文件后,可以打开以jpg格式的图片'''
        wildcard = "JPEG files (*.jpg)|*.jpg"
        dialog = wx.FileDialog(None, "choose a file",
                               wildcard=wildcard,
                               style=wx.FD_CHANGE_DIR)
        if dialog.ShowModal() == wx.ID_OK:
            self.text_ctrl.SetValue(dialog.GetPath())
        dialog.Destroy()
        self.onView()
    def onView(self):
    	'''在状态栏中显示所需内容'''
        self.filepath = self.text_ctrl.GetValue()
        self.showImage(self.filepath)
    def showImage(self, filepath):
    	'''调整图片的宽高,并在图片框中显示图片'''
        img = wx.Image(filepath, wx.BITMAP_TYPE_ANY)
        W = img.GetWidth()
        H = img.GetHeight()
        # 让显示的美观一点。
        if W > H:
            NewW = self.PhotoMaxSize
            NewH = self.PhotoMaxSize * H / W
        else:
            NewH = self.PhotoMaxSize
            NewW = self.PhotoMaxSize * H / W
        self.W = NewW
        self.H = NewH
        img = img.Scale(NewW, NewH)

        self.image.SetBitmap(wx.BitmapFromImage(img))
        self.panel.Refresh()

  整个代码中最复杂的部分可能是控件的分布于设置了,需要好好地理解一下。

总结

wxpython

wxpython+Mediapipe

代码整体与前面讲的Mediapipe一样,只是多了一个wxpython的可视化UI界面,wxpython的代码我也放在了前面讲的Mediapipe一章中,可以自行调阅查看。

猜你喜欢

转载自blog.csdn.net/weixin_44463519/article/details/126240816
今日推荐