[PYTHON] Ich habe versucht, das 3D-Modell zu bewegen, indem ich so etwas wie eine Bewegungserfassung mit nur einem Notebook-PC + einer Webkamera durchgeführt habe

Überblick

Dieser Artikel Wenn Sie ein Modell zur Schätzung der Körperhaltung verwenden, das in der Verarbeitung relativ leicht ist, können Sie die Bewegungserfassung nur mit einem Notebook-PC und einer Webkamera (eingebaute Kamera) durchführen. Ich denke, ich kann es schaffen, also habe ich es versucht. Der Fluss ist fast der gleiche wie beim Originalartikel.

Dinge notwendig

Verfahren

Python-Seite

1. 1. Erstellung eines Haltungsschätzungsmodells

Bitte klonen Sie Folgendes https://github.com/ildoonet/tf-pose-estimation/tree/master Auf diese Weise kann die Haltung der Person im zweidimensionalen Bild geschätzt werden.

2. Wiederherstellung von 3D-Informationen

Sie benötigen 3D-Informationen, um beispielsweise eine Bewegungserfassung durchzuführen.

    1. Das Modell von kann nur zweidimensionale Informationen erhalten. Verwenden Sie daher den Prozess im Entwicklungszweig des Repositorys, um die 3D-Informationen abzurufen. (Es sieht so aus, als wäre es ursprünglich im Master, aber es ist weg)

Bitte klonen Sie Folgendes https://github.com/ildoonet/tf-pose-estimation/tree/devel Verschieben Sie dann den Ordner devel / src / lift zum Master

3. Vorbereitung des WebSocket-Servers

In diesem System führt die Python-Seite eine Verarbeitung durch, z. B. das Schätzen der Körperhaltung einer Person, und die Unity-Seite zeigt nur das 3D-Modell an. Dieses Mal werden wir den Teil der Informationskommunikation von Python und Unity mithilfe von WebSocket implementieren.

Führen Sie den folgenden Befehl aus pip install git+https://github.com/Pithikos/python-websocket-server

server.py


import logging

import cv2
import json
import numpy as np
import common

from tf_pose.estimator import TfPoseEstimator
from tf_pose.networks import get_graph_path, model_wh
from websocket_server import WebsocketServer
from lifting.prob_model import Prob3dPose

PORT = 5000
HOST = '127.0.0.1'

# logger_setup
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter(' %(module)s -  %(asctime)s - %(levelname)s - %(message)s'))
logger.addHandler(handler)


def create_json(pose3d):
    global old_data

    data = {'body_parts': []}

    """
    // 0 :Hip
    // 1 :RHip
    // 2 :RKnee
    // 3 :RFoot
    // 4 :LHip
    // 5 :LKnee
    // 6 :LFoot
    // 7 :Spine
    // 8 :Thorax
    // 9 :Neck/Nose
    // 10:Head
    // 11:LShoulder
    // 12:LElbow
    // 13:LWrist
    // 14:RShoulder
    // 15:RElbow
    // 16:RWrist
    """

    for i in range(17):
        data['body_parts'].append({'id': i, 'x': pose3d[0][0][i], 'y': pose3d[0][2][i], 'z': pose3d[0][1][i]})

    old_data = data
    return data


def new_client(client, server):
    logger.info('NewClient {}:{} has left.'.format(client['address'][0], client['address'][1]))


def client_left(client, server):
    logger.info('Client {}:{} has left.'.format(client['address'][0], client['address'][1]))


def message_received(client, server, message):
    _, image = cam.read()

    humans = e.inference(image, resize_to_default=(w > 0 and h > 0), upsample_size=4.0)

    pose_2d_mpiis = []
    visibilities = []

    standard_w = 640
    standard_h = 480

    try:
        pose_2d_mpii, visibility = common.MPIIPart.from_coco(humans[0])
        pose_2d_mpiis.append([(int(x * standard_w + 0.5), int(y * standard_h + 0.5)) for x, y in pose_2d_mpii])
        visibilities.append(visibility)
        pose_2d_mpiis = np.array(pose_2d_mpiis)
        visibilities = np.array(visibilities)
        transformed_pose2d, weights = poseLifting.transform_joints(pose_2d_mpiis, visibilities)
        pose_3d = poseLifting.compute_3d(transformed_pose2d, weights)
        print(pose_3d)
        server.send_message(client, json.dumps(create_json(pose_3d)))

    except :
        server.send_message(client, json.dumps(old_data))


