Nowe technologie w fizyce biomedycznej/Kamery 3D: Różnice pomiędzy wersjami

Z Brain-wiki
(Utworzono nową stronę "=Kamery 3D = ==Plan zajęć== Zajęcia 1: *Wstęp teoretyczny: **Budowa i zasada działania sensora Kinect. **Opis podstawowych bibliotek wykorzystywanych do komunikacj...")
 
 
(Nie pokazano 24 pośrednich wersji utworzonych przez tego samego użytkownika)
Linia 12: Linia 12:
 
**W ramach pomiarów studenci wykonają standardowy test wykorzystywany w medycynie sportowej do oceny prawdopodobieństwa urazów więzadła krzyżowego przedniego (ACL).  
 
**W ramach pomiarów studenci wykonają standardowy test wykorzystywany w medycynie sportowej do oceny prawdopodobieństwa urazów więzadła krzyżowego przedniego (ACL).  
  
[[Media:3D_Kinect.pdf]] Informacje wstępne oraz opis zadań
+
[[Media:3D_Kinect.pdf]] Informacje wstępne oraz opis zadań <br>
 +
[[Media:3D_Kinect_ENG.pdf]] Theoretical information and description of tasks
  
 
Zajęcia 2,3,4:
 
Zajęcia 2,3,4:
Linia 37: Linia 38:
 
==Pomiary==
 
==Pomiary==
  
 +
Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu. Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.
 +
 +
Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów przy użyciu kamery 3D wybieramy opcję 'Kinect App', która otworzy okno do zapisu lub odczytu danych.
 +
 +
[[Plik:KinectApp.png|300px|thumb|left|<figure id="fig:wbb"></figure>Interfejs graficzny aplikacji Brain4edu]]
 +
[[Plik:KinectAppStart.png|300px|thumb|right|<figure id="fig:wbb"></figure>Okno wyboru rejestracji/odczytu danych aplikacji KinectApp]]
 +
 +
W wyświetlonym oknie wpisz katalog zapisu/odczytu, wybierz tryb działania, a następnie naciśnij przycisk Start. Po uruchomieniu wyświetlone zostanie okno z podglądem zarówno mapy głębokości jak i obrazu RGB.
 +
 +
<!--
 
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie:  
 
Rejestracja danych odbywa się w środowisku OpenBCI. System ten uruchamiamy wykonując w terminalu polecenie:  
  
Linia 58: Linia 69:
  
 
[[Plik:obci_gui.png|600px|thumb|center|<figure id="fig:obci_kinect"></figure>Scenariusz w OpenBCI do rejestracji danych przy pomocy Kinecta.]]
 
[[Plik:obci_gui.png|600px|thumb|center|<figure id="fig:obci_kinect"></figure>Scenariusz w OpenBCI do rejestracji danych przy pomocy Kinecta.]]
 +
-->
  
 +
=== Drop Vertical Jump ===
 
Zeskok z następującym wyskokiem pionowym (''drop vertical jump'', DVJ) należy do badań przesiewowych, pozwalających oszacować ryzyko występienia urazu (w szczególności więzadła krzyżowego przedniego u kobiet) lub określić efekty rehabilitacji. Przed rozpoczęciem skoku osoba badana stoi na platformie o wysokości ok. 30 cm. Ma ona za zadanie wykonać zeskok z platformy na ziemię, a następnie maksymalny skok pionowy w górę. W dalszej analizie interesujące będą momenty: kontaktu pięt z podłożem (''initial contact'', IC) zaraz po wykonaniu zeskoku oraz moment maksymalnego zgięcia kolan (''peak flexion'', PF) zaraz po IC, ale przed oderwaniem pięt od podłoża w celu wykonania skoku pionowego.
 
Zeskok z następującym wyskokiem pionowym (''drop vertical jump'', DVJ) należy do badań przesiewowych, pozwalających oszacować ryzyko występienia urazu (w szczególności więzadła krzyżowego przedniego u kobiet) lub określić efekty rehabilitacji. Przed rozpoczęciem skoku osoba badana stoi na platformie o wysokości ok. 30 cm. Ma ona za zadanie wykonać zeskok z platformy na ziemię, a następnie maksymalny skok pionowy w górę. W dalszej analizie interesujące będą momenty: kontaktu pięt z podłożem (''initial contact'', IC) zaraz po wykonaniu zeskoku oraz moment maksymalnego zgięcia kolan (''peak flexion'', PF) zaraz po IC, ale przed oderwaniem pięt od podłoża w celu wykonania skoku pionowego.
 +
 +
