【问题标题】:Draw lines into skeleton joints (coordinates) with Python and Matplotlib使用 Python 和 Matplotlib 将线条绘制到骨骼关节(坐标)中
【发布时间】:2021-09-16 13:26:04
【问题描述】:

下面的代码表示对应于读取具有 n 行的文本文件的图形的绘制。每行包含 4 列,前三列是 (x,y,z) 点的坐标,第四列是此绘图不需要的二进制变量。

每读取 20 行,就会读取一个骨架,该骨架是一组 20 个 (x,y,z) 点或关节,每个关节由每行的前三列组成。

文本文件包含 860 行,并且 860/20 = 43,即 20 个关节数,以创建 (x,y,z) 关节的骨架。然后,文本文件由 43 个骨架组成,生成一个运动。因此,文本文件代表一个动作

我在构建将每个 (x,y,z) 点以逻辑方式连接到其他点的边(线)时遇到问题,以便点的绘图看起来像骨架。那必须在里面一个循环,因此在每读取 20 行时,生成一个骨架,并且在按键事件之后,比如说右箭头键,读取接下来的 20 行并生成另一个骨架。

我是 Python 和 Matplotlib 的初学者。我已经发布了下面这张由 Matploblit 生成的没有边缘的骨架的图片,以及与我需要用边缘实现的结果类似的另一张图片。

文本文件内容示例:

1.3200000e+002  8.0000000e+001  6.8100000e+002  1.0000000e+000
1.6900000e+002  8.1000000e+001  6.6500000e+002  1.0000000e+000
1.4800000e+002  7.5000000e+001  6.5000000e+002  0.0000000e+000
1.5100000e+002  9.8000000e+001  6.9800000e+002  0.0000000e+000
1.3200000e+002  1.2000000e+002  6.7400000e+002  1.0000000e+000
1.6100000e+002  1.2200000e+002  6.6200000e+002  8.1730800e-001

另外,在绘制骨架时,只取了两个坐标,(x,y) 来生成一个二维骨架,所以第三个坐标被忽略了。并且,绘制已经在循环中,但是按键事件部分还没有实现,下一个骨架是在当前画布关闭时绘制的。

此外,您可能会注意到绘图正在生成前一个骨架与下一个骨架的重叠。我也发布了重叠的图片,这是在第一个骨架之后生成的 42 个骨架之一。

绘制的第一个没有关节的骨架: https://i.stack.imgur.com/FNFTL.png

接下来绘制的 42 个没有关节的骨架之一,存在重叠问题: https://i.stack.imgur.com/D8FQt.png

所需结果的一种方法: https://i.stack.imgur.com/PkWUc.png

from pylab import *
from matplotlib import gridspec
import numpy as np
import sys
import math
import matplotlib.pyplot as plt

movement = np.loadtxt("file01.txt")
number_of_postures = int(len(movement)/20)

listing = []
for i in range(number_of_postures):
    listing.append(movement[(i*20):((i+1)*20),:3]) 

matrixCoord = np.array(listing)

num_plots = number_of_postures
z = 0

for m in range(num_plots):      
   gs = gridspec.GridSpec(1, 2, width_ratios=[3, 1]) # create figure at start of loop

    z += 20
    skeleton = movement[:z,:2]
    x = skeleton[:,0]
    y = -skeleton[:,1]
    plt.subplot(gs[1]) 
    plt.scatter(x,y, s=40)
    plt.title('Skeleton')
    plt.show()

【问题讨论】:

  • 也许您可以发布文本文件,以便我们可以看到应该从中绘制线条的数据。
  • 1.3200000E+002 8.0000000E+001 6.8100000E+002 1.0000000E+000 1.6900000E+002 8.10000E+001 6.6500000E+002 1.002 1.002 1.002 1.000000 000E+0000 0000 000E+0000 000 E+0000 000 E+0000 000 E+0000 000 E+0000 000E+0000 000 E+0000 000 E+0000 000 E+0000 0000 +002 0.0000000e+000 1.5100000e+002 9.8000000e+001 6.9800000e+002 0.0000000e+000 1.3200000e+002 1.2000000e+002 6.7400000e+002 1.0000000e+000 1.6100000e+002 1.2200000e+002 6.6200000e+002 8.1730800e-001 7.9567300e-001 文件太长,举例,800行.
  • 好的,我的意思是你写的 20 行构成一个骨架 - 即使这样也没有必要,也许 3 行,这样就可以设置三个线图的示例
  • 请注意,您可以将这几行也像问题中的代码一样发布。通过这种方式,我们可以看到文件中数字的结构。不幸的是,上面的评论只是一个巨大的数字列表,并没有告诉没有参与的人任何事情。请添加描述文件中的一行如何描述要绘制的联合线:哪个数字表示什么(x1、x2、y1、y2 或其他...)
  • 我已经更改了描述。

