Motionbuilder from AutoDesk and OpenCV in Harmony

November 14, 2008 by dasacc22

For anyone ever curious, recently I have delved into the world of motion capture, image recognition and the likes for the past week. The task, build a headset with a mounted usb camera that tracks the eye and moves it accordingly to a model in motionbuilder. Just to get this out there, I know nothing about 3D art, modelling or anything of the likes, including motionbuilder. This would be the first time I’ve ever even used the software.

That aside, I asked someone for a model with a moveable eye and what i got was basically a head with the eyes fixed to a null point. when the point moves, the eyes move. So next was to get the data I had been receiving from opencv to motionbuilder. Just to clarify, currently I am simply using a default haarcascade for face detection so as to track something with motion on the screen. Im taking the center point of the face and using it as proof of concept to move the null. Books are expected Monday so i can delve into tracking the pupil.

The thing about motionbuilder though is its python implementation is hooorrible. As in the worst of the worst. If i were to say its barely usable, i might be hitting the head on the nail for some, but it still feels like a bit of an overstatement. That said, its still great that it has python support so kudos for someone atleast trying to implement it. Im sure its a daunting task for the type of project.

Let me briefly describe the limitations for any that might be unfamiliar. For one, the python version used is 2.4.1 and it comes with pyfbsdk library and nothing else. Considering the lack of documentation for the python module, i would typically resort to something like,

import inspect
for x in inspect.getmembers(FBSystem().Scene):
    print x

but as i said no libraries. So the first thing i did was go to the python site and download 2.4.1. Its not actually listed there but just click on whatever the latest 2.4.x is and then change the revision number to 2.4.1 in your address bar. Download, install, then copy over from your c:\python24\Lib directory all the .py’s to your program\ files\\autodesk\\python\\lib folder. Now you can you do some basic stuff like inspect.getmembers. Secondly, the python console in motionbuilder is horrid. You can type in no more than one line at a time. Syntax error’s have crashed the console. I cant up-arrow to previous commands. The output is limited to whatever the last command was that you ran, aaaaand the text of the output isn’t selectable. So that means no copy and paste of all the methods of whatever after you inspect.getmembers… aaargh! I still have the screenshot on my desktop somewhere …

But fear not! b/c there is telnet. From the python console from within motionbuilder, there is a tab that lets you enable telnet. So you can open up a telnet client and go to addy 127.0.0.1 port 4242 and hopefully you should be presented with a python console. I say hopefully b/c i didn’t have the best of luck the first few times b/c of motionbuilder (and/or my own) quirkiness.

And finally, the real bugger in it all is that if you write a python script that takes some time to run, all of motionbuilder locks until the script is finished. So this means no script thats running in the background waiting to receive data. Instead, this data needs to be sent via the telnet link to motionbuilder. I found some great resources, but mainly ill list this particular one,

http://chrisevans3d.com/tutorials/mbui.htm

He’s got some great sample code for integrating a seperate wxpython script into motionbuilder and breaks down a number of things as well. Unfortunately, his code for making use of telnetlib from within a seperate python instance to issue commands to motionbuilder didn’t work out so hot, which is precisely what prompted me to write about this. The code he had listed seemed a bit cryptic with these read_until’s with params of 0.1 and 0.01, and i didn’t see anything of the sort mentioned in python docs (barely looking of course) so I wrote my class for doing this and saved it in a mbpipe.py and it reads as follows

import telnetlib

class MBPipeline:
    def __init__(self, host="127.0.0.1", port="4242"):
        self.tn = telnetlib.Telnet(host, port)
        self.tn.read_until('>>> ')

    def call(self, command):
        self.tn.write(command + '\n')
        r = self.tn.read_until('>>> ')[:-6]
        try:
            return eval(r)
        except:
            return str(r)

Now from my script where i am doing opencv stuff (or simply from your console) I can do a

from mbpipe import MBPipeline
mb = MBPipeline()
mb.call('FBSystem().Scene.Components[216].PropertyList.Find("Lcl Translation")')

and what it returns is the actual tuple from motionbuilder. In any case where the string from the telnet session can be eval’d, you’ll receive the object. Otherwise just the string.

Just thought I’d share. :D

I may comment later on my experiences with opencv, which so far have been great. QueryFrame, haarcascade, convert to image and push over to pyglet and render to screen my live video (note, opencv has its own windowing and controls which most will probably find useful).

Pandora minus the cruft with XUL

November 6, 2008 by dasacc22

