【python】OpenCV—Single Human Pose Estimation

news2024/9/22 4:03:51

文章目录

  • 1、Human Pose Estimation
  • 2、模型介绍
  • 3、基于图片的单人人体关键点检测
  • 4、基于视频的单人人体关键点检测
  • 5、左右校正
  • 6、关键点平滑
  • 7、涉及到的库函数
    • scipy.signal.savgol_filter
  • 8、参考

1、Human Pose Estimation

Human Pose Estimation,即人体姿态估计,是一种基于计算机视觉和深度学习的技术,用于自动检测和识别人体的姿态和动作。它可以在图像或视频中准确地确定人体各个关节的位置和运动。

一、定义与分类

  • 定义:人体姿态估计是指图像或视频中人体关节的定位问题,也可表述为在所有关节姿势的空间中搜索特定姿势。
  • 分类:
    2D姿态估计:从RGB图像估计每个关节的2D坐标(x,y)。
    3D姿态估计:从RGBD图像中估计每个关节的3D坐标(x,y,z)。
    根据应用场景,还可分为单人姿态估计、多人姿态估计、人体姿态跟踪等。

二、技术原理

  • 实现方式:人体姿态识别的实现通常基于深度学习模型,如卷积神经网络(CNN)和循环神经网络(RNN)。首先,通过训练模型使用大量标记的姿势数据,模型能够学习到人体各个关节的特征表示。然后,当输入一张图像或视频时,模型会对每个关节进行定位和跟踪,进而恢复出人体的姿态。
  • 改进技术:为了提高模型的鲁棒性和准确性,研究人员还提出了一些改进技术,如引入上下文信息、多尺度特征融合、姿势关系建模等。

三、应用领域

  • 健身和运动:帮助跟踪和纠正运动姿势,提供更高效、精确的训练指导。
  • 医疗:用于康复治疗、姿势评估等方面。
  • 安防:用于行为分析、异常检测等。
  • 虚拟现实(VR)与增强现实(AR):创建更真实的互动体验。
  • 健康管理:监控老年人的身体活动,预防跌倒风险等。

四、未来展望

  • 随着深度学习和计算机视觉技术的不断发展,人体姿态估计技术将在更多领域发挥重要作用。未来,该技术有望进一步提高准确性和实时性,为人们的训练、康复、安全和生活提供更加有效的支持。同时,随着数据量的增加和计算能力的提升,人体姿态估计技术也将更加智能化和个性化,满足不同场景下的需求。

2、模型介绍

在这里插入图片描述

COCO 输出格式

  • 鼻子- 0,脖子- 1,右肩- 2,右手肘- 3,右手腕- 4,左肩- 5,左肘- 6,左腕- 7,右髋部- 8,右膝- 9,右脚踝- 10,左臀部- 11,左膝- 12,左脚踝 - 13,右眼- 14,左眼- 15,右耳- 16,左耳- 17,背景-18

MPII 输出格式

  • 头-0,颈-1,右肩-2,右手肘-3,右手腕-4,左肩-5,左肘-6,左腕-7,右髋部-8,右膝-9,右脚踝-10,左臀部-11,左膝-12,左脚踝-13,胸部-14,背景-15

COCO 输出格式的模型
在这里插入图片描述
在这里插入图片描述

MPII 格式模型

在这里插入图片描述

在这里插入图片描述

3、基于图片的单人人体关键点检测

import cv2
import time
import numpy as np
import argparse

parser = argparse.ArgumentParser(description='Run keypoint detection')
parser.add_argument("--device", default="gpu", help="Device to inference on")
parser.add_argument("--image_file", default="1.jpg", help="Input image")

args = parser.parse_args()


MODE = "COCO"
# MODE = "MPI"


if MODE is "COCO":
    protoFile = "pose/coco/pose_deploy_linevec.prototxt"
    weightsFile = "pose/coco/pose_iter_440000.caffemodel"
    nPoints = 18
    POSE_PAIRS = [ [1,0],[1,2],[1,5],[2,3],[3,4],[5,6],[6,7],[1,8],[8,9],[9,10],[1,11],[11,12],[12,13],[0,14],[0,15],[14,16],[15,17]]

elif MODE is "MPI":
    protoFile = "pose/mpi/pose_deploy_linevec_faster_4_stages.prototxt"
    weightsFile = "pose/mpi/pose_iter_160000.caffemodel"
    nPoints = 15
    POSE_PAIRS = [[0,1], [1,2], [2,3], [3,4], [1,5], [5,6], [6,7], [1,14], [14,8], [8,9], [9,10], [14,11], [11,12], [12,13] ]


