« June 2009 | Main | September 2009 »

July 19, 2009


I find that for some of the books that I've read, mostly when it comes to fiction, a complete entry seems a bit much. My goal of writing up these entries has always been about capturing notes, since I'd say the majority of what I read is non-fiction. While I have reviewed fiction books I've read in the past, most of the time a short summary and rating would be better to capture my feelings should someone ask me what I thought about a book I'd read some time ago. As such a few months ago I signed up for Goodreads. I'm using it to its full potential but have found it useful.

Tags: books

Billions & Billions

Carl Sagan's "Billions & Billions" is a collection of essays covering a wide variety of topics. The essays are grouped into three parts: "The Power and Beauty of Quantification", "What Are Conservatives Conserving?", and "Where Hearts and Minds Collide." I started reading the book some time ago and interspersed it with others so my recollection of the book as a whole is a little fuzzy. Some of the essays did feel dated as the facts and conditions presented have clearly changed, mostly for the better, since originally written.

I had originally picked up the book after reading an excerpt from the essay entitled "Abortion: Is It Possible to Be Both 'Pro-Life' and 'Pro-Choice'?" This along with most of the other essays in part three is a reason to read the book. The reasoned approach and insight brought to many of the subjects touched upon gives ample evidence to the impact he had on so many lives.

Tags: books life

July 5, 2009

Image Rotation with Pixel Bender

Unlike my previous experiments with Pixel Bender, today I set out to implement a basic image manipulation routine, image rotation. While Flash natively provides the ability to rotate a DisplayObject that doesn't help if you want to combine multiple Pixel Bender filters that should use the rotated image as the source image. Turns out rotating an image in Pixel Bender was a little harder than I thought, but I ended up with a nice solution.

Rotation is a simple image manipulation that can take advantage of transformation matrixes like you can create in Flash. The normal 2D rotation transformation matrix looks like this, given d is the angle of rotation, x and y are the original pixel location, and x' and y' are the new pixel location:

 cos(d)-sin(d)  *  x  =  x' 
sin(d)cos(d) y y'

The problem with this rotation (and the standard DisplayObject.rotation property) is that the rotation is performed relative to the origin. In this case it is (0, 0) or the upper left corner of the image. To address this problem we switch to 3x3 transformation matrixes and first translate the image to define a new origin (like changing the registration point on a MovieClip) before performing the rotation. By combining a translation, rotation, and reverse translation we can rotate the image around an arbitrary point but still have the result appear anchored in the upper left. The full matrix transform then looks like this, given a and b are the translation in x and y respectively:

 10a  *  cos(d)-sin(d)0  *  10-a  *  x  =  x' 
01b sin(d)cos(d)0 01-b y y'
001 001 001 1 1

Now we are getting somewhere. The next problem is that we don't know what x and y are. We do know x' and y' as that is what outCoord() gives us. In order to use this transformation matrix in Pixel Bender we need to solve for x and y. It turns out the matrixes reduce to a linear system of equations. Thankfully I have an old symbolic solver kicking around that did the dirty work. First simplify the transform matrixes:

 (x - a)*cos(d) + (b - y)*sin(d) + a  =  x' 
(y - b)*cos(d) + (x - a)*sin(d) + b y'
1 1

That leaves us with two equations and two unknowns. Using a linear equation solver, we end up with:

x = (x' - a)*cos(d) + (y' - b)*sin(d) + a
y = (y' - b)*cos(d) + (a - x')*sin(d) + b

The translation into a Pixel Bender kernel is straight forward from here. Using a parameter called origin I've replaced a and b, outCoord() replaced x' and y', and a parameter called rotation (specified in degrees) is used for d.

float2 dstCoord = outCoord();
float angle = radians(rotation);
float cosAngle = cos(angle);
float sinAngle = sin(angle);
float x = (dstCoord.x - origin.x) * cosAngle + (dstCoord.y - origin.y) * sinAngle + origin.x;
float y = (dstCoord.y - origin.y) * cosAngle + (origin.x - dstCoord.x) * sinAngle + origin.y;
dst = sampleNearest(src, float2(x, y));

After the kernel was created and exported for use in Flash I slapped together a simple test application to play with it (view source enabled). Note: if you use the kernel in the Pixel Bender toolkit you will want to setup a minValue and maxValue for the origin parameter based on your test image size, otherwise you can't meaningfully adjust it.

If you played with the application you probably noticed the extension slider. By default a shader filter in Flash will map the source image to an equally sized output image. Increasing the various extension properties of ShaderFilter you can create an output image larger than the input which avoids any output image clipping.

I suspect if Pixel Bender graphs were supported in Flash you could easily setup a series of filters that do the image translation and rotation separately instead of combining them all into a single matrix. It might even be easy enough to do that with an array of filters but this isn't something I've played with much.

Tags: flex graphics image pixelbender