<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Andy Li’s Blog - FLARtoolkit</title><link href="https://blog.onthewings.net/" rel="alternate"></link><link href="http://feeds.feedburner.com/tag/flartoolkit/feed/atom.xml" rel="self"></link><id>https://blog.onthewings.net/</id><updated>2009-05-23T10:40:00+08:00</updated><entry><title>FLARtoolkit trick: use a colored marker</title><link href="https://blog.onthewings.net/2009/05/23/flartoolkit-trick-use-a-colored-marker/" rel="alternate"></link><published>2009-05-23T10:40:00+08:00</published><updated>2009-05-23T10:40:00+08:00</updated><author><name>Andy Li</name></author><id>tag:blog.onthewings.net,2009-05-23:/2009/05/23/flartoolkit-trick-use-a-colored-marker/</id><summary type="html">&lt;iframe allowfullscreen="" frameborder="0" height="390" src="//www.youtube.com/embed/DY7TPBRPpFI" width="640"&gt;&lt;/iframe&gt;
&lt;h2&gt;Reasons why should we use colored marker instead of standard black and white only marker&lt;/h2&gt;
&lt;h3&gt;Using a black and white only marker is boring&lt;/h3&gt;
&lt;p&gt;There are more and more &lt;span class="caps"&gt;AR&lt;/span&gt; applications in the world, but seems
everybody use only the black square marker. May be the public is not yet …&lt;/p&gt;</summary><content type="html">&lt;iframe allowfullscreen="" frameborder="0" height="390" src="//www.youtube.com/embed/DY7TPBRPpFI" width="640"&gt;&lt;/iframe&gt;
&lt;h2&gt;Reasons why should we use colored marker instead of standard black and white only marker&lt;/h2&gt;
&lt;h3&gt;Using a black and white only marker is boring&lt;/h3&gt;
&lt;p&gt;There are more and more &lt;span class="caps"&gt;AR&lt;/span&gt; applications in the world, but seems
everybody use only the black square marker. May be the public is not yet
bored by the black square yet, but if can use other color for the
square, we can integrate the marker into real-life objects more
beautifully and more flexible.&lt;/p&gt;
&lt;h3&gt;Increase marker detection performance&lt;/h3&gt;
&lt;p&gt;The internal algorithm of &lt;span class="caps"&gt;AR&lt;/span&gt; marker detection has a characteristic that,
the less pixels’ color is the same of the marker, faster the detection
can be done. When we use black square marker, the detector will waste a
lot of time to process non-marker pixels as you can imagine that it is
common to have black objects in real-life (especially we the Chinese
people have black hair). So if we target less common color, the detector
will be able to ignore most of the non-marker area.&lt;/p&gt;
&lt;h2&gt;How to achieve this in FLARtoolkit&lt;/h2&gt;
&lt;p&gt;We will create a custom detector class since we need to work at lower
level of the FLARtoolkit. If you have not look into the internal classes
of FLARtoolkit (because the &lt;a href="http://words.transmote.com/wp/20090328/flarmanager-v03/"&gt;FLARmanager&lt;/a&gt; is so much easier to work
with ;-) ), there are two detectors: FLARSingleMarkerDetector and
FLARMultiMarkerDetector. As their names suggest, one is for single
marker detection and the other one can detect multiple markers. For
simplicity, I will go through only the single detection for a red marker
(if you want me to cover the other ones too, leave comment).&lt;/p&gt;
&lt;p&gt;First we just copy all the codes inside FLARSingleMarkerDetector to a
new class, I named it FLARSingleRedMarkerDetector.&lt;/p&gt;
&lt;p&gt;To detect markers, we use the detectMarkerLite method, which is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;public function detectMarkerLite(i_raster:IFLARRgbRaster, i_threshold:int):Boolean
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;IFLARRgbRaster wraps a BitmapData, we can get it by:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;var&lt;/span&gt; &lt;span class="nt"&gt;srcImg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;BitmapData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;i_raster&lt;/span&gt; &lt;span class="nt"&gt;as&lt;/span&gt; &lt;span class="nt"&gt;FLARRgbRaster_BitmapData&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;bitmapData&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Originally, the method uses a threshold filter to extract black areas
and give the result to other classes to process. As you might think of,
we can simply swap the filter code. Originally the black areas will be
turned to white pixels and others will be turned black and be ignored.
We now want to detect red markers, so just try to turn everything black
except the red regions to white. You may use ColorTransform if you want,
but I am now obsessed with PixelBender. My version of kernel is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;kernel&lt;/span&gt; &lt;span class="nt"&gt;extractRedARMarker&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;   &lt;span class="nt"&gt;namespace&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"net.onthewings.filters"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nt"&gt;vendor&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Andy Li"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nt"&gt;version&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nt"&gt;description&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"used for FLARtoolkit, pre-proccess for red marker."&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;input&lt;/span&gt; &lt;span class="err"&gt;image4&lt;/span&gt; &lt;span class="err"&gt;src&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="err"&gt;output&lt;/span&gt; &lt;span class="err"&gt;pixel4&lt;/span&gt; &lt;span class="err"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="err"&gt;parameter&lt;/span&gt; &lt;span class="err"&gt;float&lt;/span&gt; &lt;span class="err"&gt;threshold&amp;lt;&lt;/span&gt;
        &lt;span class="n"&gt;minValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;maxValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"decrease to increase likelihood of marker detection."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="err"&gt;void&lt;/span&gt;
    &lt;span class="err"&gt;evaluatePixel()&lt;/span&gt;
    &lt;span class="err"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;float4&lt;/span&gt; &lt;span class="err"&gt;p&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="err"&gt;sampleNearest(src,outCoord())&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="err"&gt;float&lt;/span&gt; &lt;span class="err"&gt;sum&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="err"&gt;p.r+p.g+p.b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="err"&gt;float&lt;/span&gt; &lt;span class="err"&gt;val&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="err"&gt;p.r&lt;/span&gt; &lt;span class="err"&gt;-&lt;/span&gt; &lt;span class="err"&gt;(p.g&lt;/span&gt; &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="err"&gt;p.b)*0.5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="err"&gt;if&lt;/span&gt; &lt;span class="err"&gt;(val+(1.0-(sum/3.0))*0.1&lt;/span&gt; &lt;span class="err"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="err"&gt;threshold)&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
            &lt;span class="err"&gt;val&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="err"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="err"&gt;val&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="err"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nt"&gt;dst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;float4&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;val&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;val&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;val&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="err"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that I let the dark red pass the threshold easier since I find it