frame = cv2.imread(args.image_file)
frameCopy = np.copy(frame)
frameWidth = frame.shape[1]
frameHeight = frame.shape[0]
threshold = 0.1

net = cv2.dnn.readNetFromCaffe(protoFile, weightsFile)

if args.device == "cpu":
    net.setPreferableBackend(cv2.dnn.DNN_TARGET_CPU)
    print("Using CPU device")
elif args.device == "gpu":
    net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)
    net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)
    print("Using GPU device")

t = time.time()
# input image dimensions for the network
inWidth = 368
inHeight = 368
inpBlob = cv2.dnn.blobFromImage(frame, 1.0 / 255, (inWidth, inHeight),
                          (0, 0, 0), swapRB=False, crop=False)

net.setInput(inpBlob)

output = net.forward()
print("time taken by network : {:.3f}".format(time.time() - t))

H = output.shape[2]
W = output.shape[3]

# Empty list to store the detected keypoints
points = []

for i in range(nPoints):
    # confidence map of corresponding body's part.
    probMap = output[0, i, :, :]

    # Find global maxima of the probMap.
    minVal, prob, minLoc, point = cv2.minMaxLoc(probMap)
    
    # Scale the point to fit on the original image
    x = (frameWidth * point[0]) / W
    y = (frameHeight * point[1]) / H

    if prob > threshold : 
        cv2.circle(frameCopy, (int(x), int(y)), 8, (0, 255, 255), thickness=-1, lineType=cv2.FILLED)
        cv2.putText(frameCopy, "{}".format(i), (int(x), int(y)), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2, lineType=cv2.LINE_AA)

        # Add the point to the list if the probability is greater than the threshold
        points.append((int(x), int(y)))
    else :
        points.append(None)

# Draw Skeleton
for pair in POSE_PAIRS:
    partA = pair[0]
    partB = pair[1]

    if points[partA] and points[partB]:
        cv2.line(frame, points[partA], points[partB], (0, 255, 255), 2)
        cv2.circle(frame, points[partA], 8, (0, 0, 255), thickness=-1, lineType=cv2.FILLED)


cv2.imshow(MODE+'-Output-Keypoints', frameCopy)
cv2.imshow(MODE+'-Output-Skeleton', frame)


cv2.imwrite(MODE+'-Output-Keypoints.jpg', frameCopy)
cv2.imwrite(MODE+'-Output-Skeleton.jpg', frame)

print("Total time taken : {:.3f}".format(time.time() - t))

cv2.waitKey(0)

输入图片

在这里插入图片描述

COCO 输出

在这里插入图片描述
关键点连起来

在这里插入图片描述

可以看出脸部关键点预测的不太准,特别是鼻子

MPII 输出格式

在这里插入图片描述
关键点连起来

在这里插入图片描述

脚踝还是有一点点瑕疵

再看一组例子

输入图片

在这里插入图片描述

COCO 输出格式

在这里插入图片描述

在这里插入图片描述
同样的,脸部关键点不太准,耳朵鼻子

MPII 格式输出

在这里插入图片描述

在这里插入图片描述
MPII 结果不错

4、基于视频的单人人体关键点检测

import cv2
import time
import numpy as np
import argparse

parser = argparse.ArgumentParser(description='Run keypoint detection')
parser.add_argument("--device", default="gpu", help="Device to inference on")
parser.add_argument("--video_file", default="sample_video.mp4", help="Input Video")

args = parser.parse_args()

# MODE = "MPI"
MODE = "COCO"

if MODE is "COCO":
    protoFile = "pose/coco/pose_deploy_linevec.prototxt"
    weightsFile = "pose/coco/pose_iter_440000.caffemodel"
    nPoints = 18
    POSE_PAIRS = [ [1,0],[1,2],[1,5],[2,3],[3,4],[5,6],[6,7],[1,8],[8,9],[9,10],[1,11],[11,12],[12,13],[0,14],[0,15],[14,16],[15,17]]

elif MODE is "MPI" :
    protoFile = "pose/mpi/pose_deploy_linevec_faster_4_stages.prototxt"
    weightsFile = "pose/mpi/pose_iter_160000.caffemodel"
    nPoints = 15
    POSE_PAIRS = [[0,1], [1,2], [2,3], [3,4], [1,5], [5,6], [6,7], [1,14], [14,8], [8,9], [9,10], [14,11], [11,12], [12,13] ]