[[Plik:drop_vertical_jump.png|600px|thumb|center|<figure id="fig:obci_kinect"></figure>Przebieg zeskoku z następującym wyskokiem pionowym. Źródło: Stone et al., 2013]]
  
 
==Analiza danych==
 
==Analiza danych==
  
Studenci zapoznają się z modułami (napisanymi w języku programowania Python) do wczytywania oraz wstępnego przetwarzania danych. Następnie samodzielnie wyznaczą następujące wskaźniki biomechaniczne (opisane w pracy (Stone et al., 2013), którą można znaleźć pod adresem: [https://www.eldertech.missouri.edu/wp-content/uploads/2016/07/Evaluation-of-the-Microsoft-Kinect-for-Screening-ACL-Injury.pdf]):
+
Studenci zapoznają się z modułami (napisanymi w języku programowania Python) do wczytywania oraz wstępnego przetwarzania danych. Następnie samodzielnie wyznaczą wskaźniki biomechaniczne, opisane w pracy (Stone et al., 2013), którą można znaleźć pod adresem: [https://www.eldertech.missouri.edu/wp-content/uploads/2016/07/Evaluation-of-the-Microsoft-Kinect-for-Screening-ACL-Injury.pdf].
*knee valgus motion (KVM),
+
 
*frontal plane knee angle (FPKA) w dwóch momentach (w trakcie kontaktu pięt z podłożem zaraz po wykonaniu zeskoku oraz w trakcie maksymalnego zgięcia kolan),
+
Zeskok z pionowym wyskokiem powtórzony został 3-krotnie w celu większej wiarygodności wyników. Należy zatem dla każdego powtórzenia oddzielnie wyznaczyć momenty IC oraz PF, wyliczyć wartość każdego z parametrów. A następnie należy uśrednić uzyskane wyniki i podać je wraz z niepewnością średniej. Omawiane wskaźniki biomechaniczne:
*knee-to-ankle separation ration (KASR) w momencie PF,
+
*knee valgus motion (KVM) - przesunięcie kolan w płaszczyźnie czołowej (x) pomiędzy momentami IC a PF
*zmiana w czasie średniej pozycji bioder.
+
[[Plik:KVM.png|400px|thumb|center|<figure id="fig:kinect_joints"></figure>Knee valgus motion]]
Wyniki opracowane powinny zostać w formie tabeli, gdzie zestawione zostaną wartości KVM, FPKA, KASR otrzymane dla każdej osoby z grupy. Trajektoria średniej pozycji bioder podczas wykonywania zadania powinna zostać przedstawiona na wykresie.
+
*frontal plane knee angle (FPKA) - kąt pod jakim znajduje się wektor (od kolana do stopy) oddzielnie dla prawej i lewej nogi, w dwóch momentach: IC oraz PF
 +
[[Plik:FPKA.png|400px|thumb|center|<figure id="fig:kinect_joints"></figure>Frontal plane knee angle]]
 +
*knee-to-ankle separation ration (KASR) - stosunek rozsunięcia kolan do kostek w momencie PF
 +
[[Plik:KASR.png|400px|thumb|center|<figure id="fig:kinect_joints"></figure>knee-to-ankle separation ration]]
 +
*zmiana w czasie średniej pozycji bioder, kolan i stóp.
 +
Wyniki opracowane powinny zostać w formie tabeli, gdzie zestawione zostaną wartości KVM, FPKA, KASR otrzymane dla każdej osoby z grupy (uśrednione po realizacjach - 3 powtórzeniach). Trajektoria (w kierunku pionowym i poziomym) średniej pozycji bioder, kolan i stóp podczas wykonywania zadania powinna zostać przedstawiona na wykresie.
  
 
===Analiza danych===
 
===Analiza danych===
  
Przykładowy skrypt do wczytywania wyników algorytmów śledzenia pozycji anatomicznych (wraz z metadanymi rejestracji):
+
Implementacja klasy Serialization umożliwiająca łatwe wczytanie danych (proszę zapisać ten plik jako KinectUtils).
 +
 
 +
{{Solution|title=implementacja klasy|text=
  
 
<source lang="Python">
 
<source lang="Python">
#!/usr/bin/env python
+
#!/usr/bin/env python3
 
# -*- coding: utf-8 -*-
 
# -*- coding: utf-8 -*-
  
from __future__ import print_function
+
import struct
 +
 
 +
class KinectException(Exception):
 +
    pass
 +
 
 +
class JointStruct(struct.Struct):
 +
    def __init__(self):
 +
        super(JointStruct, self).__init__('iffffff')
 +
 
 +
class HandStruct(struct.Struct):
 +
    def __init__(self):
 +
        super(HandStruct, self).__init__('ifffff')
 +
 
 +
class UserStruct(struct.Struct):
 +
    def __init__(self):
 +
        super(UserStruct, self).__init__('hfffi')
 +
 
 +
class FrameStruct(struct.Struct):
 +
    def __init__(self):
 +
        super(FrameStruct, self).__init__('iQ')
 +
 
 +
class HeaderStruct(struct.Struct):
 +
    def __init__(self):
 +
        super(HeaderStruct, self).__init__('i??diQiQ')
 +
 
 +
class Point3Mock(object):
 +
    def __init__(self, x, y, z):
 +
        self.x = x
 +
        self.y = y
 +
        self.z = z
  
import sys
+
class JointMock(object):
sys.path.append('/usr/share/openbci/drivers/kinect/')
+
    def __init__(self, id, positionConfidence, x, y, z, x_converted, y_converted):
 +
        self.id = id
 +
        self.positionConfidence = positionConfidence
 +
        self.x = x
 +
        self.y = y
 +
        self.z = z
 +
        self.x_converted = x_converted
 +
        self.y_converted = y_converted
  
from KinectUtils import Serialization
+
class SkeletonFrameMock(object):
 +
    def __init__(self, frame_index, frame_timestamp, user_id, x, y, z, user_state, joints):
 +
        self.frame_index = frame_index
 +
        self.frame_timestamp = frame_timestamp
 +
        self.user_id = user_id
 +
        self.user_x = x
 +
        self.user_y = y
 +
        self.user_z = z
 +
        self.user_state = user_state
 +
        self.joints = joints
 +
 
 +
class HandDataMock(object):
 +
    def __init__(self, hand_id, x, y, z, x_converted, y_converted):
 +
        self.id = hand_id
 +
        self.x = x
 +
        self.y = y
 +
        self.z = z
 +
        self.x_converted = x_converted
 +
        self.y_converted = y_converted
 +
 
 +
class HandFrameMock(object):
 +
    def __init__(self, frame_index, frame_timestamp, hands):
 +
        self.frame_index = frame_index
 +
        self.frame_timestamp = frame_timestamp
 +
        self.hands = hands
 +
 
 +
class Serialization(object):
 +
    def __init__(self):
 +
        self.joint_s = JointStruct()
 +
        self.hand_s = HandStruct()
 +
        self.user_s = UserStruct()
 +
        self.frame_s = FrameStruct()
 +
        self.header_s = HeaderStruct()
 +
 
 +
    def serialize_frame(self, header, hand_frame, user_frame, frame_index):
 +
        buf = self.header_s.pack(*header)
 +
        buf += self.serialize_skeleton(user_frame, frame_index)
 +
        buf += self.serialize_hands(hand_frame, frame_index)
 +
        return buf
 +
 
 +
    def unserialize_frame(self, data_file):
 +
        data = []
 +
        try:
 +
            data += self.header_s.unpack(data_file.read(self.header_s.size))
 +
            data.append(self.unserialize_skeleton(data_file))
 +
            data.append(self.unserialize_hands(data_file))
 +
        except struct.error:
 +
            return
 +
        return data
 +
 
 +
    def register_hand_coordinates(self, convert_hand_coordinates):
 +
        self.convert_hand_coordinates = convert_hand_coordinates
 +
 
 +
    def register_joint_coordinates(self, convert_joint_coordinates):
 +
        self.convert_joint_coordinates = convert_joint_coordinates
 +
 
 +
    def serialize_hands(self, hand_frame, frame_index):
 +
        if hand_frame is not None:
 +
            buf = self.frame_s.pack(frame_index, hand_frame.timestamp)
 +
            hands = hand_frame.hands
 +
            if hands:
 +
                if len(hands) == 1:
 +
                    hand = hands[0]
 +
                    if hand.isTracking():
 +
                        rc, x_new, y_new = self.convert_hand_coordinates(hand.position.x, hand.position.y, hand.position.z)
 +
                        buf += self.hand_s.pack(hand.id,
 +
                                                hand.position.x,
 +
                                                hand.position.y,
 +
                                                hand.position.z,
 +
                                                x_new,
 +
                                                y_new)
 +
                    else:
 +
                        buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)
 +
                    buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)
 +
                else:
 +
                    for hand in hands[:2]:
 +
                        rc, x_new, y_new = self.convert_hand_coordinates(hand.position.x, hand.position.y, hand.position.z)
 +
                        buf += self.hand_s.pack(hand.id,
 +
                                                hand.position.x,
 +
                                                hand.position.y,
 +
                                                hand.position.z,
 +
                                                x_new,
 +
                                                y_new)
 +
            else:
 +
                for i in range(2):
 +
                    buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)
 +
        else:
 +
            buf = self.frame_s.pack(0, 0)
 +
            for i in range(2):
 +
                buf += self.hand_s.pack(0, 0, 0, 0, 0, 0)
 +
        return buf
 +
 
 +
    def serialize_joint(self, joint):
 +
        if joint is not None:
 +
            pos = joint.position
 +
            rc, x_new, y_new = self.convert_joint_coordinates(pos.x, pos.y, pos.z)
 +
            return self.joint_s.pack(joint.type,
 +
                                    joint.positionConfidence,
 +
                                    joint.position.x,
 +
                                    joint.position.y,
 +
                                    joint.position.z,
 +
                                    x_new,
 +
                                    y_new)
 +
        else:
 +
            return self.joint_s.pack(0, 0, 0, 0, 0, 0, 0)
 +
 
 +
    def serialize_skeleton(self, user_frame, frame_index):
 +
        if user_frame is not None:
 +
            buf = self.frame_s.pack(frame_index, user_frame.timestamp)
 +
            users = user_frame.users
 +
            if users:
 +
                user = users[0]
 +
                user_coordinates = user.centerOfMass
 +
                state = int(user.skeleton.state)
 +
                buf += self.user_s.pack(user.id,
 +
                                        user_coordinates.x,
 +
                                        user_coordinates.y,
 +
                                        user_coordinates.z,
 +
                                        state)
 +
                for i in range(15):
 +
                    buf += self.serialize_joint(user.skeleton[JointType(i)])
 +
            else:
 +
                buf += self.user_s.pack(0, 0, 0, 0, 0)
 +
                for i in range(15):
 +
                    buf += self.serialize_joint(None)
 +
        else:
 +
            buf = self.frame_s.pack(0, 0)
 +
            buf += self.user_s.pack(0, 0, 0, 0, 0)
 +
            for i in range(15):
 +
                buf += self.serialize_joint(None)
 +
        return buf
 +
 
 +
    def unserialize_hands(self, f):
 +
        v = self.frame_s.unpack(f.read(self.frame_s.size))
 +
        data = []
 +
        for i in range(2):
 +
            hands = self.hand_s.unpack(f.read(self.hand_s.size))
 +
            data.append(HandDataMock(hands[0], hands[1], hands[2], hands[3], hands[4], hands[5]))
 +
        return HandFrameMock(v[0], v[1], data)
 +
 
 +
    def unserialize_joint(self, f):
 +
        v = self.joint_s.unpack(f.read(self.joint_s.size))
 +
        return JointMock(*v)
 +
 
 +
    def unserialize_skeleton(self, f):
 +
        v = []
 +
        v += self.frame_s.unpack(f.read(self.frame_s.size))
 +
        v += self.user_s.unpack(f.read(self.user_s.size))
 +
        joints = []
 +
        for i in range(15):
 +
            joints.append(self.unserialize_joint(f))
 +
        return SkeletonFrameMock(v[0], v[1], v[2], v[3], v[4], v[5], v[6], joints)
  
 
class KinectDataReader(object):
 
class KinectDataReader(object):
Linia 95: Linia 304:
 
         return self._s.unserialize_frame(self.in_algs_file)
 
         return self._s.unserialize_frame(self.in_algs_file)
  
if __name__ == '__main__':
+
</source>
    try:
+
{{clear}}
        file_name = sys.argv[1]
+
}}
    except Exception:
 
        file_name = 'test'
 
    kinect = KinectDataReader(file_name)
 
    while True:
 
        frame = kinect.readNextFrame()
 
        if frame is None:
 
            print('END OF FILE')
 
            break
 
  
        frame_index = frame[0]
