Skip to content

Commit

Permalink
Version 1.4 : added root bone configuration and denoising configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
moraell committed Aug 25, 2019
1 parent ce279c8 commit 38292bf
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 18 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
Version 1.4:
- changed recording method for Blender 2.80. No checkbox to activate recording anymore, use of standard Blender auto keying method instead.
- added root bone selection for position tracking
- added denoising (Kalman filter) strength configuration

Version 1.3:
- added position tracking, and ability to lock position an each axis
Expand Down
8 changes: 5 additions & 3 deletions kinectMocap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@ inline void SafeRelease(Interface *& pInterfaceToRelease)
}

// start kinect sensor
int initSensor(double inDt) {
int initSensor(double inDt, double inSensorNoise, double inUNoise) {
HRESULT hr;
int res = 0;
tilt = -100;
dt = inDt;
sensorNoise = inSensorNoise;
uNoise = inUNoise;

hr = GetDefaultKinectSensor(&m_pKinectSensor);
if (FAILED(hr)) {
Expand Down Expand Up @@ -109,7 +111,7 @@ int applyKalman(int jointNumber) {
}
else {
// init filter
kalman[jointNumber] = new SimpleKalman(dt);
kalman[jointNumber] = new SimpleKalman(dt, sensorNoise, 0, uNoise);
kalman[jointNumber]->init(joints[jointNumber].Position.X, joints[jointNumber].Position.Y, joints[jointNumber].Position.Z);
}
return 0;
Expand Down Expand Up @@ -184,7 +186,7 @@ int updateFrame() {

struct Sensor {
tuple getJoint(int jointNumber) { return make_tuple(joints[jointNumber].Position.X, joints[jointNumber].Position.Y, joints[jointNumber].Position.Z, static_cast<int>(joints[jointNumber].TrackingState)); }
int init(double dt) { return initSensor(dt); }
int init(double dt, double sNoise, double uNois) { return initSensor(dt, sNoise, uNois); }
int close() { return closeSensor(); }
int update() { return updateFrame(); }
};
Expand Down
3 changes: 2 additions & 1 deletion kinectMocap.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ IBodyFrameReader* m_pBodyFrameReader;

// Kalman filters data
SimpleKalman* kalman[25];
double sensorNoise, uNoise;

// store framerate
double dt;
double dt;
55 changes: 47 additions & 8 deletions scripts/2.79/kinect_mocap.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,8 @@
"name": "Kinect Motion Capture plugin",
"description": "Motion capture using MS Kinect v2",
"author": "Morgane Dufresne",
"version": (1, 3),
"version": (1, 4),
"blender": (2, 79, 0),
"warning": "You need a MS Kinect v2 sensor (XBox One)",
"support": "COMMUNITY",
"category": "Animation"
}
Expand Down Expand Up @@ -57,6 +56,32 @@ def validateTarget(self, context):
self.value = ""
return None

KBonesEnum = [("Head", "Head", "Head"),
("Neck", "Neck", "Neck"),
("Spine1", "Spine1", "Spine1"),
("Spine0", "Spine0", "Spine0"),
("LeftShoulder", "LeftShoulder", "LeftShoulder"),
("LeftUpperArm", "LeftUpperArm", "LeftUpperArm"),
("LeftLowerArm", "LeftLowerArm", "LeftLowerArm"),
("LeftHand", "LeftHand", "LeftHand"),
("RightShoulder", "RightShoulder", "RightShoulder"),
("RightUpperArm", "RightUpperArm", "RightUpperArm"),
("RightLowerArm", "RightLowerArm", "RightLowerArm"),
("RightHand", "RightHand", "RightHand"),
("LeftUpperLeg", "LeftUpperLeg", "LeftUpperLeg"),
("LeftLowerLeg", "LeftLowerLeg", "LeftLowerLeg"),
("LeftFoot", "LeftFoot", "LeftFoot"),
("RightUpperLeg", "RightUpperLeg", "RightUpperLeg"),
("RightLowerLeg", "RightLowerLeg", "RightLowerLeg"),
("RightFoot", "RightFoot", "RightFoot")
]

KalmanStrengthEnum = [("Strong", "Strong", "Strong denoising (ideal for slow movement)"),
("Normal", "Normal", "Normal denoising (good balance between speed and precision)"),
("Low", "Low", "Low denoising (for fast movement, less precise)"),
("VeryLow", "Very low", "Very low denoising (only for very fast movement, almost no noise reduction")
]

class KmcTarget(bpy.types.PropertyGroup):
name = bpy.props.StringProperty(name="KBone")
value = bpy.props.StringProperty(name="TBone", update=validateTarget)
Expand All @@ -72,7 +97,8 @@ class KmcProperties(bpy.types.PropertyGroup):
lockHeight = bpy.props.BoolProperty(name="height", description="ignore vertical movement", default=True)
lockwidth = bpy.props.BoolProperty(name="width", description="ignore lateral movement", default=True)
lockDepth = bpy.props.BoolProperty(name="depth", description="ignore depth movement", default=True)

rootBone = bpy.props.EnumProperty(name="root bone", items=KBonesEnum, default="Spine0", description="Kinect identifier of the bone that is used as root of the skeleton")
kalmanStrength = bpy.props.EnumProperty(name="Denoising", items=KalmanStrengthEnum, default="Normal")

jointType = {
"SpineBase":0,
Expand Down Expand Up @@ -176,14 +202,13 @@ def initialize(context):
context.scene.kmc_props.firstFramePosition = (-1,-1,-1)
context.scene.kmc_props.initialOffset = (0,0,0)


for target in context.scene.kmc_props.targetBones:
if target.value is not None and target.value != "" :
bone = bpy.data.objects[context.scene.kmc_props.arma_list].pose.bones[target.value]
bone.rotation_mode = 'QUATERNION'

# Store initial position of spine0 bone
if target.name == "Spine0":
if target.name == context.scene.kmc_props.rootBone:
context.scene.kmc_props.initialOffset = bpy.data.objects[context.scene.kmc_props.arma_list].pose.bones[target.value].matrix.translation

# Store rest pose angles for column, head and feet bones
Expand Down Expand Up @@ -211,7 +236,7 @@ def updatePose(context, bone):
boneV = Vector((head[X] - tail[X], tail[Y] - head[Y], tail[Z] - head[Z]))

# if first bone, update position (only for configured axes)
if target.name == "Spine0":
if target.name == context.scene.kmc_props.rootBone:
# initialize firstFramePosition if fit isn't
if context.scene.kmc_props.firstFramePosition[1] == -1:
context.scene.kmc_props.firstFramePosition = (-1.0*head[X], head[Y], head[Z])
Expand Down Expand Up @@ -245,7 +270,7 @@ def updatePose(context, bone):
context.scene.kmc_props.currentFrame += 1
if context.scene.kmc_props.record :
bone.keyframe_insert(data_path="rotation_quaternion", frame=context.scene.kmc_props.currentFrame)
if target.name == "Spine0":
if target.name == context.scene.kmc_props.rootBone:
bone.keyframe_insert(data_path="location", frame=context.scene.kmc_props.currentFrame)

# update child bones
Expand Down Expand Up @@ -290,6 +315,7 @@ def draw(self, context):
if target.name == strBone :
box.prop(target, "value", text=target.name)
break
layout.prop(context.scene.kmc_props, "rootBone")

# configure movement tracking
layout.separator()
Expand All @@ -300,6 +326,10 @@ def draw(self, context):
col.prop(context.scene.kmc_props, "lockHeight")
col.prop(context.scene.kmc_props, "lockwidth")

# denoising strength
layout.separator()
layout.prop(context.scene.kmc_props, "kalmanStrength")

# activate
layout.separator()
layout.operator("kmc.start")
Expand Down Expand Up @@ -335,7 +365,16 @@ class KmcStartTrackingOperator(bpy.types.Operator):

def modal(self, context, event):
wm = context.window_manager
context.scene.k_sensor.init(1.0 / context.scene.kmc_props.fps)
uNoise = 5.0
if context.scene.kmc_props.kalmanStrength == "VeryLow" :
uNoise=50.0
elif context.scene.kmc_props.kalmanStrength == "Low" :
uNoise=20.0
elif context.scene.kmc_props.kalmanStrength == "Normal" :
uNoise=5.0
elif context.scene.kmc_props.kalmanStrength == "Strong" :
uNoise=1.0
context.scene.k_sensor.init(1.0 / context.scene.kmc_props.fps, 0.0005, uNoise)
if event.type == 'TIMER':
if(context.scene.k_sensor.update() == 1):
# update pose
Expand Down
53 changes: 47 additions & 6 deletions scripts/2.80/kinect_mocap.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
"author": "Morgane Dufresne",
"version": (1, 4),
"blender": (2, 80, 0),
"warning": "You need a MS Kinect v2 sensor (XBox One)",
"support": "COMMUNITY",
"category": "Animation"
}
Expand Down Expand Up @@ -58,6 +57,32 @@ def validateTarget(self, context):
self.value = ""
return None

KBonesEnum = [("Head", "Head", "Head"),
("Neck", "Neck", "Neck"),
("Spine1", "Spine1", "Spine1"),
("Spine0", "Spine0", "Spine0"),
("LeftShoulder", "LeftShoulder", "LeftShoulder"),
("LeftUpperArm", "LeftUpperArm", "LeftUpperArm"),
("LeftLowerArm", "LeftLowerArm", "LeftLowerArm"),
("LeftHand", "LeftHand", "LeftHand"),
("RightShoulder", "RightShoulder", "RightShoulder"),
("RightUpperArm", "RightUpperArm", "RightUpperArm"),
("RightLowerArm", "RightLowerArm", "RightLowerArm"),
("RightHand", "RightHand", "RightHand"),
("LeftUpperLeg", "LeftUpperLeg", "LeftUpperLeg"),
("LeftLowerLeg", "LeftLowerLeg", "LeftLowerLeg"),
("LeftFoot", "LeftFoot", "LeftFoot"),
("RightUpperLeg", "RightUpperLeg", "RightUpperLeg"),
("RightLowerLeg", "RightLowerLeg", "RightLowerLeg"),
("RightFoot", "RightFoot", "RightFoot")
]

KalmanStrengthEnum = [("Strong", "Strong", "Strong denoising (ideal for slow movement)"),
("Normal", "Normal", "Normal denoising (good balance between speed and precision)"),
("Low", "Low", "Low denoising (for fast movement, less precise)"),
("VeryLow", "Very low", "Very low denoising (only for very fast movement, almost no noise reduction")
]

class KMC_PG_KmcTarget(bpy.types.PropertyGroup):
name : bpy.props.StringProperty(name="KBone")
value : bpy.props.StringProperty(name="TBone", update=validateTarget)
Expand All @@ -73,6 +98,8 @@ class KMC_PG_KmcProperties(bpy.types.PropertyGroup):
lockHeight : bpy.props.BoolProperty(name="height", description="ignore vertical movement", default=True)
lockwidth : bpy.props.BoolProperty(name="width", description="ignore lateral movement", default=True)
lockDepth : bpy.props.BoolProperty(name="depth", description="ignore depth movement", default=True)
rootBone : bpy.props.EnumProperty(name="root bone", items=KBonesEnum, default="Spine0", description="Kinect identifier of the bone that is used as root of the skeleton")
kalmanStrength : bpy.props.EnumProperty(name="Denoising", items=KalmanStrengthEnum, default="Normal")

jointType = {
"SpineBase":0,
Expand Down Expand Up @@ -181,8 +208,8 @@ def initialize(context):
bone = bpy.data.objects[context.scene.kmc_props.arma_list].pose.bones[target.value]
bone.rotation_mode = 'QUATERNION'

# Store initial position of spine0 bone
if target.name == "Spine0":
# Store initial position of root bone
if target.name == context.scene.kmc_props.rootBone:
context.scene.kmc_props.initialOffset = bpy.data.objects[context.scene.kmc_props.arma_list].pose.bones[target.value].matrix.translation

# Store rest pose angles for column, head and feet bones
Expand Down Expand Up @@ -210,7 +237,7 @@ def updatePose(context, bone):
boneV = Vector((head[X] - tail[X], tail[Y] - head[Y], tail[Z] - head[Z]))

# if first bone, update position (only for configured axes)
if target.name == "Spine0":
if target.name == context.scene.kmc_props.rootBone:
# initialize firstFramePosition if fit isn't
if context.scene.kmc_props.firstFramePosition[1] == -1:
context.scene.kmc_props.firstFramePosition = (-1.0*head[X], head[Y], head[Z])
Expand Down Expand Up @@ -242,7 +269,7 @@ def updatePose(context, bone):

if context.scene.tool_settings.use_keyframe_insert_auto:
bone.keyframe_insert(data_path="rotation_quaternion")
if target.name == "Spine0":
if target.name == context.scene.kmc_props.rootBone:
bone.keyframe_insert(data_path="location")

# update child bones
Expand Down Expand Up @@ -288,6 +315,7 @@ def draw(self, context):
if target.name == strBone :
box.prop(target, "value", text=target.name)
break
layout.prop(context.scene.kmc_props, "rootBone")

# configure movement tracking
layout.separator()
Expand All @@ -298,6 +326,10 @@ def draw(self, context):
col.prop(context.scene.kmc_props, "lockHeight")
col.prop(context.scene.kmc_props, "lockwidth")

# denoising strength
layout.separator()
layout.prop(context.scene.kmc_props, "kalmanStrength")

# activate
layout.separator()
layout.operator("kmc.start")
Expand Down Expand Up @@ -359,7 +391,16 @@ def execute(self, context):
# init system
initialize(context)

context.scene.k_sensor.init(1.0 / context.scene.kmc_props.fps)
uNoise = 5.0
if context.scene.kmc_props.kalmanStrength == "VeryLow" :
uNoise=50.0
elif context.scene.kmc_props.kalmanStrength == "Low" :
uNoise=20.0
elif context.scene.kmc_props.kalmanStrength == "Normal" :
uNoise=5.0
elif context.scene.kmc_props.kalmanStrength == "Strong" :
uNoise=1.0
context.scene.k_sensor.init(1.0 / context.scene.kmc_props.fps, 0.0005, uNoise)
bpy.app.timers.register(functools.partial(captureFrame, context))
context.scene.kmc_props.isTracking = True

Expand Down

0 comments on commit 38292bf

Please sign in to comment.