Giter Club home page Giter Club logo

openma's Introduction

OpenMA

Introduction

OpenMA is an open-source and cross-platform library for movement analysis and required data processing. The goal of OpenMA is to provide tools for scientists to perform computations and analysis based on published and existing algorithms without the need to modify their workflow. For example, most of the motion capture (mocap) system provides their own biomechanical model with an associated marker set. However, it would be beneficial to be independent of a mocap system to choose a particular model (because this one is known as better than the provided one, in terms of reliability for a specific population, etc.). The project OpenMA wants to provide such possibilities.

Documentation

The user documentation is centralized and accessible over our website openma.org. The developer documentation is available on the Github wiki.

Programming languages

Most of the code is written in C++. If this language is mostly used in the industry, this is not the case in research laboratories. To tackle this problem, the C++ code was wrapped to different scientific programming languages.

  • Matlab toolbox composed of packages and classes
  • Python 2 & 3 packages composed of classes (coming soon)

The API for binding languages is as close as possible to the C++ API. But when possible it uses native types (e.g. matrices, cells, etc.).

Technologies

This project uses lots of features introduced in the C++11 standard (variadic template, smart pointer, unordered map, auto keyword, etc.). For this reason, a compiler supporting the C++11 standard must be used (e.g MSVC 2013, GCC 4.8, or clang 3.3). The application CMake used for the build system must be at least the release version 3.1.

The numerical computation is realized internally by the Eigen library that uses template expression. On top of Eigen, OpenMA propose the nested namespace math. Several types and operations are proposed to handle data occlusion automatically. Thus, the implementation of numerical analysis is simplified (e.g. no need of for loop to process each sample, or to know if the sample is occluded or not).

The opaque pointer technique (also known as the pimpl idiom) is used in order to keep ABI compatibility between minor release of OpenMA. This point is important for third-party software (and plugins) which uses OpenMA as dynamic libraries.

The internal data structure relies on a dynamic hierarchical tree structure (i.e. a collection of nodes). This kind of structure has the advantage to be very flexible. Indeed, the addition of new kinds of data type is possible without modifying the existing internal structure.

The operations on files are realized using the memory-mapped mechanism to increase input/output performance. Thus, the data loading is faster for files physically present on-disk (or present on the network and temporary downloaded on your computer).

Development testing

In order to ensure the development and its quality over supported operating systems and processors, automated processes are executed each time modification in the code is done on the server. Hence, it strengthens the development, but also reduce undetected errors (bugs, missing documentation, etc.) when a new version is released.

Continuous integration

This part compiles the code on different operating systems in release mode and verify that all units tests passed. The unit tests are implemented using a modified version of CxxTest embedded into the source of OpenMA.

  • MacOS X Build Status

  • Compiler(s): Clang >= 3.1 / GCC >= 4.8

  • Processor architecture(s): x86_64

  • Libraries build mode(s): Static / Shared

  • Linux CircleCI

  • Compiler(s): GCC >= 4.8

  • Processor architecture(s): x86_64

  • Libraries build mode(s): Shared

  • Microsoft Windows Build status

  • Compiler(s): MSVC 2013 / GCC >= 4.8 (MinGW)

  • Processor architecture(s): x86 / x86_64

  • Libraries build mode(s): Shared

Static code analysis Coverity Scan Build Status

This part verifies the quality of the implementation (i.e. no lexical, syntactic, and semantic mistakes which could crash the software or create vulnerabilities) as well as its maintenance.

Test coverage Coveralls Coverage Status

To be sure that unit tests executed in the continuous integration part covers all the classes/functions proposed in OpenMA, a coverage analysis is realized. It gives a metrics regarding the number of calls used in the unit tests for each methods/functions.

API documentation Doxygen Coverage Status

The documentation of the API is built each time a commit is sent on the server. Internally, Doxygen is used to verify and generate documentation of the C++ code (classes, methods, etc.). Then, a custom engine is used to generate the online documentation available on openma.org.

License

OpenMA use the generous open-source New BSD license. Yes, you can use OpenMA in commercial products. The complete text of the copyright is presented below:

