目次
(3) 画像の各フレーム内のキーノードの座標を読み取ります。
(1) キャラクターのアクションを読み取り、キーノードにマークを付ける
I.はじめに
『カンフー・パンダ』や『ティーンエイジ・ミュータント・ニンジャ・タートルズ』などの大ヒット映画は誰もが知っていると思いますが、それらに登場するキャラクターの造形は人間のアクションを上手く演じていますが、それはどのようにして実現されているのでしょうか?今日は、あなたと協力してビデオ内のキャラクターの動きを一からキャプチャし、モデル化されたキャラクターに追加します。これにより、モデル化された仮想キャラクターも人間と同様にさまざまな動作を実現できるようになります。このプロジェクトの実装は、興味のある友達は段階的に試してみると、完了後に多くのことを学ぶことができます。
2. プロジェクト紹介
1。目的
このプロジェクトの名前は3D モーションキャプチャ.動くキャラクターのポーズをビデオやカメラでキャプチャし、3D で表示する必要があることは推測に難しくありません。簡単に言うと、キャラクターの動きを抽出してその後の研究や観察を容易にするためのものであり、仮想ビデオを作成して視聴者に視覚的な刺激を与えるためにも使用できます。
2. 技術的なポイント
(1) ファイルを読み込む
3Dモーションキャプチャと呼ばれるので、必ずキャラクターのポーズをビデオやカメラに収める必要がありますが、最初のステップは当然ファイルを読み込みます。読み込まれるファイルは完全なキャラクターモーションビデオだけでよいので、ビデオカメラは固定されており、プロジェクトの精度が大幅に向上します。
(2) キーノードにマークを付ける
ビデオ ファイルを取得したら、次のステップは、ビデオ内のキャラクターのボディのキー ノードをマークすることです。これは、 Python のサードパーティ ライブラリcvzoneにとって簡単な作業です。ライブラリには人体の33個のキーノードが記録されており、ビデオを読み取った後、キャラクターのキーノードにマークを付けることができ、ノード座標の変化によりキャラクターの動作姿勢を把握することができます。
(3) 画像の各フレーム内のキーノードの座標を読み取ります。
33 個のキー ノードの座標を取得しました。その値は画像の各フレームで変化するため、画像の各フレームで座標値を記録する必要があります。記録された座標値を保存するファイルを作成でき、これらの座標点は後続のプロセスで使用されます。特定のレコードの実装方法については、次の実装手順で説明します。腹を立てて読み続けていただければ幸いです。!
(4) Unityで3Dキャラクターを作成する
Unity を使用して、33 個の球といくつかの線分で構成されるシンプルなキャラクターを作成します。Unity のダウンロードとインストールについてはここでは詳しく説明しません。オンラインで検索してたくさん検索できます。!3D キャラクターの作成手順については、以下の実装手順で詳しく説明します。
(5) キャラクターの動きを3D化する
主にUnity で C# スクリプトを使用して、座標点の変更を作成した 3D キャラクターに接続します。もう 1 つは、Unity でカメラのパラメーターを調整して、3D 画像をより合理的で「写真映え」させることです。
3. 何をすべきか
(1) サードパーティライブラリ
このプロジェクトでは、主に人の動きをキャプチャして主要なノードをマークし、単純な座標点の変化を記録するために Python を使用するため、必要なのはいくつかの基本的なビジョン ライブラリのみです。
cvzone.PoseModule からcv2 をインポートimport PoseDetector
cvzone を使用しているときに、いくつかの問題が発生したので記録しました。誰かが同じ問題に遭遇した場合は、簡単に解決できるはずです: cvzone の PoseDetector がビデオ座標情報を読み取る問題
(2) Unityのインストールと使用方法
このソフトウェアのダウンロードとインストールには大きな問題はありません。vxパブリック アカウント Partner Godを使用してダウンロードしましたが、提供されている 2020 バージョンに問題があります。2019 バージョンをダウンロードしてインストールします。使い方に関しては、難しいことではありませんので、今すぐ学習して販売しましょう。
(3) C#の理解
C#言語を使って座標点と3Dモデルを接続するスクリプトを書く必要があるので、「習ったことがない」「難しい」などと思われるかもしれませんが、すべてをマスターする必要はありませんので、ご安心ください。いくつかの文法を使用し、いくつかのリストを作成するだけで、目標を達成できます。
3. プロジェクトの実施手順
1.Python部分
今回のプロジェクトは複数のツールを組み合わせて完成させる必要があり、Pythonを使用して動画ファイル内のキャラクターの動作状況を取得し、ボディ上の33個のキーノードにマークを付け、これらのキーの座標値を保存することができます。ファイル内のノード. .
(1) キャラクターのアクションを読み取り、キーノードにマークを付ける
ビデオ ファイルを読み込んだ後、ビデオ内のキャラクターのボディにキー ノードをマークする必要があります。ここでは次の関数を使用するだけです。
img = detecter.findPose(img)#マークポーズキーノード
次のように、必要な座標点をマークできます。
ただし、ノードをマークしただけで、各ノードの座標は記録しませんでした。そのため、後でこれらのポイントを保存できるように、画像の各フレームのキーポイントの座標を保存するリストを作成する必要があります。もちろん、保存したリストの長さを出力して、ビデオのフレーム数を判断することもできます。各座標点の座標値を読み取るには、次の関数を使用する必要があります。
lmList, bboxInfo = detecter.findPosition(img) #ビデオ内の姿勢情報を取得する
以上の手順で動画内のキャラクターの動き状態を検出することができ、ステージングされたコードは以下の通りです(参考までに全体のコードは記事後半に掲載します)。
cap = cv2.VideoCapture('Video.mp4')
detector = PoseDetector()
posList = []
while True:
success, img = cap.read()
img = detector.findPose(img)#标记姿势关键节点
lmList, bboxInfo = detector.findPosition(img) #获取视频中的姿势信息
if bboxInfo: #判断是否检测到一个身体
lmString = '' #创建一个空的字符串
for lm in lmList: #'lm'为'landmark'的缩写,即33个关键节点
lmString += f'{lm[1]},{img.shape[0] - lm[2]},{lm[3]},' #最后一个逗号保留,这样每一个坐标值才能分离开来
posList.append(lmString)
print(len(posList))#打印视频帧数
(2) 座標値をファイルに書き込んで保存する
上記では座標値をリストに保存しましたが、その後の 3D 変換のために、これらの座標値を .txt ファイルに保存する必要があります。コードは以下のように表示されます:
if key == ord('s'): #将坐标点写入一个 .txt文件
with open("AnimationFile.txt", 'w') as f:
f.writelines(["%s\n" % item for item in posList])
ビデオの最後に「s」を押すと、取得したすべての座標点が「AnimationFile.txt」ファイルに保存されます。ファイル内の座標点の保存場所は、以前に取得したフレーム数によって判断できます。
たとえば、読み込むフレーム数は次のようになります。
すると、取得したファイルのデータ行数は以下のようになります。
ビデオのフレーム数より数行少ないですが、ビデオの最後のフレームで「s」を押すこともできないので許容範囲です。
2. ユニティ部分
Python を使用してキャラクターのキー ノードの座標値を記録した後、記録した座標点を 3D モデルに適用する必要があります。ここでは Unity を使用して作成する必要があります。一般的に言えば、比較的単純です。果敢に挑戦してみてください。
(1) プロジェクトを作成する
まず、新しいプロジェクトを作成する必要があります。次に、プロジェクト内で右クリックして、マネージャーという名前の空のフォルダーを作成します。この空のフォルダーはより重要であり、後で C# スクリプトの一部を保存するために使用する必要があります。
(2) 3D 構造部品を格納するためのブランクを作成する
3D モデリングを完了するには、いくつかの線、球、その他のオブジェクトが必要ですが、作成した空のフォルダーはこれらのパーツを保存するために使用されます。フォルダーの名前の付け方については、ご自身で考えていただいて構いません。ここでは、 body という名前を付けました。これが球と線を保持します。
(3) 球体を作成する
取得した 33 個のキー ノードを表すには 33 個の球が必要なので、次に行うことは、ボディを右クリックして球を作成し、下の空白スペースを右クリックしてマテリアルを作成し、好みの色を選択します。新しく作成したマテリアルをボディの下の球に移動し、カスタム カラーの球を作成できます。必要に応じて、球をクリックして、右側の展開された列でサイズを変更できます。最後に本体内の球体をコピーして貼り付けます 本体の下に合計32回貼り付けます名前はご自身で考えてください。
(4) キーノードとモデルの接続
Pythonパートで取得したキーノード座標値ファイルをプロジェクトにコピーし、関連付けるためのC#スクリプトを作成し、このC#ファイルをマネージャーファイルにドラッグして管理する必要があります。
上の 2 つの画像は、作成したスクリプト ファイルとマネージャーに追加したビューです。
次に、ボディクラスのサイズを 33 に変更し、下の球を対応するオブジェクトに順番にドラッグし、関連付けるための C# スクリプトを記述します (スクリプト コードは記事の後半に記載します)。
(5) 点在する球体を繋ぐ
これまでの手順で、33 個のポイントにいくつかの単純なアクションを完了させることができましたが、プロジェクトが比較的完成するように、分散したポイントを接続しようとします。
まず、本文の下に空白を作成し、「Lins」という名前を付ける必要があります(この空白の下に他のすべての行を格納するために使用するため、名前は複数形です)。次に、前の手順に従って球を作成します。 「ライン A ライン」の下で適切なマテリアルを選択します。
次に、スクリプトを再度作成する必要があります。主な目的は、各線(実際には、以前に作成した各球体) の始点と終点を選択することです。スクリプトのコードは、記事の後半で公開されます。このスクリプトを使用すると、行の配置と位置の設定を実現できます。
これらの線をどのように接続するのでしょうか? mediapipe で人体のノードを観察し、次の図と組み合わせることで、各線の始点と終点を設定できます。
次に、前の最初の行をコピーして、Lines に貼り付け、単純で退屈なドラッグを実行します (対応する球を行の始点と終点にドラッグし、1 対 1 に対応させます)。
次に、「実行」をクリックすると、プロジェクトが成功したことが確認できるはずです。
4 番目に、コード全体
1.Pythonコード
"""
Author:XiaoMa
CSDN Address:一马归一码
"""
import cv2
from cvzone.PoseModule import PoseDetector
cap = cv2.VideoCapture('Video.mp4')
detector = PoseDetector()
posList = []
while True:
success, img = cap.read()
img = detector.findPose(img)#标记姿势关键节点
lmList, bboxInfo = detector.findPosition(img) #获取视频中的姿势信息
if bboxInfo: #判断是否检测到一个身体
lmString = '' #创建一个空的字符串
for lm in lmList: #'lm'为'landmark'的缩写,即33个关键节点
lmString += f'{lm[1]},{img.shape[0] - lm[2]},{lm[3]},' #最后一个逗号保留,这样每一个坐标值才能分离开来
posList.append(lmString)
print(len(posList))
cv2.imshow("Image", img)
key = cv2.waitKey(1)
if key == ord('s'): #将坐标点写入一个文件
with open("AnimationFile.txt", 'w') as f:
f.writelines(["%s\n" % item for item in posList])
2.C#スクリプト
(1) 球体アニメーション
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using System.Threading;
public class AnimationCode : MonoBehaviour
{
public GameObject[] Body;
List<string> lines;
int counter = 0;
void Start()
{
lines = System.IO.File.ReadLines("Assets/AnimationFile.txt").ToList();
}
void Update()
{
string[] points = lines[counter].Split(',');
for (int i =0; i<=32;i++)
{
float x = float.Parse(points[0 + (i * 3)]) / 100;
float y = float.Parse(points[1 + (i * 3)]) / 100;
float z = float.Parse(points[2 + (i * 3)]) / 300;
Body[i].transform.localPosition = new Vector3(x, y, z);
}
counter += 1;
if (counter == lines.Count) { counter = 0; }
Thread.Sleep(30);
}
}
(2) ライン
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LineCode : MonoBehaviour
{
LineRenderer lineRenderer;
public Transform origin;
public Transform destination;
void Start()
{
lineRenderer = GetComponent<LineRenderer>();
lineRenderer.startWidth = 0.1f;
lineRenderer.endWidth = 0.1f;
}
void Update()
{
lineRenderer.SetPosition(0, origin.position);
lineRenderer.SetPosition(1, destination.position);
}
}
5。結論
このプロジェクトの実現は、特に Python の部分ではそれほど難しくありませんが、再現するのがより面倒なので、段階的に実行しても問題ありません。髪の先に抱擁の木が生まれる、さあ!