inWidth = 368
inHeight = 368
threshold = 0.1


input_source = args.video_file
cap = cv2.VideoCapture(input_source)
hasFrame, frame = cap.read()

vid_writer = cv2.VideoWriter(MODE+'-output.avi',cv2.VideoWriter_fourcc('M','J','P','G'), 10, (frame.shape[1],frame.shape[0]))

net = cv2.dnn.readNetFromCaffe(protoFile, weightsFile)
if args.device == "cpu":
    net.setPreferableBackend(cv2.dnn.DNN_TARGET_CPU)
    print("Using CPU device")
elif args.device == "gpu":
    net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)
    net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)
    print("Using GPU device")

while cv2.waitKey(1) < 0:
    t = time.time()
    hasFrame, frame = cap.read()
    frameCopy = np.copy(frame)
    if not hasFrame:
        cv2.waitKey()
        break

    frameWidth = frame.shape[1]
    frameHeight = frame.shape[0]

    inpBlob = cv2.dnn.blobFromImage(frame, 1.0 / 255, (inWidth, inHeight),
                              (0, 0, 0), swapRB=False, crop=False)
    net.setInput(inpBlob)
    output = net.forward()

    H = output.shape[2]
    W = output.shape[3]
    # Empty list to store the detected keypoints
    points = []

    for i in range(nPoints):
        # confidence map of corresponding body's part.
        probMap = output[0, i, :, :]

        # Find global maxima of the probMap.
        minVal, prob, minLoc, point = cv2.minMaxLoc(probMap)
        
        # Scale the point to fit on the original image
        x = (frameWidth * point[0]) / W
        y = (frameHeight * point[1]) / H

        if prob > threshold : 
            cv2.circle(frameCopy, (int(x), int(y)), 8, (0, 255, 255), thickness=-1, lineType=cv2.FILLED)
            cv2.putText(frameCopy, "{}".format(i), (int(x), int(y)), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2, lineType=cv2.LINE_AA)

            # Add the point to the list if the probability is greater than the threshold
            points.append((int(x), int(y)))
        else :
            points.append(None)

    # Draw Skeleton
    for pair in POSE_PAIRS:
        partA = pair[0]
        partB = pair[1]

        if points[partA] and points[partB]:
            cv2.line(frame, points[partA], points[partB], (0, 255, 255), 3, lineType=cv2.LINE_AA)
            cv2.circle(frame, points[partA], 8, (0, 0, 255), thickness=-1, lineType=cv2.FILLED)
            cv2.circle(frame, points[partB], 8, (0, 0, 255), thickness=-1, lineType=cv2.FILLED)

    cv2.putText(frame, "time taken = {:.2f} sec".format(time.time() - t), (50, 50), cv2.FONT_HERSHEY_COMPLEX, .8, (255, 50, 0), 2, lineType=cv2.LINE_AA)
    # cv2.putText(frame, "OpenPose using OpenCV", (50, 50), cv2.FONT_HERSHEY_COMPLEX, 1, (255, 50, 0), 2, lineType=cv2.LINE_AA)
    # cv2.imshow('Output-Keypoints', frameCopy)
    cv2.imshow(MODE + '-Output-Skeleton', frame)

    vid_writer.write(frame)

vid_writer.release()

COCO 格式输出

COCO-output

MPII 格式输出

MPI-output

手腕脚腕是难点,左右存在混淆,抖动比较明显

下面章节我们来优化缓解下上述问题,基于 MPII 格式的输出

5、左右校正

身体部分预测的关键点不合理时被交换,这样左边的部分就总是在左边(要确保人一直是对着屏幕前的我们的吧,背对着和正面切换这样的校正就没有意义了)

先把正常预测的结果保存下来,save_pose_data,py 检测结果保存在 workout.csv

#!/usr/bin/python3
# -*- encoding: utf-8 -*-
"""
@File    : save_pose_data.py.py
@Time    : 2021/9/27 16:21
@Author  : David
@Software: PyCharm
"""
import cv2, numpy as np, csv

# https://github.com/opencv/opencv/blob/master/samples/dnn/openpose.py
outfile_path = 'workout.csv'

protoFile = "./pose/mpi/pose_deploy_linevec_faster_4_stages.prototxt"
weightsFile = "./pose/mpi/pose_iter_160000.caffemodel"
net = cv2.dnn.readNetFromCaffe(protoFile, weightsFile)