+
Przykładowy skrypt do wczytywania wyników algorytmów śledzenia pozycji anatomicznych (wraz z metadanymi rejestracji):
        hands_included = frame[1]
 
        skeleton_included = frame[2]
 
        frame_time = frame[3]
 
  
         if skeleton_included:
+
<source lang="Python">
            skel = frame[8]
+
#!/usr/bin/env python3
        else:
+
# -*- coding: utf-8 -*-
            skel = None
+
 
 +
from KinectUtils import KinectDataReader
 +
 
 +
FILE_PATH = '......'
 +
file_name = '......'
 +
 
 +
kinect = KinectDataReader(FILE_PATH+file_name)
 +
 
 +
first_time = 0
 +
joints = []
 +
Time = []
 +
 
 +
while True:
 +
    frame = kinect.readNextFrame()
 +
    if frame is None:
 +
        print('END OF FILE')
 +
         break
 +
 +
    frame_index = frame[0]
 +
    hands_included = frame[1]
 +
    skeleton_included = frame[2]
 +
    frame_time = frame[3]
 +
 +
    if not first_time:
 +
        first_time = frame_time
  
        if hands_included:
+
    if skeleton_included:
            hands = frame[9]
+
        skel = frame[8]
         else:
+
         Time.append(frame_time-first_time)
            hands = None