Open Source Movement Analysis Library
Copyright (C) 2016, Moveck Solution Inc., all rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above
      copyright notice, this list of conditions and the following
      disclaimer.
    * Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials
      provided with the distribution.
    * Neither the name(s) of the copyright holders nor the names
      of its contributors may be used to endorse or promote products
      derived from this software without specific prior written
      permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

openma's People

Contributors

alzathar avatar marnunez avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

openma's Issues

Improve the class DynamicDescriptor

This class compute joint forces, moments and power in a specific reference frame. This class might do too many operations and need to be split.

  1. Create its name by using the parent name
  2. Compute forces and express it in the requested reference frame (proximal/distal/global)
  3. Compute moments and express it in the requested reference frame (proximal/distal/global)
  4. If not found try to compute joint angular velocity
  5. Compute joint power

It might be better to separate some computation into children descriptors probes. For example, the class DynamicDescriptor can be replaced by the class JointKineticsProbe. This class will define children. Each of them will compute a specific component (i.e. force, moment and power). The classes for these children could be:

  • JointForceProbe
  • JointMomentProbe
  • JointPowerProbe

Important: This means that the Probe class has to implement a generic processing mechanism to look for children and update them.

Rename classes *Descriptor by *Probe

The noun descriptor is not well adapted as its definition is (from merriam-webster)

something (as a word or characteristic feature) that serves to describe or identify; especially : a word or phrase (as an index term) used to identify an item (as a subject or document) in an information retrieval system

Instead the noun probe might be better. From merriam-webster:

a careful examination or investigation of something

The noun probe is also used by the project OpenSim.

Option to delete segments when associated markers are missing during model's reconstruction

The deletion has be applied also on the associated joint (and chain?).
Moreover, this is model definition dependent. If the relative segment needs informations from ancestors that is deleted, it should be deleted too.

For example:

  • Missing marker for the left hand: This segment is deleted as well as the left wrist joint
  • Missing marker for the left arm (left forearm reconstruction is dependent, same for the hand that needs information from the forearm): The three segments are deleted as well as the associated joint (wrist, elbow, shoulder)

Better management of joint centre definition

Some joint centres are defined using formula (i.e hip joint centre, shoulder joint centre, lumbar joint centre). Currently, these definitions are hardcoded in the skeleton helper (e.g. ma::body::PluginGait) and it is only possible to pass a ma::body::Point to create a custom centre.This needs to be improved by creating external classes corresponding to joint centre definition published in the literature.

Implement the parser for the Elite file formats.

The parsers in the BTK project is a good start to implement the parsers of the Elite file formats.

