<?xml version="1.0" encoding="iso-8859-1"?>
<rss version="2.0" 
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
    xmlns:admin="http://webns.net/mvcb/"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:content="http://purl.org/rss/1.0/modules/content/">

  <channel>
    <title>Quasimondo</title>
    <link>http://www.quasimondo.com/</link>
    <description>The world of Flash according to Mario Klingemann. 
quasi: Having a likeness to something; resembling
mondo (ital.): World</description>
    <dc:language>en-us</dc:language>
    <dc:creator>mario@quasimondo.com</dc:creator>
    <dc:rights>Copyright 2011</dc:rights>
    <dc:date>2011-01-31T19:45:21+01:00</dc:date>
    <admin:generatorAgent rdf:resource="http://www.movabletype.org/?v=2.661" />
    <admin:errorReportsTo rdf:resource="mailto:mario@quasimondo.com"/>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <sy:updateBase>2000-01-01T12:00+00:00</sy:updateBase>

    <item>
      <title>Fast Radial Blur</title>
      <link>http://www.quasimondo.com/archives/000697.php</link>
      <description>Given my track record of last year - a total of 4 blog posts - I do not have very high hopes that I&apos;ll do much better in 2011, but since I decided not to speak on any conferences this year I might have a little bit more time to share my experiments here instead of on stages only. I don&apos;t want to over-promise, but I hope that over the next weeks I&apos;ll find the time to finally explain and release the source codes for several projects that I have exclusively shown in my talks over the last years. Of</description>
      <guid isPermaLink="false">697@http://www.quasimondo.com/</guid>
      <content:encoded><![CDATA[<p>Given my track record of last year - a total of 4 blog posts - I do not have very high hopes that I'll do much better in 2011, but since I decided not to speak on any conferences this year I might have a little bit more time to share my experiments here instead of on stages only. I don't want to over-promise, but I hope that over the next weeks I'll find the time to finally explain and release the source codes for several projects that I have exclusively shown in my talks over the last years. Of course some of them have in the time since I've presented them been independently discovered by others, but I think I've still got a few aces in my pockets which are worth sharing.</p>

<p>I'll start with a simple visual effect: Radial Blur, which can give images the 200mph speed zoom look. In a naive approach you could achieve this effect by replacing every pixel with a weighted average of all neighboring pixels within the blur radius that lie on a line that goes through the center of zoom and the pixel itself. The problem with this method is that it is very slow since it would require many calculations to collect each neighbor and since the angle is different at every pixel there is not much room for other optimizations, like reusing already read pixels, which is key for every fast blur algorithm.</p>

<p>But using a neat trick that I remembered from my early Photoshop days allows to speed up this process a lot. Here is a demo:</p>

<div id="radialBlurBox"></div>
<script type="text/javascript">
   var fo = new FlashObject("http://www.quasimondo.com/examples/radial_blur/RadialBlurDemo.swf", "radialBlurBox", "400", "610", "10", "#ffffff");
   fo.write("radialBlurBox");
</script>

<p>The way this works is by converting the pixels from cartesian mapping (where the axes are x & y) to polar mapping (with axes angle & distance to the center) which arranges them in a way that all the neighbors that need to be averaged arrange themselves nicely in a straight line. This allows us to use a simple native Blur filter to quickly calculate the average. Depending if the blur is in x direction or y direction the final result will either be a Radial Blur (the well-known zoom effect) or a Circular Blur (which looks like a fast spinning wheel). The final step is to convert the pixels back from polar mapping to cartesian.</p>

<p><a href="http://www.quasimondo.com/examples/radial_blur/RadialBlurDemo2.html">Open this link in a new window</a> to see the process in a step by step demo.</p>

<p>By default the mapping uses the center of the image as the center of the polar coordinate system. This will result the center of the zoom to also be in the center of the image. So what if we want the zoom center to be at a different location? There are two ways of going about this - unfortunately I did not manage the faster way to work correctly yet which would be to simply use that center in the mapping algorithm. For some reason I have not found the right equations which work both ways. So for now I am using the slower method which does always work:</p>

<p>The trick here is to first make the image bigger by padding the borders so that the desired center of the zoom is temporarily the center of the image. So if you want the zoom center to be in the upper half of the image you add as many border pixels to the top that the chosen spot becomes the new vertical center. Then follows the cartesian-to-polar transform, the linar blur and the polar-to-cartesian mapping. The final step is to crop the image back to its original size by removing the previously added top pixels.</p>

<p>Another issue are artifacts that show due to the mapping. The problem is that since all the pixels that lie on a circle with a certain radius are mapped to a straight line, once the circumference of that circle gets bigger than the width of the mapped image pixel information gets lost. To fix this it is required to make the bitmap that holds the polar map as wide as the biggest possible circumference. Unfortunately that is not always possible since the temporary bitmaps could get pretty huge this way. The good news is that since we are blurring those artifacts will mostly not become too visible. Only for small blurs it improves the quality when using a bigger resolution for the cartesian image map.</p>

<p>You can find the source code for the RadialBlur class and the required pixel bender kernels as usual inside <a href="http://code.google.com/p/quasimondolibs/source/browse/#svn%2Ftrunk%2Fquasimondolibs%2Fcom%2Fquasimondo%2Fbitmapdata">QuasimondoLibs</a></p>]]></content:encoded>
      <dc:subject>Relevation</dc:subject>
      <dc:date>2011-01-31T19:45:21+01:00</dc:date>
    </item>
    <item>
      <title>Converting RGB to HSL differently</title>
      <link>http://www.quasimondo.com/archives/000696.php</link>
      <description>Sometimes when working with bitmaps you might find the need to work in a HSL (Hue, Saturation, Luminance) mode, for example when trying to detect skintones in an image. So what you do is probably to use the classic formula from Wikipedia that uses min/max and a whole lot of ifs: http://en.wikipedia.org/wiki/HSL_and_HSV Well, here is a little alternative method: whilst working with the YUV colorspace I figured that since Y contains all the luminance information, the U + V channels must thus contain the hue and saturation. And it turns out that indeed when looking at u and v as</description>
      <guid isPermaLink="false">696@http://www.quasimondo.com/</guid>
      <content:encoded><![CDATA[<p>Sometimes when working with bitmaps you might find the need to work in a HSL (Hue, Saturation, Luminance) mode, for example when trying to detect skintones in an image. So what you do is probably to use the classic formula from Wikipedia that uses min/max and a whole lot of ifs: <a href="http://en.wikipedia.org/wiki/HSL_and_HSV#Converting_to_RGB">http://en.wikipedia.org/wiki/HSL_and_HSV</a></p>

<p>Well, here is a little alternative method: whilst working with the YUV colorspace I figured that since Y contains all the luminance information, the U + V channels must thus contain the hue and saturation. And it turns out that indeed when looking at u and v as the coordinates of a vector, its angle will represent the hue and its length will be the saturation.</p>

<p>So a formula that does not need any min/max and ifs to convert rgb to hsl looks like this:</p>

<pre>
// r,b and b are assumed to be in the range 0...1
luminance =  r * 0.299 + g * 0.587 + b * 0.114;
u = - r * 0.1471376975169300226 - g * 0.2888623024830699774 + b * 0.436;
v =   r * 0.615 - g * 0.514985734664764622 - b * 0.100014265335235378;
hue = atan( v, u );
saturation = Math.sqrt( u*u + v*v );</pre>

<p>In this case hue will be between -Pi and Pi and saturation will be between 0 and 1/sqrt(2), so you might want to multiply the saturation by sqrt(2) to get it in a range between 0 and 1.</p>

<p>Of course this also works the other way round - hsl to rgb looks like this:</p>

<pre>// hue is an angle in radians (-Pi...Pi)
// for saturation the range 0...1/sqrt(2) equals 0% ... 100%
// luminance is in the range 0...1
u = cos( hue ) * saturation;
v = sin( hue ) * saturation;
r =  luminance  + 1.139837398373983740  * v;
g = luminance  - 0.3946517043589703515  * u - 0.5805986066674976801 * v;
b = luminance + 2.03211091743119266 * u;</pre>

<p>And here is a demo of a Pixel Bender kernel that allows you to adjust hue, saturation and brightness of a bitmap using this technique: <a href="http://www.quasimondo.com/examples/hsldemo/">HSL Adjust Demo</a>, Source: <a href="http://www.quasimondo.com/scrapyard/hsladjust.zip">hsladjust.zip</a></p>

<p>[Edit]As it was correctly noticed in the comments, the values that this method returns are not the HSL values that you get when you are using the classic formula. Nevertheless I think that this method has its uses, for example if you want to quickly create color schemes or if you are using it like in the demo to change the hue/saturation/Luminance of a photo.[/Edit]</p>

<p>[Edit]I updated the factors in the matrix one more time with values I found in the Wikipedia YUV discussion page. Those look better to me at least.[edit]<br />
</p>]]></content:encoded>
      <dc:subject>Information</dc:subject>
      <dc:date>2010-05-24T14:21:25+01:00</dc:date>
    </item>
    <item>
      <title>Pibeca - Pixel Bender for Canvas</title>
      <link>http://www.quasimondo.com/archives/000695.php</link>
      <description>Let me say this first - I am not a fan of Canvas and tinkering around with this project I realized why I prefer programming in AS3 so much more to Javascript: my goodness - this language is a dirty mess, how can anyone get anything done with it? But for fairness sake - I guess there must be some pro development tools out there which I don&apos;t know about and my using of notepad might not be the true JS developer experience. So even though I think that compared to the capabilities of the Flash Player Canvas still lacks</description>
      <guid isPermaLink="false">695@http://www.quasimondo.com/</guid>
      <content:encoded><![CDATA[<p>Let me say this first - I am not a fan of Canvas and tinkering around with this project I realized why I prefer programming in AS3 so much more to Javascript: my goodness - this language is a dirty mess, how can anyone get anything done with it? But for fairness sake - I guess there must be some pro development tools out there which I don't know about and my using of notepad might not be the true JS developer experience.</p>

<p>So even though I think that compared to the capabilities of the Flash Player Canvas still lacks a lot, it cannot be ignored since it is now available on most major browsers. As a Flasher I find it especially entertaining to watch how history keeps repeating - browsing Canvas community blogs is like time traveling: plasma effects, l-systems, bitmap manipulations, physics engines, vector drawing experiments, emulators - in short everything that we were excited and enthusiastic about years ago is now being rediscovered, ported or reinvented on Canvas, just like we rediscovered, ported or reinvented things that had been done in Java or C years before Flash. But hey, I actually envy these guys - there is nothing more rewarding and creativity boosting than trying to push a limited platform to the maximum.</p>

<p>So since we are not so different after all, here's a little contribution to world platform peace - Pibeca allows you to use pixel shaders on Canvas Bitmaps. It achieves that by using Adobe® <a href="http://www.adobe.com/devnet/pixelbender/">Pixel Bender™ filters</a> which can be written with the freely available Pixel Bender™ toolkit. Those kernels are very small programs who's only purpose in life it is to push pixels around very fast.</p>

<p>So here is an proof of concept which should work on any browser that supports canvas:</p>

<p><iframe src="http://www.quasimondo.com/PixelBenderForCanvas/pibeca_demo1.html" style="border:0px;padding:0px;" width=520 height=430></iframe></p>

<p>Under the hood a canvas bitmap and a kernel url is being sent to an invisible SWF which loads the Pixel Bender filter kernel, processes the bitmap and then sends it back to JavaScript which passes it back to a canvas. That's all. Given that I have to encode the bitmap to a string in order to get it to the other side and back the speed is pretty okay I think.</p>

<p>I wanted to get this prototype out quickly, so until I have prepared some docs and more examples those who are adventurous can already have a look at <a href="http://code.google.com/p/quasimondolibs/source/browse/#svn/trunk/PixelBenderForCanvas">QuasimondoLibs</a> and check out the Actionscript and Javascript source code for this demo. Pibeca is released under MIT License.</p>]]></content:encoded>
      <dc:subject>Relevation</dc:subject>
      <dc:date>2010-01-14T12:59:59+01:00</dc:date>
    </item>
    <item>
      <title>Galactose - Emergent Behavior of Particles</title>
      <link>http://www.quasimondo.com/archives/000694.php</link>
      <description>I have added a new experiment called Galactose to my Incubator. The motion of a particle field is controlled by the shape of the random clusters they form among each other. The orientation of the clusters control each particle&apos;s further motion which leads to all kind of interesting feedback effects and emergent patterns. The core algorithm which calculates the overall alignment and orientation of the clusters is written in Pixel Bender.</description>
      <guid isPermaLink="false">694@http://www.quasimondo.com/</guid>
      <content:encoded><![CDATA[<p>I have added a new experiment called <a href="http://incubator.quasimondo.com/flash/galactose.php">Galactose</a> to my <a href="http://incubator.quasimondo.com">Incubator</a>. </p>

<p><a href="http://incubator.quasimondo.com/flash/galactose.php"><img alt="galactose.jpg" src="http://www.quasimondo.com/archives/galactose.jpg" width="484" height="325" border="0" /></a></p>

<p>The motion of a particle field is controlled by the shape of the random clusters they form among each other. The orientation of the clusters control each particle's further motion which leads to all kind of interesting feedback effects and emergent patterns. The core algorithm which calculates the overall alignment and orientation of the clusters is written in Pixel Bender.</p>]]></content:encoded>
      <dc:subject>Incubation</dc:subject>
      <dc:date>2010-01-10T20:04:02+01:00</dc:date>
    </item>
    <item>
      <title>Bloom</title>
      <link>http://www.quasimondo.com/archives/000693.php</link>
      <description></description>
      <guid isPermaLink="false">693@http://www.quasimondo.com/</guid>
      <content:encoded><![CDATA[<p><a href="http://www.letitbloom.com/#mario"><img alt="Bloom" src="http://www.quasimondo.com/archives/bloom_teaser.jpg" width="450" height="271" border="0" /></a><br />
</p>]]></content:encoded>
      <dc:subject>Relevation</dc:subject>
      <dc:date>2009-12-02T09:22:57+01:00</dc:date>
    </item>
    <item>
      <title>Flash Median Filter</title>
      <link>http://www.quasimondo.com/archives/000692.php</link>
      <description>As you might have read in Eugene&apos;s blog, he, Nicoptere and me were having a little competition who could come up with the fastest implementation of a median filter. Median filters have the unpleasant property that they can not be as easily optimized as for example blur filters. The median filter is also one of those types of filters that are not very well suited for an implementation in Pixel Bender due to the way Pixel Bender processes images (except maybe for a trivial 3x3 median). What a median filter does is to take all the pixels within a certain</description>
      <guid isPermaLink="false">692@http://www.quasimondo.com/</guid>
      <content:encoded><![CDATA[<p>As you might have read in <a href="http://blog.inspirit.ru/?p=351">Eugene's blog</a>, he, <a href="http://en.nicoptere.net/">Nicoptere</a> and me were having a little competition who could come up with the fastest implementation of a median filter. Median filters have the unpleasant property that they can not be as easily optimized as for example blur filters. The median filter is also one of those types of filters that are not very well suited for an implementation in Pixel Bender due to the way Pixel Bender processes images (except maybe for a trivial 3x3 median).</p>

<p>What a median filter does is to take all the pixels within a certain radius around a pixel, sort them numerically ( channel by channel) and then return the color that ends up in the middle of the sorted list. You can imagine that doing this for every pixel in an image is quite a processing effort. Fortunately people much smarter than me have found ways to speed this up considerably. The paper I had stumbled across sometimes in the past was <a href="http://nomis80.org/ctmf.html">this one</a> by Simon Perreault and Patrick Hebert. And whilst the authors even provided the C source for this filter I did not bother to look at it since I thought that things that are fast in C are not necessarily fast in Flash and decided to roll my own version of the algorithm based on maintaining the histograms and the kernel in the form of sorted linked lists. I figured that this would speed up the process of joining and separating the histograms since I could use a kind of "zipper" technique to do that. To my astonishment the first tests were extremely slow - even though I tested the speed with a release version (testing this with the debug version is about 10 times slower).</p>

<p>The breakthrough came with a tip <a href="http://www.unitzeroone.com/blog">Ralph Hauwert</a> gave me: whenever you create a linked list class in Actionscript make sure that you use the "final" keyword for it. Until then I had thought that this keyword acted more as a decorative element without real impact. Well, I'm happy that I was wrong since the speedup in this case was extraordinary.</p>

<p>When you compare <a href="http://www.quasimondo.com/examples/median/Median.html">my implementation</a> with <a href="http://blog.inspirit.ru/?p=351">Eugene's</a> note that a kernel size of 7x7 in his example is the equivalent of a radius of 3 in mine (3+3+1=7), 17x17 is a radius of 8 (8+8+1=17). As far as I can see my version is faster until a radius of 7 but after that his version surpasses mine. I have to study his code now to see how he has solved it.</p>

<p>Since the median filter still takes considerable rendering time I added a "asynchronous" switch which allows to render the effect in background without stalling the rest of the application. Of course this will slow down the whole rendering process.</p>

<p>Here is my <a href="http://www.quasimondo.com/examples/median/Median.html">Median example</a><br />
<a href="http://www.quasimondo.com/examples/median/srcview/">sourcecode</a> and <a href="http://www.quasimondo.com/examples/median/srcview/Median.zip">zipped sources</a></p>]]></content:encoded>
      <dc:subject>Manipulation</dc:subject>
      <dc:date>2009-10-20T13:05:55+01:00</dc:date>
    </item>
    <item>
      <title>Flash Player Memory Management</title>
      <link>http://www.quasimondo.com/archives/000691.php</link>
      <description>Whilst working with some huge bitmaps for Aviary I had to face the undeniable fact that huge bitmaps are memory hogs and that the memory that is made available to the Flash Player by the browser is not unlimited. Actually it is quite limited - on my Vista machine that has 4GB of RAM I max out the memory at ca 1.5GB in FireFox 3.5.2. - that theoretically allows to keep 25 of the 64MB 4095*4095 bitmaps in memory which are the maximum sized bitmaps that Flash Player 10 allows for. In practice it turns out though that this value</description>
      <guid isPermaLink="false">691@http://www.quasimondo.com/</guid>
      <content:encoded><![CDATA[<p>Whilst working with some huge bitmaps for <a href="http://aviary.com">Aviary</a> I had to face the undeniable fact that huge bitmaps are memory hogs and that the memory that is made available to the Flash Player by the browser is not unlimited. Actually it is quite limited - on my Vista machine that has 4GB of RAM I max out the memory at ca 1.5GB in FireFox 3.5.2. - that theoretically allows to keep 25 of the 64MB 4095*4095 bitmaps in memory which are the maximum sized bitmaps that Flash Player 10 allows for. </p>

<p>In practice it turns out though that this value is much smaller, the reason for it I learned from <a href="http://blog.joa-ebert.com">Joa</a>: memory fragmentation does have a big impact on how big the chunks of memory can be that you can allocate at a certain time. So while you might be able to create 4 bitmaps of 10 MB each you might not be able to create a single one of 40MB. </p>

<p>But being limited to "just" 1.5GB is unfortunately not the end of the story. It shows that in most browsers (like FireFox 3.5.2) these ca. 1.5GB are not available to every SWF individually. No, all SWFs in all open tabs or windows of Firefox are sharing that one Pool of 1.5GB. That means the more one SWF requests the less is available for the others. </p>

<p>So in order that you can figure out what is happening yourself I've built <a href="http://www.quasimondo.com/examples/memoryhog.html">MemoryHog</a>, a tiny tool which will allocate and release memory. When you open multiple instances of it in your browser of choice you can see how memory is managed between all the open SWFs. A warning though: some browsers in some systems do crash when you press the "request maximum" button. Seems like Macs are more susceptible to this than PCs. </p>

<p>One thing you can see very good with MemoryHog is the influence of memory fragmentation. Sometimes whilst you cannot allocate a 100MB block anymore you are still able to get more than 10 10MB blocks.</p>

<p>My resume for Aviary: whilst it it nice to be able to finally use bigger bitmaps in Flash player 10 when it comes to using more than a few of them at the same time we will have to think about a implementing a tile based solution that makes better use of the fragmenting memory.</p>]]></content:encoded>
      <dc:subject>Observation</dc:subject>
      <dc:date>2009-09-04T16:35:43+01:00</dc:date>
    </item>
    <item>
      <title>Automated Threshold &amp; Edge Detection</title>
      <link>http://www.quasimondo.com/archives/000690.php</link>
      <description>It&apos;s a tiny bit late maybe, but here are two image processing techniques that deal with automated thresholding and edge detection that I showed in my &quot;2d or not 2d&quot; talk in 2007 and in &quot;The Pixel Whisperer&quot; in 2008. I&apos;ve had a look at my presentation demos and repackaged their code into a single class called ThresholdBitmap. This is a BitmapData class with a few extras that help you if you plan to extract blobs or edges from a camera stream or some other bitmap. The general problem when you do camera based experiments is that you have unnown</description>
      <guid isPermaLink="false">690@http://www.quasimondo.com/</guid>
      <content:encoded><![CDATA[<p>It's a tiny bit late maybe, but here are two image processing techniques that deal with automated thresholding and edge detection that I showed in my "2d or not 2d" talk in 2007 and in "The Pixel Whisperer" in 2008. </p>

<p>I've had a look at my presentation demos and repackaged their code into a single class called ThresholdBitmap. This is a BitmapData class with a few extras that help you if you plan to extract blobs or edges from a camera stream or some other bitmap. </p>

<p>The general problem when you do camera based experiments is that you have unnown lighting conditions. Using a simple fixed threshold might work at your development machine but might fail completely on a user's computer that has a different camera model or a different backdrop.</p>

<p>In image processing there are several automated thresholding methods, that are supposed to help with this problem, by looking at an image's histogram and adjusting the threshold to a level that separates the foreground from the background in an optimum way: <a href="http://books.google.de/books?id=5xcIErZZIN8C&pg=PA114&lpg=PA114&dq=Moment-Preservation+threshold&source=bl&ots=Z_NgvH6nIZ&sig=JCyCEXIOWFk_O3rbimRNwNQieQQ&hl=en&ei=MK5LSuecEcrEsAbr8PXFBQ&sa=X&oi=book_result&ct=result&resnum=1">Moment-Preservation, Maximum Entropy, Discriminant and Otsu</a>. Those are quite capable in finding the optimum threshold level if you have relatively uniform lighting over the whole scene.</p>

<p>As an (better) alternative I included an adaptive threshold method which is implemented in PixelBender and which works very well also with uneven lighting, especially if you try to detect QR codes or other markers. </p>

<p>Furthermore the class includes a very fast edge detection (based on the thresholded image) which gives you nice 1 pixel wide edges in most cases.</p>

<p><a href="http://www.quasimondo.com/examples/threshold_and_edge_detection/">Here is a demo that allows you to play around (you'll need a webcam)</a></p>

<p>Sourceview and code can be found <a href="http://www.quasimondo.com/examples/threshold_and_edge_detection/srcview/index.html">here</a></p>

<p>Credits: the demo uses the super useful <a href="http://www.bit-101.com/minimalcomps/">Minimal Components by Keith Peters</A> and the <a href="http://code.google.com/p/mrdoob/wiki/stats">Hi.RES! Stats by Mr. Doob</a>.</p>]]></content:encoded>
      <dc:subject>Information</dc:subject>
      <dc:date>2009-07-01T20:27:48+01:00</dc:date>
    </item>
    <item>
      <title>A fix for createGradientBox()</title>
      <link>http://www.quasimondo.com/archives/000689.php</link>
      <description>Whilst playing around with some geometry that involved gradient fills I had to realize that the native implementation of Flash&apos;s createGradientBox() is unfortunately entirely useless as soon as you try to introduce rotation and scaling to a gradient. The reason seems to be that internally the order of matrix operations is unsuited for that task. Maybe I&apos;ve searched not thoroughly enough, but I didn&apos;t find any solution for this out there. So I&apos;ve written a tiny class that fixes it. Here&apos;s a comparison of the difference between matrix.createGradientBox() and my new GradientMatrix.getGradientBox() var fo = new FlashObject(&quot;http://www.quasimondo.com/examples/gradientMatrix/GradientBoxDemo.swf&quot;, &quot;gradientBox&quot;, &quot;500&quot;, &quot;400&quot;,</description>
      <guid isPermaLink="false">689@http://www.quasimondo.com/</guid>
      <content:encoded><![CDATA[<p>Whilst playing around with some geometry that involved gradient fills I had to realize that the native implementation of Flash's createGradientBox() is unfortunately entirely useless as soon as you try to introduce rotation and scaling to a gradient. The reason seems to be that internally the order of matrix operations is unsuited for that task. </p>

<p>Maybe I've searched not thoroughly enough, but I didn't find any solution for this out there. So I've written a tiny class that fixes it. Here's a comparison of the difference between matrix.createGradientBox() and my new GradientMatrix.getGradientBox()</p>

<div id="gradientBox"></div>
<script type="text/javascript">
   var fo = new FlashObject("http://www.quasimondo.com/examples/gradientMatrix/GradientBoxDemo.swf", "gradientBox", "500", "400", "10", "#000000");
   fo.write("gradientBox");
</script>

<p>To use it you can use the same values that you would use in the native function, the only difference is that you don't have to create a new Matrix first. The syntax is var myGradientMatrix:Matrix = GradientMatrix.getGradientBox( width, height, rotation, tx, ty);</p>

<p>Download <a href="http://www.quasimondo.com/examples/gradientMatrix/GradientMatrix.as">GradientMatrix.as</a> here<br />
</p>]]></content:encoded>
      <dc:subject>Manipulation</dc:subject>
      <dc:date>2009-05-17T00:58:49+01:00</dc:date>
    </item>
    <item>
      <title>Face Tracking Fun</title>
      <link>http://www.quasimondo.com/archives/000688.php</link>
      <description>I&apos;ve started to have a bit of fun with the optimized Marilena face-tracking class and build a webcam based magic mirror. The specialty here is that it tries to displace your face only and leave the rest of the scenery untouched and additionaly adjusts the displacement scale based on how close you are to the camera: Check out Manic Mirror at the Incubator</description>
      <guid isPermaLink="false">688@http://www.quasimondo.com/</guid>
      <content:encoded><![CDATA[<p>I've started to have a bit of fun with the <a href="http://www.quasimondo.com/archives/000687.php">optimized Marilena face-tracking class</a> and build a webcam based magic mirror. The specialty here is that it tries to displace your face only and leave the rest of the scenery untouched and additionaly adjusts the displacement scale based on how close you are to the camera:</p>

<p>Check out <a href="http://incubator.quasimondo.com/flash/manic_mirror.php">Manic Mirror</a> at the <a href="http://incubator.quasimondo.com">Incubator</a></p>]]></content:encoded>
      <dc:subject>Incubation</dc:subject>
      <dc:date>2009-03-15T15:08:47+01:00</dc:date>
    </item>
    <item>
      <title>Optimizing Flash Based Face Detection</title>
      <link>http://www.quasimondo.com/archives/000687.php</link>
      <description>Yesterday Seb-Lee Delisle pointed us via Twitter to this great example of a Flash based real-time face detection. It turns out that already more than half a year ago Ohtsuka Masakazu had been porting the face detection part of OpenCV to AS3 and added the source code to the Spark project - which is like a Actionscript candy box full of surprises. So I had a look at the source code and found one feature which I wanted to change: face detection is based on so-called Haar Cascades, simplified one could say that this is a very long list of</description>
      <guid isPermaLink="false">687@http://www.quasimondo.com/</guid>
      <content:encoded><![CDATA[<p>Yesterday <a href="http://twitter.com/sebleedelisle/status/1322257365">Seb-Lee Delisle</a> pointed us via Twitter to <a href="http://www.squidder.com/2009/02/26/realtime-face-detection-in-flash/">this great example of a Flash based real-time face detection</a>. It turns out that already more than half a year ago <a href="http://maaash.jp/as3/as3marilena-object-detection-in-as3/">Ohtsuka Masakazu</a> had been porting the face detection part of <a href="http://opencvlibrary.sourceforge.net/">OpenCV</a> to AS3 and added the source code to the <a href="http://www.libspark.org/wiki/mash/Marilena">Spark project</a> - which is like a Actionscript candy box full of surprises. </p>

<p><br />
So I had a look at the source code and found one feature which I wanted to change: face detection is based on so-called Haar Cascades, simplified one could say that this is a very long list of zones that get checked for certain features in an image. In the orginal version this is an xml file of almost 1 MB size. Because this is so big the xml file gets compressed into a zip file where it fortunately becomes just 100K. So in the orginal version the zip file has first to be loaded and then unpacked and parsed. My consideration was that swfs get zipped anyway, so why not turn the whole xml file directly into a class? </p>

<p>So that's what I did. My adapted version does not need to load any external files anymore  (which was my goal) and the whole swf becomes even about 50K smaller than the original version. I also did a few other optimizations like replacing Arrays with linked lists and reading a from ByteArray instead of using getPixel(). The downside is that since the Haar data is being hardcoded into the class now you will not be able to use this class to track anything else but faces (which in theory you could). But I expect that most people will not even know how to prepare a different Haar cascade recognition set - for example I'm one of those.</p>

<p>What's interesting is that this code will even run in Flash Player 9, since there is no PixelBender or Alchemy and neither the new Vector data type being used. Obviously by targeting Flash Player 10 one could even add a few more optimizations, but that's something for another weekend.</p>

<p>Example 1: <a href="http://www.quasimondo.com/examples/face_detection/FaceDetector.html">Ohtsuka Masakazu's modified sample file</a></p>

<p>Example 2: <a href="http://www.quasimondo.com/examples/face_detection/FaceDetector_Camera.html">Real-time webcam face tracking</a></p>

<p>Here's the modified sourcecode which includes two example files: <a href="http://www.quasimondo.com/examples/face_detection/Marilena_mod10.zip">Marilena_mod10.zip</a><br />
</p>]]></content:encoded>
      <dc:subject>Transformation</dc:subject>
      <dc:date>2009-03-14T18:56:09+01:00</dc:date>
    </item>
    <item>
      <title>#tweetcoding Round 1 - a few more</title>
      <link>http://www.quasimondo.com/archives/000686.php</link>
      <description><![CDATA[Here are a few more of my entries for #tweetcoding: "Moskitos": g.clear();ls(1);o[i++]=[mouseX,mouseY,2*r(),2*r()]; for each(p in o){mt(p[0],p[1]); lt(p[0]+=2*s(p[1]*p[2]),p[1]+=2*s(p[0]*p[3])); };i%=2000 "Love in 3D": if(i "Hyperdrive": if (!o.b)addChild(o.c=new Bitmap(o.b=new BitmapData(500,500))),o.b.noise(2); z=s(i-=0.01)*15;o.c.z=-z;o.b.draw(this,o.o,o.o,"hardlight"); "Fibonacci Sequence": if(!i)i=1,o.b=0,o.c=addChild(new TextField),o.c.autoSize="left",o.c.wordWrap=o.c.multiline=1; o.c.appendText(" "+i),o.a=o.b,o.b=i,i+=o.a "All Invaders": if(!i) g.beginFill(0),a=b=i=64,d=511; g.drawRect(a&=d,b&=d,i,i); g.drawRect(d-a+1-i,b,i,i); a+=r() "The Golden Days": g.clear();g.beginFill(0); x=y=20;for(i=81;i--;g.drawCircle(40*a,40*b,d*2)) a=(i%9),b=int(i/9), d=m.sqrt((d=mouseX/40-a)*d+(d=mouseY/40-b)*d) "Superstar": g.beginFill(r()]]></description>
      <guid isPermaLink="false">686@http://www.quasimondo.com/</guid>
      <content:encoded><![CDATA[<p>Here are a few more of my entries for <a href="http://gskinner.com/playpen/tweetcoding.html">#tweetcoding</a>:</p>

<p><a href="http://www.quasimondo.com/scrapyard/moskitos.html">"Moskitos"</a>:<br />
g.clear();ls(1);o[i++]=[mouseX,mouseY,2*r(),2*r()]; for each(p in o){mt(p[0],p[1]); lt(p[0]+=2*s(p[1]*p[2]),p[1]+=2*s(p[0]*p[3])); };i%=2000</p>

<p><a href="http://www.quasimondo.com/scrapyard/love3d.html">"Love in 3D"</a>:<br />
if(i<250&&(x=y++)) with(addChild(new TextField)) text="<3",x=r()*500-250,y=r()*500-250,z=i*2-250, rotationX=rotationZ=r()*360;rotationY=i++</p>

<p><a href="http://www.quasimondo.com/scrapyard/hyperdrive.html">"Hyperdrive"</a>:<br />
if (!o.b)addChild(o.c=new Bitmap(o.b=new BitmapData(500,500))),o.b.noise(2); z=s(i-=0.01)*15;o.c.z=-z;o.b.draw(this,o.o,o.o,"hardlight");</p>

<p><a href="http://www.quasimondo.com/scrapyard/fibonacci.html">"Fibonacci Sequence"</a>:<br />
if(!i)i=1,o.b=0,o.c=addChild(new TextField),o.c.autoSize="left",o.c.wordWrap=o.c.multiline=1; o.c.appendText(" "+i),o.a=o.b,o.b=i,i+=o.a</p>

<p><a href="http://www.quasimondo.com/scrapyard/allinvaders.html">"All Invaders"</a>:<br />
if(!i) g.beginFill(0),a=b=i=64,d=511; g.drawRect(a&=d,b&=d,i,i); g.drawRect(d-a+1-i,b,i,i); a+=r()<0.4?i:0;b+=r()<0.4?i:0;</p>

<p><a href="http://www.quasimondo.com/scrapyard/circles2.html">"The Golden Days"</a>:<br />
g.clear();g.beginFill(0); x=y=20;for(i=81;i--;g.drawCircle(40*a,40*b,d*2)) a=(i%9),b=int(i/9), d=m.sqrt((d=mouseX/40-a)*d+(d=mouseY/40-b)*d)</p>

<p><a href="http://www.quasimondo.com/scrapyard/superstar.html">"Superstar"</a>:<br />
g.beginFill(r()<0.4?0:1e8);q=r()*640;c=r()*480;a=2;u=r()*10; for(d=12;--d;(d<11?lt:mt)(q+u*a*s(i+=0.63), c+u*a*s(i+1.57)),a=7-a){}<br />
	</p>]]></content:encoded>
      <dc:subject>Vibration</dc:subject>
      <dc:date>2009-02-20T16:06:13+01:00</dc:date>
    </item>
    <item>
      <title>#tweetcoding Round 1 - 1967 / Boids</title>
      <link>http://www.quasimondo.com/archives/000685.php</link>
      <description>Another two entries for #tweetcoding. &quot;1967&quot;: i+=0.06;g.clear();g.beginFill(0);for(x=80;x--;){g.drawCircle(25+70*(x%9),25+70*(y=int(x/9)),70+(s(x%9*0.7+i+s(y*0.7+i)))*35)} var fo = new FlashObject(&quot;http://www.quasimondo.com/scrapyard/drawing1.swf&quot;, &quot;tweetcode2&quot;, &quot;500&quot;, &quot;360&quot;, &quot;10&quot;, &quot;#e0e0e0&quot;); fo.write(&quot;tweetcode2&quot;);</description>
      <guid isPermaLink="false">685@http://www.quasimondo.com/</guid>
      <content:encoded><![CDATA[<p>Another two entries for <a href="http://gskinner.com/playpen/tweetcoding.html">#tweetcoding</a>.</p>

<p>"1967":<br />
<strong>i+=0.06;g.clear();g.beginFill(0);for(x=80;x--;){g.drawCircle(25+70*(x%9),25+70*(y=int(x/9)),70+(s(x%9*0.7+i+s(y*0.7+i)))*35)}</strong></p>

<div id="tweetcode2"></div>
<script type="text/javascript">
   var fo = new FlashObject("http://www.quasimondo.com/scrapyard/drawing1.swf", "tweetcode2", "500", "360", "10", "#e0e0e0");
   fo.write("tweetcode2");
</script>]]></content:encoded>
      <dc:subject>Vibration</dc:subject>
      <dc:date>2009-02-19T16:21:40+01:00</dc:date>
    </item>
    <item>
      <title>#tweetcoding Round 1 - Alien Vacation</title>
      <link>http://www.quasimondo.com/archives/000684.php</link>
      <description>Grant Skinner has started a litte competition on Twitter called tweetcoding where the goal is to create something nice in 140 chars of Actionscript 3. And the fine folks at Adobe actually will give a free copy of Flash CS4 to the winner, who will be picked on March 1st. As a starting point there is a small wrapper which predefines a few common functions and objects with short variable names. Above you see my first entry - which requires Flash Player 10 btw: which looks like this as a tweet</description>
      <guid isPermaLink="false">684@http://www.quasimondo.com/</guid>
      <content:encoded><![CDATA[<p>Grant Skinner has started a litte competition on Twitter called <a href="http://gskinner.com/playpen/tweetcoding.html">tweetcoding</a> where the goal is to create something nice in 140 chars of Actionscript 3. And the fine folks at Adobe actually will give a free copy of Flash CS4 to the winner, who will be picked on March 1st.</p>

<p>As a starting point there is a small wrapper which predefines a few common functions and objects with short variable names. Above you see my first entry - which requires Flash Player 10 btw: <a href="http://twitter.com/Quasimondo/status/1223779411">which looks like this as a tweet</a></p>]]></content:encoded>
      <dc:subject>Vibration</dc:subject>
      <dc:date>2009-02-18T22:16:27+01:00</dc:date>
    </item>
    <item>
      <title>Getting the First Non-transparent Pixel in an Image</title>
      <link>http://www.quasimondo.com/archives/000683.php</link>
      <description>I just came across Sakri Rosenstrom&apos;s posts (1 2) about his methods of finding the first non-transparent pixel in a bitmap. Looks like he got inspired by my talk at MAX Europe - unfortunately he seems to have misunderstood my explanation back then. My bad - I should have posted my method a long time ago - so here we go. [Notice: it turns out that Sakri&apos;s method is faster than mine - please check the update at the bottom of this post] Here&apos;s a little demo. First you might ask what the hell this method is needed for at</description>
      <guid isPermaLink="false">683@http://www.quasimondo.com/</guid>
      <content:encoded><![CDATA[<p>I just came across Sakri Rosenstrom's posts (<a href="http://www.sakri.net/blog/2009/02/10/get-first-non-transparent-pixel-in-a-bitmap-3-approaches-and-benchmarks/">1</a> <a href="http://www.sakri.net/blog/2009/02/10/get-first-non-transparent-pixel-in-a-bitmap-update/">2</a>) about his methods of finding the first non-transparent pixel in a bitmap. Looks like he got inspired by my talk at MAX Europe - unfortunately he seems to have misunderstood my explanation back then. My bad - I should have posted my method a long time ago - so here we go. <strong>[Notice: it turns out that Sakri's method is faster than mine - please check the update at the bottom of this post]</strong></p>

<p><a href="http://www.quasimondo.com/examples/non_transparent_pixels/NonTransparentPixel.html">Here's a little demo.</a></p>

<p>First you might ask what the hell this method is needed for at all. There are three applications that come to my mind right away: blob tracking for multi-touch interfaces (using my flood fill method), QR-code recognition and bitmap vectorization. All of them have in common that after having detected a blob of uniform color in a bitmap you want to trace the outline of it. In order to do that you need to have a starting point of which you know that it lies on the edge. That's what the method I will show you here does.</p>

<p>If we were programming in C the approach would be to start at the top left corner of the bitmap and do a getPixel(x,y) from left to right and top to bottom until you find a pixel that is not 0x00000000. But since we are using Actionscript there are a few methods in the BitmapData class that will be quite faster than a loop.</p>

<p>The workhorse in this case is the getColorBoundsRect() method. In case you forgot what it does: this method will return you a Rectangle which encloses all pixels of a certain color inside a BitmapData object. </p>

<p>The starting situation: we have a transparent bitmap which contains non-transparent pixels somewhere. In step one we use getColorBoundsRect to narrow down on the minimum area that still contains any non transparent pixels:</p>

<p><strong>var r1:Rectangle = bitmapData.getColorBoundsRect( 0xff000000, 0, false );</strong></p>

<p>If the height of r1 equals 0 we know that the image is completely empty and can stop rightaway. If not we can continue. And here's the trick. We've got a rectangle now and we know for sure that somewhere in the topmost row of that rectangle there is a non-transparent pixel. What we cannot count on is that it is the one at the very left, aka r1.topLeft - it's absolutely possible that there is just a single pixel set in that row and it can be anywhere between r1.left and r1.right.</p>

<p>But here's the trick: we simply use getColorBoundsRect again - unfortunately we cannot do this using the same bitmapData. We need to extract that first row of pixels into a separate temporary bitmap:<br />
<strong><br />
var temp:BitmapData = new BitmapData( r1.width, 1, true, 0 );<br />
temp.copyPixels( bitmapData, r1, new Point());</strong></p>

<p>Now that we've got a 1 pixel high bitmapdata which contains at least one non-transparent pixel we can continue:</p>

<p><strong>var r2:Rectangle = temp.getColorBoundsRect( 0xff000000, 0, false );</strong></p>

<p>The last step is to add the offset we have found here to the previously found top left corner of first colorbounds:<br />
<strong><br />
var startPoint:Point = r1.topLeft.add( r2.topLeft );</strong></p>

<p>All together it looks like this:<br />
<strong><strike><br />
public static function getFirstNonTransparentPixel( bmd:BitmapData ):Point<br />
{<br />
			var r1:Rectangle = bmd.getColorBoundsRect( 0xff000000, 0, false );<br />
			if ( r1.width > 0 )<br />
			{<br />
				var temp:BitmapData = new BitmapData( r1.width, 1, true, 0 );<br />
				temp.copyPixels( bmd, r1, new Point());<br />
				var r2:Rectangle = temp.getColorBoundsRect( 0xff000000, 0, false );<br />
				return r1.topLeft.add( r2.topLeft );<br />
			}<br />
			return null;<br />
}</strike></strong></p>

<p>Or you can <a href="http://www.quasimondo.com/examples/non_transparent_pixels/EdgeFinder.as">download the EdgeFinder.as</a> class here</p>

<p><strong><emph>[Important Notice]</emph></strong> I should have made some speed test before recommending this method. It turns out that getColorBoundsRect() is not as fast as I thought it was. Sakri Rosenstrom's HitTest method is twice as fast as mine. So I've taken another look at his implementation and optimized it a bit more, making a kind of hybrid between both of our methods. My test tell me that this optimzed version is about twice as fast - I have updated the code in EdgeFinder.as already</p>

<p><strong><br />
public static function getFirstNonTransparentPixel( bmd:BitmapData ):Point<br />
		{<br />
			var hit_rect:Rectangle=new Rectangle(0,0,bmd.width,1);<br />
			var p:Point = new Point();<br />
			for( hit_rect.y = 0; hit_rect.y < bmd.height; hit_rect.y++ )<br />
			{<br />
				if( bmd.hitTest( p, 0x01, hit_rect) )<br />
				{<br />
					var hit_bmd:BitmapData=new BitmapData( bmd.width, 1, true, 0 );<br />
					hit_bmd.copyPixels( bmd, hit_rect, p );<br />
					return hit_rect.topLeft.add( hit_bmd.getColorBoundsRect(0xFF000000, 0, false).topLeft );<br />
				}<br />
			}<br />
			return null;<br />
		}<br />
</strong></p>]]></content:encoded>
      <dc:subject>Relevation</dc:subject>
      <dc:date>2009-02-17T17:24:47+01:00</dc:date>
    </item>


  </channel>
</rss>