+
         joints.append(skel.joints)
                   
 
        print('Idx:', frame_index, 'Time:', frame_time)
 
         if skel is not None:
 
            print('Skeleton: ', skel.user_x, skel.user_y, skel.user_z)
 
  
         if hands is not None:
+
         print('Idx:', frame_index, 'Time:', frame_time-first_time)
            print('Hands: ', hands.hands[0].x, hands.hands[0].y, hands.hands[0].z)
+
        print('Head x,y,z [mm]: ', joints[-1][0].x, joints[-1][0].y, joints[-1][0].z)
 +
        print('Torso x,y,z [mm]: ', joints[-1][8].x, joints[-1][8].y, joints[-1][8].z)
 
</source>
 
</source>
  

Aktualna wersja na dzień 06:48, 9 maj 2018

Kamery 3D

Plan zajęć

Zajęcia 1:

  • Wstęp teoretyczny:
    • Budowa i zasada działania sensora Kinect.
    • Opis podstawowych bibliotek wykorzystywanych do komunikacji z urządzeniem.
    • Profesjonalne systemy do rejestracji ruchu
    • Zastosowania w biomechanice oraz rehabilitacji.
  • Zapoznanie się z działaniem sensora Kinect
  • Pomiary:
    • W ramach pomiarów studenci wykonają standardowy test wykorzystywany w medycynie sportowej do oceny prawdopodobieństwa urazów więzadła krzyżowego przedniego (ACL).