Compared to BTK, OpenMA will manage all the Elite file in the same plugin with one handler by file format. The data provided in the project BTKData will be used for the validation (see the subfolder EliteSamples). However, these data came from 2010. New data would be necessary to verify that BTS does or does not change their file format (see issue #47).

compute joint moment contribution

Might be worth to compute the joint Moment contribution for CGA.
a joint moment can be splited as follow ๐Ÿ‘

  • inertial contribution
  • gravitational contribution
  • distal segment contribution .

setProperties

A node object should have a setProperties method so as to input a list of data instead of to add them though SetProperty.

Mokka warning : impossible to scale

I got this warning in the mokka logger :
2016-10-05 22:56:12 - Unknown unit. Impossible to scale correctly the data in the 3D views
when i create a c3d from scratch :
root = ma.Node('root') trial = ma.Trial('my_analysis',root) trial.setProperty('MY_GROUP:MY_PARAMETER',10.0) angle = ma.TimeSequence('LHipAngles.Left', 4, 101, 1.0, 0.0, ma.TimeSequence.Type_Angle, 'deg', trial.timeSequences()) angle.setData(np.random.rand(101,4)) ma.io.write(root,"test.c3d")

Split the class EulerDescriptor

The class EulerDescriptor is able to compute Euler angles for joint and segment. Instead two classes should be created:

  • JointEulerProbe
  • SegmentEulerProbe

Improve the API of *Probe (*Descriptor) classes

After the implementations of issues #31 and #32, the definition of these probes could be something like the following lines:

new JointEulerProbe("L.Hip.Angle", EulerDescriptor::YXZ, {{-1.,-1.,-1.}}, jnt);
new JointKineticsProbe("L.Hip.Kinetics", "L.Hip", {{0,1,2,1,0,2,0,1,2}}, {{1.,1.,1.,1.,1.,1.,1.,1.,-1.}}, jnt);

Still the API looks not clear about the usage of the axes orders and the scaling. Instead it is proposed to replace the static arrays in the EulerDescriptor class (i.e. XYZ etc). by a new class with static method. For example, the previous class can be replaced by

new JointEulerProbe("L.Hip.Angle", AxesOrder::xyz{-1.,-1.,-1.}, jnt);
new JointKineticsProbe("L.Hip.Kinetics", "L.Hip", AxesOrder::xyz{}, AxesOrder::yxz{}, AxesOrder::xyz{1.,1.,-1.}, jnt);

The same class explains the Euler sequence to use for the joint angles but also the storage order for the joint kinetics (force, moment, power). The content of the constructor of this classe correspond to scale factors for each axis (usually 1. and -1. to take the opposite for clinical interpretation).

improve findChildren

In case of we want extract only Moment from a trial, i suggest to alter the statement :
kineticAnalysis.findChildren(ma.T_TimeSequence ,".*",[["type",ma.TimeSequence.Type_Moment]])

by a quite simple method :
kineticAnalysis.findChildren(ma.T_TimeSequence ,ma.TimeSequence.Type_Moment)

Improve the behaviour of the class ma::body::Joint

The goal of the ma::body::Joint class is to define a link between two ma::body::Segment objects. For that, two ma::body::Anchorobjects (one for each segment) are used to define the location of the joint. The following lines show the definition of a joint.

// The joint is defined between the segments pelvis and leftThigh
// The location of the joint is at the point L.HJC defined by the pelvis for both anchor
jnt = new Joint("L.Hip", pelvis, Anchor::point("L.HJC"), leftThigh, Anchor::point("L.HJC", pelvis), joints);

The problem with this behaviour is there is no reference frame associated with each extremity of the joint. Instead, they are chosen independently depending of the definition of the model (for example ma::body::EulerDescriptor ma::body::JointEulerProbe. This behaviour is complex to understand and requires to correctly set the name of the reference frames to use. Several indirect links needs to be done to find the good objects.

It is proposed to redesign the definition of a joint to be linked directly to reference frames instead of segments. This gives several advantages when designing a model. Moreover, it removes some steps to compute joint kinematics and kinetics. The new code could be for example

// The joint is defined between the segment coordinate system of the pelvis and leftThigh
// The location of the joint is at the point L.HJC defined by the pelvis for both anchor
// The anchor will come the children of the joint
jnt = new Joint("L.Hip",
                new Anchor("L.Hip.Anchor.Prox", pelvisSCS, pelvisLeftHJC),
                new Anchor("L.Hip.Anchor.Dist", leftThighSCS, pelvisLeftHJC),
                joints);

The new design attaches directly the reference frame of interest as well as the location. This means that when the model is setup all the relative elements (reference frame and position) has to be defined.

Graphically, the new behaviour should look like the following figure.

openma_pig_tree_hip_part

time of two events should be the same.

look inside this c3d.
generally, i identify kinetics cycle through general events.
At frame 253, i have defined both foot strike and general event.
I am surprised event.times are different when i called the convenient openMA event method.

cheers

Fabien

Implement support for the FORCE_PLATFORM:ZERO c3d parameter

The FORCE_PLATFORM:ZERO parameter can be used to provide a range of frames where the force plate is unloaded and that can be used to determine a zero baseline for each plate, see here.

As many force plates output some residual force values even after zeroing the amplifier, it would be useful if OpenMA could read the frame numbers and apply them accordingly.

No baseline subtraction should be performed if the parameter does not exist or is set to an array containing [0,0].

Implement a resampling method

Currently it is possible to downsample a math::XprBase expression with an integer ratio by taking only a sample every ratio samples. However, this is not complete to create a decimation by an integer factor.

In general, it will be more interesting to implement a resampling function to be able to downsample and upsample a signal. As mentioned in this post, this resampling function would use a method similar to the resample function proposed in Scipy.

Units standardization in internal storage and computation

Currently, OpenMA stores units as strings for time sequences and assumes them for other objects (like force plate geometry). This gives virtually the possibility to store any kind of units. However, the major draw back is that people can mix data with different units (e.g. markers with coordinates in millimeters and meters). The problem is worst for algorithms that need to know inputs' unit to correctly set outputs' unit (e.g. moment units from force units and distance units). The question is how to have a generic storage unit (e.g. for position, forces, acceleration, moment, power, etc.) but ensure it will not wrongly influence computation.

It is proposed to keep only one kind of unit by physical quantity. Internally, this will simplify the checking of data as well as the creation of new time sequences. However, this means that each data stored within OpenMA objects must be converted (scales) to fit with the units used by OpenMA (i.e. file format, data entered manually).

If this is accepted, what should be the units to be used? The International System of Quantities might be the best choice. If users prefer their outputs to a different format, they will have to scale them in consequence.

Fix foot flat Z-axis option

The current code assumes that the vertical axis is always the Z-axis in the Plug-in Gait Model. The implementation of a ma::LaboratorySettings as discussed in the issue #16 should fix the problem.

Computation of the Pig model with optional offsets

Thigh offset, shank offset and tibialRotation angle are optional parameter , they can get closer the model with anatomy.
These parameters are calculated during static calibration with the Knee Aligmenent device.
Well established gait labs use the KAD :-)
In consequence,

  • the openMA chord function should accept an additional parameters ( ie, shank and thigh offset)
  • the openMA pig configurator shoudl consider an untorsioned tibia

Options to choose the finite derivate methods in the inverse dynamic algorithms

Currently, the class ma::body:: InverseDynamicsMatrix uses central/forward/backward methods to compute 1st and 2nd derivate with a 2nd order of accuracy. However, other methods can be used for that (central method + mirroring on the boundaries, cascaded 1st derivate), The possibility to choose the finite derivate method will help to validate the inverse dynamic part. Indeed, no reference data correspond to the implementation of the class ma::body:: InverseDynamicsMatrix.

Reference counting mechanism not enough robust in the bindings

The bindings use a reference counting mechanism to determine the lifetime of an object. This helps to know if an object is linked to a variable. If this is the case, the latest parent in the internal C++ must not delete this object.

However, the current implementation in SWIG is not enough. The following code crashes as the reference counter did not increase correctly

% This code crashes when the command 'clear all' is used or it is called in a function.
% The reason is because the landmark translator is added internally to the models
% but its is not increased
staticTrials = ma.io.read('myfile1.c3d');
motionTrials = ma.io.read('myfile1.c3d');
translator = ma.body.LandmarksTranslator('CGM', {...}, helper); % MISSING TRANSLATIONS INTENDED
helper = ma.body.PluginGait(ma.body.Region_Full,ma.body.Side_Both);
ma.body.calibrate(helper, staticTrials);
models1 = ma.body.reconstruct(helper, staticTrials);
models2 = ma.body.reconstruct(helper, motionTrials);
% Crash due to the next line
models3 = ma.body.reconstruct(helper, motionTrials);

Of course, we can specify which wrapped methods take the ownership of a node in SWIG. However, this must be done manually for each method. This is too much unreliable and easily forgettable.

In consequence a new reference counting mechanism must be implemented called directly at the core level and not the SWIG level.

OpenMA building problem

Hi! I'm having some trouble building OpenMA. After successfully configuring a base build with CMake (3.7.1), and running make (GNU Make 4.1), it continuously finds fabs and isnan out of scope. I'm solving it by adding #include <cmath> and changing isnan by std::isnan each time, but this is clearly not the right way to do this. What am I missing here?

uname -a
Linux DEBIAN-MARCOS 4.8.0-2-amd64 #1 SMP Debian 4.8.11-1 (2016-12-02) x86_64 GNU/Linux

gcc --version
gcc (Debian 6.2.1-5) 6.2.1 20161124

Improve the management of the gravity

Currently the gravity must be set for eachma::body::SkeletonHelper object as a property. This could be improved and simplified. As already commented for the issue #16, the implementation of the class ma::LaboratorySettings would be a good way to set the gravity and store supplementary information on the experiment setup.

Computation of the total center of mass

In case a model is set as a ma::body::Region::Full, the computation of the total center of mass should be proposed (or automatically done during the computation of the inverse dynamics). The projection on the ground might also be done at the same time.

OpenMA cheat sheet

there is an amazing cheat sheet for Btk ( ;-)

could we write an openMA sheet ?

Fabien

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.