Jump to content

ASF Reader Help?


Atom

Recommended Posts

Hi All,

I am trying to make a python script that will read the Acclaim .asf file and generate a skeleton from the file. I have the basics of bone creations and parsing done but I just can't figure out the bone rotations. What I end up with is a skeleton that curves in on itself.

The code can be placed in a shelf tool button to run. The rotation calculation occur around line # 120.

import os

file_asf = r"C:\Users\Admin\Documents\Mocap\amc_original_data\61.asf"
lst_source_axis = ["rx","ry","rz"]
lst_target_axis = ["rx","ry","rz"]

def returnIndexForAxis(passedAxis):
    for (i,axis) in enumerate(lst_source_axis):
        if axis == passedAxis:
            return i
    return None
    
def returnASFBoneRecord(passedBoneName):
    # Read the .asf skeleton file looking for DOF information.
    lst_record = []
    if os.path.isfile(file_asf):
        lines = [line.rstrip('\n') for line in open(file_asf)]
        gather_data = False
        found_section = False
        last_name = ""
        for raw_line in lines:
            line = raw_line.lstrip()
            if found_section:
                if gather_data:
                    if line == "end":
                        if last_name == passedBoneName:
                            # This is the record, we are done.
                            return lst_record
                        else:
                            # Blank record and wait for next begin.
                            lst_record = []
                        # Stop gathering we have encountered an end.
                        gather_data = False
                    else:
                        # Split this line an review.
                        ary = line.split(" ")
                        if ary[0] == "name":
                            last_name = ary[1]
                            #print "last_name:%s" % last_name
                        lst_record.append(line)
                else:
                    if line == "begin": gather_data = True
            else:
                if line == ":bonedata":
                    found_section = True
        else:
            print "File [%s] not found." % file_asf
    return lst_record
    
def returnASFHierarchy():
    # Read the .asf skeleton file looking for bone hierarchy.
    lst_record = []
    if os.path.isfile(file_asf):
        lines = [line.rstrip('\n') for line in open(file_asf)]
        gather_data = False
        found_section = False
        last_name = ""
        for raw_line in lines:
            line = raw_line.lstrip()
            if found_section:
                if gather_data:
                    if line == "end":
                        return lst_record
                    else:
                        lst_record.append(line)
                else:
                    if line == "begin": gather_data = True
            else:
                if line == ":hierarchy":
                    found_section = True
        else:
            print "File [%s] not found." % file_asf
    return lst_record
    
# Button click handlers.
# ----------------------
def generateSkeleton():
    bone_length_mult = 0.45     #global scale from .asf files (they all seem to be the same).
    skeleton_root_name = 'ap_skeleton_asf'
    lst_hierarchy_record = returnASFHierarchy()
    if len(lst_hierarchy_record) > 0:
        node_subnet = hou.node('/obj').createNode('subnet',skeleton_root_name)
        #print  ""
        for parent_child_bone_chain in lst_hierarchy_record:
            ary = parent_child_bone_chain.split(' ')
            l = len(ary)
            if l > 1:
                # Create each bone in this bone chain.
                for index in range(l):
                    bone_name = ary[index]
                    bone_candidate = "%s/%s" % ('/obj/%s' % skeleton_root_name, bone_name)
                    bone_node = hou.node(bone_candidate)
                    if bone_node == None:
                        # Time to create this bone node.
                        if index == 0:
                            bone_node = hou.node('/obj/%s' % skeleton_root_name).createNode('null',bone_name)
                        else:
                            bone_node = hou.node('/obj/%s' % skeleton_root_name).createNode('bone',bone_name)
                    
                # The first name is the parent of all children in this bone chain.
                parent_candidate = "%s/%s" % ('/obj/%s' % skeleton_root_name, ary[0])
                parent_node = hou.node(parent_candidate)
                if parent_node != None:
                    for index in range(1,l):
                        #print l, index
                        bone_name = ary[index]
                        bone_candidate = "%s/%s" % ('/obj/%s' % skeleton_root_name, bone_name)
                        bone_node = hou.node(bone_candidate)
                        if bone_node != None:
                            print "connecting [%s] to [%s]." % (parent_node.name(), bone_node.name())
                            bone_node.setInput(0,parent_node)
                            lst_bone_record = returnASFBoneRecord(bone_name)

                            lst_items = lst_bone_record[3].split(' ')                   # bone length.
                            bone_length = float(lst_items[1]) * bone_length_mult
                            bone_node.parm("length").set(bone_length)
                            
                            lst_items = lst_bone_record[4].split(' ')                   # axis offset in degrees.
                            lst_degrees_offset = [float(lst_items[1]),float(lst_items[2]),float(lst_items[3])]
                           
                            lst_items = lst_bone_record[2].split(' ')                   # direction
                            vec_target = hou.Vector3(float(lst_items[1]),float(lst_items[2]),float(lst_items[3]))
                            vec_source = hou.Vector3(0,0,-1) * parent_node.worldTransform() #Bones in Houdini are oriented down the -Z axis by default
                            rot_result = vec_source.matrixToRotateTo(vec_target)
                            eulerAngles = rot_result.extractRotates()
                            for (i,value) in enumerate(lst_degrees_offset):
                                bone_degrees = eulerAngles[i] #+ value
                                bone_node.parm(lst_target_axis[i]).set(bone_degrees)
                else:
                    print "unable to locate [%s]." % parent_candidate
generateSkeleton()

Does anyone know how to fix such rotation issues?

 

The above script and an example .asf file to test with are attached in the ZIP file.

asf_file_reader.zip

Untitled-1.jpg