Media:3D_Kinect.pdf Informacje wstępne oraz opis zadań
Media:3D_Kinect_ENG.pdf Theoretical information and description of tasks

Zajęcia 2,3,4:

  • Analiza zebranych danych
  • Zaprezentowanie uzyskanych wyników

Sensor Kinect

Śledzenie ruchów postaci ludzkiej w ogólności znajduje zastosowanie m.in. w analizie chodu, diagnostyce chorób związanych z układem ruchu człowieka, analizie ruchu sportowców, czy nawet w procesie animacji postaci na potrzeby produkcji filmów i gier. W tym celu wykorzystuje się głównie profesjonalne markerowe systemy śledzenia ruchu (marker-based motion capture systems) określane w skrócie jako systemy mocap. Systemy te wymagają zastosowania specjalistycznego sprzętu, a na ciele śledzonej postaci muszą zostać umieszczone odpowiednie markery, przez co rejestracja musi odbywać się w warunkach laboratoryjnych. Systemy te nie nadają się do śledzenia ruchu w czasie rzeczywistym, a przesłonięcie lub przemieszczenie markerów w trakcie ruchu może być przyczyną błędów. Z tych względów coraz większe zainteresowanie zyskują bezmarkerowe systemy śledzenia ruchu, które wykorzystują zaawansowane algorytmy analizy obrazu.