I made this a while back then found out a couple months ago that pandora has a ?cmd=mini getvar that shows a smaller player. So I updated this xul package I made. Im no expert or even novice in xul. Very basic stuff is all I’ve cared to do, but i figured this was a great way to use the service minus the cruft and get it out of my browser. Google Chrome’s save as application is great too if your on windows.

Pandora via XUL can be downloaded from this link: http://dasacc22.googlepages.com/pandora.tar.gz

This should work on any platform with xulrunner. You can run it from linux by

$> xulrunner application.ini

in the folder, similarly on other platforms. Ive also created a sh shortcut in the folder that runs

$> nohup xulrunner application.ini > /dev/null 2>&1 &

to background the service. When starting from the shortcut, click “run” to start it. I have adobe flash complain on startup saying it prevented something dangerious from happening, i guess b/c the flash object is embedded in XUL?? And that it shutdown the offending application. Just click ok and it runs just fine. No need to click settings like it prompts you to (it doesn’t seem to launch settings anyway).

If the ?cmd=mini ever dissappears you can just update the xul package by opening chrome/content/main.xul and replacing the embed object with the one from the site.

IBM Sliding Puzzle Contest

October 23, 2008 by dasacc22

So someone passed onto me a pdf for an IBM sliding puzzle contest. Basically, it consists of a 3 row by 3 column puzzle with one empty space, you know the ones, and you have to write a piece of software that solves for the answer. The instructional pdf suggests that while its acceptable for your answer to be over 20 moves, it should optimally be about 20 or less and be relatively quick.

At first I had no clue about how to do something like this but found the idea very interesting. Four hours later I had a python script that solves for all possible solutions up to how ever many moves you choose it too. Turns out the shortest answer is 12 moves, according to my script. I haven’t validated the 12 move answer, but i did validate a 14 move answer by hand with success (which was actually a twelve move answer with a repeat move making it 14), and i see little reason for the 12 move answer to be wrong.

Anyway, here it is in all its glory

puzzle = ['0', '4', '2', '5', '8', '3', '1', '7', '6']

answers = []

possible_moves = [
    [lambda p: swap(p, 1, 0), lambda p: swap(p, 3, 0)],
    [lambda p: swap(p, 0, 1), lambda p: swap(p, 2, 1), lambda p: swap(p, 4, 1)],
    [lambda p: swap(p, 1, 2), lambda p: swap(p, 5, 2)],
    [lambda p: swap(p, 0, 3), lambda p: swap(p, 4, 3), lambda p: swap(p, 6, 3)],
    [lambda p: swap(p, 1, 4), lambda p: swap(p, 3, 4), lambda p: swap(p, 5, 4), lambda p: swap(p, 7, 4)],
    [lambda p: swap(p, 2, 5), lambda p: swap(p, 4, 5), lambda p: swap(p, 8, 5)],
    [lambda p: swap(p, 3, 6), lambda p: swap(p, 7, 6)],
    [lambda p: swap(p, 4, 7), lambda p: swap(p, 6, 7), lambda p: swap(p, 8, 7)],
    [lambda p: swap(p, 5, 8), lambda p: swap(p, 7, 8)]
]

def serialize(p):
    return ''.join(p)

def swap(L, m, t):
    if L[t] is '0':
        L[t] = L[m]
        L[m] = '0'
        return serialize(L)

def no_dups(S):
    if len(S.split("-")) != len(set(S.split("-"))):
        return False
    else:
        return True

def search(tree, index=0):
    if index < 12:
        for each in tree:
            for i, val in enumerate(list(each.split("-")[-1])):
                if val is '0':
                    generation = []
                    for move in possible_moves[i]:
                        result = each+"-"+move(list(each.split("-")[-1]))
                        if "123456780" in result:
                            answers.append(result)
                        elif no_dups(result):
                            generation.append(result)
                    search(generation, index+1)

search(["-"+serialize(puzzle)])
shortest_answer = sorted(answers)[0]
print "=========="
print "Shortest Answer: " + str(len(shortest_answer.split("-"))-2) + " Moves"
print "++++++++++"
print shortest_answer

Edit: I just thought i would add,
yeah so the thing that was the turning point for solving this thing was how you look at solving the puzzle. Ive always looked at those puzzles as, ok what can i move into the empty space and rotate these pieces around and this and that but thats totally the wrong viewpoint. The way to visualize solving the answer is to look at the empty space as your focus and to move the empty space around, pushing the other numbers around into place. The puzzle suddenly becomes eaiser to solve by hand on your own and thats how the program solves for the answer too, by moving the empty space around, not trying to calculate how to get a particular number to its destination