if __name__ == '__main__':
    # main
    w, h = model_wh("432x368")
    e = TfPoseEstimator(get_graph_path("mobilenet_thin"), target_size=(432, 368), trt_bool=False)
    poseLifting = Prob3dPose('lifting/models/prob_model_params.mat')

    cam = cv2.VideoCapture(0)

    old_data = {}

    server = WebsocketServer(port=PORT, host=HOST)
    server.set_fn_new_client(new_client)
    server.set_fn_client_left(client_left)
    server.set_fn_message_received(message_received)
    server.run_forever()

Jetzt ist die Python-Seite fertig

Einheitsseite

1. Vorbereitung des 3D-Modells

Lassen Sie uns zunächst das 3D-Modell vorbereiten, das Sie verschieben möchten. Dieses Mal habe ich das Modell "Unity-Chan!" Aus dem Asset Store verwendet.

2. Installation der erforderlichen Bibliotheken

Klonen Sie SAFullBodyIK und verschieben Sie es in den Ordner "Assets". Klonen und erstellen Sie außerdem https://github.com/sta/websocket-sharp, damit Sie WebSocket empfangen können. Das Folgende ist leicht zu verstehen, wie man baut https://qiita.com/oishihiroaki/items/bb2977c72052f5dd5bd9

2. Unity-Seitencode

Ich habe den Code von [Referenzquelle dieses Artikels] ausgeliehen (https://qiita.com/keel/items/0d64167850566586d22a).

IKSetting.cs


using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using WebSocketSharp;
using WebSocketSharp.Net;

public class IKSetting : MonoBehaviour {
    private BodyParts bodyParts;
    private string receivedJson;
    private WebSocket ws;

    [SerializeField, Range(10, 120)]
    float FrameRate;
    public List<Transform> BoneList = new List<Transform>();
    GameObject FullbodyIK;
    Vector3[] points = new Vector3[17];
    Vector3[] NormalizeBone = new Vector3[12];
    float[] BoneDistance = new float[12];
    float Timer;
    int[,] joints = new int[,] { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 0, 4 }, { 4, 5 }, { 5, 6 }, { 0, 7 }, { 7, 8 }, { 8, 9 }, { 9, 10 }, { 8, 11 }, { 11, 12 }, { 12, 13 }, { 8, 14 }, { 14, 15 }, { 15, 16 } };
    int[,] BoneJoint = new int[,] { { 0, 2 }, { 2, 3 }, { 0, 5 }, { 5, 6 }, { 0, 9 }, { 9, 10 }, { 9, 11 }, { 11, 12 }, { 12, 13 }, { 9, 14 }, { 14, 15 }, { 15, 16 } };
    int[,] NormalizeJoint = new int[,] { { 0, 1 }, { 1, 2 }, { 0, 3 }, { 3, 4 }, { 0, 5 }, { 5, 6 }, { 5, 7 }, { 7, 8 }, { 8, 9 }, { 5, 10 }, { 10, 11 }, { 11, 12 } };
    int NowFrame = 0;

    float[] x = new float[17];
    float[] y = new float[17];
    float[] z = new float[17];

    bool isReceived = false;

    // Use this for initialization
    void Start () {

        ws = new WebSocket("ws://localhost:5000/");
        ws.OnOpen += (sender, e) =>
        {
            Debug.Log("WebSocket Open");
        };
        ws.OnMessage += (sender, e) =>
        {
            receivedJson = e.Data;
            Debug.Log("Data: " + e.Data);
            isReceived = true;
        };
        ws.OnError += (sender, e) =>
        {
            Debug.Log("WebSocket Error Message: " + e.Message);
        };
        ws.OnClose += (sender, e) =>
        {
            Debug.Log("WebSocket Close");
        };
        ws.Connect();

        ws.Send("");
    }

    // Update is called once per frame
    void Update () {

        Timer += Time.deltaTime;
        ws.Send("");

        if (Timer > (1 / FrameRate))
        {
            Timer = 0;
            PointUpdate();
        }
        if (!FullbodyIK)
        {
            IKFind();
        }
        else
        {
            IKSet();
        }
    }

    void OnDestroy()
    {
        ws.Close();
        ws = null;
    }

    void PointUpdate()
    {
        if (NowFrame < 600)
        {
            NowFrame++;
            if (isReceived)
            {
                bodyParts = JsonUtility.FromJson<BodyParts>(receivedJson);
                for (int i = 0; i < 17; i++)
                {
                    x[i] = bodyParts.body_parts[i].x;
                    y[i] = bodyParts.body_parts[i].y;
                    z[i] = bodyParts.body_parts[i].z;
                }

                isReceived = false;
            }

            for (int i = 0; i < 17; i++)
            {
                points[i] = new Vector3(x[i], y[i], -z[i]);
                Debug.Log(points[i]);
            }

            for (int i = 0; i < 12; i++)
            {
                NormalizeBone[i] = (points[BoneJoint[i, 1]] - points[BoneJoint[i, 0]]).normalized;
            }
        }
    }

    void IKFind()
    {
        FullbodyIK = GameObject.Find("FullBodyIK");
        if (FullbodyIK)
        {
            for (int i = 0; i < Enum.GetNames(typeof(OpenPoseRef)).Length; i++)
            {
                Transform obj = GameObject.Find(Enum.GetName(typeof(OpenPoseRef), i)).transform;
                if (obj)
                {
                    BoneList.Add(obj);
                }
            }
            for (int i = 0; i < Enum.GetNames(typeof(NormalizeBoneRef)).Length; i++)
            {
                BoneDistance[i] = Vector3.Distance(BoneList[NormalizeJoint[i, 0]].position, BoneList[NormalizeJoint[i, 1]].position);
            }
        }
    }

    void IKSet()
    {
        if (Math.Abs(points[0].x) < 1000 && Math.Abs(points[0].y) < 1000 && Math.Abs(points[0].z) < 1000)
        {
            BoneList[0].position = points[0] * 0.001f + Vector3.up * 0.8f;
        }
        for (int i = 0; i < 12; i++)
        {
            BoneList[NormalizeJoint[i, 1]].position = Vector3.Lerp(
                BoneList[NormalizeJoint[i, 1]].position,
                BoneList[NormalizeJoint[i, 0]].position + BoneDistance[i] * NormalizeBone[i]
                , 0.05f
            );
            DrawLine(BoneList[NormalizeJoint[i, 0]].position, BoneList[NormalizeJoint[i, 1]].position, Color.red);
        }
        for (int i = 0; i < joints.Length / 2; i++)
        {
            DrawLine(points[joints[i, 0]] * 0.001f + new Vector3(-1, 0.8f, 0), points[joints[i, 1]] * 0.001f + new Vector3(-1, 0.8f, 0), Color.blue);
        }
    }

    void DrawLine(Vector3 s, Vector3 e, Color c)
    {
        Debug.DrawLine(s, e, c);
    }
}

