来源: 日本中二少年教你用姿势估计把自己变成3D人物,动作实时同步,iOS上也能实现
// Properties for onnx and estimation
private Net Onnx;
private Mat[] outputs = new Mat[4];
private const int inputImageSize = 224;
private const int JointNum = 24;
private const int HeatMapCol = 14;
private const int HeatMapCol_Squared = 14 * 14;
private const int HeatMapCol_Cube = 14 * 14 * 14;
char[] heatMap2Dbuf = new char[JointNum * HeatMapCol_Squared * 4];
float[] heatMap2D = new float[JointNum * HeatMapCol_Squared];
char[] offset2Dbuf = new char[JointNum * HeatMapCol_Squared * 2 * 4];
float[] offset2D = new float[JointNum * HeatMapCol_Squared * 2];
char[] heatMap3Dbuf = new char[JointNum * HeatMapCol_Cube * 4];
float[] heatMap3D = new float[JointNum * HeatMapCol_Cube];
char[] offset3Dbuf = new char[JointNum * HeatMapCol_Cube * 3 * 4];
float[] offset3D = new float[JointNum * HeatMapCol_Cube * 3];
public void InitONNX()
{
Onnx = Net.ReadNetFromONNX(Application.dataPath + @"\MobileNet3D2.onnx");
for (var i = 0; i < 4; i++) outputs[i] = new Mat();
}
/// <summary>
/// Predict
/// </summary>
/// <param name="img"></param>
public void Predict(Mat img)
{
var blob = CvDnn.BlobFromImage(img, 1.0 / 255.0, new OpenCvSharp.Size(inputImageSize, inputImageSize), 0.0, false, false);
Onnx.SetInput(blob);
Onnx.Forward(outputs, new string[] { "369", "373", "361", "365" });
// copy 2D outputs
Marshal.Copy(outputs[2].Data, heatMap2Dbuf, 0, heatMap2Dbuf.Length);
Buffer.BlockCopy(heatMap2Dbuf, 0, heatMap2D, 0, heatMap2Dbuf.Length);
Marshal.Copy(outputs[3].Data, offset2Dbuf, 0, offset2Dbuf.Length);
Buffer.BlockCopy(offset2Dbuf, 0, offset2D, 0, offset2Dbuf.Length);
for (var j = 0; j < JointNum; j++)
{
var maxXIndex = 0;
var maxYIndex = 0;
jointPoints[j].score2D = 0.0f;
for (var y = 0; y < HeatMapCol; y++)
{
for (var x = 0; x < HeatMapCol; x++)
{
var l = new List<int>();
var v = heatMap2D[(HeatMapCol_Squared) * j + HeatMapCol * y + x];
if (v > jointPoints[j].score2D)
{
jointPoints[j].score2D = v;
maxXIndex = x;
maxYIndex = y;
}
}
}
jointPoints[j].Pos2D.x = (offset2D[HeatMapCol_Squared * j + HeatMapCol * maxYIndex + maxXIndex] + maxXIndex / (float)HeatMapCol) * (float)inputImageSize;
jointPoints[j].Pos2D.y = (offset2D[HeatMapCol_Squared * (j + JointNum) + HeatMapCol * maxYIndex + maxXIndex] + maxYIndex / (float)HeatMapCol) * (float)inputImageSize;
}
// copy 3D outputs
Marshal.Copy(outputs[0].Data, heatMap3Dbuf, 0, heatMap3Dbuf.Length);
Buffer.BlockCopy(heatMap3Dbuf, 0, heatMap3D, 0, heatMap3Dbuf.Length);
Marshal.Copy(outputs[1].Data, offset3Dbuf, 0, offset3Dbuf.Length);
Buffer.BlockCopy(offset3Dbuf, 0, offset3D, 0, offset3Dbuf.Length);
for (var j = 0; j < JointNum; j++)
{
var maxXIndex = 0;
var maxYIndex = 0;
var maxZIndex = 0;
jointPoints[j].score3D = 0.0f;
for (var z = 0; z < HeatMapCol; z++)
{
for (var y = 0; y < HeatMapCol; y++)
{
for (var x = 0; x < HeatMapCol; x++)
{
float v = heatMap3D[HeatMapCol_Cube * j + HeatMapCol_Squared * z + HeatMapCol * y + x];
if (v > jointPoints[j].score3D)
{
jointPoints[j].score3D = v;
maxXIndex = x;
maxYIndex = y;
maxZIndex = z;
}
}
}
}
jointPoints[j].Now3D.x = (offset3D[HeatMapCol_Cube * j + HeatMapCol_Squared * maxZIndex + HeatMapCol * maxYIndex + maxXIndex] + (float)maxXIndex / (float)HeatMapCol) * (float)inputImageSize;
jointPoints[j].Now3D.y = (float)inputImageSize - (offset3D[HeatMapCol_Cube * (j + JointNum) + HeatMapCol_Squared * maxZIndex + HeatMapCol * maxYIndex + maxXIndex] + (float)maxYIndex / (float)HeatMapCol) * (float)inputImageSize;
jointPoints[j].Now3D.z = (offset3D[HeatMapCol_Cube * (j + JointNum * 2) + HeatMapCol_Squared * maxZIndex + HeatMapCol * maxYIndex + maxXIndex] + (float)(maxZIndex - 7) / (float)HeatMapCol) * (float)inputImageSize;
}
}
public void InitONNX()
{
Onnx = Net.ReadNetFromONNX(Application.dataPath + @"\MobileNet3D2.onnx");
for (var i = 0; i < 4; i++) outputs[i] = new Mat();
}
public void Predict(Mat img)
{
var blob = CvDnn.BlobFromImage(img, 1.0 / 255.0, new OpenCvSharp.Size(inputImageSize, inputImageSize), 0.0, false, false);
Onnx.SetInput(blob);
Onnx.Forward(outputs, new string[] { "369", "373", "361", "365" });
// copy 2D outputs
Marshal.Copy(outputs[2].Data, heatMap2Dbuf, 0, heatMap2Dbuf.Length);
Buffer.BlockCopy(heatMap2Dbuf, 0, heatMap2D, 0, heatMap2Dbuf.Length);
Marshal.Copy(outputs[3].Data, offset2Dbuf, 0, offset2Dbuf.Length);
Buffer.BlockCopy(offset2Dbuf, 0, offset2D, 0, offset2Dbuf.Length);