Google Chrome, Os’, and Web Development

September 13, 2008 by dasacc22

Ok so everyone, their mama, and her pet hamster have written an article about google chrome. Ive also read an interesting article that some-what theorizes on a google os based on chrome in the distant future. Only interesting b/c of what I have been planning to do.

First off, I read about people complaining over initial memory consumption of Google Chrome. I dont know why but I feel a need to state my opinion on the matter. What I care about most is a responsive system and chrome does that, short and simple. If i were to liken chrome to something id say starting an instance of google chrome is like typing

$> ls

at a command prompt. Its freaggin fast. Period. Running chrome nay interferes with most anything else i do. That is using it on a core 2 duo laptop with 2 gigs of ram and a amd64 desktop with 1 gig of ram. Just a quick statement of facts. Anyway, im not really interested in the distant future, what i AM interested in is the possibility of now. Honestly with very few modifications i would use chrome as a full shell replacement, on both linux and windows. Here’s my wish list,

  1. A better file manager
  2. the ability to launch local programs from the address bar
Ok so thats all i have for the most part. Frequently used programs, I could simply bookmark. Launching them from the addy bar would be very similar to what Ive always enjoyed doing on linux using the likes of katapult in the past and gnome-do nowadays (which does alot more interesting stuff). Ubiquity is a mozilla project that has a similarly driven concept of a type-into pop console to accomplish tasks (a little more complex than just launching a program). To accomplish this my local computer would need to be indexed or the standard entries for programs installed would need to be, but id prefer the first so i can search my computer for a file
local:[search-term]
anyone? I think alot of this couldn’t really be accomplished without patching some code (mostly the use of the addy bar).
As for the file manager, the builtin file manager is of the likes of firefox. just a point and click and launch scheme. An actual robust file system could be written as a local webapp. Chrome is like a staging ground for writing a new breed of applications as I see it, I actually just wrote something today to display an index of my movie collection and made a shortcut with chrome, works beautifully. Yes it runs in firefox and anything else for that matter, but would i ever use it in such? likely not b/c when i want to watch a movie, i want to click an icon and i WANT it NOW. I dont have all day to wait for something to start up. Well I do, but its a real buzz-killer.
Ok enough ranting. I am looking at chrome as a means to develop desktop centric applications (one of which is a music app based on the likes of the sndobj library that would allow multiple people to mix at the same time) and I think the best first place to start is to write a file manager and be able to bookmark applications i use and also index my local drive so i can search it. the urls wont be the prettiest with accessing 127. but it will do for now. Then on X startup or on windows startup, chrome is launched instead of gnome or kde or fluxbox or my beloved openbox which has always come to save my day in one way or another, or explorer.exe
Those are my ideas, I will be starting some of them soon and developing in python/cherrypy (unless theres due cause for something else) and then looking into investigating how to create a windows service. If anyones interested in collaborating, feel free to contact me.

Ableton Live, Linux, and Wine

August 27, 2008 by dasacc22

Well, a title doesn’t get much more concise then that I guess. For anyone ever interested in running ableton live in a linux platform of their choice via wine, it has been disheartening to say the least. Mainly due to a direct draw issue thats been around for a while. Well a couple days ago the issue was resolved with wine 1.1.3 and ableton is now very usable! I installed Ableton Live 6 on my laptop after getting wind of the possible fix, started the app and immediately noticed it was copying files to the library! Normally ableton dumps the dialog here, doesn’t copy anything, and presents you with an empty “this is an evaluation” blah blah blah empty dialog where i have to click an invisible button. Well long story short, its working and working very well.

There are a couple of issues ive noted thus far that i need to open bugs for or find bugs already opened for. One, when i arm a track for recording in live, it prompts me with an error message saying it can’t open such and such a file for writing. Also while working with a simple project of dragging in some songs and doing some loops everything went fine, with a more complex project of dragging in loops, samples, and other fun stuff and throwing in some midi sequences and effects and more fun stuff, well.. everything went great! and then i saved it, and then later i went to open it and it couldn’t find a file related to the project, but it was looking somewhere i wouldn’t normally expect ableton to look (i dont think..). If i recall correctly, im pretty sure ableton live records loops and junk into a folder of the name of the project, but instead it was looking for a file from my ~/Samples/Recorded/ folder. I dunno maybe thats right, but that folder is empty and the file its asking for i cannot slocate on my hard drive so i dunno ..

Once these quirky file issues go aside and i can save complex projects without any hitches, id probably give it a platinum status b/c it runs damn smooth.