Sensor Kinect firmy Microsoft do śledzenia ruchu postaci wykorzystuje informacje z kamery głębokości. Znajduje on zastosowanie w różnego rodzaju systemach umożliwiających interakcję człowiek-komputer, ale zaczyna również budzić coraz większe zainteresowanie w dziedzinach związanych z biomechaniką i rehabilitacją. W tym celu konieczne jest jednak określenie dokładności pozycji estymowanych przy pomocy bibliotek obsługujących sensor. Problem ten został poruszony w pracy (Webster, 2014).


Sensor Kinect Xbox 360.


Budowa sensora Kinect Xbox 360 (rys. 1):

  • kamera wizyjna RGB (typu CMOS, o rozdzielczości 640x480) - przesyła serię obrazów z prędkością 30 klatek na sekundę,
  • kamera głębokości (typu CMOS, o rozdzielczości ~300x200) - zwraca informację o głębokości poprzez analizę zniekształconej przez obiekt wiązki promieni podczerwonych,
  • emiter podczerwieni - emituje wiązkę promieni podczerwonych,
  • 4 mikrofony kierunkowe - wykorzystywane przez funkcje rozpoznawania mowy,
  • napęd umożliwiający ruch głowicą z akcelerometrem.

Pomiary

Pomiary przeprowadzane są w środowisku OpenBCI przy użyciu aplikacji Brain4edu. Obsługa sensora wraz z algorytmami estymacji poszczególnych pozycji anatomicznych śledzonej postaci, możliwa jest dzięki bibliotekom OpenNI i NiTE.

Zaczynamy od uruchomienia aplikacji Brain. W prawym górnym rogu ekranu pojawi się ikona mózgu będąca interfejsem graficznym aplikacji. Do pomiarów przy użyciu kamery 3D wybieramy opcję 'Kinect App', która otworzy okno do zapisu lub odczytu danych.

Interfejs graficzny aplikacji Brain4edu
Okno wyboru rejestracji/odczytu danych aplikacji KinectApp

W wyświetlonym oknie wpisz katalog zapisu/odczytu, wybierz tryb działania, a następnie naciśnij przycisk Start. Po uruchomieniu wyświetlone zostanie okno z podglądem zarówno mapy głębokości jak i obrazu RGB.


Drop Vertical Jump

Zeskok z następującym wyskokiem pionowym (drop vertical jump, DVJ) należy do badań przesiewowych, pozwalających oszacować ryzyko występienia urazu (w szczególności więzadła krzyżowego przedniego u kobiet) lub określić efekty rehabilitacji. Przed rozpoczęciem skoku osoba badana stoi na platformie o wysokości ok. 30 cm. Ma ona za zadanie wykonać zeskok z platformy na ziemię, a następnie maksymalny skok pionowy w górę. W dalszej analizie interesujące będą momenty: kontaktu pięt z podłożem (initial contact, IC) zaraz po wykonaniu zeskoku oraz moment maksymalnego zgięcia kolan (peak flexion, PF) zaraz po IC, ale przed oderwaniem pięt od podłoża w celu wykonania skoku pionowego.

Przebieg zeskoku z następującym wyskokiem pionowym. Źródło: Stone et al., 2013

Analiza danych

Studenci zapoznają się z modułami (napisanymi w języku programowania Python) do wczytywania oraz wstępnego przetwarzania danych. Następnie samodzielnie wyznaczą wskaźniki biomechaniczne, opisane w pracy (Stone et al., 2013), którą można znaleźć pod adresem: [1].