data, input_width, input_height, threshold, frame_number = [], 368, 386, 0.1, 0

input_source = "sample_video.mp4"
cap = cv2.VideoCapture(input_source)

# use the previous location of the body part if the model is wrong
previous_x, previous_y = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                                                                            0]

while True:

    ret, img = cap.read()
    if not ret: break

    # get the image shape
    img_width, img_height = img.shape[1], img.shape[0]

    # get a blob from the image
    inputBlob = cv2.dnn.blobFromImage(img, 1.0 / 255, (input_width, input_height), (0, 0, 0), swapRB=False, crop=False)

    # set the input and perform a forward pass
    net.setInput(inputBlob)
    output = net.forward()

    # get the output shape
    output_width, output_height = output.shape[2], output.shape[3]

    # Empty list to store the detected keypoints
    x_data, y_data = [], []

    # Iterate through the body parts
    for i in range(15):

        # find probability that point is correct
        _, prob, _, point = cv2.minMaxLoc(output[0, i, :, :])

        # Scale the point to fit on the original image
        x, y = (img_width * point[0]) / output_width, (img_height * point[1]) / output_height

        # Is the point likely to be correct?
        if prob > threshold:
            x_data.append(x)
            y_data.append(y)
            xy = tuple(np.array([x, y], int))
            cv2.circle(img, xy, 5, (25, 0, 255), 5)
        # No? us the location in the previous frame
        else:
            x_data.append(previous_x[i])
            y_data.append(previous_y[i])

    # add these points to the list of data
    data.append(x_data + y_data)
    previous_x, previous_y = x_data, y_data
    frame_number += 1
    # use this break statement to check your data before processing the whole video
    # if frame_number == 300: break
    print(frame_number)

    cv2.imshow('img', img)
    k = cv2.waitKey(1)
    if k == 27: break

# write the data to a .csv file
import pandas as pd

df = pd.DataFrame(data)
df.to_csv(outfile_path, index=False)
print('save complete')

读取模型预测的结果,进行左右校正,swap_body_parts.py 输出 swapped_body_parts.csv

#!/usr/bin/python3
# -*- encoding: utf-8 -*-
"""
@File    : swap_body_parts.py.py
@Time    : 2021/9/27 16:52
@Author  : David
@Software: PyCharm
"""
# swap_body_parts.py
import pandas as pd
import numpy as np
import cv2, os
import csv

input_source = "sample_video.mp4"
cap = cv2.VideoCapture(input_source)
frame_number = 0
font, scale, colorText, thick = cv2.FONT_HERSHEY_SIMPLEX, .5, (234, 234, 234), 1
size, color, thickness = 5, (255, 255, 255), 5
# get pose data - data is generated by open pose video
df = pd.read_csv('workout.csv')

# there are 15 points in the skeleton
# 0 head
# 1 neck
# 2, 5 shoulders
# 3, 6 elbows
# 4, 7 hands
# 8, 11 hips
# 9, 12 knees
# 10, 13 ankles
# 14 torso

data = []
while cv2.waitKey(10) < 0 and frame_number < len(df.values) - 2:
    ret, img = cap.read()
    if not ret: break
    try:
        values = df.values[frame_number]
    except:
        break
    values = np.array(values, int)
    points = []
    points.append((values[0], values[1]))
    points.append((values[2], values[3]))
    points.append((values[4], values[5]))
    points.append((values[6], values[7]))
    points.append((values[8], values[9]))
    points.append((values[10], values[11]))
    points.append((values[12], values[13]))
    points.append((values[14], values[15]))
    points.append((values[16], values[17]))
    points.append((values[18], values[19]))
    points.append((values[20], values[21]))
    points.append((values[22], values[23]))
    points.append((values[24], values[25]))
    points.append((values[26], values[27]))
    points.append((values[28], values[29]))

    # create a blank list to store the non-swapped poitns
    non_swap_points = []
    for i in range(15): non_swap_points.append((0, 0))
    # add the head, that point never changes
    non_swap_points[0] = points[0]
    # add the neck, that point never changes
    non_swap_points[1] = points[1]
    # add the torso, that never changes
    non_swap_points[14] = points[14]

    # swap the left and right shoulders (2 and 5)
    if points[2][0] < points[5][0]:
        non_swap_points[2] = points[2]
        non_swap_points[5] = points[5]
    else:
        non_swap_points[2] = points[5]
        non_swap_points[5] = points[2]
    # swap the elbows
    if points[3][0] < points[6][0]:
        non_swap_points[3] = points[3]
        non_swap_points[6] = points[6]
    else:
        non_swap_points[6] = points[3]
        non_swap_points[3] = points[6]

    # swap the hands
    if points[4][0] < points[7][0]:
        non_swap_points[4] = points[4]
        non_swap_points[7] = points[7]
    else:
        non_swap_points[7] = points[4]
        non_swap_points[4] = points[7]
    # swap the hips
    if points[8][0] < points[11][0]:
        non_swap_points[11] = points[11]
        non_swap_points[8] = points[8]
    else:
        non_swap_points[8] = points[11]
        non_swap_points[11] = points[8]

    # swap the knees
    if points[9][0] < points[12][0]:
        non_swap_points[9] = points[9]
        non_swap_points[12] = points[12]
    else:
        non_swap_points[12] = points[9]
        non_swap_points[9] = points[12]

    # swap the feet
    if points[10][0] < points[13][0]:
        non_swap_points[10] = points[10]
        non_swap_points[13] = points[13]
    else:
        non_swap_points[13] = points[10]
        non_swap_points[10] = points[13]

    for point in non_swap_points:
        cv2.circle(img, point, 3, (0, 0, 255), 3)
        cv2.putText(img, str(non_swap_points.index(point)), point, font, scale, colorText, thick, cv2.LINE_AA)

    cv2.imshow('Output-Skeleton', img)
    frame_number += 1
    data.append(non_swap_points)
