apply bind pose to a kinect skeleton - kinect
I want to normalize a skeleton in order to make it invariant to the size of the person
in front of the kinect; in the same way as the aveteering example.
But I don't want to animate a 3D model using XNA, the only thing I need is to normalize an
skeleton.
So in order to do this task, I have divided it in two functions:
(a) apply a bind pose to an skeleton in order to see how to work this matrix. Obviously this is not what i want to do, but it is a first step in order to
know how to work whit matrix, and so on.
(b) apply any arbitrary pose to a normalized-size-skeleton
First of all, I want to apply a bind pose to an skeleton (a).
First, I have to load the matrix that describe the bone length/ offset between bones and store it in
List BindPose.
Due to I have no idea how to do it, I modified the Aveteering example and write in a file all the Matrix that define
the BindPose, InverseBindPose and SkeletonHierarchy of the dude. I only need BindPose to this first task, but I have the
code prepared in order to do the second task (b)
The file looks like this:
1,331581E-06;-5,551115E-17;1;0;1;-4,16881E-11;-1,331581E-06;0;4,16881E-11;1;8,153579E-23;0;0,03756338;37,46099;2,230549;1
1,110223E-16;-4,435054E-22;1;0;1;1,426127E-06;-2,220446E-16;0;-1,426127E-06;1;-7,654181E-22;0;-0,9558675;-4,079016E-08;-6,266987E-12;1
0,9954988;-0,09477358;1,501821E-06;0;0,09477358;0,9954988;-4,019565E-06;0;-1,114112E-06;4,143805E-06;1;0;3,786007;-0,003599779;5,107028E-06;1
0,9948416;-0,101441;-3,23556E-07;0;0,101441;0,9948416;-2,266755E-08;0;3,241862E-07;-1,027114E-08;1;0;4,543321;-0,00359975;-1,33061E-07;1
0,9950595;0,09927933;2,388133E-07;0;-0,09927933;0,9950595;-2,333792E-08;0;-2,399506E-07;-4,86646E-10;1;0;4,544049;-0,003599948;6,324596E-08;1
0,9992647;0,02747673;0,02674458;0;-0,02928042;0,9971476;0,06956656;0;-0,02475683;-0,07029849;0,9972187;0;4,543965;-0,004398902;2,258555E-07;1
0,9154034;0,4025377;1,107153E-06;0;-0,4025377;0,9154033;-2,437432E-07;0;-1,109319E-06;-2,115673E-07;1;0;5,536249;-0,00288291;1,332601E-07;1
0,9812952;-0,1925096;-4,732622E-07;0;0,1925095;0,9812951;-3,00921E-08;0;4,697166E-07;-5,889972E-08;1;0;3,953898;1,702301E-07;4,88653E-08;1
.......
So each line is a 4X4 matrix defining the BindPose.
To generate this file, the code is like this:
private void ViewSkinningData(SkinningData data)
{
string nameFile = "bind_pose_transformations";
bool append = false;
// The using statement automatically closes the stream and calls IDisposable.Dispose on the stream object.
using (System.IO.StreamWriter file = new System.IO.StreamWriter(#nameFile, append))
{
for (int i = 0; i < data.BindPose.Count; i++)
{
Matrix m = data.BindPose[i];
string matrixString = MatrixToString(m);
file.WriteLine(matrixString);
}
for (int i = 0; i < data.InverseBindPose.Count; i++)
{
Matrix m = data.InverseBindPose[i];
string matrixString = MatrixToString(m);
file.WriteLine(matrixString);
}
for (int i = 0; i < data.SkeletonHierarchy.Count; i++)
{
file.Write(data.SkeletonHierarchy[i] + ";");
}
}
}
string MatrixToString(Matrix m)
{
string result;
result = m.M11 + ";" + m.M12 + ";" + m.M13 + ";" + m.M14 + ";" + m.M21 + ";" + m.M22 + ";" + m.M23 + ";" + m.M24 + ";" + m.M31 + ";" + m.M32 + ";" + m.M33 + ";" + m.M34 + ";" + m.M41 + ";" + m.M42 + ";" + m.M43 + ";" + m.M44;
return result;
}
Next step is to load all this Skinning data in my program:
private void InitializeSkinningDataFromFile()
{
string filename = "bind_pose_transformations";
int number_avatar_joints = 58;
List<Matrix> binpose = new System.Collections.Generic.List<Matrix>();
List<Matrix> inversebindpose = new System.Collections.Generic.List<Matrix>();
List<int> skeletonhierarchy = new System.Collections.Generic.List<int>();
// The using statement automatically closes the stream and calls IDisposable.Dispose on the stream object.
using (System.IO.StreamReader file = new System.IO.StreamReader(filename))
{
string s;
int count = 0;
while (!String.IsNullOrEmpty(s = file.ReadLine()))
{
string[] values = s.Split(';');
Matrix m = BuildMatrix(values);
binpose.Add(m);
count++;
if (count == number_avatar_joints)
{
break;
}
}
count = 0;
while (!String.IsNullOrEmpty(s = file.ReadLine()))
{
string[] values = s.Split(';');
Matrix m = BuildMatrix(values);
inversebindpose.Add(m);
count++;
if (count == number_avatar_joints)
{
break;
}
}
string[] skeletonHierarchy = file.ReadLine().Split(';'); //lee un caracter de separacion al final...
//for (int i = 0; i < skeletonHierarchy.Count(); i++)
for (int i = 0; i < number_avatar_joints; i++)
{
skeletonhierarchy.Add(int.Parse(skeletonHierarchy[i]));
}
}
skinningDataValue = new SkinningData(binpose, inversebindpose, skeletonhierarchy);
}
After, I have to construct boneTransforms structure:
// Bone matrices for the "dude" model
this.boneTransforms = new Matrix[skinningDataValue.BindPose.Count];
this.skinningDataValue.BindPose.CopyTo(this.boneTransforms, 0);
Now boneTransforms have the transformation for my skeleton. So now, i have to apply these trasnformations to an skeleton
Skeleton skeleton = new Skeleton();
foreach (Joint joint in skeleton.Joints)
{
int indexMatrix = AvatarBoneToNuiJointIndex(joint.JointType);
Matrix transform;
if (indexMatrix >= 0)
{
transform = this.boneTransforms[indexMatrix];
}
else
{
transform = Matrix.Identity;
}
Joint aux = ApplyMatrixTransformationToJoint(joint, transform);
normalizeSkel.Joints[joint.JointType] = aux;
}
This is a helper function AvatarBoneToNuiJointIndex:
public int AvatarBoneToNuiJointIndex(JointType jointType)
{
switch (jointType)
{
case JointType.HipCenter:
return 1;
case JointType.Spine:
return 4;
case JointType.ShoulderCenter:
return 6;
case JointType.Head:
return 7;
case JointType.ShoulderLeft:
return 12;
case JointType.ElbowLeft:
return 13;
case JointType.WristLeft:
return 14;
case JointType.HandLeft:
return 15;
case JointType.ShoulderRight:
return 31;
case JointType.ElbowRight:
return 32;
case JointType.WristRight:
return 33;
case JointType.HandRight:
return 34;
case JointType.KneeLeft:
return 50;
case JointType.AnkleLeft:
return 51;
case JointType.FootLeft:
return 52;
case JointType.KneeRight:
return 54;
case JointType.AnkleRight:
return 55;
case JointType.FootRight:
return 56;
default: return -1;
}
}
This is a helper function ApplyMatrixTransformationToJoint:
public Joint ApplyMatrixTransformationToJoint(Joint skeletonJoint, Matrix tranformations)
{
Vector3 pos = SkeletonPointToVector3(skeletonJoint.Position);
Vector3 result = ApplyMatrixTransformationToVector(pos, tranformations);
SkeletonPoint newPosition = new SkeletonPoint()
{
X = result.X,
Y = result.Y,
Z = result.Z
};
skeletonJoint.Position = newPosition;
return skeletonJoint;
}
This is the code for ApplyMatrixTransformationToVector:
static Vector3 ApplyMatrixTransformationToVector(Vector3 v, Matrix m)
{
return Vector3.Transform(v, m);
}
But the problem is that I can't see anything.
I don't know if this approach is correct.
Any help would be fantastic.
Many thanks!
Related
Running solve multiple timese
I need to run a solve three times. Every time solve needs to have different input from different columns of a tuple. That is why I need to access the loop variable with in the OPL as a parameter and need to change that parameter with every loop. Please suggest how to do that in ODM OPL. (I am able to do it when running a standalone model with a physical .dat file by introducing a int in dat file and changing its values with each loop, but same is not possible when running through an ODM application).
You can do this using a scripting main() function: .dat file: param = 0; // This value is actually never used .mod file: tuple T { int round1; int round2; } T t = <1, 2>; int param = ...; dvar float x; minimize x; subject to { x >= param; } main { thisOplModel.generate(); var def = thisOplModel.modelDefinition; var data = thisOplModel.dataElements; for (var i = 0; i < 2; ++i) { if (i == 0) data.param = thisOplModel.t.round1; else data.param = thisOplModel.t.round2; var opl = new IloOplModel(def, cplex); opl.addDataSource(data); opl.generate(); cplex.solve(); writeln("Round " + i + ": " + cplex.getObjValue() + ", " + data.param); opl.end(); } } The scripting code modifies the data before creating a new model in each iteration. You have a more elaborate version of code like this in the cutstock_main.mod example that ships with CPLEX.
What Daniel wrote works fine. If you do not want to have the non necessary .dat file you could write sub.mod tuple T { int round1; int round2; } T t = <1, 2>; int param = ...; dvar float x; minimize x; subject to { x >= param; } and then in another model that will be the main one: tuple T { int round1; int round2; } T t = <1, 2>; main { thisOplModel.generate(); var src = new IloOplModelSource("sub.mod"); var def=new IloOplModelDefinition(src); var data = new IloOplDataElements();; for (var i = 0; i < 2; ++i) { if (i == 0) data.param = thisOplModel.t.round1; else data.param = thisOplModel.t.round2; var opl = new IloOplModel(def, cplex); opl.addDataSource(data); opl.generate(); cplex.solve(); writeln("Round " + i + ": " + cplex.getObjValue() + ", " + data.param); opl.end(); } } which will give Round 0: 1, 1 Round 1: 2, 2 and tuple T { int round1; int round2; } T t = <1, 2>; int solutions[0..1]; main { thisOplModel.generate(); var src = new IloOplModelSource("sub.mod"); var def=new IloOplModelDefinition(src); var data = new IloOplDataElements();; for (var i = 0; i < 2; ++i) { if (i == 0) data.param = thisOplModel.t.round1; else data.param = thisOplModel.t.round2; var opl = new IloOplModel(def, cplex); opl.addDataSource(data); opl.generate(); cplex.solve(); writeln("Round " + i + ": " + cplex.getObjValue() + ", " + data.param); thisOplModel.solutions[i]=opl.x.solutionValue; opl.end(); } writeln(thisOplModel.solutions); } to address your next question about populating tables which gives Round 0: 1, 1 Round 1: 2, 2 [1 2]
Null pointer exception on Processing (ldrValues)
My code involves both Processing and Arduino. 5 different photocells are triggering 5 different sounds. My sound files play only when the ldrvalue is above the threshold. The Null Pointer Exception is highlighted on this line for (int i = 0; i < ldrValues.length; i++) { I am not sure which part of my code should be changed so that I can run it. import processing.serial.*; import processing.sound.*; SoundFile[] soundFiles = new SoundFile[5]; Serial myPort; // Create object from Serial class int[] ldrValues; int[] thresholds = {440, 490, 330, 260, 450}; int i = 0; boolean[] states = {false, false, false, false, false}; void setup() { size(200, 200); println((Object[])Serial.list()); String portName = Serial.list()[3]; myPort = new Serial(this, portName, 9600); soundFiles[0] = new SoundFile(this, "1.mp3"); soundFiles[1] = new SoundFile(this, "2.mp3"); soundFiles[2] = new SoundFile(this, "3.mp3"); soundFiles[3] = new SoundFile(this, "4.mp3"); soundFiles[4] = new SoundFile(this, "5.mp3"); } void draw() { background(255); //serial loop while (myPort.available() > 0) { String myString = myPort.readStringUntil(10); if (myString != null) { //println(myString); ldrValues = int(split(myString.trim(), ',')); //println(ldrValues); } } for (int i = 0; i < ldrValues.length; i++) { println(states[i]); println(ldrValues[i]); if (ldrValues[i] > thresholds[i] && !states[i]) { println("sensor " + i + " is activated"); soundFiles[i].play(); states[i] = true; } if (ldrValues[i] < thresholds[i]) { println("sensor " + i + " is NOT activated"); soundFiles[i].stop(); states[i] = false; } } }
You're approach is shall we say optimistic ? :) It's always assuming there was a message from Serial, always formatted the right way so it could be parsed and there were absolutely 0 issues buffering data (incomplete strings, etc.)) The simplest thing you could do is check if the parsing was successful, otherwise the ldrValues array would still be null: void draw() { background(255); //serial loop while (myPort.available() > 0) { String myString = myPort.readStringUntil(10); if (myString != null) { //println(myString); ldrValues = int(split(myString.trim(), ',')); //println(ldrValues); } } // double check parsing int values from the string was successfully as well, not just buffering the string if(ldrValues != null){ for (int i = 0; i < ldrValues.length; i++) { println(states[i]); println(ldrValues[i]); if (ldrValues[i] > thresholds[i] && !states[i]) { println("sensor " + i + " is activated"); soundFiles[i].play(); states[i] = true; } if (ldrValues[i] < thresholds[i]) { println("sensor " + i + " is NOT activated"); soundFiles[i].stop(); states[i] = false; } } }else{ // print a helpful debugging message otherwise println("error parsing ldrValues from string: " + myString); } } (Didn't know you could parse a int[] with int(): nice!)
How to count letter differences of two strings in bigquery?
For example i have: 1: 6c71d997ba39 2: 6c71d997d269 I need to get 4.
You can consider using Levenshtein distance for your use-case the Levenshtein distance is a string metric for measuring the difference between two sequences. Informally, the Levenshtein distance between two words is the minimum number of single-character edits (insertions, deletions or substitutions) required to change one word into the other Below example is for BigQuery Standard SQL #standardSQL CREATE TEMPORARY FUNCTION EDIT_DISTANCE(string1 STRING, string2 STRING) RETURNS INT64 LANGUAGE js AS """ var _extend = function(dst) { var sources = Array.prototype.slice.call(arguments, 1); for (var i=0; i<sources.length; ++i) { var src = sources[i]; for (var p in src) { if (src.hasOwnProperty(p)) dst[p] = src[p]; } } return dst; }; var Levenshtein = { /** * Calculate levenshtein distance of the two strings. * * #param str1 String the first string. * #param str2 String the second string. * #return Integer the levenshtein distance (0 and above). */ get: function(str1, str2) { // base cases if (str1 === str2) return 0; if (str1.length === 0) return str2.length; if (str2.length === 0) return str1.length; // two rows var prevRow = new Array(str2.length + 1), curCol, nextCol, i, j, tmp; // initialise previous row for (i=0; i<prevRow.length; ++i) { prevRow[i] = i; } // calculate current row distance from previous row for (i=0; i<str1.length; ++i) { nextCol = i + 1; for (j=0; j<str2.length; ++j) { curCol = nextCol; // substution nextCol = prevRow[j] + ( (str1.charAt(i) === str2.charAt(j)) ? 0 : 1 ); // insertion tmp = curCol + 1; if (nextCol > tmp) { nextCol = tmp; } // deletion tmp = prevRow[j + 1] + 1; if (nextCol > tmp) { nextCol = tmp; } // copy current col value into previous (in preparation for next iteration) prevRow[j] = curCol; } // copy last col value into previous (in preparation for next iteration) prevRow[j] = nextCol; } return nextCol; } }; var the_string1; try { the_string1 = decodeURI(string1).toLowerCase(); } catch (ex) { the_string1 = string1.toLowerCase(); } try { the_string2 = decodeURI(string2).toLowerCase(); } catch (ex) { the_string2 = string2.toLowerCase(); } return Levenshtein.get(the_string1, the_string2) """; WITH strings AS ( SELECT '1: 6c71d997ba39' string1, '2: 6c71d997d269' string2 ) SELECT string1, string2, EDIT_DISTANCE(string1, string2) changes FROM strings with result Row string1 string2 changes 1 1: 6c71d997ba39 2: 6c71d997d269 4
SELECT (SELECT COUNTIF(c != s2[OFFSET(off)]) FROM UNNEST(SPLIT(s1, '')) AS c WITH OFFSET off) AS count FROM dataset.table
Source: https://stackoverflow.com/a/57499387/11059644 Ready to use shared UDFs - Levenshtein distance: SELECT fhoffa.x.levenshtein('felipe', 'hoffa'), fhoffa.x.levenshtein('googgle', 'goggles'), fhoffa.x.levenshtein('is this the', 'Is This The')
Quick help turning sum into mean
I was helped earlier in creating this code that would create a histogram of a randomint. Everything looks good except I accidently had the output as a sum instead of a mean of all the numbers that were randomly chosen.I dont want to mess anything up so I was just going to ask, How can I convert this sum into a mean output instead? import java.util.Random; class Assignment4 { public static void main(String[] args) { Random r = new Random(); int sum = 0; int[] bins = new int[10]; for(int i = 0; i < 100; i++) { int randomint = 1 + r.nextInt(10); sum += randomint; bins[randomint-1]++; //System.out.print(randomint + ", "); } System.out.println("Sum = " + sum); System.out.println("Data shown below: "); for (int i = 0; i < bins.length; i++) { int binvalue = bins[i]; System.out.print((i+1) + ": "); for(int j = 0; j < binvalue; j++) { System.out.print('*'); } System.out.println(" (" + binvalue + ")"); } } }
Never mind figured it out.... just turned System.out.println("Sum = " + sum); into System.out.println("Mean = " + sum/100);
Zedgraph - Change X-Axis from points to frequency
i have a working program where i can add an array to a Zedgraph and show this in a form. Now i only want to change the display of the x-axis from points (0..400) to frequency (9e3..6e9 Hz). Here are my currently working functions: public void AddGraph(double[] Values, string LegendName) { int i = 0; PointPairList list = new PointPairList(); for (i = 0; i < Values.Length; i++) { list.Add(i, Values[i]); } if (i > MaxXAxis) MaxXAxis = i; SList.Add(list); SListColor.Add(Color.Black); } SListName.Add(LegendName); } public void ShowDiagram(string Title, string XAxisName, string YAxisName, int Timeout_ms) { ZedGraph.ZedGraphControl zgc = new ZedGraphControl(); GraphPane myPane = zgc.GraphPane; LineItem myCurve = null; // Set the titles and axis labels myPane.Title.Text = Title; myPane.XAxis.Title.Text = XAxisName; myPane.YAxis.Title.Text = YAxisName; for (int i = 0; i < SList.Count(); i++) { myCurve = myPane.AddCurve(SListName[i], SList[i], SListColor[i], SymbolType.None); myCurve.Line.Width = 2; } // Add gridlines to the plot, and make them gray myPane.XAxis.MinorGrid.IsVisible = true; myPane.YAxis.MinorGrid.IsVisible = true; myPane.XAxis.MinorGrid.Color = Color.LightGray; myPane.YAxis.MinorGrid.Color = Color.LightGray; myPane.XAxis.MinorGrid.DashOff = 0; myPane.YAxis.MinorGrid.DashOff = 0; myPane.XAxis.MajorGrid.IsVisible = true; myPane.YAxis.MajorGrid.IsVisible = true; myPane.XAxis.MajorGrid.Color = Color.Gray; myPane.YAxis.MajorGrid.Color = Color.Gray; myPane.XAxis.MajorGrid.DashOff = 0; myPane.YAxis.MajorGrid.DashOff = 0; // Move Legend to bottom myPane.Legend.Position = LegendPos.Bottom; zgc.AxisChange(); myPane.XAxis.Scale.Max = MaxXAxis; zgc.Location = new Point(0, 0); zgc.Size = new Size(panel_diagramm.ClientRectangle.Width, panel_diagramm.ClientRectangle.Height); panel_diagramm.Controls.Add(zgc); } How can i change the above two functions that they display the frequency in the x-axis? I already tried to change the AddGraph-function to pass the needed parameters and to calculate the list to have the correct values. But what then...? public void AddGraph_Frequency(int **Points**, double **StartFrequency**, double **StopFrequency**, double[] Values, string GraphColor, string LegendName) { ... double frequency = StartFrequency; //der erste Punkt double Intervall = (StopFrequency - StartFrequency) / Points; for (i = 0; i < Points; i++) { list.Add(frequency, Values[i]); frequency = frequency + Intervall; } .... } Thanks for any help best regards
Solved. Missing was: myPane.XAxis.Scale.Max = Stopfrequency; myPane.XAxis.Scale.Min = Startfrequency;