enum OpenPoseRef
{
    Hips,
    LeftKnee, LeftFoot,
    RightKnee, RightFoot,
    Neck, Head,
    RightArm, RightElbow, RightWrist,
    LeftArm, LeftElbow, LeftWrist
};

enum NormalizeBoneRef
{
    Hip2LeftKnee, LeftKnee2LeftFoot,
    Hip2RightKnee, RightKnee2RightFoot,
    Hip2Neck, Neck2Head,
    Neck2RightArm, RightArm2RightElbow, RightElbow2RightWrist,
    Neck2LeftArm, LeftArm2LeftElbow, LeftElbow2LeftWrist
};

[System.Serializable]
public class BodyParts
{
    public Position[] body_parts;
}

[System.Serializable]
public class Position
{
    public int id;
    public float x;
    public float y;
    public float z;
}

Das ist alles zur Vorbereitung.

Lauf

Drücken Sie nach dem Ausführen von server.py die Wiedergabetaste auf der Unity-Seite.

Zusammenfassung

Es bewegte sich schneller als erwartet, obwohl es einige Verzögerungen gab. Wenn Sie nach einem leichteren Modell suchen, können Sie es finden, sodass es eine Vorhersage für eine Verbesserung zu geben scheint.

Recommended Posts

Ich habe versucht, das 3D-Modell zu bewegen, indem ich so etwas wie eine Bewegungserfassung mit nur einem Notebook-PC + einer Webkamera durchgeführt habe
Ich habe versucht, mit dem Seq2Seq-Modell von TensorFlow so etwas wie einen Chatbot zu erstellen
Ich habe versucht, ein Modell mit dem Beispiel von Amazon SageMaker Autopilot zu erstellen
Ich habe versucht, mit einem Foto einfach ein hochpräzises 3D-Bild zu erstellen [0]. (Bestätigt, wie der Raum erfasst und beschattet wird)
Ich habe versucht, in einem tief erlernten Sprachmodell zu schreiben
Ich habe versucht, den Ball zu bewegen
Ich wollte das ABC164 A ~ D-Problem mit Python lösen
Ich habe versucht, die Anzahl der im Inland infizierten Menschen der neuen Korona mit einem mathematischen Modell vorherzusagen
Ich habe versucht, mit einem Remote-Server über Socket-Kommunikation mit Python zu kommunizieren.
Ich habe mir eine Möglichkeit ausgedacht, aus einem Foto ein 3D-Modell zu erstellen.
765 Ich habe versucht, die drei Berufsfamilien durch CNN zu identifizieren (mit Chainer 2.0.0).
Ich habe versucht, das Ergebnis des A / B-Tests mit dem Chi-Quadrat-Test zu überprüfen
Ich habe versucht, das Verhalten des neuen Koronavirus mit dem SEIR-Modell vorherzusagen.
# Ich habe so etwas wie Vlookup mit Python # 2 ausprobiert
Ich habe versucht, mit einem Foto einfach ein hochpräzises 3D-Bild zu erstellen [-1]. (Ist der versteckte Bereich wirklich sichtbar?)
Ich dachte, ich könnte einen netten Gitignore-Editor machen, also habe ich vorerst versucht, so etwas wie MVP zu machen
Ich habe versucht, GAN (mnist) mit Keras zu bewegen
Ich habe versucht, die Daten mit Zwietracht zu speichern
Ich habe versucht, mit OpenCV Bewegungen schnell zu erkennen
Ich habe mir eine Möglichkeit ausgedacht, aus einem Foto ein 3D-Modell zu erstellen. 0 Projektion in den 3D-Raum
Ich habe versucht, die Sündenfunktion mit Chainer zu trainieren
Ich habe versucht, maschinelles Lernen (Objekterkennung) mit TouchDesigner zu verschieben
Ich habe versucht, Faster R-CNN mit Pytorch auszuführen
Ich habe versucht, eine CSV-Datei mit Python zu berühren
Ich habe versucht, Soma Cube mit Python zu lösen
Ich habe versucht, das Problem mit Python Vol.1 zu lösen
Django super Einführung von Python-Anfängern! Teil 6 Ich habe versucht, die Login-Funktion zu implementieren
Ich habe mir eine Möglichkeit ausgedacht, aus einem Foto ein 3D-Modell zu erstellen. Teil 04 Generieren von Polygonen
Ich habe versucht, eine RESTful-API zu erstellen, indem ich die explosive Fast-API des Python-Frameworks mit MySQL verbunden habe.
Ich habe eine Klasse erstellt, um das Analyseergebnis von MeCab in ndarray mit Python zu erhalten
Tag 71 Ich habe versucht vorherzusagen, wie lange diese Selbstbeherrschung mit dem SIR-Modell anhalten wird
Ich habe versucht, mit OpenCV eine Bewegungserkennungsüberwachungskamera mit einer WEB-Kamera mit Raspberry Pi herzustellen
[Shell-Start] Ich habe versucht, die Shell mit einem billigen Linux-Board-G-Cluster auf dem Fernseher anzuzeigen
Ich habe auch versucht, die Funktionsmonade und die Zustandsmonade mit dem Generator in Python nachzuahmen
Erstellen Sie ein zweidimensionales Array, indem Sie am Ende eines leeren Arrays mit numpy eine Zeile hinzufügen
Ich schrieb einen Test in "Ich habe versucht, die Wahrscheinlichkeit eines Bingospiels mit Python zu simulieren".
Ich habe versucht, mit PI Fu aus einem Bild ein 3D-Modell einer Person zu erstellen
Ich habe versucht, den Verkauf von Spielesoftware mit VARISTA anhand des Artikels von Codexa vorherzusagen
Eine Person, die das D-Problem mit ABC von AtCoder lösen möchte, hat versucht, zu kratzen
Ich habe versucht, mit Quantx eine Linie mit gleitendem Durchschnitt des Volumens zu implementieren
Ich habe versucht, das grundlegende Modell des wiederkehrenden neuronalen Netzwerks zu implementieren
Ich habe versucht, die Entropie des Bildes mit Python zu finden
Ich habe versucht zu simulieren, wie sich die Infektion mit Python ausbreitet
Ich habe versucht, die Emotionen des gesamten Romans "Wetterkind" zu analysieren
Ich habe versucht, automatisch einen Bericht mit der Markov-Kette zu erstellen
Ich habe versucht, die Zugverspätungsinformationen mit LINE Notify zu benachrichtigen
Ich habe versucht, die Windows 10-Festplatte durch eine kleinere SSD zu ersetzen
Ich habe eine Funktion erstellt, um das Modell von DCGAN zu überprüfen
Ich habe versucht, das Problem der Kombinationsoptimierung mit Qiskit zu lösen
Ich habe versucht, mit Hy ・ Define a class zu beginnen
Ich habe versucht, MNIST nach GNN zu klassifizieren (mit PyTorch-Geometrie).
Ich habe versucht, eine zufällige FizzBuzz-Spalte mit Blasensortierung zu sortieren.
Ich habe versucht, SSD jetzt mit PyTorch zu implementieren (Modellversion)
Ich habe versucht, den Sesam für Eingang 2 mit einem einzigen Druck auf die AWS IoT-Taste zu entsperren