Zeskok z pionowym wyskokiem powtórzony został 3-krotnie w celu większej wiarygodności wyników. Należy zatem dla każdego powtórzenia oddzielnie wyznaczyć momenty IC oraz PF, wyliczyć wartość każdego z parametrów. A następnie należy uśrednić uzyskane wyniki i podać je wraz z niepewnością średniej. Omawiane wskaźniki biomechaniczne:

  • knee valgus motion (KVM) - przesunięcie kolan w płaszczyźnie czołowej (x) pomiędzy momentami IC a PF
Knee valgus motion
  • frontal plane knee angle (FPKA) - kąt pod jakim znajduje się wektor (od kolana do stopy) oddzielnie dla prawej i lewej nogi, w dwóch momentach: IC oraz PF
Frontal plane knee angle
  • knee-to-ankle separation ration (KASR) - stosunek rozsunięcia kolan do kostek w momencie PF
knee-to-ankle separation ration
  • zmiana w czasie średniej pozycji bioder, kolan i stóp.

Wyniki opracowane powinny zostać w formie tabeli, gdzie zestawione zostaną wartości KVM, FPKA, KASR otrzymane dla każdej osoby z grupy (uśrednione po realizacjach - 3 powtórzeniach). Trajektoria (w kierunku pionowym i poziomym) średniej pozycji bioder, kolan i stóp podczas wykonywania zadania powinna zostać przedstawiona na wykresie.

Analiza danych

Implementacja klasy Serialization umożliwiająca łatwe wczytanie danych (proszę zapisać ten plik jako KinectUtils).


Przykładowy skrypt do wczytywania wyników algorytmów śledzenia pozycji anatomicznych (wraz z metadanymi rejestracji):

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from KinectUtils import KinectDataReader

FILE_PATH = '......'
file_name = '......'

kinect = KinectDataReader(FILE_PATH+file_name)

first_time = 0
joints = []
Time = []

while True:
    frame = kinect.readNextFrame()
    if frame is None:
        print('END OF FILE')
        break
 
    frame_index = frame[0]
    hands_included = frame[1]
    skeleton_included = frame[2]
    frame_time = frame[3]
 
    if not first_time:
        first_time = frame_time

    if skeleton_included:
        skel = frame[8]
        Time.append(frame_time-first_time)
        joints.append(skel.joints)

        print('Idx:', frame_index, 'Time:', frame_time-first_time)
        print('Head x,y,z [mm]: ', joints[-1][0].x, joints[-1][0].y, joints[-1][0].z)
        print('Torso x,y,z [mm]: ', joints[-1][8].x, joints[-1][8].y, joints[-1][8].z)

Plik z metadanymi rejestracji zawiera: nagłówek, wyniki algorytmów śledzenia 15 pozycji anatomicznych, wyniki algorytmów śledzenia pozycji rąk (oddzielna opcja w scenariuszu). Pozycje anatomiczne sylwetki zapisane są w następującej kolejności:

   joints = [JOINT_HEAD,
             JOINT_NECK,
             JOINT_RIGHT_SHOULDER,
             JOINT_LEFT_SHOULDER,
             JOINT_RIGHT_ELBOW,
             JOINT_LEFT_ELBOW,
             JOINT_RIGHT_HAND,
             JOINT_LEFT_HAND,
             JOINT_TORSO,
             JOINT_RIGHT_HIP,
             JOINT_LEFT_HIP,
             JOINT_RIGHT_KNEE,
             JOINT_LEFT_KNEE,
             JOINT_RIGHT_FOOT,
             JOINT_LEFT_FOOT]

Ich położenie (x,y,z) wyrażone jest w jednostkach [mm].

Układ pozycji anatomicznych.

Literatura

  • Stone E.E., Butler M., McRuer A., Gray A., Marks J., Skubic M., Evaluation of the Microsoft Kinect for Screening ACL Injury, Conference proceedings: ... Annual International Conference of the IEEE Engineering in Medicine and Biology Society, 2013:4152-5, 2013.
  • Webster D., Celik O., Systematic review of Kinect applications in elderly care and stroke rehabilitation, Journal of NeuroEngineering and Rehabilitation, 11:108, 2014.