使用 Java 中的 Kinect 数据集计算两条线(代表人体手臂)之间的角度
Calculate angle between two lines (which are represent human arm) using Kinect data set in Java
我使用Microsoft Kinect 设备获得了人体肩部、肘部和手腕的坐标(数据是针对Kinect 设备获取的)。
在获取坐标时,我上下移动了手臂。示例数据集如下所示。
7/7/2015 12:02:49 AM shoulder X -0.06475954 shoulder Y 0.266225 shoulder Z 1.414332 elbow X 0.002287441 elbow Y 0.03676218 elbow Z 1.424792 wrist X 0.1791002 wrist Y -0.06900118 wrist Z 1.455758
7/7/2015 12:02:49 AM shoulder X -0.06655618 shoulder Y 0.2654685 shoulder Z 1.413007 elbow X 0.001183244 elbow Y 0.0374795 elbow Z 1.424512 wrist X 0.1779053 wrist Y -0.06793896 wrist Z 1.4554
7/7/2015 12:02:49 AM shoulder X -0.0703955 shoulder Y 0.264899 shoulder Z 1.408783 elbow X -0.001478138 elbow Y 0.03802216 elbow Z 1.422277 wrist X 0.1769906 wrist Y -0.06481737 wrist Z 1.4514
然后我尝试在两种情况下计算手臂的角度。
- 假设Z坐标是固定的(实际上上面的数据集是这样取的,这个假设成立)
- 假设Z坐标不固定
我使用了java代码来计算上述两种情况下的角度。
Java代码如下
import java.io.*;
class main {
public static void main(String args[]){
try{
FileInputStream fstream = new FileInputStream("C:\Users\Chathu\Desktop\project code\src\output.txt");
DataInputStream in = new DataInputStream(fstream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
while ((strLine = br.readLine()) != null) {
String[] tokens = strLine.split(" ");
//time
//shoulder cordinates
double ShoulderX= Double.parseDouble(tokens[5]);
double ShoulderY= Double.parseDouble(tokens[8]);
double ShoulderZ= Double.parseDouble(tokens[11]);
//elbow cordinates
double ElbowX= Double.parseDouble(tokens[14]);
double ElbowY= Double.parseDouble(tokens[17]);
double ElbowZ= Double.parseDouble(tokens[20]);
//wrist cordinates
double WristX= Double.parseDouble(tokens[23]);
double WristY= Double.parseDouble(tokens[26]);
double WristZ= Double.parseDouble(tokens[29]);
//calculate angle if Z is fixed
double M1=((ShoulderY-ElbowY)/(ShoulderX-ElbowX));
double M2=((WristY-ElbowY)/(WristX-ElbowX));
double tanAlfa=Math.abs((M1-M2)/(1+(M1*M2)));
System.out.println("Time : "+getTimeinInt(tokens[1]));
System.out.println("2D angle: "+Math.toDegrees(Math.atan(tanAlfa)));
//calculate andgle when Z is not fixed
//Create 2 vectors
double[] u={ShoulderX-ElbowX,ShoulderY-ElbowY,ShoulderZ-ElbowZ };
double[] v={WristX-ElbowX,WristY-ElbowY,WristZ-ElbowZ };
double absu=Math.sqrt(Math.pow(u[0],2)+Math.pow(u[1],2)+Math.pow(u[2],2));
double absv=Math.sqrt(Math.pow(v[0],2)+Math.pow(v[1],2)+Math.pow(v[2],2));
double cosTheata=((dotProd(u,v))/(absu*absv));
System.out.println("3D angle: "+Math.acos(cosTheata));
}
in.close();
}catch (Exception e){
System.err.println("Error: " + e.getMessage());
}
}
public static int getTimeinInt(String time){
String[] tokens = time.split(":");
int hours = Integer.parseInt(tokens[0]);
int minutes = Integer.parseInt(tokens[1]);
int seconds = Integer.parseInt(tokens[2]);
int duration = 3600 * hours + 60 * minutes + seconds;
return duration;
}
public static double dotProd(double[] a, double[] b){
if(a.length != b.length){
throw new IllegalArgumentException("The dimensions have to be equal!");
}
double sum = 0;
for(int i = 0; i < a.length; i++){
sum += a[i] * b[i];
}
return sum;
}
}
但是当我 运行 此代码并检查计算的角度值时,我在上述两个假设下得到了完全不同的值。
前3个答案如下(答案对应以上样本数据集)
Time : 43369
2D angle: 42.82568606638748
3D angle: 2.3907040436551847
Time : 43369
2D angle: 42.63544266854971
3D angle: 2.3947689168198463
Time : 43369
2D angle: 43.151072486090776
3D angle: 2.387883634441205
谁能帮我找出问题所在?
你可以用余弦求出两条线之间的夹角。
wrist = point1
elbo = point2
soulder = point3
vector1 = point1 - point2
vector2 = point1 - point3
现在您有向量 1 和 2 分别从肘部指向手腕和肩部,可以通过以下方式找到角度:
这 2 个向量的点积与其量级乘积之比的反余弦值。
有关数学的更多信息,请查看 This page on Wikipedia
你有什么“3d 角度...”
您不能使用 atan 方法,因为您的肘部角度不是 90 度。
如果你知道它是你为什么要寻找它?
我真的不确定您要使用“2d 角...”到底是什么意思
谢谢大家的帮助。
最后我在我的 java 代码中发现了错误。我使用 System.out.println("3D angle: "+Math.acos(cosTheata));
打印 3D space 中两个向量之间的角度。当我阅读 acos()
方法的文档时,它说此方法 returns 弧度的角度。在 2D 平面结果中,我使用 Math.toDegrees()
方法将角度转换为度数。所以我所有的3D坐标角度值都是弧度的。
我使用Microsoft Kinect 设备获得了人体肩部、肘部和手腕的坐标(数据是针对Kinect 设备获取的)。 在获取坐标时,我上下移动了手臂。示例数据集如下所示。
7/7/2015 12:02:49 AM shoulder X -0.06475954 shoulder Y 0.266225 shoulder Z 1.414332 elbow X 0.002287441 elbow Y 0.03676218 elbow Z 1.424792 wrist X 0.1791002 wrist Y -0.06900118 wrist Z 1.455758
7/7/2015 12:02:49 AM shoulder X -0.06655618 shoulder Y 0.2654685 shoulder Z 1.413007 elbow X 0.001183244 elbow Y 0.0374795 elbow Z 1.424512 wrist X 0.1779053 wrist Y -0.06793896 wrist Z 1.4554
7/7/2015 12:02:49 AM shoulder X -0.0703955 shoulder Y 0.264899 shoulder Z 1.408783 elbow X -0.001478138 elbow Y 0.03802216 elbow Z 1.422277 wrist X 0.1769906 wrist Y -0.06481737 wrist Z 1.4514
然后我尝试在两种情况下计算手臂的角度。
- 假设Z坐标是固定的(实际上上面的数据集是这样取的,这个假设成立)
- 假设Z坐标不固定
我使用了java代码来计算上述两种情况下的角度。 Java代码如下
import java.io.*;
class main {
public static void main(String args[]){
try{
FileInputStream fstream = new FileInputStream("C:\Users\Chathu\Desktop\project code\src\output.txt");
DataInputStream in = new DataInputStream(fstream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
while ((strLine = br.readLine()) != null) {
String[] tokens = strLine.split(" ");
//time
//shoulder cordinates
double ShoulderX= Double.parseDouble(tokens[5]);
double ShoulderY= Double.parseDouble(tokens[8]);
double ShoulderZ= Double.parseDouble(tokens[11]);
//elbow cordinates
double ElbowX= Double.parseDouble(tokens[14]);
double ElbowY= Double.parseDouble(tokens[17]);
double ElbowZ= Double.parseDouble(tokens[20]);
//wrist cordinates
double WristX= Double.parseDouble(tokens[23]);
double WristY= Double.parseDouble(tokens[26]);
double WristZ= Double.parseDouble(tokens[29]);
//calculate angle if Z is fixed
double M1=((ShoulderY-ElbowY)/(ShoulderX-ElbowX));
double M2=((WristY-ElbowY)/(WristX-ElbowX));
double tanAlfa=Math.abs((M1-M2)/(1+(M1*M2)));
System.out.println("Time : "+getTimeinInt(tokens[1]));
System.out.println("2D angle: "+Math.toDegrees(Math.atan(tanAlfa)));
//calculate andgle when Z is not fixed
//Create 2 vectors
double[] u={ShoulderX-ElbowX,ShoulderY-ElbowY,ShoulderZ-ElbowZ };
double[] v={WristX-ElbowX,WristY-ElbowY,WristZ-ElbowZ };
double absu=Math.sqrt(Math.pow(u[0],2)+Math.pow(u[1],2)+Math.pow(u[2],2));
double absv=Math.sqrt(Math.pow(v[0],2)+Math.pow(v[1],2)+Math.pow(v[2],2));
double cosTheata=((dotProd(u,v))/(absu*absv));
System.out.println("3D angle: "+Math.acos(cosTheata));
}
in.close();
}catch (Exception e){
System.err.println("Error: " + e.getMessage());
}
}
public static int getTimeinInt(String time){
String[] tokens = time.split(":");
int hours = Integer.parseInt(tokens[0]);
int minutes = Integer.parseInt(tokens[1]);
int seconds = Integer.parseInt(tokens[2]);
int duration = 3600 * hours + 60 * minutes + seconds;
return duration;
}
public static double dotProd(double[] a, double[] b){
if(a.length != b.length){
throw new IllegalArgumentException("The dimensions have to be equal!");
}
double sum = 0;
for(int i = 0; i < a.length; i++){
sum += a[i] * b[i];
}
return sum;
}
}
但是当我 运行 此代码并检查计算的角度值时,我在上述两个假设下得到了完全不同的值。
前3个答案如下(答案对应以上样本数据集)
Time : 43369
2D angle: 42.82568606638748
3D angle: 2.3907040436551847
Time : 43369
2D angle: 42.63544266854971
3D angle: 2.3947689168198463
Time : 43369
2D angle: 43.151072486090776
3D angle: 2.387883634441205
谁能帮我找出问题所在?
你可以用余弦求出两条线之间的夹角。
wrist = point1
elbo = point2
soulder = point3
vector1 = point1 - point2
vector2 = point1 - point3
现在您有向量 1 和 2 分别从肘部指向手腕和肩部,可以通过以下方式找到角度:
这 2 个向量的点积与其量级乘积之比的反余弦值。
有关数学的更多信息,请查看 This page on Wikipedia
你有什么“3d 角度...”
您不能使用 atan 方法,因为您的肘部角度不是 90 度。 如果你知道它是你为什么要寻找它?
我真的不确定您要使用“2d 角...”到底是什么意思
谢谢大家的帮助。
最后我在我的 java 代码中发现了错误。我使用 System.out.println("3D angle: "+Math.acos(cosTheata));
打印 3D space 中两个向量之间的角度。当我阅读 acos()
方法的文档时,它说此方法 returns 弧度的角度。在 2D 平面结果中,我使用 Math.toDegrees()
方法将角度转换为度数。所以我所有的3D坐标角度值都是弧度的。