Opcje klasyfikacji ułożenia

Dzięki interfejsowi ML Kit Pose Detection API możesz uzyskać istotne interpretacje pozycji, sprawdzając względne położenie różnych części ciała. Na tej stronie znajdziesz kilka przykładów.

Klasyfikacja pozycji i zliczanie powtórzeń za pomocą algorytmu k-NN

Jednym z najczęstszych zastosowań wykrywania pozycji jest monitorowanie aktywności fizycznej. Dla deweloperów stworzenie klasyfikatora pozycji, który rozpoznaje określone pozycje fitness i zlicza powtórzenia, może być wyzwaniem.

W tej sekcji opisujemy, jak za pomocą MediaPipe Colab stworzyliśmy klasyfikator pozycji niestandardowej, a także zademonstrowaliśmy działający klasyfikator w naszej przykładowej aplikacji ML Kit.

Jeśli nie znasz jeszcze Google Colaboratory, zapoznaj się z przewodnikiem wprowadzającym.

Do rozpoznawania pozycji używamy algorytmu k-najbliższych sąsiadów (k-NN), ponieważ jest on prosty i łatwy. Algorytm określa klasę obiektu na podstawie najbliższych przykładów w zbiorze treningowym.

Aby utworzyć i wytrenować moduł rozpoznawania, wykonaj te czynności:

1. Zbieranie próbek obrazów

Zebraliśmy próbki obrazów docelowych ćwiczeń z różnych źródeł. Do każdego ćwiczenia wybraliśmy kilkaset obrazów, np. w przypadku pompek i pozycji „w górę” i „w dół”. Ważne jest, by zbierać próbki przedstawiające różne kąty kamery, warunki otoczenia, budowę ciała i warianty ćwiczeń.

Rysunek 1. Pozycje pompek w górę i w dół

2. Uruchom wykrywanie pozycji na przykładowych obrazach

W ten sposób powstaje zestaw punktów orientacyjnych umiejscowienia do wykorzystania podczas trenowania. Nie interesuje nas samo wykrywanie pozycji, ponieważ w kolejnym kroku będziemy wytrenować własny model.

Algorytm k-NN wybrany do niestandardowej klasyfikacji pozycji wymaga przedstawienia wektorowej reprezentacji każdej próbki oraz danych do obliczenia odległości między 2 wektorami w celu znalezienia miejsca docelowego najbliżej próbki pozycji. Oznacza to, że musimy przekonwertować uzyskane w ten sposób punkty orientacyjne.

Aby przekonwertować punkty orientacyjne ułożenia na wektor cech, korzystamy z odległości między predefiniowanymi listami stawów, np. odległości między nadgarstkiem a ramieniem, kostką i biodrem oraz lewym i prawym nadgarstkiem. Ponieważ skala zdjęć może być różna, znormalizowaliśmy pozycje tak, aby miały tę samą wielkość tułów i pionową orientację tułów, zanim przekonwertujemy punkty orientacyjne.

3. Wytrenuj model i zliczaj powtórzenia

Użyliśmy usługi MediaPipe Colab, aby uzyskać dostęp do kodu klasyfikatora i wytrenować model.

Aby zliczyć powtórzenia, zastosowaliśmy inny algorytm Colab do monitorowania progu prawdopodobieństwa wystąpienia pozycji docelowej. Na przykład:

  • Gdy prawdopodobieństwo, że klasa pozycji „w dół” po raz pierwszy przekroczy dany próg, algorytm zaznaczy, że wpisano klasę „niżej”.
  • Gdy prawdopodobieństwo spada poniżej progu, algorytm oznacza, że klasa pozycji „w dół” została opuszczona, i zwiększa licznik.
Rysunek 2. Przykład zliczania powtórzeń

4. Integracja z aplikacją z krótkim wprowadzeniem do ML Kit

Powyższe polecenie w Colab utworzy plik CSV, w którym możesz umieścić wszystkie przykładowe pozycje. W tej sekcji dowiesz się, jak zintegrować plik CSV z aplikacją z krótkim wprowadzeniem do aplikacji ML Kit na Androida, aby zobaczyć klasyfikację niestandardowych pozycji w czasie rzeczywistym.

Wypróbuj klasyfikację pozycji z przykładami dołączonymi do aplikacji z krótkim wprowadzeniem

Dodaj własny plik CSV

  • Dodaj plik CSV do folderu komponentów w aplikacji.
  • W PoseClassifierProcessor zaktualizuj zmienne POSE_SAMPLES_FILE i POSE_CLASSES, aby pasowały do pliku CSV i próbek pozy.
  • Skompiluj i uruchom aplikację.

Pamiętaj, że klasyfikacja może nie działać prawidłowo, jeśli nie ma wystarczającej liczby próbek. Na każdą klasę pozycji potrzebujesz około 100 próbek.

Aby dowiedzieć się więcej i samodzielnie wypróbować tę funkcję, zapoznaj się z artykułami na temat MediaPipe Colab i przewodnika po klasyfikacji MediaPipe.

Rozpoznawanie prostych gestów przez obliczanie odległości punktu orientacyjnego

Jeśli co najmniej 2 punkty orientacyjne znajdują się blisko siebie, można ich używać do rozpoznawania gestów. Jeśli na przykład punkt orientacyjny co najmniej jednego palca na dłoni znajduje się blisko punktu orientacyjnego z nosem, możesz wywnioskować, że użytkownik najprawdopodobniej dotyka twarzy.

Rysunek 3. Interpretowanie pozy

Rozpoznawanie pozycji jogi za pomocą heurystyki kąta

Pozycja jogi można rozpoznać po obliczeniu kątów różnych stawów. Na przykład rysunek 2 poniżej przedstawia pozycję w jodze Wojownik II. Przybliżone kąty, które określają tę pozycję, są zapisane:

