<br />
<b>Warning</b>:  Declaration of Jetpack_IXR_Client::query() should be compatible with IXR_Client::query(...$args) in <b>/home/clients/7267bc096562fcdb78c0ab60d3ac51fb/web/blog/wp-content/plugins/jetpack/class.jetpack-ixr-client.php</b> on line <b>91</b><br />
{"id":391,"date":"2014-11-10T19:03:13","date_gmt":"2014-11-10T19:03:13","guid":{"rendered":"http:\/\/barradeau.com\/blog\/?p=391"},"modified":"2015-12-07T14:56:10","modified_gmt":"2015-12-07T14:56:10","slug":"marching-squares","status":"publish","type":"post","link":"http:\/\/barradeau.com\/blog\/?p=391","title":{"rendered":"marching squares"},"content":{"rendered":"<p>a short post about the marching squares algorithm,\u00a0a technique mostly used to vectorize the outline of a binary image.<\/p>\n<p>it&#8217;s a very well known &amp;\u00a0very well spread technique, I happened to have some spare time &amp;\u00a0the urge to do something graphic.<br \/>\nfor a start let&#8217;s look at how things work.<\/p>\n<p>the idea is to draw a shape through the edges of cells which vertices are &#8220;weighted&#8221; ( each point of the cell has a value ).\u00a0in our case, we use an image to represent the cells&#8217; grid ( an image is a grid of pixels\u00a0) &amp;\u00a0if we use a binary image (black &amp; white, no greyscale), the weights are the colors of the pixels ( 0 or 1 ) .\u00a0then we need a <em>structuring element<\/em> or <em>kernel<\/em> to scan our grid &amp;\u00a0find the outline.<\/p>\n<p>the algorithm goes as follow:<\/p>\n<ol>\n<li>apply a threshold to the image to obtain a binary image<\/li>\n<li>find the first non transparent pixel<\/li>\n<li>position the kernel at this location<\/li>\n<li>while the kernel has not reached the starting location\n<ul>\n<li>move the kernel <em>around<\/em> the shape<\/li>\n<li>store the new location<\/li>\n<li>if the number of iteration is too high, break<\/li>\n<li>else continue<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p>the first step is fairly easy ; when you access the imageData of a given canvas, you can scan all the pixels&#8217; components ( r,g,b or a ) &amp;\u00a0match them against a given value.<\/p>\n<p>a good idea though is to <em>reduce the image&#8217;s colors\u00a0<\/em>before performing the marching square process\u00a0; this can be done quite simply either beforehand by using a restricted palette or on the fly by applying a simple reduction\u00a0algorithm like:<\/p>\n<pre class=\"lang:js decode:true \">function segment( imageOrCanvas, steps )\r\n{\r\n\r\n    var w = imageOrCanvas.width;\r\n    var h = imageOrCanvas.height;\r\n    var canvas = document.createElement(\"canvas\");\r\n    document.body.appendChild( canvas );\r\n    canvas.width = w;\r\n    canvas.height = h;\r\n\r\n    var context = canvas.getContext(\"2d\");\r\n    context.fillStyle = \"rgba(255,255,255,255)\";\r\n    context.fillRect(0, 0, w, h);\r\n    context.drawImage(imageOrCanvas, 0, 0 );\r\n\r\n    var imgData = context.getImageData(0, 0, w, h);\r\n    var data = imgData.data;\r\n\r\n    for( var i = 0; i &lt; data.length; i += 4 )\r\n    {\r\n        data[i]     = parseInt(parseInt( ( data[i] \/ 0xFF ) * steps + .5 ) * ( 0xFF \/ steps ) );\r\n        data[i + 1] = parseInt(parseInt( ( data[i + 1] \/ 0xFF ) * steps + .5 ) * ( 0xFF \/ steps ) );\r\n        data[i + 2] = parseInt(parseInt( ( data[i + 2] \/ 0xFF ) * steps + .5 ) * ( 0xFF \/ steps ) );\r\n    }\r\n\r\n    imgData.data = data;\r\n    context.putImageData( imgData, 0, 0 );\r\n\r\n}\r\nvar img = document.getElementById( \"me_gusta\" );\r\nsegment( img, 16 );\r\nsegment( img, 8 );\r\nsegment( img, 1 );<\/pre>\n<p>which will give you something like<\/p>\n<p><a href=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/segmentation.jpg\" data-rel=\"lightbox-image-0\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter wp-image-396 size-large\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/segmentation-1021x1024.jpg\" alt=\"segmentation\" width=\"700\" height=\"702\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/segmentation-1021x1024.jpg 1021w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/segmentation-150x150.jpg 150w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/segmentation-300x300.jpg 300w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/segmentation-360x360.jpg 360w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/segmentation-700x702.jpg 700w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/segmentation.jpg 1044w\" sizes=\"(max-width: 700px) 100vw, 700px\" \/><\/a><\/p>\n<p>the idea is\u00a0simple, for each component of the color,\u00a0first\u00a0normalize it ( data[ X ] \/ 0xFF ) then\u00a0interpolate between 0 &amp;\u00a0the desired amount of steps ( * steps ) &amp;\u00a0Math.ceil\u00a0it ( parseInt( X + .5 ) \u00a0) then multiply this by the value of a color step ( 0xFF \/ steps ).<\/p>\n<p>the lower the number of steps, the easier it should\u00a0be to vectorize, adding a blur step before reduces the noise &amp;\u00a0gives more usable regions.<\/p>\n<p>to understand what comes next, you may\u00a0need to understand\u00a0the notion of kernel but there&#8217;s this example by Sakri that shows exactly what\u00a0the last step of the algorithm is about: \u00a0<a href=\"http:\/\/codepen.io\/sakri\/pen\/aIirl\" target=\"_blank\">http:\/\/codepen.io\/sakri\/pen\/aIirl<\/a><\/p>\n<p>as we&#8217;re using a simple 2 * 2 kernel, there are very few possibilities\u00a0(\u00a0only 16 actually )\u00a0to move the kernel when\u00a0looking for the direction. here&#8217;s a table with the integers 0-15 in binary form, the 4 rectangles below the figure represent the\u00a0bytes ( white=0, black = 1 ) &amp;\u00a0the squares are the kernel itself ; what we&#8217;ll use to actually\u00a0determine the direction to move to (represented by\u00a0the arrow above the box).<\/p>\n<p><a href=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/binary_table.png\" data-rel=\"lightbox-image-1\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter wp-image-393 size-large\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/binary_table-969x1024.png\" alt=\"binary_table\" width=\"700\" height=\"739\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/binary_table-969x1024.png 969w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/binary_table-283x300.png 283w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/binary_table-700x739.png 700w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/binary_table.png 1047w\" sizes=\"(max-width: 700px) 100vw, 700px\" \/><\/a><\/p>\n<p>by sampling the right, bottom &amp; bottom right pixels, this table allows us to quickly determine where we should go next but there are 2 flaws.<\/p>\n<p>a minor flaw is that it contains both a 2 * 2 void square ( 0000 ) and a 2 * 2 full square ( 1111 ). this is not that bad ; as we select the first non-transparent pixel, it is usually located on the top left area of the picture so <em>0000<\/em> will head towards the bottom right &amp; <em>1111<\/em> will head towards the top left.<\/p>\n<p>the second flaw is more embarrassing though, it rises about the values\u00a06 ( 0110 ) &amp; 9 ( 1001 ) and form a diagonal\u00a0pattern. in these cases, there is no way to tell where to send the kernel next, ending up in infinite loops. there are ways to\u00a0deal with this problem\u00a0but\u00a0that&#8217;s beyond the scope of this article.<\/p>\n<p>to prevent the infinite loops,\u00a0I tried simply not to use those patterns.<\/p>\n<p>which failed of course.<\/p>\n<p>but it gave me an idea ; why not alter the binary shape so that this pattern doesn&#8217;t occur?<\/p>\n<p>enter the <a href=\"http:\/\/www.coe.utah.edu\/~cs4640\/slides\/Lecture11.pdf\" target=\"_blank\">Morphological operators<\/a>.<br \/>\nthe morphological operators work on binary images &amp; perform very simple\u00a0tests between a pixel &amp; its neighborhood\u00a0to\u00a0determine whether or not to <em>toggle\u00a0<\/em>a pixel.<\/p>\n<p>this simple operators fill the smaller gaps that cause most of the infinite loops and applying this during the collection phase ( step 1 of the algorithm ) allows for not having to bother with ambiguous case anymore.<\/p>\n<p>let&#8217;s take this <em>burning head<\/em>\u00a0I did so it has\u00a0a fair amount of ambiguous cases (click to view full size) especially in the bottom right corner.<\/p>\n<p><a href=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/burning_head.png\" data-rel=\"lightbox-image-2\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter wp-image-412 size-large\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/burning_head-1024x790.png\" alt=\"burning_head\" width=\"700\" height=\"540\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/burning_head-1024x790.png 1024w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/burning_head-300x231.png 300w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/burning_head-700x540.png 700w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/burning_head.png 1490w\" sizes=\"(max-width: 700px) 100vw, 700px\" \/><\/a><\/p>\n<p>trying a brute force marching square will fail, but applying the following kernel:<\/p>\n<pre class=\"lang:js decode:true \">buffer[ id ] = 0;\r\nif (sum != 9 &amp;&amp; sum &gt; 1 )\r\n{\r\n    buffer[ id ] = 1;\r\n}\r\n\r\n\/\/then \r\nif( sum &gt; dilation )\/\/dilation default: 5, lower = more greedy\r\n{\r\n    buffer[ i ] = 1;\r\n}<\/pre>\n<p>where <em>sum<\/em>\u00a0is the sum of the neighboring pixels&#8217; values, allows to preserve only the outline of the shape and gives the red outline (click to view full size)<\/p>\n<p><a href=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/burning_head_border.png\" data-rel=\"lightbox-image-3\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter wp-image-413 size-large\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/burning_head_border-1024x755.png\" alt=\"burning_head_border\" width=\"700\" height=\"516\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/burning_head_border-1024x755.png 1024w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/burning_head_border-300x221.png 300w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/burning_head_border-700x516.png 700w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/burning_head_border.png 1474w\" sizes=\"(max-width: 700px) 100vw, 700px\" \/><\/a><\/p>\n<p>if you look closely, you can follow the whole border without finding any ambiguous case + smaller elements (namely single pixels) are being discarded. now\u00a0instead of 16 possibilities, we end up managing only 12 the Lookup table now looks like this:<\/p>\n<p><a href=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/binary_path.png\" data-rel=\"lightbox-image-4\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-full wp-image-392\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/binary_path.png\" alt=\"binary_path\" width=\"591\" height=\"901\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/binary_path.png 591w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/binary_path-196x300.png 196w\" sizes=\"(max-width: 591px) 100vw, 591px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>the <em>burning head<\/em>\u00a0vectorized output looks like this<\/p>\n<p><a href=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/burning_head_vector.png\" data-rel=\"lightbox-image-5\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter wp-image-414 size-large\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/burning_head_vector-1024x790.png\" alt=\"burning_head_vector\" width=\"700\" height=\"540\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/burning_head_vector-1024x790.png 1024w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/burning_head_vector-300x231.png 300w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/burning_head_vector-700x540.png 700w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/burning_head_vector.png 1490w\" sizes=\"(max-width: 700px) 100vw, 700px\" \/><\/a><\/p>\n<p>the blue area is the vectorized outline\u00a0and the orange line &amp; dots is the simplified version of the path. nice isn&#8217;t it?<\/p>\n<p>here&#8217;s the code of\u00a0the marching squares method:<\/p>\n<pre class=\"lang:js decode:true \">\/**\r\n * function that performs a marching squares vectorization\r\n * @param imageOrCanvas an image or a canvas to vectorize, preferably a binary image.\r\n * @param color the color you want to vectorize ( between 0 &amp; 0xFFFFFF )\r\n * @param dilation value used in the dilation step ( 0 - 8 )\r\n * @param maxIterations this prevents infinte loops ( default 10e5 )\r\n * @returns {Array} a series of x, y coordinates\r\n * @constructor\r\n *\/\r\nfunction MarchingSquares( imageOrCanvas, color, dilation, maxIterations )\r\n{\r\n\r\n    dilation = dilation == null ? 5 : dilation;\r\n\r\n    maxIterations = maxIterations == null ? 10e5 : maxIterations;\r\n\r\n    var canvas = document.createElement( \"canvas\" );\r\n    var w = canvas.width = imageOrCanvas.width + 4;\r\n    var h = canvas.height = imageOrCanvas.height + 4;\r\n\r\n    var context = canvas.getContext(\"2d\");\r\n    context.fillStyle = \"rgba(255,255,255,255)\";\r\n    context.fillRect( 0,0, w, h );\r\n    context.drawImage( imageOrCanvas, 2, 2 );\r\n\r\n    var imgData= context.getImageData( 0,0,w,h );\r\n    var data = imgData.data;\r\n    var buffer = new Int8Array(w*h);\r\n    var path = [];\r\n    var first = NaN;\r\n\r\n    var i;\r\n    var r = color &gt;&gt; 16  &amp; 0xFF;\r\n    var g = color &gt;&gt; 8  &amp; 0xFF;\r\n    var b = color  &amp; 0xFF;\r\n\r\n    for( i = 0; i &lt; data.length; i+=4 )\r\n    {\r\n        \/\/ discard if the pixel has a different\r\n        \/\/ color than what we're looking for\r\n        if( data[ i ]       != r\r\n        &amp;&amp;  data[ i + 1 ]   != g\r\n        &amp;&amp;  data[ i + 2 ]   != b )\r\n        {\r\n            data[ i + 3 ] = 0;\r\n        }\r\n        else\r\n        {\r\n            data[ i + 3 ] = 1;\r\n        }\r\n    }\r\n\r\n    \/\/morphological operation extracting the border\r\n    for( i = 0; i &lt; data.length; i+=4 )\r\n    {\r\n        id = i \/ 4;\r\n        var sum = neighborSum( data, i, 4, 3 );\r\n\r\n        buffer[ id ] = 0;\r\n        if (sum != 9 &amp;&amp; sum &gt; 1 )\r\n        {\r\n            buffer[ id ] = 1;\r\n        }\r\n    }\r\n\r\n    \/\/morphological dilation\r\n    \/\/this prevents infinite loops\r\n    for( i = 0; i &lt; buffer.length; i++ )\r\n    {\r\n\r\n        sum = neighborSum( buffer, i, 1, 0 );\r\n        if( sum &gt; dilation )\r\n        {\r\n            buffer[ i ] = 1;\r\n        }\r\n\r\n        \/\/ first non transparent pixel ( top left to current pixel )\r\n        if( isNaN( first ) &amp;&amp; buffer[ i  ] == 1 )\r\n        {\r\n            first = i - w - 1;\r\n        }\r\n    }\r\n\r\n    if( isNaN( first ) )\r\n    {\r\n        console.log( \"warning: no empty pixels was found, exiting.\" );\r\n        return [];\r\n    }\r\n\r\n    \/\/morphological operators\r\n\r\n    function neighborIds( id, stride )\r\n    {\r\n        stride = stride || 1;\r\n\r\n        var to = id - w * stride;\/\/top\r\n        var tr = to + stride;\/\/top right\r\n        var tl = to - stride;\/\/top left\r\n\r\n        var ri = id + stride; \/\/ right\r\n        var le = id - stride;\/\/left\r\n\r\n        var bo = id + w * stride;\/\/bottom\r\n        var br = bo + stride;\/\/bottom right\r\n        var bl = bo - stride;\/\/bottom left\r\n\r\n        return [ tl, to, tr, le, id, ri, bl, bo, br ];\r\n    }\r\n\r\n    function neighborValues( data, id, stride, offset )\r\n    {\r\n        var values = [];\r\n        var ids = neighborIds( id, stride );\r\n        ids.forEach( function( id )\r\n        {\r\n            values.push( data[ id + offset ] );\r\n        });\r\n        return values;\r\n    }\r\n\r\n    function neighborSum( data, id, stride, offset )\r\n    {\r\n        var values = neighborValues( data, id, stride, offset );\r\n        var sum = 0;\r\n        values.forEach( function( value )\r\n        {\r\n            sum += ( value &gt; 0 ) ? 1 : 0;\r\n        });\r\n        return sum;\r\n    }\r\n\r\n    \/\/marching square\r\n\r\n    var iteration = 0;\r\n    var id = getDirection( buffer, first );\r\n    while( iteration++ &lt; maxIterations )\r\n    {\r\n        id = getDirection( buffer, id );\r\n\r\n        path.push( id % w - 1, parseInt( id \/ w ) - 1 );\r\n\r\n        if( id == first )    break;\/\/done\r\n    }\r\n\r\n    \/\/determine where to move next\r\n    function getDirection( data, id  )\r\n    {\r\n\r\n        var ri  = id + 1;\/\/ right pixel\r\n        var bo  = id + w;\/\/bottom pixel\r\n        var br = bo + 1;\/\/bottom right pixel\r\n\r\n        var x = 0;\r\n        var y = 0;\r\n        var key = data[ id ] &lt;&lt; 3 | data[ ri ] &lt;&lt; 2 | data[ bo ] &lt;&lt; 1 | data[ br ];\r\n\r\n        if( key == 1 || key ==  3 || key == 11  ) x =  1;\/\/ rightt\r\n        if( key == 8 || key == 12 || key == 13  ) x = -1;\/\/ left\r\n        if( key == 4 || key ==  5 || key ==  7  ) y = -1;\/\/ up\r\n        if( key == 2 || key == 10 || key == 14  ) y =  1;\/\/ down\r\n\r\n        return id + x + y * w;\r\n\r\n    }\r\n    return path;\r\n}<\/pre>\n<p>it&#8217;s intentionally unoptimized for legibility but one would probably merge &amp;\u00a0inline the morphological operator, unfold &amp; reorganize the way getDirection sets the x\/y\u00a0directions,\u00a0reuse the canvas &amp; the buffer instead of recreating it\u00a0a.s.o.<\/p>\n<p>and a standard call would go like :<\/p>\n<pre class=\"lang:js decode:true \">function sample( img )\r\n{\r\n\r\n    var out = document.createElement( \"canvas\" );\r\n    out.width = img.width;\r\n    out.height = img.height;\r\n    document.body.appendChild( out );\r\n\r\n    var out_context = out.getContext(\"2d\");\r\n    out_context.drawImage( img,0,0,out.width, out.height );\r\n\r\n    var path = MarchingSquares( img, 0, 5, 10e5 );\r\n\r\n    out_context.fillStyle = \"rgba( 255,0,0,.35 )\";\r\n    out_context.strokeStyle = \"rgba( 255,0,0, .7 )\";\r\n    out_context.lineWidth = 3;\r\n    out_context.beginPath();\r\n\r\n    for( var i = 0; i &lt; path.length; i+=2 )\r\n    {\r\n        out_context.lineTo( path[ i ], path[ i+1 ] );\r\n    }\r\n    out_context.closePath();\r\n    out_context.stroke();\r\n    out_context.fill();\r\n\r\n}\r\n\r\nwindow.onload = function()\r\n{\r\n    var img = document.getElementById( \"my_favorite_unicorn\" );\r\n    sample( segment( img,1 ) );\r\n};<\/pre>\n<p>for instance calling this on a unicorn\u00a0picture would give this kind of output<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter wp-image-416 size-full\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/unicorn_vector.png\" alt=\"unicorn_vector\" width=\"700\" height=\"914\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/unicorn_vector.png 700w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/unicorn_vector-229x300.png 229w\" sizes=\"(max-width: 700px) 100vw, 700px\" \/><\/p>\n<p>one of the greatest benefits of vectorization being to make\u00a0images <em>scale-free,\u00a0<\/em>my favourite results come from smaller images\u00a0; here are 2 32 * 32 pictures vectorized &amp; simplified:<\/p>\n<p><a href=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/gun.png\" data-rel=\"lightbox-image-6\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-full wp-image-394\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/gun.png\" alt=\"gun\" width=\"32\" height=\"32\" \/><\/a><a href=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/monster.png\" data-rel=\"lightbox-image-7\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-full wp-image-395\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/monster.png\" alt=\"monster\" width=\"32\" height=\"32\" \/><\/a><\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter wp-image-415 size-full\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/gun_monster.png\" alt=\"gun_monster\" width=\"700\" height=\"1200\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/gun_monster.png 700w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/gun_monster-175x300.png 175w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/gun_monster-597x1024.png 597w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/gun_monster-582x999.png 582w\" sizes=\"(max-width: 700px) 100vw, 700px\" \/><\/p>\n<p>that&#8217;s far from bulletproof and I wouldn&#8217;t recommend using it in production but that&#8217;s a fun little algorithm to play with. it allows on the fly vectorization of free shapes to use in\u00a0physics games for instance.<\/p>\n<p>possible enhancements include, multiple shapes vectorization\u00a0&amp;\u00a0triangulation, using better interpolation techniques than binary, using integral images (?!)\u00a0also, I&#8217;d recommend reading this lovely article: <a href=\"http:\/\/jamie-wong.com\/2014\/08\/19\/metaballs-and-marching-squares\/\" target=\"_blank\">Metaballs and marching squares<\/a> by Jamie Wong.<\/p>\n<p>that was it!<br \/>\n<a href=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/cover_burning.png\" data-rel=\"lightbox-image-8\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><br \/>\n<\/a>enjoy :)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>a short post about the marching squares algorithm,\u00a0a technique mostly used to vectorize the outline of a binary image. it&#8217;s a very well known &amp;\u00a0very well spread technique, I happened to have some spare time &amp;\u00a0the urge to do something graphic. for a start let&#8217;s look at how things work. the idea is to draw &#8230; <span class=\"more\"><a class=\"more-link\" href=\"http:\/\/barradeau.com\/blog\/?p=391\">[Read more&#8230;]<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":414,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"sharing_disabled":false,"spay_email":"","jetpack_publicize_message":""},"categories":[3],"tags":[],"jetpack_featured_media_url":"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/11\/burning_head_vector.png","jetpack_publicize_connections":[],"jetpack_shortlink":"https:\/\/wp.me\/p4oXhx-6j","_links":{"self":[{"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/391"}],"collection":[{"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=391"}],"version-history":[{"count":12,"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/391\/revisions"}],"predecessor-version":[{"id":422,"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/391\/revisions\/422"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/media\/414"}],"wp:attachment":[{"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=391"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=391"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=391"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}