How can I read text files and compile a joint XY Position history

2 visualizzazioni (ultimi 30 giorni)
Hello eveyone,
I am struggling with finding a solution to my problem. I have numerous a json text files with XY position co-ordinates obtained from a 2D human pose estimation. I would like to read and use particular data keypoints from the XY coordinates for each JSON file in order to plot joint angle history for example. Is there a way to convert the data into an array? I have been struggling with numerous Matlab functions (fgets, fscanf) albeit with no luck and I am a bit lost.
The below data is what is contained on the numerous JSON files I have (a json file for each frame captured during the pose estimation video). The XY data below indicates the XY coordinate for each pose keypoint with a confidence reading/percentage for how accurate the pose estimation software believes that XY coordinate is. For example for the first keypoint for the Nose, the XY coordinate (with its confidence reading) is 314.19, 94.238, 0.934092 (both pieces of info are in BOLD in the data below.
{"version":1.3,"people":[{"person_id":[-1],"pose_keypoints_2d":[314.19,94.238,0.934092,305.601,109.546,0.891856,288.369,111.457,0.862389,268.27,130.557,0.860192,280.744,125.806,0.860478,322.797,106.684,0.84053,353.393,92.3152,0.859181,375.415,77.0249,0.859859,310.392,186.998,0.760913,296.043,186.045,0.705134,277.88,246.273,0.866712,234.798,229.088,0.834373,325.659,187.963,0.724311,354.392,233.851,0.880398,343.864,294.145,0.808459,309.387,88.5102,0.968337,317.993,89.4436,0.927254,295.042,87.5593,0.901007,0,0,0,364.873,300.81,0.505551,362.036,297.926,0.442485,338.115,300.781,0.724548,213.795,238.663,0.719225,212.839,233.886,0.699098,232.92,223.355,0.603927],"face_keypoints_2d":[],"hand_left_keypoints_2d":[],"hand_right_keypoints_2d":[],"pose_keypoints_3d":[],"face_keypoints_3d":[],"hand_left_keypoints_3d":[],"hand_right_keypoints_3d":[]}]}
{"version":1.3,"people":[{"person_id":[-1],"pose_keypoints_2d":[314.19,94.238,0.934092,305.601,109.546,0.891856,288.369,111.457,0.862389,268.27,130.557,0.860192,280.744,125.806,0.860478,322.797,106.684,0.84053,353.393,92.3152,0.859181,375.415,77.0249,0.859859,310.392,186.998,0.760913,296.043,186.045,0.705134,277.88,246.273,0.866712,234.798,229.088,0.834373,325.659,187.963,0.724311,354.392,233.851,0.880398,343.864,294.145,0.808459,309.387,88.5102,0.968337,317.993,89.4436,0.927254,295.042,87.5593,0.901007,0,0,0,364.873,300.81,0.505551,362.036,297.926,0.442485,338.115,300.781,0.724548,213.795,238.663,0.719225,212.839,233.886,0.699098,232.92,223.355,0.603927],"face_keypoints_2d":[],"hand_left_keypoints_2d":[],"hand_right_keypoints_2d":[],"pose_keypoints_3d":[],"face_keypoints_3d":[],"hand_left_keypoints_3d":[],"hand_right_keypoints_3d":[]}]}
[dpb edit -- added copy as code so the select button will work to get the text if folks want to try their hand at it...]
description of each XY coordinate: (not in json file)
# {0, "Nose"},
# {1, "Neck"},
# {2, "RShoulder"},
# {3, "RElbow"},
# {4, "RWrist"},
# {5, "LShoulder"},
# {6, "LElbow"},
# {7, "LWrist"},
# {8, "MidHip"},
# {9, "RHip"},
# {10, "RKnee"},
# {11, "RAnkle"},
# {12, "LHip"},
# {13, "LKnee"},
# {14, "LAnkle"},
# {15, "REye"},
# {16, "LEye"},
# {17, "REar"},
# {18, "LEar"},
# {19, "LBigToe"},
# {20, "LSmallToe"},
# {21, "LHeel"},
# {22, "RBigToe"},
# {23, "RSmallToe"},
# {24, "RHeel"},
# {25, "Background"}
  1 Commento
dpb
dpb il 28 Feb 2021
Modificato: dpb il 28 Feb 2021
Attach a file, not the representation of a file...
But, in the meantime, you can try
fname = 'youFile.json';
val = jsondecode(fileread(fname));
That may be excessively optimistic; I've yet to learn anything about JSON so have no idea about how clever the TMW decode function is having never used it. The example given is so trivially simple in content as to be ludicrous -- cellstr() would return the same result as does it.

Accedi per commentare.

Risposta accettata

dpb
dpb il 28 Feb 2021
Well, it does seem to "just work" -- almost. jsondecode doesn't know about the 2D array bit, but it did decode the JSON info block --
I put the data block into a file named 'pose.json', and then:
>> vals=jsondecode(fileread('pose.json'))
vals =
struct with fields:
version: 1.3000
people: [1×1 struct]
>> vals.people
ans =
struct with fields:
person_id: -1
pose_keypoints_2d: [75×1 double]
face_keypoints_2d: []
hand_left_keypoints_2d: []
hand_right_keypoints_2d: []
pose_keypoints_3d: []
face_keypoints_3d: []
hand_left_keypoints_3d: []
hand_right_keypoints_3d: []
>>
Don't see anything inside the JSON itself that identifies the 3-vector for each point, but given that outside information you provided, then:
>> keypoints=reshape(vals.people.pose_keypoints_2d,3,[]).';
>> keypoints(1:10,:)
ans =
314.1900 94.2380 0.9341
305.6010 109.5460 0.8919
288.3690 111.4570 0.8624
268.2700 130.5570 0.8602
280.7440 125.8060 0.8605
322.7970 106.6840 0.8405
353.3930 92.3152 0.8592
375.4150 77.0249 0.8599
310.3920 186.9980 0.7609
296.0430 186.0450 0.7051
>>
Looks like it works as advertised. Amazing!!! :)
  1 Commento