is common the web cam image is too dark.&lt;/p&gt;
&lt;p&gt;To use the finished detector class:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;tempFLARRgbRaster_BitmapData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bitmapData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;videoDisplay&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;detector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;detectMarkerLite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tempFLARRgbRaster_BitmapData&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;170&lt;/span&gt;&lt;span class="p"&gt;)){&lt;/span&gt;
    &lt;span class="nx"&gt;detector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getTransformMatrix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lastDetectionResult&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;//FLARPVGeomUtils is from FLARmanager&lt;/span&gt;
    &lt;span class="nx"&gt;overlay3dObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;FLARPVGeomUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;convertFLARMatrixToPVMatrix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lastDetectionResult&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;overlay3dObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;overlay3dObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now you get all the concepts. So let’s skip all the boring stuff and
&lt;a href="http://www.onthewings.net/"&gt;see it in action&lt;/a&gt;. Or &lt;a href="/files/2009/redmarkerdetection.zip"&gt;get the finished codes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy &lt;span class="caps"&gt;AR&lt;/span&gt;!&lt;/p&gt;
&lt;hr/&gt;
&lt;p&gt;Update: Here I have a &lt;span class="caps"&gt;PB&lt;/span&gt; kernel that works with any color. &lt;a href="https://blog.onthewings.net/2009/12/10/chroma-key-and-thresholding-in-flash-pixel-bender-revised/"&gt;Try it&lt;/a&gt;!&lt;/p&gt;</content><category term="FLARtoolkit"></category><category term="Flash"></category><category term="Pixel Bender"></category><category term="trick"></category></entry></feed>