Rysunek 4. Rozłożenie pozy na różne kąty

Tę pozycję można opisać jako kombinację przybliżonych kątów ciała:

  • Obie ramiona pod kątem 90 stopni
  • 180 stopni na obu łokciach
  • Pod kątem 90 stopni przy przedniej nodze i talii
  • Kąt kolana z tyłu pod kątem 180 stopni
  • Kąt w pasie pod kątem 135 stopni

Możesz użyć punktów orientacyjnych pozycji do obliczenia tych kątów. Na przykład kąt między przednimi nogami i talią to kąt między linii od prawego ramienia do prawego biodra i linii od prawego biodra do prawego kolana.

Gdy obliczysz wszystkie kąty potrzebne do zidentyfikowania pozycji, możesz sprawdzić, czy nic nie pasuje i wtedy udało Ci się rozpoznać pozę.

Fragment kodu poniżej pokazuje, jak użyć współrzędnych X i Y do obliczenia kąta między dwiema częściami ciała. Takie podejście do klasyfikacji ma pewne ograniczenia. Wystarczy zaznaczyć X i Y, a obliczone kąty będą się różnić zależnie od kąta między obiektem a kamerą. Najlepsze wyniki uzyskasz, używając poziomego obrazu z przodu. Możesz też spróbować rozszerzyć ten algorytm, używając współrzędnej Z, i sprawdzić, czy sprawdza się on w Twoim przypadku.

Obliczanie kątów punktu orientacyjnego na Androidzie

Ta metoda oblicza kąt między dowolnymi 3 punktami orientacyjnymi. Zapewnia on, że zwrócony kąt wynosi od 0 do 180 stopni.

Kotlin

fun getAngle(firstPoint: PoseLandmark, midPoint: PoseLandmark, lastPoint: PoseLandmark): Double {
        var result = Math.toDegrees(atan2(lastPoint.getPosition().y - midPoint.getPosition().y,
                lastPoint.getPosition().x - midPoint.getPosition().x)
                - atan2(firstPoint.getPosition().y - midPoint.getPosition().y,
                firstPoint.getPosition().x - midPoint.getPosition().x))
        result = Math.abs(result) // Angle should never be negative
        if (result > 180) {
            result = 360.0 - result // Always get the acute representation of the angle
        }
        return result
    }

Java

static double getAngle(PoseLandmark firstPoint, PoseLandmark midPoint, PoseLandmark lastPoint) {
  double result =
        Math.toDegrees(
            atan2(lastPoint.getPosition().y - midPoint.getPosition().y,
                      lastPoint.getPosition().x - midPoint.getPosition().x)
                - atan2(firstPoint.getPosition().y - midPoint.getPosition().y,
                      firstPoint.getPosition().x - midPoint.getPosition().x));
  result = Math.abs(result); // Angle should never be negative
  if (result > 180) {
      result = (360.0 - result); // Always get the acute representation of the angle
  }
  return result;
}

Oto jak obliczyć kąt w prawym biodrze:

Kotlin

val rightHipAngle = getAngle(
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_SHOULDER),
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_HIP),
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_KNEE))

Java

double rightHipAngle = getAngle(
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_SHOULDER),
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_HIP),
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_KNEE));

Obliczanie kątów punktu orientacyjnego na urządzeniu z iOS

Ta metoda oblicza kąt między dowolnymi 3 punktami orientacyjnymi. Zapewnia on, że zwrócony kąt wynosi od 0 do 180 stopni.

Swift

func angle(
      firstLandmark: PoseLandmark,
      midLandmark: PoseLandmark,
      lastLandmark: PoseLandmark
  ) -> CGFloat {
      let radians: CGFloat =
          atan2(lastLandmark.position.y - midLandmark.position.y,
                    lastLandmark.position.x - midLandmark.position.x) -
            atan2(firstLandmark.position.y - midLandmark.position.y,
                    firstLandmark.position.x - midLandmark.position.x)
      var degrees = radians * 180.0 / .pi
      degrees = abs(degrees) // Angle should never be negative
      if degrees > 180.0 {
          degrees = 360.0 - degrees // Always get the acute representation of the angle
      }
      return degrees
  }

Objective-C

(CGFloat)angleFromFirstLandmark:(MLKPoseLandmark *)firstLandmark
                      midLandmark:(MLKPoseLandmark *)midLandmark
                     lastLandmark:(MLKPoseLandmark *)lastLandmark {
    CGFloat radians = atan2(lastLandmark.position.y - midLandmark.position.y,
                            lastLandmark.position.x - midLandmark.position.x) -
                      atan2(firstLandmark.position.y - midLandmark.position.y,
                            firstLandmark.position.x - midLandmark.position.x);
    CGFloat degrees = radians * 180.0 / M_PI;
    degrees = fabs(degrees); // Angle should never be negative
    if (degrees > 180.0) {
        degrees = 360.0 - degrees; // Always get the acute representation of the angle
    }
    return degrees;
}

Oto jak obliczyć kąt w prawym biodrze:

Swift

let rightHipAngle = angle(
      firstLandmark: pose.landmark(ofType: .rightShoulder),
      midLandmark: pose.landmark(ofType: .rightHip),
      lastLandmark: pose.landmark(ofType: .rightKnee))

Objective-C

CGFloat rightHipAngle =
    [self angleFromFirstLandmark:[pose landmarkOfType:MLKPoseLandmarkTypeRightShoulder]
                     midLandmark:[pose landmarkOfType:MLKPoseLandmarkTypeRightHip]
                    lastLandmark:[pose landmarkOfType:MLKPoseLandmarkTypeRightKnee]];