Edited by Atom
Link to comment
Share on other sites

I am trying to leverage motion capture but no matter what software I use the end result is a bound up junky looking character. I remember the first time I applied a motion capture to a poser figure over ten years ago. I thought wow, look, I animated that. But I was, of course, looking past the fact that the shoulders were all jacked up and the feet slid all over the place. Ten years have gone by and I am still looking into how to leverage mocap. I only have access to the free mocap data posted on the web. While this data does have some issues, the main issue I have is with the binding of the mesh to mocap skeleton. If I use Poser, Blender, Houdini it does not matter, in the end I get a mesh that bends wrong and interpenetrates with itself. In Houdini, I have carefully set weights and event sculpted and smoothed them but there is no volume preserving in the deform node AFAIK.

My recent approach was to try to adjust bone chain lengths via scripting to better fit the target mesh but I still cant get a decent looking mesh after weeks of coding.

After reading a bit on the Carnegie Mellon University page I noticed that the original acclaim mocap data was converted to BVH and other formats using a tool that no longer exists. I wanted to return to the original data and try to import it to see if something was lost during the conversion.

I have used mcbiovision but not mcacclaim. I as I poke around with command line parameters I can not get the mcacclaim.exe to work.

Here is my line from the Windows BATch file which produces no results.

"C:\Program Files\Side Effects Software\Houdini 15.5.480\bin\mcacclaim.exe" "C:\Users\Admin\Documents\Mocap\amc_original_data\61_11.acm" "C:\Users\Admin\Documents\Mocap\amc_original_data\61.asf"
Edited by Atom
Link to comment
Share on other sites

vec_source = hou.Vector3(0,0,-1) * parent_bone_world_matrix #Bones in Houdini are oriented down the -Z axis of the parent transform
rot_result = vec_source.matrixToRotateTo(vec_target)
eulerAngles = rot_result.extractRotates()

 

I said on your other thread "#Bones in Houdini are oriented down the -Z axis by default".  My phrasing probably should have been more clear (see above).

 

However this won't solve your problem with poor deformation, it's not that it is wrong it's simply that an anatomical being of bone and flesh is always interpenetrating itself, it's just that flesh will move out of the way of the other flesh.

You need to simulate the flesh and bones.  I highly recommend diving into PBD(rather then FEM, but that's just my opinion though) for this, a good way to do this is convert the entire character mesh into a grain object then capture and drive the particles using the bone skeleton.  However this solution is not simple and will likely require months of work to get appealing(rather then just non-interpenetrating) results.

Edited by MrScienceOfficer
Link to comment
Share on other sites

Thank you Tom, I am just getting back to this task and I was implementing your suggestion from the other thread in this stand alone shelf button. Now I see your addition of the parent matrix for the source. The addition of the parent matrix to the source vector does help!

Now I mainly have to deal with arms fixup which might require applying those axis offsets from the .asf file.

vec_source = hou.Vector3(0,0,-1) * parent_node.worldTransform()                           #Bones in Houdini are oriented down the -Z axis by default
rot_result = vec_source.matrixToRotateTo(vec_target)
eulerAngles = rot_result.extractRotates()
for (i,value) in enumerate(lst_degrees_offset):
    bone_degrees = eulerAngles[i]
    bone_node.parm(lst_target_axis[i]).set(bone_degrees)
	

Untitled-1.jpg

Edited by Atom
Link to comment
Share on other sites

@Michael: I have copied my .asf and .acm files into the bin folder where the mcaaclaim.exe resides. When I specify the files the tool can not read the .acm file? I have tried other paths as well (not residing under Program Files) but the tool can not read the .acm file.

It looks like a valid .amc file...

Have you tried the tool recently?

#!OML:ASF I:\salsa\salsa 7_09\Patient 1\Session 1\dancerfemale.ASF
:FULLY-SPECIFIED
:DEGREES
1
root 20.2295 16.0545 -0.871178 -179.638 -87.324 -175.278
lowerback -2.21309 1.89048 -0.205027
upperback -4.94698 2.37668 -1.31581
thorax -3.8039 1.12054 -1.26386
lowerneck -2.9433 -3.43647 -6.60136
upperneck 9.01638 -5.03474 7.89536
	.
	.
	.
	

Untitled-1.jpg

acclaim_example_set_acm+asf.zip

Edited by Atom
Link to comment
Share on other sites

running Houdini 15.5.557 Linux Mint

extracted your acclaim_example_set_acm+asf.zip file into a directory

in a shell:

> mcacclaim 61_11.amc 61.asf 61_11_test

I get these two warnings

Quote

Warning 14: Ignoring unsupported 'axis' tag for :root (assuming 'xyz')
Warning 16: Ignoring unsupported 'orientation' tag for :root (assuming 0,0,0)

but I do get the following files:

61_11_test.cmd

61_11_test.bclip

and I can run the cmd file in Houdini

 

61_11_test.zip

 

I'll find someone to test this on Windows to see if that might be where the problem is...

Link to comment
Share on other sites

Thanks for testing Michael, the resulting file does work, however the FPS seems OFF compared to the .bclip generated by mcbiovision for the same mocap clip.

I still can't get any mcacclaim conversion to work at all on windows 7. I have tried backwards and forwards slashes, putting the path in quotes and not putting the path in quotes. This is the same exact batch file that does work with mcbiovision.

Your resulting skeleton is the same as the one generated by the BVH version generated by mcbiovision.exe. The hierarchy is the same as my script code except for a slight naming convention.

I guess there is no point in re-inventing the wheel if the skeleton is the same.

Edited by Atom
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...