dpb
dpb il 28 Feb 2021
Or, turn it into a table--
>> keypoints=array2table(reshape(vals.people.pose_keypoints_2d,3,[]).','VariableNames',{'PoseX','PoseY','PoseErr'});
>> head(keypoints)
ans =
8×3 table
PoseX PoseY PoseErr
______ ______ _______
314.19 94.238 0.93409
305.6 109.55 0.89186
288.37 111.46 0.86239
268.27 130.56 0.86019
280.74 125.81 0.86048
322.8 106.68 0.84053
353.39 92.315 0.85918
375.42 77.025 0.85986
>>

Accedi per commentare.

Più risposte (1)

Ross Norman
Ross Norman il 2 Mar 2021
Modificato: Ross Norman il 3 Mar 2021
That's fantastic, works as shown importing the json file data, Thanks.
I have been trying to input those keypoint data co-ordinates to compute the joint angle for a specified joint (right knee). I want to plot the joint angle as a function of time for all frames (separate json files, with each file representing a frame). I would also like to create an animation plot of the 25 keypoints representing the movement of the data captured in each frame. There are 150 frames, which was recorded over 5 seconds thus the frame rate is 30 frames/sec. All the files have been included in the zip file attached.
I have added my code below which needs some work and tidying up. Need to include a for loop still for the keypoint positioning. If someone knows whether a for loop cna import numeorus files or if every file will need to be imported and have for example the rows represent the 150 frames and the columns represent the 25 different keypoint variables. For the joint angle calc, the dot product formula is correct for that joint angle calculation just need to correctly plot all the joint angles over the whole time range.
close all; clear; clc;
%frame rate = 30 frames/sec
%looking to add a loop to process all keypoints recorded for each frame
%looking to plot an animation of keypoints for each frame (i:1:end)
%this will include all keypoints except for outliers that aren't recorded
%correctly e.g. at the origin (0,0).
fname = 'larissa/larissa_000000000100_keypoints.json'; %insert file name
vals= jsondecode(fileread(fname));
keypoints=array2table(reshape(vals.people.pose_keypoints_2d,3,[]).','VariableNames',{'PoseX','PoseY','PoseErr'});
%would like to add labels on the table labelling each row
keypoints(1:25,:)
% Keypoint #1 to #25 descriptions:
% {0, "Nose"},
% {1, "Neck"},
% {2, "RShoulder"},
% {3, "RElbow"},
% {4, "RWrist"},
% {5, "LShoulder"},
% {6, "LElbow"},
% {7, "LWrist"},
% {9, "RHip"},
% {10, "RKnee"},
% {11, "RAnkle"},
% {12, "LHip"},
% {13, "LKnee"},
% {14, "LAnkle"},
% {15, "REye"},
% {16, "LEye"},
% {17, "REar"},
% {18, "LEar"},
% {19, "LBigToe"},
% {20, "LSmallToe"},
% {21, "LHeel"},
% {22, "RBigToe"},
% {23, "RSmallToe"},
% {24, "RHeel"},
% {25, "Background"}
figure(1); hold on; box on; grid on;
x_points = table2array(keypoints(:,1));
y_points = table2array(keypoints(:,2));
% work needed to plot the keypoints as a stick man,
% currently wrong plot as all points connected but not sequentially.
plot (x_points,y_points, 'r-');
legend('Pose Estimation Keypoints')
xlabel('X Co-ordinates');
ylabel('Y Co-ordinates')
title('Pose Estimation Keypoints')
%alternative is len = height(keypoints) need further work on this
len=length(x_points)
%this code to compute and plot joint angle (knee joint in this instance) as
%a function of time
for i = 1:len ;
%extract the X, Y coordinate for each keypoint
RHip_x(i) = x_points(9) % postion in keypoint array {9, "RHip"},
RHip_y(i) = y_points (9)
RKnee_x(i) = x_points (10) % postion in keypoint array{10, "RKnee"},
RKnee_y(i) = y_points (10)
RAnkle_x(i) = x_points (11) % postion in keypoint array{11, "RAnkle"},
RAnkle_y(i) = y_points (11)
LHip_x(i) = x_points (12) % postion in keypoint array{12, "LHip"},
LHip_y(i) = y_points (12)
LKnee_x(i) = x_points (13) % postion in keypoint array{13, "LKnee"},
LKnee_y(i) = y_points (13)
LAnkle_x(i) = x_points (14) % postion in keypoint array{14, "LAnkle"},
LAnkle_y(i) = y_points (14)
femurx = RKnee_x(i)- RHip_x(i)
femury = RKnee_y(i)- RHip_y(i)
femur = [femurx femury]
unit_femur = femur/norm(femur)
tibiax = RAnkle_x(i)- RKnee_x(i)
tibiay = RAnkle_y(i)- RKnee_y(i)
tibia = [tibiax tibiay]
unit_tibia = tibia/norm(tibia)
angle_right_knee_deg(i) = acosd(dot(unit_tibia,unit_femur))
end
%plot the joint angles as a function of time (joint angle at each frame)
figure(2); hold on; box on; grid on;
xlabel('Joint Angle - degree');
ylabel('Time - s')
title('Joint Angle')
  1 Commento
dpb
dpb il 3 Mar 2021
You can either use a timetable or timesries where each row is the time and column is the node or leave organized by row by node and make each column of the table a time.

Accedi per commentare.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by