Edit: Just to note, im using Ubuntu Hardy 8.04 and the repo’s from winehq.org

Project Eulier and XSLT

August 22, 2008 by dasacc22

Well when i came across Project Euler and saw the first problem, i naturally did what anyone in their right mind would do … solve it using xslt

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="text"/>
    <xsl:variable name="iterations" select="1000"/>

    <xsl:template name="sum_multiples">
        <xsl:param name="i">0</xsl:param>
        <xsl:param name="incrementer"></xsl:param>
        <xsl:param name="result">0</xsl:param>

        <xsl:choose>
            <xsl:when test="$i < $iterations">
                <xsl:call-template name="sum_multiples">
                    <xsl:with-param name="i" select="$i + $incrementer"/>
                    <xsl:with-param name="result" select="$result + $i"/>
                    <xsl:with-param name="incrementer" select="$incrementer"/>
                </xsl:call-template>
            </xsl:when>

            <xsl:otherwise>
                <xsl:value-of select="$result"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template match="/">
    <xsl:param name="three">
        <xsl:call-template name="sum_multiples">
            <xsl:with-param name="incrementer">3</xsl:with-param>
        </xsl:call-template>
    </xsl:param>
    <xsl:param name="five">
        <xsl:call-template name="sum_multiples">
            <xsl:with-param name="incrementer">5</xsl:with-param>
        </xsl:call-template>
    </xsl:param>
    <xsl:param name="dups">
        <xsl:call-template name="sum_multiples">
            <xsl:with-param name="incrementer">15</xsl:with-param>
        </xsl:call-template>
    </xsl:param>
    <xsl:value-of select="$three + $five - $dups"/>
    </xsl:template>
</xsl:stylesheet>

the same thing in python could go something like

three = [x for x in range(1000) if x % 3 is 0]
five = [x for x in range(1000) if x % 5 is 0]
print sum(set(three + five))

Edit: Im still learning python, well after posting this and on the ride home i realized i could define my list with one line.

print sum([x for x in range(1000) if x % 3 is 0 or x % 5 is 0])

CherryPy, SQLAlchemy, & URI to SQL method

August 14, 2008 by dasacc22

Ok some basic info first. I have sqlalchemy objects defined. I use cherrypy and have been writing methods for doing queries to my tables in the various means ive learned how over the past couple years. that is to say, /show_actor?id=4&production_id=2

I keep looking at this code and thinking, this just isn’t right, i was even recently looking at the turbogears2 wiki example (getting ideas for decorator usage and such) and seeing similar code, Again thinking, this just isn’t right. Then somewhere between thinking and writing some code, i ended up halfway through the following and dont know how i got there. Basically its a uri to sql method. I make use of cherrypy’s default method to traverse the uri that gets passed as *args … well traverse it as in translate it into traversing my sql tables. Its all very short and concise i think.

I got the first draft of my uri to sql done, it goes something like this,

@expose
def default(self, *args, **kwargs):
    for n in args:
        if n in globals():
            query=Session.query(globals()[n])
    for k,v in make_filters(args):
        query=query.filter(globals()[k].name==v)
    yield json(query.all())

and uses this outside function

def make_filters(uri):
    for n in range(len(uri)):
        if not n%2 and n+1 < len(uri):
            yield [uri[n], uri[n+1]]

Basically now, the args passed to my default method let me traverse my sql tables like it was a directory tree. So you might say, i can open my folder Productions and find “aa” in there, and then i can open my Capture data related to “aa” and find MC001, or go to my Actor folder and get all my actor files such as “Jon” all accessible via

/show/Production/aa/Capture/MC001
or
/show/Production/aa/Actor/Jon

, then using keyword arguments like

/show/Production/aa/Actor/Jon?type=json

i can specify special conditions or whatever and ive totally eliminated this really lame reiterative code of multiple methods for calling different data like /show_actor?prod_id=1, or calls with multiple if statements for handling what im asking for and its totally recursive no matter how deeply nested my tables are.

Im sure theres tons of problems and some shortsightedness here, and im still a relative newb to python (going on 6 months of use now i think) but anyway, i really dig this. Now I can start coding my ajax app to grab this or grab that and as I define tables through sqlalchemy, i will automatically be able to access my data.

Some things I need/want to do now is to provide custom filter options via keyword arguments and some sort of deliver data as type .. w/e, json, xml, yaml, yadda yadda yadda

Also to note, i call a json method in my code, thats part of a (probably overly complicated) generator i wrote that takes an sqlalchemy result object and produces a usable dict that gets dumped to json. It needs some extra work I think to be more useful but does what i need it to for now. Heres the code for that

