pyomeca / ezc3d

Easy to use C3D reader/writer for C++, Python and Matlab
https://pyomeca.github.io/Documentation/ezc3d/index.html
MIT License
145 stars 46 forks source link

MATLAB - ezc3dWrite goes to wrong "subject" #296

Closed cosnyd closed 11 months ago

cosnyd commented 1 year ago

Hi pyomeca,

I have marker structure which contains trajectory data from an existing c3d file, in which some coordinates have been modified, and others added. I want to write over existing marker data, and append new markers into the existing c3d file. The function ezc3d write works fine, however when viewing the modified data (example in Vicon), the trajectory data is written into a "New Subject" rather than the original. Am I missing something?

Marker_names = fieldnames(struct_of_marker); c3d = ezc3dRead(Absoluter_Dateiname);

for ind = 1:size(Marker_names,1) if sum(ismember(c3d.parameters.POINT.LABELS.DATA,Marker_names{ind})) marker_ind = find(ismember(c3d.parameters.POINT.LABELS.DATA,Marker_names{ind})); c3d.data.points(:,marker_ind,:) = reshape(transpose(struct_of_marker.(Marker_names{ind})),[3,1,c3d.parameters.POINT.FRAMES.DATA]); else c3d.data.meta_points.residuals = cat(2,c3d.data.meta_points.residuals,zeros(1,1,c3d.parameters.POINT.FRAMES.DATA)); c3d.data.meta_points.camera_masks = cat(2,c3d.data.meta_points.camera_masks,zeros(size(c3d.data.meta_points.camera_masks,1),1,c3d.parameters.POINT.FRAMES.DATA)); c3d.parameters.POINT.USED.DATA = c3d.parameters.POINT.USED.DATA + 1; c3d.parameters.POINT.LABELS.DATA{end+1} = Marker_names{ind}; c3d.data.points = cat(2,c3d.data.points,reshape(transpose(struct_of_marker.(Marker_names{ind})),[3,1,c3d.parameters.POINT.FRAMES.DATA])); end end

ezc3dWrite(Absoluter_Dateiname,c3d);

This also occurs when specifying the subject name in the trajectory labels (i.e. 'Old Subject:LASI').

Thanks in advance for the help!

pariterre commented 1 year ago

Hi @cosnyd !

I made a test using a simplified version of your snippet, using th Vicon.c3d shipped with the test suite of ezc3d:

c3d = ezc3dRead('Vicon.c3d');
npoints = c3d.header.points.lastFrame;

c3d.parameters.POINT.USED.DATA = c3d.parameters.POINT.USED.DATA + 1;
c3d.parameters.POINT.LABELS.DATA{end+1} = 'Daphnee:Coucou';
c3d.data.meta_points.residuals = cat(2, c3d.data.meta_points.residuals, zeros(1, 1, npoints));
c3d.data.meta_points.camera_masks = cat(2, c3d.data.meta_points.camera_masks, zeros(7, 1, npoints));
c3d.data.points = cat(2, c3d.data.points, rand(3, 1, npoints));

ezc3dWrite('Vicon_Modified', c3d);

When loaded in Vicon, I did not see anything peculiar... The markers were appearing in the subject's data and even in the label zone so I can manually label it in the main screen. This c3d does not have an actual model template loaded though... If this is what you meant, I think the problem may come from the fact that the model in the new c3d does not conform to the template saved in Vicon, would that make sense?

A way to test that would be to update the template marker model to conform with the expected new c3d file...

Let me know if it helps!

cosnyd commented 1 year ago

Hi @pariterre !

Thanks for the suggestion, it seems like it would make sense. However I have also tried just reading and writing sample c3d files, without modifying the content, and I get the same result. The only difference that I can see to your code above would be the point label. If there are not multiple subjects loaded in the trial, does the label name need to also contain the subject name (i.e "SubjectName:PointName")?

pariterre commented 1 year ago

As fas as I know, there is no concept of "subject" in a c3d file. This means that Vicon probably have their own convention for what they call "subject". Based on that, and based on seeing a lot of c3d from Vicon, I would suspect that the convention is indeed to add "SubjectName" to every point name you interact with!