cv2.destroyAllWindows()

with open('swapped_body_parts.csv', 'w') as csvfile:
    fieldnames = []
    for i in range(30): fieldnames.append(str(i))
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
    writer.writeheader()

    for trick in data:
        writer.writerow({'0': trick[0][0],
                         '1': trick[0][1],
                         '2': trick[1][0],
                         '3': trick[1][1],
                         '4': trick[2][0],
                         '5': trick[2][1],
                         '6': trick[3][0],
                         '7': trick[3][1],
                         '8': trick[4][0],
                         '9': trick[4][1],
                         '10': trick[5][0],
                         '11': trick[5][1],
                         '12': trick[6][0],
                         '13': trick[6][1],
                         '14': trick[7][0],
                         '15': trick[7][1],
                         '16': trick[8][0],
                         '17': trick[8][1],
                         '18': trick[9][0],
                         '19': trick[9][1],
                         '20': trick[10][0],
                         '21': trick[10][1],
                         '22': trick[11][0],
                         '23': trick[11][1],
                         '24': trick[12][0],
                         '25': trick[12][1],
                         '26': trick[13][0],
                         '27': trick[13][1],
                         '28': trick[14][0],
                         '29': trick[14][1]})

结果会在下一小节展示

6、关键点平滑

在应用平滑算法之前,所有帧的姿态数据必须是已知的(我们保存在了workout.csv 之中)

#!/usr/bin/python3
# -*- encoding: utf-8 -*-
"""
@File    : smooth_pose_data.py.py
@Time    : 2021/9/27 16:15
@Author  : David
@Software: PyCharm
"""
import pandas as pd
import numpy as np
import cv2
from scipy import signal

circle_color, line_color = (255, 255, 0), (0, 0, 255)
window_length, polyorder = 13, 2

input_source = "sample_video.mp4"

# Get pose data - data is generated by OpenPose
df = pd.read_csv('workout.csv')
# df = pd.read_csv('swapped_body_parts.csv')

cap = cv2.VideoCapture(input_source)

# get width of video
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))