def gmap(obj):
    for item in obj.__dict__.items():
        if item[0][0] is '_':
            continue
        if isinstance(item[1], unicode):
            yield [item[0], str(item[1])]
        else:
            yield item

def json(obj):
    if isinstance(obj, list):
        return simplejson.dumps( map(lambda x: dict(x), map(lambda x: gmap(x), obj)) )
    else:
        return simplejson.dumps( dict(gmap(obj)) )

Thanks to google’s advanced python talk on video.google for breaking down some key concepts on generators and such.

WordPress, Blogspot

August 11, 2008 by dasacc22

Ive only recently started blogging and there were two choices that came to mind. WordPress, which ive heard about and a rather famous blogging util, and blogger, which i once looked at many years ago and also integrates with my other google services. I figured i would give both a go and after a few hours of accumulative use, I decided i liked blogger best as i accomplished what i wanted more quickly. Unfortunately i noticed that nothing i posted in blogger showed up as a google search result, whereas my post in wordpress would show up as a first result, when typing in two keywords, overnight! Since my utmost main concern is access to my meager blog, I will be discontinuing my use of blogger but leaving it up incase it was indexed by some other service. Here is a Link to both blogs

http://dasacc22.wordpress.com
http://dasacc22.blogspot.com

CherryPy, SndObj, and SVG

August 11, 2008 by dasacc22

Ok so sometime back when i first started tinkering with pysndobj, i was toying with some ideas for a user interface. Primarily i come from a web background and i decided to toy with the idea of a web frontend to a sndobj thread(s) that would write to an output stream that multiple people could connect to to work collaboratively together semi-realtime. Yeah, it sounds a bit amibitious but anyway I decided to take the time to toy around with SVG as well, which ive never worked with, to see what I might come up with.

Ultimately, I got this, cpsndobj.

This is the source code to my simple cherrypy/sndobj/svg demo. Basically I have an svg knob that i made that you can manipulate by clicking and dragging the mouse down on it. Unfortunately with a browser you cannot lock the mouse down in place so it can seem a bit odd if you reach the edge of your screen. But anyways, tar -xzf this bad boy and ./python cpsndobj.py and you will find a local webserver at http://127.0.0.1:8080/. Of course you need to sudo easy_install-2.5 cherrypy if you wanna use it. The rest is javascript(jquery if i remember correctly(been a while since i looked(i think this is why i like python, avoiding all these tags(woot!)))). And I believe I have it set to connect to a jack server so you’ll want to change it to SndRTIO if you want otherwise or start your jack first. After you get it up and running, visit the local address /on to turn on the modulating frequency the visit the root of the site to display the svg knob. Now click and drag it. and youll see it do its thing. Things to note, if your using internet explorer, you’ll need to install the adobe svg viewer (though ive not tested it in IE). Here in firefox land, we apparently like things to run slow so if youd like to experience a smooth svg knob .. experience, then get opera installed and notice the difference.

Uh but yet, i dont use opera past playing with an svg knob and playing flash movies that dont lock up my browser in linux.

One might say, ultimately i basically have a tinker toy thats ok (woot!).

–Edit: I suddenly realized the fallacy of my “i like python” statement above, python still has paranthesis.. duh..

SndObj, Jack, and Inputs

August 9, 2008 by dasacc22

Ok so I have been tinkering with pysndobj on and off for a while. One thing I have been wanting to do is get it setup where i have a thread using SndJackIO and doing a line in from my edirol ua-25 usb soundcard with my guitar. I couldn’t find any documentation on how to do it with SndJackIO for a while, though there was plenty for SndRTIO. But then i noticed a reference to core audio on mac and doing inputs. Effectively, there is a single SndJackIO for both input and output. So when instantiating for such just do a

outp = sndobj.SndJackIO(“MyName”)
inp = outp

Anyway, here it is in all its glory

import sndobj

jack = sndobj.SndJackIO(‘test5′)
inp = jack

snd = sndobj.SndIn(inp, 1)
cmb = sndobj.Comb(0.001, 0.001, snd)

jack.SetOutput(1, cmb)

thread = sndobj.SndThread()
thread.AddObj(snd)
thread.AddObj(cmb)
thread.AddObj(inp, sndobj.SNDIO_IN)
thread.AddObj(jack, sndobj.SNDIO_OUT)

thread.ProcOn()

–Edit: Above, cmb is a filter that is not needed. You can simply SetOutput to snd instead of cmb and bypass that.