标签: python matplotlib


【解决方案1】:

首先直接回答您的问题:

绘制关节之间的线:
首先创建“骨骼列表”,该列表包含构建骨架线的所有关节对。可以从您发布的带有枚举关节的图片中获得:

bone_list = [[1, 3], [2, 3], [3, 4], [4, 7], [5, 7], [6, 7], [1, 8], [2, 9], [8, 10], [9, 11], [10, 12], [11, 13], [5, 14], [6, 15], [14, 16], [15, 17], [16, 18], [17, 19], [3, 20]]

由于枚举从1 开始,但python 索引从0 开始,将列表转换为numpy-array 以轻松将所有值减1:

bone_list = np.array(bone_list) - 1

准备好之后,您可以在运动循环中绘制线条,并为每条线添加一个额外的循环(紧跟在plt.scatter(x, y, s=40) 之后):

for bone in bone_list:
    plt.plot([x[bone[0]], x[bone[1]]], [y[bone[0]], y[bone[1]]], 'r')

关于您的重叠问题:
这只是因为在

skeleton = movement[:z, :2]

您总是从零开始切片,即第一个循环中的 [0:20, :2](绘制一个骨架),第二个循环中的 [0:40, :2](绘制两个骨架)等等。
改成

skeleton = movement[z-20:z, :2]    # or [z:z+20, :2] and do z+=20 afterwards

但是,如果我可以为您的脚本添加一些一般性提示:

进口太多(至少对于您发布的部分而言)
有已重命名的变量已经存在
有未使用的变量
您没有在循环中使用迭代变量 m
gridspec 用于在不均匀分布的网格中创建子图 - 您需要吗?

考虑到这一点,您想要的脚本可能如下所示:

import matplotlib.pyplot as plt
import numpy as np

movement = np.loadtxt("file01.txt")
bone_list = [[1, 3], [2, 3], [3, 4], [4, 7], [5, 7], [6, 7], [1, 8], [2, 9], [8, 10], [9, 11], [10, 12], [11, 13], [5, 14], [6, 15], [14, 16], [15, 17], [16, 18], [17, 19], [3, 20]]
bone_list = np.array(bone_list) - 1
number_of_postures = int(len(movement)/20)

for i in range(number_of_postures):
    fig, ax = plt.subplots(1, figsize=(3, 8))
    plt.title('Skeleton')
    plt.xlim(100, 180)
    plt.ylim(-250, 0)
    skeleton = movement[i*20:(i+1)*20]

    x = skeleton[:, 0]
    y = -skeleton[:, 1]

    sc = ax.scatter(x, y, s=40)
    for bone in bone_list:
        ax.plot([x[bone[0]], x[bone[1]]], [y[bone[0]], y[bone[1]]], 'r')

【讨论】:

  • 非常感谢!我已经在两个不同的文件中实现了你上面所说的所有内容。第一个是我在问题中发布的原始脚本的修改版本,我已经添加了你的答案。第二个文件是您最后发布的脚本,作为提示,但在那个文件中,没有显示任何画布。我认为这可能与以下行有关:fig, ax = plt.subplots(1, figsize=(3, 8)),我从中删除了“fig”,但后来我得到了错误:sc = ax.scatter(x, y, s=40): TUPLE 对象没有属性 SCATTER。我不知道为什么它会显示该错误。
  • 请撤消删除图,我认为没有显示图的原因只是缺少 plt.show(),您在原始脚本中有但我没有。跨度>
  • 删除 fig 后出现错误信息的原因是,现在 ax 正在获取 plt.subplots 的整个返回值,它是一个图形和该图形内的 ax 的元组。通过将它分配给两个变量 fig 和 ax,这个元组被拆分,它的元素分散到 fig 和 ax 中。
  • 我在 for 循环中添加了类似的 plt.show():for i in range(number_of_postures): ax = plt.subplots(1, figsize=(3, 8)) plt .title('骨架') plt.xlim(100, 180) plt.ylim(-250, 0) 骨架 = 运动[i*20:(i+1)*20] x = 骨架[:, 0] y = -skeleton[:, 1] sc = ax.scatter(x, y, s=40) for bone_list 中的骨骼:ax.plot([x[bone[0]], x[bone[1]]], [y [bone[0]], y[bone[1]]], 'r') plt.show() ---但是“元组”错误仍然存​​在。
  • 对,“input()”是一个控制台命令,所以需要关注那里。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-17
相关资源
最近更新 更多