# get height of video
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
out = cv2.VideoWriter('smooth_pose.avi',
                      cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'), 30, (frame_width, frame_height))
# There are 15 points in the skeleton
pairs = [[0, 1],  # head
         [1, 2], [1, 5],  # sholders
         [2, 3], [3, 4], [5, 6], [6, 7],  # arms
         [1, 14], [14, 11], [14, 8],  # hips
         [8, 9], [9, 10], [11, 12], [12, 13]]  # legs

# Smooth it out
for i in range(30):
    df[str(i)] = signal.savgol_filter(df[str(i)], window_length, polyorder)

frame_number = 0
while True:
    print(frame_number)
    ret, img = cap.read()  # 720, 576
    if not ret:
        break
    # img = np.zeros_like(img)
    values = np.array(df.values[frame_number], int)

    points, lateral_offset = [], 18
    points = list(zip(values[:15] + lateral_offset, values[15:]))

    cc = 0
    for point in points:
        cc += 90
        xy = tuple(np.array([point[0], point[1]], int))
        cv2.circle(img, xy, 5, (cc, cc, cc), 5)

    # Draw Skeleton
    for pair in pairs:
        partA = pair[0]
        partB = pair[1]
        cv2.line(img, points[partA], points[partB], line_color, 3, lineType=cv2.LINE_AA)

    cv2.imshow('Output-Skeleton', img)
    out.write(img)
    k = cv2.waitKey(100)
    if k == 27: # Esc
        break
    frame_number += 1
out.release()
cv2.destroyAllWindows()

我们仅平滑,不左右校正,看看结果

smooth pose direct

smooth_pose_data.py 平滑结果,可以看到结果丝滑了很多,抖动明显减少,不过大幅度动作关键点预测的还是不太准确,特别是手腕脚腕这些比较难的地方,而且也容易出现左右混淆

下面我们先左右校正,再平滑,输入 df = pd.read_csv('swapped_body_parts.csv')

smooth pose

感觉哪里有点问题,哈哈,比直接平滑效果变差了

7、涉及到的库函数

scipy.signal.savgol_filter

scipy.signal.savgol_filter 是 SciPy 库中用于数据平滑的一个函数,它实现了 Savitzky-Golay 滤波器。Savitzky-Golay 滤波器是一种在一维数据上应用的滤波技术,通过局域多项式最小二乘法拟合来平滑数据并去除噪声,同时保留信号的形状和变化信息。

函数签名

scipy.signal.savgol_filter(x, window_length, polyorder, deriv=0, delta=1.0, axis=-1, mode='interp', cval=0.0)

参数说明

  • x (array_like): 要过滤的数据。如果 x 不是单精度或双精度浮点型数组,则会在过滤前被转换为 numpy.float64 类型。
  • window_length (int): 滤波器窗口的长度(即系数的数量)。该值必须为正奇数,决定了平滑的范围。如果 mode 是 ‘interp’,则 window_length 必须小于或等于 x 的大小。
  • polyorder (int): 用于拟合样本的多项式的阶数。该值必须小于 window_length。
  • deriv (int, 可选): 要计算的导数的阶数。默认为 0,表示仅平滑数据而不进行微分。如果大于 0,则计算指定阶数的导数。
  • delta (float, 可选): 样本间隔。当 deriv 大于 0 时使用。默认为 1.0。
  • axis (int, 可选): 应用滤波器的轴。对于多维数组,该参数指定在哪个轴上应用滤波器。默认为 -1,即最后一个轴。
  • mode (str, 可选): 用于处理边界的模式。可以是 ‘mirror’、‘constant’、‘nearest’、‘wrap’ 或 ‘interp’。默认为 ‘interp’。这些模式决定了在窗口移出数组边界时如何处理边界值。
    ‘mirror’: 通过镜像反射填充边界。
    ‘constant’: 使用 cval 指定的常量值填充边界。
    ‘nearest’: 使用最近的值填充边界。
    ‘wrap’: 通过环绕的方式填充边界。
    ‘interp’: 使用多项式插值填充边界。
  • cval (scalar, 可选): 当 mode 为 ‘constant’ 时,用于填充边界的常量值。默认为 0.0。

返回值

  • Y (ndarray): 过滤后的数据。

注意事项

  • Savitzky-Golay 滤波器是一种局部多项式回归方法,它通过最小化窗口内数据的局部多项式拟合误差来平滑数据。
    选择合适的 window_length 和 polyorder 是非常重要的,它们将直接影响平滑的效果和信号的保留程度。
  • window_length 必须是奇数,以便窗口能够对称地围绕中心点。
  • 在处理多维数据时,axis 参数允许用户指定在哪个维度上应用滤波器。

示例

import numpy as np  
import matplotlib.pyplot as plt  
from scipy.signal import savgol_filter  
  
# 创建示例数据  
x = np.linspace(-4, 4, 500)  
y = np.exp(-x**2) + np.random.normal(0, 0.05, x.shape)  
  
# 应用 Savitzky-Golay 滤波器  
y_filtered = savgol_filter(y, window_length=51, polyorder=3)  
  
# 绘制原始数据和平滑后的数据  
plt.plot(x, y, label='Noisy data')  
plt.plot(x, y_filtered, label='Smoothed data', color='red')  
plt.legend()  
plt.show()

在这里插入图片描述

以上示例展示了如何使用 scipy.signal.savgol_filter 函数对带有噪声的数据进行平滑处理。

8、参考

参考学习来自以下链接

  • Code and model
    链接:https://pan.baidu.com/s/1OoDWEc7bdwKbKBEqQ5oOdA
    提取码:123a

  • OpenCV进阶(5)基于OpenCV的深度学习人体姿态估计之单人篇

  • https://learnopencv.com/deep-learning-based-human-pose-estimation-using-opencv-cpp-python/

  • Cao Z, Simon T, Wei S E, et al. Realtime multi-person 2d pose estimation using part affinity fields[C]//Proceedings of the IEEE conference on computer vision and pattern recognition. 2017: 7291-7299.
    https://arxiv.org/pdf/1611.08050

  • MPII Human Pose Dataset
    http://human-pose.mpi-inf.mpg.de/

  • Human Pose Evaluator Dataset
    https://www.robots.ox.ac.uk/~vgg/data/pose_evaluation/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2072034.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

通过主成分分析实现检测金融中的异常交易模式

主成分分析&#xff08;PCA&#xff09;是一种在机器学习和数据科学中广泛使用的降维技术。它的主要目的是将高维数据转换为低维数据&#xff0c;同时尽可能保留原始数据中的信息。以下是PCA的一些关键点&#xff1a; 1. 基本概念&#xff1a;PCA的核心思想是将n维特征映射到k维…

5步实现猫眼电影爬虫与k-means算法可视化分析

&#x1f34a;作者&#xff1a;计算机毕设匠心工作室 &#x1f34a;简介&#xff1a;毕业后就一直专业从事计算机软件程序开发&#xff0c;至今也有8年工作经验。擅长Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等。 擅长&#xff1a;按照需求定制化开发项目…

C#二叉搜索树算法

二叉搜索树算法实现原理 二叉搜索树&#xff08;Binary Search Tree&#xff0c;简称BST&#xff09;是一种节点有序排列的二叉树数据结构。它具有以下性质&#xff1a; 每个节点最多有两个子节点。 对于每个节点&#xff0c;其左子树的所有节点值都小于该节点值&#xff0c;…

MySQL数据库连接超时问题排查报告

1、问题描述 边端设备访问云端过程中有概率出现MySQL数据库连接超时报错&#xff0c;具体报错代码如下&#xff1a; [2024-08-13 13:47:44,036] ERROR in app: Exception on /est-tasks/start [POST] Traceback (most recent call last): File "/usr/local/lib/python3.1…

Java 入门指南:Map 接口

Map 接口是 Java 集合框架中的一个接口&#xff0c;它表示了一种键值对的映射关系。Map 接口提供了一种以键为索引的数据结构&#xff0c;通过键可以快速查找对应的值。在 Map 中&#xff0c;每个键只能对应一个值&#xff0c;键是唯一的&#xff0c;但值可以重复。 常用的实现…

在vscode上便捷运行php文件

目录 前言 1. 准备工作 2. 创建文件 3. 下载插件 4.设置访问配置文件 5. 配置默认浏览器 6. 进行验证 前言 对于学习安全的我们来说,部署环境,靶场,和配置环境都是习以为常的一件事情,平时访问靶场都是通过小皮来,今天突想着最近需要对一些漏洞的原理进行研究,所以需要能够…

ESP-WHO C++程序分析基础(七)

以按键部分的程序做为分析基础 先看app_button.hpp文件&#xff0c;文件的路径如下 examples/esp32-s3-eye/main/include/app_button.hpp // AppButton 类&#xff0c;继承自 Subject 类&#xff0c;表示应用程序按钮 首先是先定义了一个 appbutton的按键类&#xff0c;这个…

【计算机组成原理】汇总三、存储系统

三、存储系统&#xff08;存储器层次结构&#xff09; 文章目录 三、存储系统&#xff08;存储器层次结构&#xff09;1.存储器的分类1.1按在计算机中的作用&#xff08;层次&#xff09;❗多级存储结构&#xff08;层次化结构&#xff09;1.2按存储介质1.3按存取方式1.4按信息…

抢单源码修正版,带教程,自动抓取订单,十几种语言可自动切换

亚马逊抢单源码自动抓取订单任务邀请英文,西班牙语可自动切换语言亲测修正版。带完整开源的前后台。 西班牙,英文&#xff0c;巴西&#xff0c;中文&#xff0c;德国&#xff0c;拉法兰西&#xff0c;荷兰&#xff0c;缅甸&#xff0c;Sverige&#xff0c;日本&#xff0c;Trk…

C_02基础学习

c 语言 基础 gcc编译器 作用: 将代码文件编译为可执行文件 分类: 一步到位gcc 要编译的代码文件 -o 生成的可执行文件注意:要编译的代码文件可以是多个-o 生成的可执行文件:可以忽略不写,默认生成a.out文件 分步实现预编译:头文件展示,宏替换,选择型编译gcc -E 要编译的代码…

VMware NET Service在虚拟机关闭后仍然占用CPU - 解决方案

问题 VMware NET Service&#xff08;即vmnat.exe&#xff09;在虚拟机关闭后仍然占用CPU&#xff0c;这是VM 17.5.0 和 VM 17.5.1 软件本身存在的Bug&#xff0c;此问题已在 VM 17.5.2 版本修复&#xff0c;下文介绍解决方案。 时间&#xff1a;2024年8月 解决方案 临时方…

百度网盘网页提示页面过期请刷新 - 解决方案

问题 当打开百度网盘网页的分享链接后&#xff0c;点击下载会提示页面过期请刷新&#xff0c;点击保存到网盘没有响应&#xff0c;刷新后存在同样问题。 原因 这通常是因为浏览器中安装了屏蔽广告的插件&#xff0c;此插件不只拦截了百度网盘的广告&#xff0c;还拦截了一部…

零基础构建 AI 大模型数字人:开启智能交互新时代

人工智能技术的飞速发展&#xff0c;数字人正逐渐成为连接虚拟与现实世界的桥梁。无论是作为客户服务代表、教育助手还是娱乐伙伴&#xff0c;数字人都以其独特的方式丰富着我们的生活。今天&#xff0c;我们将介绍一个基于Dify生态系统的开源数字人技术框架——awesome-digita…

iis部署服务时,发现只能进行get请求,无法发起post、put请求

问题描述&#xff1a; iis部署服务时&#xff0c;发现只能进行get请求&#xff0c;无法发起post、put请求 问题原因&#xff1a; iis部署时&#xff0c;webDAV模块限制 解决方法&#xff1a; 1.搜索【服务器管理器】 2.点击【删除角色功能】 3.选中WebDAV&#xff0c;点…

MinIO实战攻略:轻松构建私有云存储解决方案

OSS 简介 OSS&#xff08;Object Storage Service&#xff09;通常指的是对象存储服务&#xff0c;它是一种数据存储架构&#xff0c;用于存储和检索非结构化数据&#xff0c;如图片、视频、文档和备份等。对象存储服务与传统的块存储和文件存储不同&#xff0c;它将数据作为对…

用户画像标签服务设计

背景 用户画像中不论是实时标签还是离线标签&#xff0c;对需要对外提供查询服务&#xff0c;以便外部接口可以重新用户的标签&#xff0c;本文就来看一下用户标签服务的设计 用户标签服务设计 不论是离线标签还是实时标签&#xff0c;我们都需要先把他们从hive表或者实时re…

OpenCV(第二关--读取图片和摄像头)实例+代码

以下内容&#xff0c;皆为原创&#xff0c;制作不易&#xff0c;感谢大家的关注和点赞。 一.读取图片 我们来读取图片&#xff0c;当你用代码读取后&#xff0c;可能会发现。怎么跟上传的图片颜色有些许的不一样。因为OpenCV的颜色通道是BGR&#xff0c;而我们平常用的matplotl…

华为云通过自定义域名访问桶内对象

问题&#xff1a;通过将自定义域名绑定至OBS桶实现在线预览文件 例如index.html入口文件 且记 自定义域名绑定暂时不支持HTTPS访问方式&#xff0c;只支持HTTP访问方式 自定义域名就先不用部署https证书。 配置完毕之后&#xff0c;将obs桶设置为公开的即可访问 如何在浏览…

若依代码生成器生成的界面查询和导出突然报错了

之前用的好好的&#xff0c;查询的时候也有数据&#xff0c;但是把参数给分页插件的时候就报错了&#xff0c;我忘了啥错误了&#xff0c;很奇怪。 ha在对应Mapper上加上&#xff1a;CacheNamespace注解&#xff0c;完。 Mapper CacheNamespace public interface BaseGoodsMa…

使用Python做一个脚本自动化机器人(二)

刚发现一个好用的Python库DrissionPage&#xff0c;使用该库不区分浏览器&#xff0c;也无需下载driver文件。 import logging from DrissionPage import WebPage from DrissionPage import ChromiumPage,ChromiumOptionsclass BaiduPage():# 创建对象page ChromiumPage()# 访…