<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" version="2.0">

<channel>
	<title>More Than Technical</title>
	
	<link>http://www.morethantechnical.com</link>
	<description>On software, code, the internet and more.</description>
	<lastBuildDate>Sun, 12 May 2013 09:20:21 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/MoreThanTechnical" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="morethantechnical" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://superfeedr.com/hubbub" /><item>
		<title>Tailing the output of multiple files in Linux</title>
		<link>http://www.morethantechnical.com/2013/05/12/tailing-the-output-of-multiple-files-in-linux/</link>
		<comments>http://www.morethantechnical.com/2013/05/12/tailing-the-output-of-multiple-files-in-linux/#comments</comments>
		<pubDate>Sun, 12 May 2013 09:20:21 +0000</pubDate>
		<dc:creator>Arnon</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[filename]]></category>
		<category><![CDATA[multiple files]]></category>
		<category><![CDATA[tail]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://www.morethantechnical.com/?p=1337</guid>
		<description><![CDATA[This is a quick post to show a trick to tail multiple files, while showing the filename in the beginning of the line What I needed was a way to grep multiple logs for an exception. But doing "tail -f *.log &#124; grep exception" only let me see the exception, but I didn't know which [...]]]></description>
				<content:encoded><![CDATA[<p>This is a quick post to show a trick to tail multiple files, while showing the filename in the beginning of the line</p>
<p>What I needed was a way to grep multiple logs for an exception. But doing "tail -f *.log | grep exception" only let me see the exception, but I didn't know which log file to look in</p>
<p>I have found <a href="http://www.thegeekstuff.com/2009/09/multitail-to-view-tail-f-output-of-multiple-log-files-in-one-terminal/" target="_blank">this guide</a>, and altered the script and added</p>
<ol>
<li>Printing the file name in the beginning of each line</li>
<li>Padding spaces after the file name (you can alter the minimal length in the ALIGN variable</li>
</ol>
<p>Anyway - here's the script. Hope you find it useful</p>
<pre class="brush: plain; title: ; notranslate">
#!/bin/bash
 
# When this exits, exit all back ground process also.
trap 'kill $(jobs -p)' EXIT
 
ALIGN=31
 
# iterate through the each given file names,
for file in &quot;$@&quot;
do
        LENGTH=`echo ${file} | wc -c`
        PADDING=`expr ${ALIGN} - ${LENGTH}`
        PAD=`perl -e &quot;print ' ' x $PADDING;&quot;`
 
        # show tails of each in background.
        tail -f $file | sed &quot;s/^/${file}${PAD}:/g&quot;  &amp;
done
 
# wait .. until CTRL+C
wait
</pre>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.morethantechnical.com%2F2013%2F05%2F12%2Ftailing-the-output-of-multiple-files-in-linux%2F&amp;title=Tailing%20the%20output%20of%20multiple%20files%20in%20Linux" id="wpa2a_2"><img src="http://www.morethantechnical.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.morethantechnical.com/2013/05/12/tailing-the-output-of-multiple-files-in-linux/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C++ library for the C329 SPI camera module [w/ code]</title>
		<link>http://www.morethantechnical.com/2013/04/25/c-library-for-the-c329-spi-camera-module-w-code/</link>
		<comments>http://www.morethantechnical.com/2013/04/25/c-library-for-the-c329-spi-camera-module-w-code/#comments</comments>
		<pubDate>Wed, 24 Apr 2013 23:19:24 +0000</pubDate>
		<dc:creator>Roy</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[electronics]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://www.morethantechnical.com/?p=1331</guid>
		<description><![CDATA[C++ Library for the C329 camera module of the SPI variety]]></description>
				<content:encoded><![CDATA[<p>Just putting it out there for whoever is trying to use the <a href="http://www.electronics123.com/s.nl/it.A/id.3011/.f?sc=8&#038;category=207684" target="_blank">C329 camera module of the SPI variety</a> (the <a href="http://www.electronics123.com/s.nl/it.A/id.3010/.f?sc=8&#038;category=207684" target="_blank">URAT module</a> has code posted online)<br />
<span id="more-1331"></span><br />
The UART code is at: <a href="https://github.com/svoisen/c329" target="_blank">https://github.com/svoisen/c329</a><br />
But <a href="http://www.electronics123.com/" title="www.electronics123.com" target="_blank">electronics123.com</a> have a SPI module as well, without code supplied.<br />
I took the UART code and changed it to work with <a href="http://arduino.cc/en/Reference/SPI" target="_blank">Arduino's SPI library</a>. The changes are minuscule, but someone might find them useful instead of writing them again.</p>
<p>I used C329 with Teensy 2.0, and connected the <a href="http://www.pjrc.com/teensy/pinout.html" target="_blank">MISO MOSI SCLK pins</a> to the defaults, the only thing left is to connect the SPI CS pin on the camera module (check out <a href="http://www.electronics123.net/amazon/datasheet/C329_SPI_UM-V1.1.pdf" target="_blank">Page 3 in the manual</a>) to some GPIO, I chose the Teensy's B0 pin.</p>
<p>So the operation of the library is very similar to the example online:</p>
<pre class="brush: plain; title: ; notranslate">
#include &quot;CameraC329.h&quot;
#include &lt;SPI.h&gt;

CameraC329 camera(PIN_B0); //set B0 as the CS pin

void getPicture_callback(uint32_t pictureSize, uint16_t packetSize, uint32_t packetStartPosition, byte* packet)
{
//do something with picture buffer
}

void setup() {
          pinMode(PIN_B0, OUTPUT);
          digitalWrite(PIN_B0,HIGH); //unselect

          SPI.setDataMode(SPI_MODE0);
          SPI.begin();

          delay(2000); //time for the module to load stuff from EEPROM

          if (!camera.sync())
          {
            Serial.println(&quot;Sync failed&quot;);
            camera.powerOff();
            SPI.end();
            return;
          } else {
            Serial.println(&quot;Camera sync&quot;);
          }
        
          if (!camera.initialize(CameraC329::BAUD14400, CameraC329::CT_JPEG, CameraC329::PR_160x120, CameraC329::JR_320x240))
          {
            Serial.println(&quot;Initialize failed&quot;);
            return;
          } else {
            Serial.println(&quot;Camera init&quot;);
          }
          
          if (!camera.setQuality(CameraC329::QL_BEST))
          {
            Serial.println(&quot;Set quality failed&quot;);
            return;
          } else {
            Serial.println(&quot;Camera quality set&quot;);
          }

          if (!camera.getPicture(CameraC329::PT_JPEG_PREVIEW, &amp;getPicture_callback))
          {
            Serial.println(&quot;Get Picture Failed&quot;);
            return;
          }
}
</pre>
<p>The major changes to the UART library are in the sendCommand and waitForResponse functions</p>
<pre class="brush: plain; title: ; notranslate">
void CameraC329::sendCommand()
{
  uint8_t i;
//Serial.print(&quot;send command &quot;);
  // Big endian
  for (i = 0; i &lt; CMD_SIZE; i++)
  {
//Serial.print(outputCommand[i]); Serial.print(&quot; &quot;);
    digitalWrite(spi_cs_pin,LOW);
    SPI.transfer(outputCommand[i]);
    digitalWrite(spi_cs_pin,HIGH);
  }
//Serial.println();
}

bool CameraC329::waitForResponse(uint32_t timeout, byte buffer[], uint16_t bufferLength)
{
  uint8_t byteCount = 0;
  unsigned long time = millis();

//Serial.print(&quot;response: &quot;);
  while (millis() - time &lt;= timeout)
  {
//    while (cameraPort.available() &gt; 0) //hmmm...
    {
      digitalWrite(spi_cs_pin,LOW);
      buffer[byteCount] = SPI.transfer(0x00); //cameraPort.read();
      digitalWrite(spi_cs_pin,HIGH);
      
//Serial.print(buffer[byteCount],DEC); Serial.print(&quot; &quot;);
      byteCount++;

      if (byteCount == bufferLength) {
//Serial.println();
        return true;
      }
    }
  }
//Serial.println();
  if (byteCount &gt; 0)
    return true;

  return false;
}
</pre>
<p>But I also found the GET PIC command to be very very picky. It really only responds very sporadically, so I added a bunch of retries:</p>
<pre class="brush: plain; title: ; notranslate">
bool CameraC329::getPicture(PictureType pictureType, void (*callback)(uint32_t pictureSize, uint16_t packetSize, uint32_t packetStartPosition, byte* packet))
{
  uint32_t pictureSize = 0;

  reset(RT_STATE);

  //Although ACK is part of the spec, we're really waiting for a DATA response, so let's skip waiting for ACK and just wait for DATA
//  while (!waitForACK(RESPONSE_DELAY, CMD_GETPICTURE) &amp;&amp; ack_counter &lt; 100) {
//    delay(10);
//  }

  //try to send the GET PIC command for 10 times before giving up
  uint32_t get_pic_tries = 0;
  while(get_pic_tries++ &lt; 10) {
    setOutputCommand(CMD_GETPICTURE, pictureType, 0, 0, 0);
    sendCommand();

    uint32_t max_tries = 0, total_tries = 10;
    while (!(waitForResponse(RESPONSE_DELAY) &amp;&amp; inputCommand[3] == CMD_DATA) &amp;&amp; max_tries++ &lt; total_tries) {
      //this is not a DATA response (start of the image data), let's wait try again shortly
      Serial.print(&quot;not DATA (&quot;); Serial.print(inputCommand[3]); Serial.println(&quot;)&quot;); 
      delay(10);
    }
    
    if(max_tries &lt; total_tries) break;
  }
  if(get_pic_tries &gt;= 10) return false;
  
  pictureSize = inputCommand[7] &lt;&lt; 8;
  pictureSize |= inputCommand[6] &lt;&lt; 8;
  pictureSize |= inputCommand[5];

  uint32_t bytePosition = 0;
  uint8_t package[DEFAULT_PACKAGE_SIZE];

  while (bytePosition &lt; pictureSize)
  {
    if (!waitForResponse(RESPONSE_DELAY, package, DEFAULT_PACKAGE_SIZE))
      return false;

    callback(pictureSize, min(DEFAULT_PACKAGE_SIZE, pictureSize - bytePosition), bytePosition, package);
    bytePosition += DEFAULT_PACKAGE_SIZE;
  }

  return true;
}
</pre>
<p>Even with that, it's not 100% stable!<br />
I think there's still problem with the SPI timing...</p>
<p>Code can be grabbed at: <a href="http://web.media.mit.edu/~roys/src/CameraC329SPI.zip" target="_blank">http://web.media.mit.edu/~roys/src/CameraC329SPI.zip</a></p>
<p>Enjoy,<br />
Roy.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.morethantechnical.com/2013/04/25/c-library-for-the-c329-spi-camera-module-w-code/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Simplified FFMPEG video writer (also for OpenFramework) [w/ code]</title>
		<link>http://www.morethantechnical.com/2013/04/11/simplified-ffmpeg-video-writer-also-for-openframework-w-code/</link>
		<comments>http://www.morethantechnical.com/2013/04/11/simplified-ffmpeg-video-writer-also-for-openframework-w-code/#comments</comments>
		<pubDate>Thu, 11 Apr 2013 15:19:19 +0000</pubDate>
		<dc:creator>Roy</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[ffmpeg]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://www.morethantechnical.com/?p=1326</guid>
		<description><![CDATA[Simplified FFMPEG video writer with example for OpenFrameworks.]]></description>
				<content:encoded><![CDATA[<p>I want to share a little snippet in case anyone is interested in writing video files from cpp context using FFMPEG, I've made it for usage with OpenFrameworks.<br />
It's basically a simple wrapper around the encoding mechanism of FFMPEG, so you can easily just say which file to write to and start dumping images into it. It will take care of choosing the codec, writing headers and trailers, encode (compress) the frames and write them to the file.<br />
<span id="more-1326"></span></p>
<pre class="brush: plain; title: ; notranslate">
class ofxFFMPEGVideoWriter {
    //instance variables...

    bool initialized;

public:
    ofxFFMPEGVideoWriter():oc(NULL),codec(NULL),initialized(false),frame_count(1) {}
    
    /**
     * setup the video writer
     * @param output filename, the codec and format will be determined by it. (e.g. &quot;xxx.mpg&quot; will create an MPEG1 file
     * @param width of the frame
     * @param height of the frame
     **/
    void setup(const char* filename, int width, int height);
    /**
     * add a frame to the video file
     * @param the pixels packed in RGB (24-bit RGBRGBRGB...)
     **/
    void addFrame(const uint8_t* pixels);
    /**
     * close the video file and release all datastructs
     **/
    void close();
    /**
     * is the videowriter initialized?
     **/
    bool isInitialized() const { return initialized; }
};
</pre>
<p>So you can see the API is as simple as possible, and specialized for writing RGB images (24-bit packed, RGBRGBRGB...)<br />
The <code>setup()</code> function will t</p>
<p>The internals are taken from the FFMPEG API examples: <a href="http://ffmpeg.org/doxygen/trunk/examples.html" title="FFMPEG API examples" target="_blank">http://ffmpeg.org/doxygen/trunk/examples.html</a><br />
But it's kind of long to put here, so check out the code.</p>
<p>In OpenFrameworks I used it to capture the screen and save it:</p>
<pre class="brush: plain; title: ; notranslate">
//--------------------------------------------------------------
void testApp::setup(){
    ofEnableSmoothing();
    ofBackground(0);
    
    videoWriter.setup(&quot;output.mpg&quot;, ofGetViewportWidth(), ofGetViewportHeight());
}

//--------------------------------------------------------------
void testApp::update(){
    if(videoWriter.isInitialized()) {
        ofscreenimg.grabScreen(0, 0, ofGetViewportWidth(), ofGetViewportHeight());
        videoWriter.addFrame((const uint8_t*)(ofscreenimg.getPixels()));
    }
}

//--------------------------------------------------------------
void testApp::draw(){
    ofFill();
    ofSetColor(255, 0, 255);
    ofCircle(mousept.x, mousept.y, 15);
}

//--------------------------------------------------------------
void testApp::mousePressed(int x, int y, int button){
    mousept.x = x; mousept.y = y;
}

//--------------------------------------------------------------
void testApp::mouseDragged(int x, int y, int button){
    mousept.x = x; mousept.y = y;
}

//--------------------------------------------------------------
void testApp::mouseReleased(int x, int y, int button){
    mousept.x = -50; mousept.y = -50;
}
</pre>
<h2>Code</h2>
<p><a href="http://web.media.mit.edu/~roys/src/FFMPEGVideoWriter.zip" target="_blank">http://web.media.mit.edu/~roys/src/FFMPEGVideoWriter.zip</a></p>
<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.morethantechnical.com/2013/04/11/simplified-ffmpeg-video-writer-also-for-openframework-w-code/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Curve tracking with a Heap&amp;Hogg's Particle Filters [w/ code, OpenCV]</title>
		<link>http://www.morethantechnical.com/2013/03/16/curve-tracking-with-a-heaphoggs-particle-filters-w-code-opencv/</link>
		<comments>http://www.morethantechnical.com/2013/03/16/curve-tracking-with-a-heaphoggs-particle-filters-w-code-opencv/#comments</comments>
		<pubDate>Fri, 15 Mar 2013 22:20:36 +0000</pubDate>
		<dc:creator>Roy</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[graphics]]></category>
		<category><![CDATA[opencv]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[video]]></category>
		<category><![CDATA[vision]]></category>
		<category><![CDATA[curve]]></category>
		<category><![CDATA[hand]]></category>
		<category><![CDATA[particle filter]]></category>
		<category><![CDATA[tracking]]></category>

		<guid isPermaLink="false">http://www.morethantechnical.com/?p=1248</guid>
		<description><![CDATA[I wanna share some code for 2D curve tracking with a particle filter, implementing the body of work of Tony Heap and David Hogg. These guys presented a relatively easy to implement method for tracking deformable curves through space and change in form using a Hierarchical Point Distribution Models (HPDM), which is another elegant way [...]]]></description>
				<content:encoded><![CDATA[<p><img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-15-at-6.18.30-PM-e1363385989369-300x201.png" alt="Screen Shot 2013-03-15 at 6.18.30 PM" width="300" height="201" class="alignleft size-medium wp-image-1320" /> I wanna share some code for 2D curve tracking with a particle filter, implementing the body of work of <a href="http://ieeexplore.ieee.org/xpls/abs_all.jsp?arnumber=710741" target="_blank">Tony Heap and David Hogg</a>. These guys presented a relatively easy to implement method for tracking deformable curves through space and change in form using a <a href="http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.54.7890" target="_blank">Hierarchical Point Distribution Models (HPDM)</a>, which is another elegant way to store shape priors. Granted, it is not perfect, but for a simple 2D shape like a hand it works pretty good, and rather fast as well.<br />
Let's dive in then,<br />
<span id="more-1248"></span></p>
<h3>Training the HPDM</h3>
<p>An HPDM is basically a <a href="http://en.wikipedia.org/wiki/Point_distribution_model" target="_blank">Point Distribution Model</a> (PDM) that has multiple levels - a hierarchy. It encodes the deformation a shape can go through, usually by means of dimension reduction (in our case a <a href="http://en.wikipedia.org/wiki/Principal_component_analysis" target="_blank">PCA</a>). In the Hierarchical PDM we generate a shape-deformation space by PCA, then discretize that space using clustering (like k-means, but an Expectation-Maximization operation works just as well) to achieve another level in the hierarchy.<br />
To train the HPDM we need (many) samples of curves. I got the samples automatically using a Kinect, blob detection, curve extraction etc., but that wasn't the end of it. The samples needed a lot of clean-up!<br />
The raw samples contain the whole arm, which is not something I'd like to track and also it throws off the alignment of all the curves because the variance is big.<br />
<img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-11-at-2.05.58-PM-e1363025215885-300x250.png" alt="hand curve from kinect" width="300" height="250" class="aligncenter size-medium wp-image-1292" /><br />
So I clean it up a bit by looking a bit further down the curve. But since we're doing an ad-hoc curve extraction from the blob, simply "capping" the curves at a certain point along the curve creates curves that are very badly aligned. For an ideal alignment we need them to be the same exact length (in points), and we need the points to be distributed along the shape in the same way, e.g. point #120 lands on the tip of the index finger in all curves.<br />
<img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-11-at-2.13.42-PM-e1363025797516.png" alt="Screen Shot 2013-03-11 at 2.13.42 PM" width="228" height="188" class="aligncenter size-full wp-image-1294" /><img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-11-at-2.13.48-PM-e1363025750116.png" alt="Screen Shot 2013-03-11 at 2.13.48 PM" width="228" height="188" class="aligncenter size-full wp-image-1293" /><br />
Here are 10 curves with the 100th point marked on them, we can see how most of the 100th points align, but some are not even close.<br />
<img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-11-at-2.57.03-PM-e1363028377305.png" alt="Screen Shot 2013-03-11 at 2.57.03 PM" width="224" height="188" class="aligncenter size-full wp-image-1296" /><br />
Since we're building a PDM, we model the variation of a single point in the curve (like the 100th point), so we need the variation to be small. We therefor look for an alignment.<br />
We start by picking an initial "mean shape", which in the first iteration is simply the average curve from all samples. But as we've seen a single point can vary greatly so the initial average shape does not reflect the true mean shape.<br />
We proceed by examining each curve, matching vs. the mean shape, adding points at the start or end of the curve so they would align. Now the "100th point test" yields better results, the 100th points are roughly at the same position.<br />
<img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-11-at-3.53.41-PM-e1363032229705.png" alt="Screen Shot 2013-03-11 at 3.53.41 PM" width="206" height="192" class="aligncenter size-full wp-image-1298" /><br />
We proceed by performing PCA and then k-means. In the papers there is a discussion around choosing the  <span class='MathJax_Preview'><img src='http://www.morethantechnical.com/wp-content/plugins/latex/cache/tex_8ce4b16b22b58894aa86c421e8759df3.gif' style='vertical-align: middle; border: none; padding-bottom:1px;' class='tex' alt="k" /></span><script type='math/tex'>k</script> , however I used  <span class='MathJax_Preview'><img src='http://www.morethantechnical.com/wp-content/plugins/latex/cache/tex_35a47e1db110dd6081df974c754031dd.gif' style='vertical-align: middle; border: none; ' class='tex' alt="k = \frac{E}{d}" /></span><script type='math/tex'>k = \frac{E}{d}</script>  where E is the number of curves in the DB (I had ~1300) and  <span class='MathJax_Preview'><img src='http://www.morethantechnical.com/wp-content/plugins/latex/cache/tex_3bb507bf2e91c9021f9f97412b4227cb.gif' style='vertical-align: middle; border: none; ' class='tex' alt="d = 50" /></span><script type='math/tex'>d = 50</script>  (I also experimented with higher  <span class='MathJax_Preview'><img src='http://www.morethantechnical.com/wp-content/plugins/latex/cache/tex_8277e0910d750195b448797616e091ad.gif' style='vertical-align: middle; border: none; padding-bottom:1px;' class='tex' alt="d" /></span><script type='math/tex'>d</script> s but they do not span the space too well). Here are the found centers:<br />
<a href="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-11-at-6.13.48-PM-e1363040146861.png" rel="lightbox[1248]"><img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-11-at-6.13.48-PM-e1363040066734-300x249.png" alt="Screen Shot 2013-03-11 at 6.13.48 PM" width="300" height="249" class="aligncenter size-medium wp-image-1301" /></a><br />
After k-means-ing, the paper then continues to say that the "subregions" (sometimes called "patches") of the shape deformation space should be local, and thus hopefully linear.<br />
They do not use the samples that were attached to each center (that's how k-means clustering works, attached samples to centers thus clustering the samples in space), but rather they look for nearest neighbors in the shape space, to get an overlapping area between subregions / patches.<br />
Then they perform PCA on each bunch of NNs around each center to get a linear patch.<br />
Here are the patches with slight deformation on the principal axis:<br />
<a href="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-12-at-9.00.08-AM-e1363093355470.png" rel="lightbox[1248]"><img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-12-at-9.00.08-AM-e1363093355470-300x203.png" alt="Screen Shot 2013-03-12 at 9.00.08 AM" width="300" height="203" class="aligncenter size-medium wp-image-1304" /></a><br />
The core parameters to tweak in the HPDM are:</p>
<ul>
<li> <span class='MathJax_Preview'><img src='http://www.morethantechnical.com/wp-content/plugins/latex/cache/tex_8ce4b16b22b58894aa86c421e8759df3.gif' style='vertical-align: middle; border: none; padding-bottom:1px;' class='tex' alt="k" /></span><script type='math/tex'>k</script>  the number of patches, which should be derived from another two parmeters:</li>
<li> <span class='MathJax_Preview'><img src='http://www.morethantechnical.com/wp-content/plugins/latex/cache/tex_8277e0910d750195b448797616e091ad.gif' style='vertical-align: middle; border: none; padding-bottom:1px;' class='tex' alt="d" /></span><script type='math/tex'>d</script>  (the divisor), which along with  <span class='MathJax_Preview'><img src='http://www.morethantechnical.com/wp-content/plugins/latex/cache/tex_3a3ea00cfc35332cedf6e5e9a32e94da.gif' style='vertical-align: middle; border: none; padding-bottom:1px;' class='tex' alt="E" /></span><script type='math/tex'>E</script>  (the number of samples) determines how many samples you have per patch</li>
<li> <span class='MathJax_Preview'><img src='http://www.morethantechnical.com/wp-content/plugins/latex/cache/tex_f186217753c37b9b9f958d906208506e.gif' style='vertical-align: middle; border: none; ' class='tex' alt="O" /></span><script type='math/tex'>O</script>  (the overlap) which determines how many nearest neighbors we're looking for per each patch (usually this number is bigger than  <span class='MathJax_Preview'><img src='http://www.morethantechnical.com/wp-content/plugins/latex/cache/tex_7cf10b19ecc9b1d0836c5a1ad3683a0b.gif' style='vertical-align: middle; border: none; ' class='tex' alt="E/d" /></span><script type='math/tex'>E/d</script>  and therefore the patches overlap)</li>
<li>the size of the shape space - the dimension of the first PCA, the number of principal components to keep. I had it at 20</li>
<li>the nubmer of principal components to keep in the subregions, I had it at 1</li>
</ul>
<h3>Using the HPDM in a Particle Filter</h3>
<p>A quick reminder, <a href="http://en.wikipedia.org/wiki/Particle_filter" target="_blank">Particle Filters</a> (PF) are a way to maintain many different hypotheses for the model (e.g. position of an object, shape, signal, etc.) looking for an unknown truth state of the model while receiving noisy measurements.<br />
In our case we're looking at the position, orientation and shape of a 2D hand object, so each particle is going to hold data that will describe such a model.</p>
<pre class="brush: plain; title: ; notranslate">
class Particle {
public:
	//according to H&amp;H section 3.1
	Point2f centroid;
	float scale;
	float orientation;
	Mat_&lt;float&gt; deformation;
	int patch_num;
}
</pre>
<p>To employ the PF we need to learn something about the shape - how it changes over time. The PF (a stochastic Markovian process) is dependent of the last iteration to determine the next, we therefore need to extract a shape variation model using the HPDM.<br />
So we go back to the samples, this time looking in chronological order for the relationship between the shape in one frame and the next frame. This can give us an idea of how the shape changes through time, and thus can be used as a prior for the PF.<br />
To that end we construct a transition matrix, one that tells us what is the probability of transforming from shape described by patch i to a shape described by patch j. Easily we just go over the curves sequentially and accumulate the transitions. Most of the frame-to-frame transitions are going to remain in the same patch...<br />
<a href="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-13-at-3.45.16-PM.png" rel="lightbox[1248]"><img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-13-at-3.45.16-PM.png" alt="Screen Shot 2013-03-13 at 3.45.16 PM" width="239" height="246" class="aligncenter size-full wp-image-1308" /></a><br />
In the end we get a transition matrix:<br />
<a href="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-13-at-3.47.24-PM-e1363204117135.png" rel="lightbox[1248]"><img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-13-at-3.47.24-PM-e1363204117135.png" alt="Screen Shot 2013-03-13 at 3.47.24 PM" width="276" height="276" class="aligncenter size-full wp-image-1309" /></a><br />
But we also need a cumulative version of it (accumulating per row) that we will use in the particle filter.</p>
<h3>Building the particle filter</h3>
<p>Particle filters work by assigning a score for each particle on how well it performs in this iteration, so that in later iterations we sample new particles that will partly preserve this strength but also be open for new hypotheses.<br />
To evaluate how good a particle is we examine it's adherence to edges in the image. Since I am working with a binary mask from the Kinect it has very strong and clear edges, but this method works the same way for regular images.<br />
<a href="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-13-at-4.02.44-PM.png" rel="lightbox[1248]"><img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-13-at-4.02.44-PM.png" alt="Screen Shot 2013-03-13 at 4.02.44 PM" width="291" height="246" class="aligncenter size-full wp-image-1311" /></a><br />
The red line is the hypothesized shape in that particle, the cyan circles mark if an edge was hit along the normal to the curve.<br />
Scores are given based on how many edges were hit, and if they are pointing in the right direction (i.e. the edge is aligned with the curve).</p>
<h4>Normalizing weights, resampling</h4>
<p>The standard PF part is normalizing weights of the current particles, and create the cumulative sum which is essential for easily choosing a</p>
<pre class="brush: plain; title: ; notranslate">
//sum all weights
Scalar s = sum(unnormalized_weights);
		
//calc normalized weights by dividing, and build cumulative distribution function
for (int i=0; i&lt;unnormalized_weights.size(); i++) {
	normalized_weights[i] = unnormalized_weights[i] / s[0];
	if (i==0) {
		cumulative_sum[i] = normalized_weights[i];
	} else {
		cumulative_sum[i] = cumulative_sum[i-1] + normalized_weights[i];
	}
}
</pre>
<p>We then resample new particles form the distribution we created with the current bunch of particles and the cumulative sum (this is called Sequential importance resampling):</p>
<pre class="brush: plain; title: ; notranslate">
void resampleParticles() {
	//draw N particles from the new distribution function (the importance density)
	vector&lt;Particle&gt; new_particles(num_particles);
	for (int i=0; i&lt;particles.size(); i++) {
		while (true) {
			float uni_rand = rng_.uniform(0.0f,1.0f); //randomize a number from [0,1]

			//binary search for position in cumulative sum
			vector&lt;float&gt;::iterator pos = lower_bound(cumulative_sum.begin(), cumulative_sum.end(), uni_rand);
			int ipos = distance(cumulative_sum.begin(), pos);
			if(particles[ipos].scale &lt; 0.85) continue; //re-sample if scale is bad
			new_particles[i].scale = particles[ipos].scale;
			new_particles[i].orientation = particles[ipos].orientation;
			new_particles[i].centroid = particles[ipos].centroid;
			new_particles[i].patch_num = particles[ipos].patch_num;
			particles[ipos].deformation.copyTo(new_particles[i].deformation);
			break;
		}
	}
		
	particles.clear(); particles.insert(particles.begin(),new_particles.begin(),new_particles.end());		
}
</pre>
<h4>Local optimization of particles</h4>
<p>In their paper Heap&#038;Hogg suggest we combing a few local optimization iterations with each step of the PF, and claim (rightfully) that it results in faster convergence and better results. The meaning of "local" means that we run it on the same frame a number of times, inside one iteration of the PF.<br />
To help the particles attract to the edges in the image, I try to find a rigid transformation that will decrease the energy of attraction to edges. This is a risky operation as it can throw the curve completely out of balance if the initial guess is no good.<br />
<img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/particle_optimize.gif" alt="particle_optimize" width="640" height="480" class="aligncenter size-full wp-image-1314" /><br />
The rigid transformation is found by <a href="http://en.wikipedia.org/wiki/Kabsch_algorithm">Kabsch algorithm</a>.<br />
We can also consider non-rigid transformations by looking at the patch deformation axes. I found this method not to be of great use, plus they add a ton of computation that hinders performance.</p>
<h4>Propagating</h4>
<p>To make the PF function we need to "propagate" the error through the particles. Basically meaning we need to put in some randomness in the process or else it quickly converges and gets stuck.<br />
I therefore use the transition matrix to see where each particle-shape likes to go (or, is likely to go). Actually the cumulative transition matrix:<br />
<img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-15-at-4.46.47-PM-e1363380442165.png" alt="Screen Shot 2013-03-15 at 4.46.47 PM" width="275" height="277" class="aligncenter size-full wp-image-1316" /><br />
Each row is the cumulative distribution function that tells what is the probablility of transitioning from prototypical-shape (patch) i to prototypical-shape (patch) j. I use that to randomly pick a target prototypical shape for each particle.</p>
<pre class="brush: plain; title: ; notranslate">
void propagate() {
	//according to section 3.2
	int changed = 0;
	for (int i=0; i&lt;particles.size(); i++) {
		float uni_rand = rng_.uniform(0.0f,1.0f);

		//binary search for new subregion (patch) in Cumulative Transition Matrix
		vector&lt;double&gt; row_a_in_CumulativeMat(Cumulative.cols); 
		int old_patch_num = particles[i].patch_num;
		Cumulative.row(old_patch_num).copyTo(row_a_in_CumulativeMat);
		vector&lt;double&gt;::iterator pos = upper_bound(row_a_in_CumulativeMat.begin(), row_a_in_CumulativeMat.end(), uni_rand);
		int new_patch_num = distance(row_a_in_CumulativeMat.begin(), pos);
//		cout &lt;&lt; &quot;particle &quot;&lt;&lt;i&lt;&lt;&quot; (&quot;&lt;&lt;uni_rand&lt;&lt;&quot;) [&quot;&lt;&lt;particles[i].patch_num&lt;&lt;&quot;] -&gt; [&quot;&lt;&lt;new_patch_num&lt;&lt;&quot;]\n&quot;;
		if (new_patch_num != old_patch_num) {
			//moved to a new patch (&quot;leap through wormhole&quot;): take the mean deformation of that patch
			particles[i].patch_num = new_patch_num;
			hpdm.getPatchMean(new_patch_num).copyTo(particles[i].deformation);
			changed++;
		}
			 
		add_noise(particles[i]);
			
		//TODO: particle should not go out of bounds or be too small/big or orientate too much
	}
	cout &lt;&lt; changed &lt;&lt; &quot; particles changed, &quot; &lt;&lt; (num_particles-changed) &lt;&lt; &quot; stayed\n&quot;;
}
</pre>
<p>Each particle then is added some random noise so the filter will not converge and actually be able to cope with movement and deformation of the shape.</p>
<h4>Getting the best guess of the PF</h4>
<p>Simply by looking at all the particles at a given moment, we can take the best ones and average over them.</p>
<pre class="brush: plain; title: ; notranslate">
void calculateMeanShape() {
	Particle p;
        p.scale = p.orientation = p.centroid.x = p.centroid.y = 0;
	p.deformation.create(1,hpdm.getShapeSpaceDim());
	p.deformation.setTo(0);

        //Take the particles that score the highest
        float N_precentile = *(max_element(normalized_weights.begin(),normalized_weights.end())) * 0.95;

	float sum_w = 0.0;
	for (int i=0; i&lt;num_particles; i++) {
		if (normalized_weights[i] &lt; N_precentile) {
			continue;
		}
		p.orientation += particles[i].orientation * normalized_weights[i];
		p.scale += particles[i].scale * normalized_weights[i];
		p.centroid += particles[i].centroid * normalized_weights[i];
		addWeighted(p.deformation, 1.0, particles[i].deformation, normalized_weights[i], 0.0, p.deformation);
		sum_w += normalized_weights[i];
	}
	p.orientation /= sum_w;
	p.scale /= sum_w;
	p.centroid *= 1.0/sum_w;
	p.deformation /= sum_w;

	mean_shape = getShapeForParticle(p);
}
</pre>
<p>Here is the filter running with all particles showing (40 particles). The yellow shape is the highest ranking shape, the pink shape is the average of the highest ranking shapes.<br />
<img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/pf.gif" alt="pf" width="320" height="240" class="aligncenter size-full wp-image-1317" /></p>
<h3>Code and Usage</h3>
<p>You can grab the code with a usage example here: <a href="http://web.media.mit.edu/~roys/src/HHParticleFilter.zip" target="_blank">http://web.media.mit.edu/~roys/src/HHParticleFilter.zip</a></p>
<p>Thanks!<br />
Roy.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.morethantechnical.com%2F2013%2F03%2F16%2Fcurve-tracking-with-a-heaphoggs-particle-filters-w-code-opencv%2F&amp;title=Curve%20tracking%20with%20a%20Heap%26Hogg%27s%20Particle%20Filters%20%5Bw%2F%20code%2C%20OpenCV%5D" id="wpa2a_4"><img src="http://www.morethantechnical.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.morethantechnical.com/2013/03/16/curve-tracking-with-a-heaphoggs-particle-filters-w-code-opencv/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Skin Detection with Probability Maps and Elliptical Boundaries [OpenCV, w/code]</title>
		<link>http://www.morethantechnical.com/2013/03/05/skin-detection-with-probability-maps-and-elliptical-boundaries-opencv-wcode/</link>
		<comments>http://www.morethantechnical.com/2013/03/05/skin-detection-with-probability-maps-and-elliptical-boundaries-opencv-wcode/#comments</comments>
		<pubDate>Tue, 05 Mar 2013 18:21:02 +0000</pubDate>
		<dc:creator>Roy</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[graphics]]></category>
		<category><![CDATA[opencv]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[video]]></category>
		<category><![CDATA[vision]]></category>
		<category><![CDATA[histogram]]></category>
		<category><![CDATA[model]]></category>
		<category><![CDATA[skin detection]]></category>
		<category><![CDATA[skin probability maps]]></category>

		<guid isPermaLink="false">http://www.morethantechnical.com/?p=1247</guid>
		<description><![CDATA[Skind detection wit Skin Probabilty Maps and Elliptical Boundary Models, implementations in c++ with OpenCV]]></description>
				<content:encoded><![CDATA[<p><img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/mask1-300x187.png" alt="mask" width="300" height="187" class="alignnone size-medium wp-image-1268" />Sharing a bit of code I created for skin detection.<br />
<span id="more-1247"></span><br />
At first I tried <strong>Skin Probability Maps</strong>, of which I read in a number of papers (<a href="http://www.sciencedirect.com/science/article/pii/S0031320306002767" target="_blank">Kukumanu et al 2007</a>, <a href="http://www.cse.unsw.edu.au/~icml2002/workshops/MLCV02/MLCV02-Morales.pdf" target="_blank">Gomez &#038; Morales 2002</a>).<br />
Basically SPMs are very easy to implement: Calculate the histogram for skin region and non-skin region, and then make a decision for each pixel based on those histograms.<br />
There's a few assumptions and decision to make, to name a few: </p>
<ol>
<li>What is the skin region in a given image? If we don't yet have a model for it. I call that the Bootstrap problem,</li>
<li>What colorspace to use/histogram?</li>
<li>The per pixel decision parameter (theta in the literature)</li>
</ol>
<h3>Bootstrap</h3>
<p>For bostratpping (namely, getting an initial guess for skin pixels) I used the method from <a href="http://www.cse.unsw.edu.au/~icml2002/workshops/MLCV02/MLCV02-Morales.pdf" target="_blank">Gomez &#038; Morales 2002</a>:</p>
<pre class="brush: plain; title: ; notranslate">
//get HSV
Mat hsv; cvtColor(rgb, hsv, CV_BGR2HSV);
//get Normalized RGB (aka rgb)
Mat nrgb = getNormalizedRGB(rgb);
		
//take the pixels that are inside the ranges in both colorspaces
Mat mask_hsv, mask_nrgb;
//H=[0,50], S= [0.20,0.68] and V= [0.35,1.0]
inRange(hsv, Scalar(0,0.2*255.0,0.35*255.0), Scalar(50.0/2.0,0.68*255.0,1.0*255.0), mask_hsv);
//r = [0.36,0.465], g = [0.28,0.363]
inRange(nrgb, Scalar(0,0.28,0.36), Scalar(1.0,0.363,0.465), mask_nrgb);

//combine the masks
outputmask = mask_hsv &amp; mask_nrgb;
</pre>
<div id="attachment_1250" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.morethantechnical.com/wp-content/uploads/2013/03/rgb.png" rel="lightbox[1247]"><img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/rgb-300x187.png" alt="Input RGB" width="300" height="187" class="size-medium wp-image-1250" /></a><p class="wp-caption-text">Input RGB</p></div>
<div id="attachment_1249" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.morethantechnical.com/wp-content/uploads/2013/03/mask.png" rel="lightbox[1247]"><img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/mask-300x187.png" alt="Bootstrap mask" width="300" height="187" class="size-medium wp-image-1249" /></a><p class="wp-caption-text">Bootstrap mask</p></div>
<h3>Training</h3>
<p>After we get a bootstrap, which you can see is pretty bad, we can start training the model to get a better segmentation. Essentially this means calculating 2 histograms, one for skin pixels and one for non-skin pixels.</p>
<pre class="brush: plain; title: ; notranslate">
Mat nrgb = getNormalizedRGB(img_rgb);

MatND skin_hist,non_skin_hist;
skin_hist = calc_rg_hist(nrgb,mask);
non_skin_hist = calc_rg_hist(nrgb,~mask);
		
//create a probabilty density function
float skin_pixels = countNonZero(mask), non_skin_pixels = countNonZero(~mask);
for (int ubin=0; ubin &lt; 250; ubin++) {
	for (int vbin = 0; vbin &lt; 250; vbin++) {
		if (skin_hist.at&lt;float&gt;(ubin,vbin) &gt; 0) {
			skin_hist.at&lt;float&gt;(ubin,vbin) /= skin_pixels;
		}
		if (non_skin_hist.at&lt;float&gt;(ubin,vbin) &gt; 0) {
			non_skin_hist.at&lt;float&gt;(ubin,vbin) /= non_skin_pixels;
		}
	}
}
</pre>
<p>We normalize the histograms with the number of skin (and non-skin) pixels to create a Probability Density Function (that sums to 1).</p>
<p><div id="attachment_1253" class="wp-caption aligncenter" style="width: 286px"><a href="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-04-at-4.11.52-PM-e1362431594398.png" rel="lightbox[1247]"><img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-04-at-4.11.52-PM-e1362431594398.png" alt="Skin pixels histogram" width="276" height="300" class="size-medium wp-image-1253" /></a><p class="wp-caption-text">Skin pixels histogram</p></div><br />
<div id="attachment_1254" class="wp-caption aligncenter" style="width: 292px"><a href="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-04-at-4.11.54-PM-e1362431637508.png" rel="lightbox[1247]"><img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-04-at-4.11.54-PM-e1362431637508.png" alt="Non-skin pixels histogram" width="282" height="300" class="size-medium wp-image-1254" /></a><p class="wp-caption-text">Non-skin pixels histogram</p></div></p>
<h3>Predicting</h3>
<p>The SPM algorithm simply states you make a binary prediction (yes or no) for each pixel based on a  <span class='MathJax_Preview'><img src='http://www.morethantechnical.com/wp-content/plugins/latex/cache/tex_2554a2bb846cffd697389e5dc8912759.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\theta" /></span><script type='math/tex'>\theta</script>  value (a variable given to the algorithm):</p>
<div style="text-align: center">
 <span class='MathJax_Preview'><img src='http://www.morethantechnical.com/wp-content/plugins/latex/cache/tex_0a2ad88de9301b67ade5390edb7b883f.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\dfrac{p(c | \text{skin})}{p(c | \text{non-skin})} > \theta" /></span><script type='math/tex'>\dfrac{p(c | \text{skin})}{p(c | \text{non-skin})} > \theta</script> 
</div>
<p>The implementation is trivial if you already have the normalized histograms (and thus PDFs):</p>
<pre class="brush: plain; title: ; notranslate">
float skin_hist_val = skin_hist.at&lt;float&gt;(gbin,rbin);
if (skin_hist_val &gt; 0) {
	float non_skin_hist_val = non_skin_hist.at&lt;float&gt;(gbin,rbin);
	if (non_skin_hist_val &gt; 0) {
		if((skin_hist_val / non_skin_hist_val) &gt; theta_thresh)
			result_mask(i) = 255;
		else 
			result_mask(i) = 0;
	} else {
		result_mask(i) = 0;
	}
} else {
	result_mask(i) = 0;
}
</pre>
<h3>Retraining</h3>
<p>I find it good to re-train the model a number of time. What I mean is that I iterate a number of times with train-predict operations, where every iteration I use the result of the prediction to train the model again:</p>
<pre class="brush: plain; title: ; notranslate">
for (int i=0; i&lt;10; i++) { //predict-train N times for convergence
      medianBlur(mask, mask, 3);
      spm.train(cameraframe, mask);
      spm.predict(cameraframe, mask);
      imshow(&quot;mask&quot;, mask);
      waitKey(50);
}
</pre>
<p>The results get kind of better with each retraining. Of course there's risk of converging around something which is not skin, and then it all goes to hell.<br />
<div id="attachment_1268" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.morethantechnical.com/wp-content/uploads/2013/03/mask1.png" rel="lightbox[1247]"><img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/mask1-300x187.png" alt="skin region mask after 10 re-trains" width="300" height="187" class="size-medium wp-image-1268" /></a><p class="wp-caption-text">skin region mask after 10 re-trains</p></div></p>
<div id="attachment_1269" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.morethantechnical.com/wp-content/uploads/2013/03/rgb1.png" rel="lightbox[1247]"><img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/rgb1-300x187.png" alt="input RGB" width="300" height="187" class="size-medium wp-image-1269" /></a><p class="wp-caption-text">input RGB</p></div>
<div id="attachment_1271" class="wp-caption aligncenter" style="width: 160px"><a href="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-04-at-5.54.19-PM-e1362437874872.png" rel="lightbox[1247]"><img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-04-at-5.54.19-PM-e1362437874872-150x150.png" alt="skin hist after 10 retrains" width="150" height="150" class="size-thumbnail wp-image-1271" /></a><p class="wp-caption-text">skin hist after 10 retrains</p></div>
<div id="attachment_1270" class="wp-caption aligncenter" style="width: 160px"><a href="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-04-at-5.54.22-PM-e1362437855516.png" rel="lightbox[1247]"><img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-04-at-5.54.22-PM-e1362437855516-150x150.png" alt="non skin hist after 10 re-trains" width="150" height="150" class="size-thumbnail wp-image-1270" /></a><p class="wp-caption-text">non skin hist after 10 re-trains</p></div>
<h2>Elliptical Boundary Model</h2>
<p>I learned of the elliptical boundary model through the paper by <a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.215.725&#038;rep=rep1&#038;type=pdf" target="_blank">Lee and Yoo from 2002</a>. But I found the results to be lesser than those of the SPM. In fact I anticipated that, since the EBM tries to model the distribution (or rather give a criterion for pixel-based decision based on the distribution), where the SPMs make no modeling of the distribution and use it as is. The SPMs are more memory-intensive (keeping the entire histograms in memory), but are more accurate since all the information is retained.</p>
<p>The EBM model the skin color distribution by fitting an ellips(oid) to the distribution of skin color values in the histogram.<br />
<a href="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-05-at-10.47.17-AM.png" rel="lightbox[1247]"><img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-05-at-10.47.17-AM-e1362498946450-150x150.png" alt="Screen Shot 2013-03-05 at 10.47.17 AM" width="150" height="150" class="aligncenter size-thumbnail wp-image-1282" /></a></p>
<p>And makes a decision by using the following inequality:  <span class='MathJax_Preview'><img src='http://www.morethantechnical.com/wp-content/plugins/latex/cache/tex_f90e2e8e0d1b4ac6faa2b249a00f154a.gif' style='vertical-align: middle; border: none; ' class='tex' alt="[X-\psi]^t \Lambda^{-1} [X-\psi] > \theta" /></span><script type='math/tex'>[X-\psi]^t \Lambda^{-1} [X-\psi] > \theta</script> <br />
Where  <span class='MathJax_Preview'><img src='http://www.morethantechnical.com/wp-content/plugins/latex/cache/tex_02129bb861061d1a052c592e2dc6b383.gif' style='vertical-align: middle; border: none; padding-bottom:1px;' class='tex' alt="X" /></span><script type='math/tex'>X</script>  is the tested pixel color-value in r-g space,  <span class='MathJax_Preview'><img src='http://www.morethantechnical.com/wp-content/plugins/latex/cache/tex_a11bd56a0ff5973a5604bb3fc9142b1d.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\psi" /></span><script type='math/tex'>\psi</script>  is the mean value in the distribution and  <span class='MathJax_Preview'><img src='http://www.morethantechnical.com/wp-content/plugins/latex/cache/tex_781ff4289c6cc5fc2973b7a57791e0e2.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\Lambda" /></span><script type='math/tex'>\Lambda</script>  is calculated like so:<br />
 <span class='MathJax_Preview'><img src='http://www.morethantechnical.com/wp-content/plugins/latex/cache/tex_982ddc747b8cdffbe2546ca3869d8406.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\Lambda = \frac{1}{N} \sum_{i=1}^n {f_i (X_i - \mu) (X_i - \mu)^t}" /></span><script type='math/tex'>\Lambda = \frac{1}{N} \sum_{i=1}^n {f_i (X_i - \mu) (X_i - \mu)^t}</script> <br />
Where  <span class='MathJax_Preview'><img src='http://www.morethantechnical.com/wp-content/plugins/latex/cache/tex_c9faf6ead2cd2c2187bd943488de1d0a.gif' style='vertical-align: middle; border: none; padding-bottom:1px;' class='tex' alt="\mu" /></span><script type='math/tex'>\mu</script>  is a weighted mean of the colors in the histogram,  <span class='MathJax_Preview'><img src='http://www.morethantechnical.com/wp-content/plugins/latex/cache/tex_59bdf0ba696e13164c5a926386f23cb0.gif' style='vertical-align: middle; border: none; ' class='tex' alt="f_i" /></span><script type='math/tex'>f_i</script>  is the frequency of the color-value  <span class='MathJax_Preview'><img src='http://www.morethantechnical.com/wp-content/plugins/latex/cache/tex_a97118fb9e8d7e006a466bfc0771f888.gif' style='vertical-align: middle; border: none; ' class='tex' alt="X_i" /></span><script type='math/tex'>X_i</script>  - both of which come from the histogram.<br />
So you kind of see how simple it is to calculate it: (given <code>f_hist</code> is the histogram on the r-g space)</p>
<pre class="brush: plain; title: ; notranslate">
	void train() {
		T ustep = range_dist[0]/hist_bins[0], vstep = range_dist[1]/hist_bins[1];
		
		//calc n, X_i and mu
		Mat_&lt;T&gt; mu(1,2); mu.setTo(0);
		vector&lt;T&gt; f;
		int n = countNonZero(f_hist);
        int count = 0;
        int N = 0;
		Mat_&lt;T&gt; X(n,2);
		for (T ubin=0; ubin &lt; hist_bins[0]; ubin++) {
			for (T vbin = 0; vbin &lt; hist_bins[1]; vbin++) {
                T histval = f_hist.at&lt;T&gt;(ubin,vbin);
				if (histval &gt; 0) {
					Mat_&lt;T&gt; sampleX = (Mat_&lt;T&gt;(1,2) &lt;&lt; low_range[0] + ustep * (ubin+.5), low_range[1] + vstep * (vbin+.5));
                    sampleX.copyTo(X.row(count++));
					f.push_back(histval);
					mu += histval * sampleX;
                    N += histval;
				}
			}
		}
        
		mu /= (T)N;
						
		//calc psi - mean of DB
		reduce(X, psi, 0, CV_REDUCE_AVG);
		
		//calc Lambda
		Lambda.create(2,2);
		for (int i=0; i &lt; n; i++) {
			Mat_&lt;T&gt; X_m_mu = (X.row(i) - mu);
			Mat_&lt;T&gt; prod = f[i] * X_m_mu.t() * X_m_mu;
			Lambda += prod;
		}
		Lambda /= N;
		Mat_&lt;T&gt; linv = Lambda.inv();
		Lambda_inv.val[0] = linv(0,0);
		Lambda_inv.val[1] = linv(0,1);
		Lambda_inv.val[2] = linv(1,0);
		Lambda_inv.val[3] = linv(1,1);
		
		cout &lt;&lt; &quot;n = &quot; &lt;&lt; n &lt;&lt; &quot; N = &quot; &lt;&lt; N &lt;&lt; &quot; mu &quot; &lt;&lt; mu &lt;&lt; &quot;\npsi &quot; &lt;&lt; psi &lt;&lt; &quot;\nlambda_inv &quot;&lt;&lt; Lambda_inv&lt;&lt;&quot;\n&quot;;
	}
</pre>
<p>But like I said the results are not so good: ( <span class='MathJax_Preview'><img src='http://www.morethantechnical.com/wp-content/plugins/latex/cache/tex_613510aefd2eab483ce1c349358b0c8b.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\theta = 2" /></span><script type='math/tex'>\theta = 2</script>  in this case)<br />
<a href="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-05-at-12.05.12-PM.png" rel="lightbox[1247]"><img src="http://www.morethantechnical.com/wp-content/uploads/2013/03/Screen-Shot-2013-03-05-at-12.05.12-PM-e1362503179350-300x211.png" alt="Screen Shot 2013-03-05 at 12.05.12 PM" width="300" height="211" class="aligncenter size-medium wp-image-1286" /></a></p>
<p>There's again the option of "retraining" the EBM, although this time it's basically just accumulating the r-g histogram with more pixels.</p>
<h3>Code</h3>
<p>Check the code out, with a snippet on how to use it at: <a href="http://web.media.mit.edu/~roys/src/SPMandEBM.zip" target="_blank">http://web.media.mit.edu/~roys/src/SPMandEBM.zip</a></p>
<p>Thanks!<br />
Roy.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.morethantechnical.com/2013/03/05/skin-detection-with-probability-maps-and-elliptical-boundaries-opencv-wcode/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>A Creative way to bypass Pattern lock on Android</title>
		<link>http://www.morethantechnical.com/2013/01/29/a-creative-way-to-bypass-pattern-lock-on-android/</link>
		<comments>http://www.morethantechnical.com/2013/01/29/a-creative-way-to-bypass-pattern-lock-on-android/#comments</comments>
		<pubDate>Tue, 29 Jan 2013 19:12:21 +0000</pubDate>
		<dc:creator>Arnon</dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Mobile phones]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[galaxy]]></category>
		<category><![CDATA[odin]]></category>
		<category><![CDATA[pattern lock]]></category>
		<category><![CDATA[pattern unlock]]></category>
		<category><![CDATA[samsung]]></category>
		<category><![CDATA[unrooted]]></category>

		<guid isPermaLink="false">http://www.morethantechnical.com/?p=1239</guid>
		<description><![CDATA[Let me start putting everything on the table – this post will describe how I eventually managed to unlock an unrooted, non-Google account linked Samsung Galaxy Mini Plus (GT-5570I) device without ADB support. There are a lot of guides on how to bypass this pattern lock on Android (and I will provide some links), but [...]]]></description>
				<content:encoded><![CDATA[<p><img alt="" src="http://www.morethantechnical.com/wp-content/uploads/2013/01/012913_1912_ACreativewa1.png" align="left" />Let me start putting everything on the table – this post will describe how I eventually managed to unlock an unrooted, non-Google account linked Samsung Galaxy Mini Plus (GT-5570I) device <span style="text-decoration: underline;">without</span> ADB support. There are a lot of guides on how to bypass this pattern lock on Android (and I will provide some links), but the purpose of this post is to show how looking for creative ways to do this can come handy</p>
<p style="text-align: justify;">So a friend gave me a locked device. This device had no Google account linked to it (which prevented me from bypassing the lock with that account), there was no root or ADB access via recovery, and the USB debugging option was disabled.</p>
<p style="text-align: justify;">I found <a href="http://forum.xda-developers.com/showthread.php?t=1800799">this guide here</a>, which states some commands you can type in ADB shell and should deactivate the pattern lock. So – How do I get ADB access on that phone?<span id="more-1239"></span></p>
<p style="text-align: justify;">My first try was to flash a recovery image which allows ADB access. This allegedly easy task that is normally done with Odin, turned out to be impossible. I managed to download all the necessary files, but Odin (which for those of you who are unfamiliar – is the software you use with Samsung phones to flash partitions, repartition and basically everything regarding flashing) refused to detect the phone. I had on my PC another version of Odin, for other phones, which detected the phone, but I could not use it with the files compatible with this model.</p>
<p style="text-align: justify;">So, back to snooping the forums. I found a <a href="www.morethantechnical.com/filesrep/pop_plus_CWM.zip">flashable zip file</a> (Link here – remember – Only Galaxy Mini) which allowed me to start ClockworkMod recovery on that phone.</p>
<p>Cool – Now I will had adb access and can type in the commands and go to eat my lunch. WRONG. I need I got CWM to start, but my PC did not recognize any ADB interface. I'm not sure why, either this CWM didn't support ADB, or that fact that it just "rebooted" into CWM from the normal recovery didn't allow it to grant the ADB access. My guess was that if I would have been able to flash it properly – it would have worked.</p>
<p>So now I have CWM, no ADB access and commands I'm unable to type.</p>
<p>And then I understood something – What if I could just create a zip file that runs these commands? I was <a href="http://www.garage4hackers.com/f54/reset-android-pin-pattern-lock-using-flashable-zip-tested-gingerbread-2630.html">not the first one to think about this</a>.</p>
<p>So.. I tried flashing <a href="http://www.morethantechnical.com/filesrep/resetpattern.zip">this zip</a>. Didn't work. Looking at what the zip is doing – I understood what was the problem. The zip tries to mount /system and /data using busybox. Which… I didn't have… since I was using stock unrooted ROM.</p>
<p>Last try – I tried mounting /system and /data via CWM.<img alt="" src="http://www.morethantechnical.com/wp-content/uploads/2013/01/012913_1912_ACreativewa2.jpg" align="right" /> Did that and Retried flashing that unlock zip. <strong>IT WORKED!!</strong></p>
<p>This took a lot of thought and thinking out of the box. But it was worth it.</p>
<p>So, to summarize what I've done to unlock the device</p>
<ol>
<li>Placed the <a href="www.morethantechnical.com/filesrep/pop_plus_CWM.zip">CWM zip</a> and <a href="http://www.morethantechnical.com/filesrep/resetpattern.zip">Pattern Unlock zip</a> on the microSD</li>
<li>Started the device to stock recovery (When device is off – Middle button + Volume UP + Power</li>
<li>Chose "Install update zip" and selected CWM zip. Now CWM interface started up</li>
<li>Go to "mounts and storage menu" and mount /data and /system</li>
<li>Go back, and flash the pattern unlock zip</li>
<li>Reboot phone</li>
</ol>
<p>This process was exhausting, but worth it. I really hope you will find this post useful</p>
<p>P.S - The photo on the right is wrong, mounting /cache is unnecessary ;) my photographic mistake</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.morethantechnical.com%2F2013%2F01%2F29%2Fa-creative-way-to-bypass-pattern-lock-on-android%2F&amp;title=A%20Creative%20way%20to%20bypass%20Pattern%20lock%20on%20Android" id="wpa2a_6"><img src="http://www.morethantechnical.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.morethantechnical.com/2013/01/29/a-creative-way-to-bypass-pattern-lock-on-android/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Using your Raspberry Pi as an SSL Proxy</title>
		<link>http://www.morethantechnical.com/2013/01/13/using-your-raspberry-pi-as-an-ssl-proxy/</link>
		<comments>http://www.morethantechnical.com/2013/01/13/using-your-raspberry-pi-as-an-ssl-proxy/#comments</comments>
		<pubDate>Sun, 13 Jan 2013 10:24:48 +0000</pubDate>
		<dc:creator>Arnon</dc:creator>
				<category><![CDATA[apache]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[Networking]]></category>
		<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[ssl]]></category>
		<category><![CDATA[proxy]]></category>
		<category><![CDATA[raspberry pi]]></category>
		<category><![CDATA[reverse proxy]]></category>

		<guid isPermaLink="false">http://www.morethantechnical.com/?p=1214</guid>
		<description><![CDATA[Not long ago, I have purchased an IP camera for my home. A nice toy I must say. I wanted to expose this camera for outside access. The issue is that this camera's interface does not support SSL. Well because privacy is involved, the least I could do is add SSL somehow. I googled a [...]]]></description>
				<content:encoded><![CDATA[<p>Not long ago, I have purchased an IP camera for my home. A nice toy I must say. I wanted to expose this camera for outside access. The issue is that this camera's interface does not support SSL.</p>
<p>Well because privacy is involved, the least I could do is add SSL somehow. I googled a bit and came across <a href="http://bitsofinfo.wordpress.com/2012/07/20/securing-foscam-ip-camera-access-over-ssl-with-apache-reverse-proxying/"><strong>this article</strong></a><strong>. </strong>I decided to use my raspberry pi for that.</p>
<p>The process itself is relatively easy but I had to do some improvisations over the article above. So I decided to make a tutorial for this.</p>
<p>You can use this to add SSL layer on top of every http you have.</p>
<p>So here we go:<span id="more-1214"></span></p>
<ol>
<li>
<div>Install apache2 on your raspberry pi:</div>
<pre class="brush: plain; title: ; notranslate">sudo apt-get install apache2</pre>
</li>
<li>
<div>Enable ssl, proxy and proxy_http modules:</div>
<pre class="brush: plain; title: ; notranslate">sudo a2enmod ssl
sudo a2enmod proxy
sudo a2enmod proxy_http</pre>
</li>
<li>
<div>Add listener to port 10001 (You can use any port, this is from the sample)<br />
I have used ports.conf file to add it. You can create a new configuration file for this if you like</div>
<pre class="brush: plain; title: ; notranslate">NameVirtualHost *:10001

Listen 10001</pre>
</li>
<li>
<div>Add definitions for you camera's reverse proxy (VirtualHost tag)</div>
<p>Few notes:</li>
</ol>
<ul style="margin-left: 54pt;">
<li>The camera's internal address and port in this example is 192.168.9.11:81</li>
<li>The logs are located in /var/log/apache2 - you can change it to a path you desire</li>
<li>The certificate are self signed. It is explained next</li>
</ul>
<pre class="brush: plain; title: ; notranslate">
&lt;VirtualHost *:10001&gt;
 ProxyRequests Off
 ProxyPreserveHost On
 ProxyVia On

 Order deny,allow
 Allow from all

 ProxyPass / http://192.168.9.11:81/
 ProxyPassReverse / http://192.168.9.11:81/
 CustomLog /var/log/apache2/access_cam1.log combined
 ErrorLog /var/log/apache2/error_cam1.log
 ServerName cam1

 SSLEngine On
 SSLCertificateFile /etc/apache2/mycrt.crt
 SSLCertificateKeyFile /etc/apache2/mycrt.key

 &lt;FilesMatch &quot;\.(cgi|shtml|phtml|php)$&quot;&gt;
 SSLOptions +StdEnvVars

 SSLOptions +StdEnvVars

 BrowserMatch &quot;MSIE [2-6]&quot; \
 nokeepalive ssl-unclean-shutdown \
 downgrade-1.0 force-response-1.0
 # MSIE 7 and newer should be able to use keepalive
 BrowserMatch &quot;MSIE [17-9]&quot; ssl-unclean-shutdown
&lt;/VirtualHost&gt;
</pre>
<p>Now we need to create certificate files. I used <a style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px;" href="http://www.thegeekstuff.com/2009/07/linux-apache-mod-ssl-generate-key-csr-crt-file/">this guide</a> in order to do it. It's pretty straight forward (In my example above I've called them "mycrt")</p>
<p>We're almost good to go. In case you created a passphrase for you certificate, you will notice that as you restart your apache2 it will require you to enter your passphrase.</p>
<p>This can be avoided, if you'd like.</p>
<ul style="margin-left: 54pt;">
<li>
<div>Create a shell script that echoes your passphrase:<br />
file: nopass.sh</div>
<pre class="brush: plain; title: ; notranslate">#!/bin/bash
 echo your-password</pre>
</li>
<li>Add execute permissions to this script</li>
<li>
<div>Edit ssl.conf, and change the SSLPassPhraseDialog line</div>
<pre class="brush: plain; title: ; notranslate">SSLPassPhraseDialog exec:/etc/apache2/nopass.sh</pre>
</li>
</ul>
<p>That's it! Now you can restart your apahce with</p>
<pre class="brush: plain; title: ; notranslate">sudo service apahce2 restart</pre>
<p>Now try accessing your raspberry pi with <a href="https://&lt;ip&gt;:10001">https://&lt;ip&gt;:10001</a></p>
<p>You should see your webcam's login interface with SSL</p>
<p>Feel free to port-forward from your router to your raspberry pi's new SSL port in order to access your camera from the outer world</p>
<p>I hope this guide is useful for you.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.morethantechnical.com%2F2013%2F01%2F13%2Fusing-your-raspberry-pi-as-an-ssl-proxy%2F&amp;title=Using%20your%20Raspberry%20Pi%20as%20an%20SSL%20Proxy" id="wpa2a_8"><img src="http://www.morethantechnical.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.morethantechnical.com/2013/01/13/using-your-raspberry-pi-as-an-ssl-proxy/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Shape manipulation with Moving Least Squares for curves [w/ code]</title>
		<link>http://www.morethantechnical.com/2013/01/05/shape-manipulation-with-moving-least-squares-for-curves-w-code/</link>
		<comments>http://www.morethantechnical.com/2013/01/05/shape-manipulation-with-moving-least-squares-for-curves-w-code/#comments</comments>
		<pubDate>Fri, 04 Jan 2013 22:37:24 +0000</pubDate>
		<dc:creator>Roy</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[graphics]]></category>
		<category><![CDATA[opencv]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[curve]]></category>
		<category><![CDATA[deformation]]></category>
		<category><![CDATA[least]]></category>
		<category><![CDATA[manipulation]]></category>
		<category><![CDATA[moving]]></category>
		<category><![CDATA[shape]]></category>
		<category><![CDATA[squares]]></category>

		<guid isPermaLink="false">http://www.morethantechnical.com/?p=1200</guid>
		<description><![CDATA[Shape manipulation with Moving Least Squares for 2D curves.]]></description>
				<content:encoded><![CDATA[<p><img src="http://www.morethantechnical.com/wp-content/uploads/2013/01/Screen-shot-2013-01-04-at-5.35.00-PM-300x243.png" alt="" title="Screen shot 2013-01-04 at 5.35.00 PM" width="300" height="243" class="alignleft size-medium wp-image-1209" />Hello,</p>
<p>I wanna share some code I've been working on lately that implements smooth shape manipulation using Moving Least Squares. More specifically, the excellent simple and powerful method by Schaefer et al. from Texas A&amp;M and Rice universities (great <a href="http://dl.acm.org/citation.cfm?id=1141920" target="_blank">paper</a>). The method was written for image deformation but very straightforward modifications made it work perfectly for 2D shapes and open curves.</p>
<p>Let's get down to business<br />
<span id="more-1200"></span></p>
<h2>Affine, similarity and rigid deformations</h2>
<p>The beauty with Schefer's method is that it simple to implement, presents powerful results and is blazing-fast because of the optimizations they suggest in the paper (decomposing the math to allow pre-computing as much as possible). Initially they show three methods for deformation: Affine, Similarity and Rigid.<br />
Affine deformation means that, locally, affected points could undergo a complete <a href="http://en.wikipedia.org/wiki/Affine_transformation" target="_blank">affine transformation</a>, meaning: Rotation, Translation, non uniform Scale, Shear and Squeeze. While it is still cool, it can unrealistically distort the shapes.<br />
<img src="http://www.morethantechnical.com/wp-content/uploads/2013/01/animation.gif" alt="" title="animation" width="700" height="350" class="aligncenter size-full wp-image-1203" /><br />
See how in extreme stretch the top fin and mouth of the fish are distorted.</p>
<p>Similarity transformations allow only Rotation, Translation and uniform Scale, which makes the deformation more appealing, but it does tend to enlarge parts on extreme stretch:<br />
<img src="http://www.morethantechnical.com/wp-content/uploads/2013/01/animation1.gif" alt="" title="animation" width="700" height="350" class="aligncenter size-full wp-image-1205" /></p>
<p>Finally, Rigid transformation only allow local Rotation and Translation, keeping the deformed shape more rigid:<br />
<img src="http://www.morethantechnical.com/wp-content/uploads/2013/01/animation2.gif" alt="" title="animation" width="700" height="350" class="aligncenter size-full wp-image-1207" /></p>
<h2>Using the code</h2>
<p>Everything is encapsulated in the SchaeferMLS template class:</p>
<pre class="brush: plain; title: ; notranslate">
template&lt;typename T&gt;
class SchaeferMLS {
public:
	void Init(const vector&lt;Point_&lt;T&gt; &gt;&amp; curve, const vector&lt;int&gt;&amp; control_idx) {...}
	
	void UpdateAffine() {...}
	void UpdateSimilarity() {...}
	void UpdateRigid() {...}
	
	const vector&lt;Point_&lt;T&gt; &gt;&amp; GetControlPts() { ...}
	vector&lt;Point_&lt;T&gt; &gt;&amp; GetDeformedControlPts() { ...}
	
	void Draw(Mat&amp; img) {...}
};
</pre>
<p>I've written a small app to show simple usage with the different deformation types, it's fairly simple to follow.<br />
But the gist is:</p>
<pre class="brush: plain; title: ; notranslate">
//Read curve
vector&lt;Point&gt; a;
GetCurveForImage(imread(&quot;a_slihouette.png&quot;, a, false);

//Convert to Point_&lt;double&gt; - optional
vector&lt;Point2d&gt; a_p2d, a_p2d_smoothed;
ConvertCurve(a, a_p2d);

//Get curvature extrema points
vector&lt;pair&lt;char,int&gt; &gt; stringrep = CurvatureExtrema(a_p2d, a_p2d_smoothed,0.05,4.0);

//Get extrema as control points
vector&lt;int&gt; control_pts; 
for(int i=0;i&lt;stringrep.size();i++) {
	control_pts.push_back(stringrep[i].second);
}

smls.Init(a_p2d, control_pts);
smls.UpdateRigid();
	
Mat visualized_curve(500,500,CV_8UC3);
smls.Draw(visualized_curve);

namedWindow(&quot;MLS&quot;);
//Implement the onMouse function (or take from repo) to reflect changes in control points
setMouseCallback(&quot;MLS&quot;, onMouse, NULL);
imshow(&quot;MLS&quot;, visualized_curve);
waitKey();
</pre>
<p>You can grab the code at github: <a href="https://github.com/royshil/CurveDeformationMLS" target="_blank">https://github.com/royshil/CurveDeformationMLS</a></p>
<p>Thanks for tuning in!<br />
Roy.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.morethantechnical.com/2013/01/05/shape-manipulation-with-moving-least-squares-for-curves-w-code/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>2D curve matching in OpenCV [w/ code]</title>
		<link>http://www.morethantechnical.com/2012/12/27/2d-curve-matching-in-opencv-w-code/</link>
		<comments>http://www.morethantechnical.com/2012/12/27/2d-curve-matching-in-opencv-w-code/#comments</comments>
		<pubDate>Thu, 27 Dec 2012 02:13:38 +0000</pubDate>
		<dc:creator>Roy</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[graphics]]></category>
		<category><![CDATA[opencv]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[school]]></category>
		<category><![CDATA[vision]]></category>
		<category><![CDATA[work]]></category>

		<guid isPermaLink="false">http://www.morethantechnical.com/?p=1189</guid>
		<description><![CDATA[Matching 2D curves in OpenCV by analysis of curvature signatures, which makes the method robust to rigid transformation but also noise and heave occlusion.]]></description>
				<content:encoded><![CDATA[<p style="text-align: left;"><img class="aligncenter  wp-image-1192" title="deer_curve_transforms" src="http://www.morethantechnical.com/wp-content/uploads/2012/12/deer_curve_transforms.png" alt="" width="396" height="351" /><br />
Just sharing some code and ideas for matching 2D curves. I was working for a while on matching 2D curves to discover shapes in images, but it didn't work out, what did succeed is this 2D curve matcher that seems to be very robust for certain applications. It's based on ideas from the Heat Kernel Signature and the CSS Image (that I introduced in <a title="Resampling, Smoothing and Interest points of curves (via CSS) in OpenCV [w/ code]" href="http://www.morethantechnical.com/2012/12/07/resampling-smoothing-and-interest-points-of-curves-via-css-in-opencv-w-code/" target="_blank">my latest post</a>), all around inspecting curves under different level of smoothing.<br />
<span id="more-1189"></span></p>
<h2>Principle</h2>
<p style="text-align: center;">The idea is simple, take the curve and build a "Signature Database" for it, which then you compare to another DB.<br />
The database is essentially every possible sub-curve of the curve, under every possible offset, all normalized to the same length.<br />
This also makes this method quite robust to occlusions! (where only part of the target curve is available)<br />
<img class="aligncenter  wp-image-1193" title="Screen shot 2012-12-26 at 8.22.35 PM" src="http://www.morethantechnical.com/wp-content/uploads/2012/12/Screen-shot-2012-12-26-at-8.22.35-PM.png" alt="" width="529" height="466" /><br />
The matching is done over the curvature of (a smoothed version of) the curve, the 2nd derivative, which was nicely explained in <a href="http://www.sciencedirect.com/science/article/pii/S0031320301000401" target="_blank">this paper</a> by Mokhtarian in 2002.</p>
<h2>Working with the functions</h2>
<p>I created a sample app that takes in a curve (binary image with contour extracted), transforms it and then tries to find a match with the original.<br />
But the central function is</p>
<pre class="brush: plain; title: ; notranslate">
template
void CompareCurvesUsingSignatureDB(const vector&lt;Point_ &gt;&amp; a,
								   const vector&lt;Point_ &gt;&amp; b,
								   int&amp; a_len,
								   int&amp; a_off,
								   int&amp; b_len,
								   int&amp; b_off,
								   double&amp; score
								   );
</pre>
<p>It takes in any type of curve (Point, Point2f, Point2d) and returns the length and offset inside each curve of the sub-curves that best match.<br />
You can then find a rigid transformation easily by</p>
<pre class="brush: plain; title: ; notranslate">
//assume you have vector a,b; from before

//Get matched subsets of curves
vector a_subset(a.begin() + a_off, a.begin() + a_off + a_len);
vector b_subset(b.begin() + b_off, b.begin() + b_off + b_len);

//Normalize to equal length
ResampleCurve(a_subset, a_subset, 200, true);
ResampleCurve(b_subset, b_subset, 200, true);

//Find rigid transformation
Mat trans = Find2DRigidTransform(a_subset, b_subset);
vector a_trans;
cv::transform(a_subset,a_trans,trans);
</pre>
<h2>Code and salutations</h2>
<p>Get the code <a href="https://github.com/royshil/CurveMatching" target="_blank">at the github repo</a></p>
<p>Enjoy!<br />
Roy.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.morethantechnical.com/2012/12/27/2d-curve-matching-in-opencv-w-code/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Resampling, Smoothing and Interest points of curves (via CSS) in OpenCV [w/ code]</title>
		<link>http://www.morethantechnical.com/2012/12/07/resampling-smoothing-and-interest-points-of-curves-via-css-in-opencv-w-code/</link>
		<comments>http://www.morethantechnical.com/2012/12/07/resampling-smoothing-and-interest-points-of-curves-via-css-in-opencv-w-code/#comments</comments>
		<pubDate>Fri, 07 Dec 2012 17:17:46 +0000</pubDate>
		<dc:creator>Roy</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[graphics]]></category>
		<category><![CDATA[opencv]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[school]]></category>
		<category><![CDATA[2d]]></category>
		<category><![CDATA[curve]]></category>

		<guid isPermaLink="false">http://www.morethantechnical.com/?p=1169</guid>
		<description><![CDATA[Utility functions for Resampling, Smoothing and finding Interest points of 2D curves in OpenCV.]]></description>
				<content:encoded><![CDATA[<p><img src="http://www.morethantechnical.com/wp-content/uploads/2012/12/camel-curve-300x111.png" alt="" title="camel-curve" width="300" height="111" class="aligncenter size-medium wp-image-1184" /><br />
I'm so glad to be back to work on a graphics project (of which you will probably hear later), because it takes me back to reading papers and implementing work by talented people. I want share a little bit of utilities I've developed for working with 2D curves in OpenCV.</p>
<p><span id="more-1169"></span></p>
<h2>Smooth operator</h2>
<p>So I've been implementing a paper called "Affine-invariant Shape Matching and Recognition Under Partial<br />
Occlusion" by Mai, Chang and Hung from 2010 (<a href="http://hub.hku.hk/handle/10722/136450" target="_blank">Here</a>), that is using the CSS Image (Curvature Scale Space, rather an old concept, developed by Mukhtarian in the mid-1990s) to extract affine-invariant points on curves. The work is rather simple and the paper is short, but nevertheless powerful.<br />
In the process of computing the CSS Image, once must smooth the curve with gaussian kernels of varying sizes, and this I'd like to show you.<br />
<img src="http://www.morethantechnical.com/wp-content/uploads/2012/12/smooth_curve-661x1024.png" alt="" title="smooth_curve" width="500" class="aligncenter size-large wp-image-1170" /></p>
<p>The implementation is simple:</p>
<pre class="brush: plain; title: ; notranslate">
/* 1st and 2nd derivative of 1D gaussian 
 */
void getGaussianDerivs(double sigma, int M, vector&lt;double&gt;&amp; gaussian, vector&lt;double&gt;&amp; dg, vector&lt;double&gt;&amp; d2g) {
	int L = (M - 1) / 2;
	double sigma_sq = sigma * sigma;
	double sigma_quad = sigma_sq*sigma_sq;
	dg.resize(M); d2g.resize(M); gaussian.resize(M);
	
	Mat_&lt;double&gt; g = getGaussianKernel(M, sigma, CV_64F);
	for (double i = -L; i &lt; L+1.0; i += 1.0) {
		int idx = (int)(i+L);
		gaussian[idx] = g(idx);
		// from http://www.cedar.buffalo.edu/~srihari/CSE555/Normal2.pdf
		dg[idx] = (-i/sigma_sq) * g(idx);
		d2g[idx] = (-sigma_sq + i*i)/sigma_quad * g(idx);
	}
}

/* 1st and 2nd derivative of smoothed curve point */
void getdX(vector&lt;double&gt; x, 
		   int n, 
		   double sigma, 
		   double&amp; gx, 
		   double&amp; dgx, 
		   double&amp; d2gx, 
		   vector&lt;double&gt; g, 
		   vector&lt;double&gt; dg, 
		   vector&lt;double&gt; d2g,
		   bool isOpen = false) 
{		
	int L = (g.size() - 1) / 2;

	gx = dgx = d2gx = 0.0;
//	cout &lt;&lt; &quot;Point &quot; &lt;&lt; n &lt;&lt; &quot;: &quot;;
	for (int k = -L; k &lt; L+1; k++) {
		double x_n_k;
		if (n-k &lt; 0) {
			if (isOpen) {
				//open curve - mirror values on border
				x_n_k = x[-(n-k)]; 
			} else {
				//closed curve - take values from end of curve
				x_n_k = x[x.size()+(n-k)];
			}			
		} else if(n-k &gt; x.size()-1) {
			if (isOpen) {
				//mirror value on border
				x_n_k = x[n+k]; 
			} else {
				x_n_k = x[(n-k)-(x.size())];
			}			
		} else {
//			cout &lt;&lt; n-k;
			x_n_k = x[n-k];
		}
//		cout &lt;&lt; &quot;* g[&quot; &lt;&lt; g[k + L] &lt;&lt; &quot;], &quot;;

		gx += x_n_k * g[k + L]; //gaussians go [0 -&gt; M-1]
		dgx += x_n_k * dg[k + L]; 
		d2gx += x_n_k * d2g[k + L];
	}
//	cout &lt;&lt; endl;
}


/* 0th, 1st and 2nd derivatives of whole smoothed curve */
void getdXcurve(vector&lt;double&gt; x, 
				double sigma, 
				vector&lt;double&gt;&amp; gx, 
				vector&lt;double&gt;&amp; dx, 
				vector&lt;double&gt;&amp; d2x, 
				vector&lt;double&gt; g, 
				vector&lt;double&gt; dg, 
				vector&lt;double&gt; d2g,
				bool isOpen = false) 
{	
	gx.resize(x.size()); 
	dx.resize(x.size()); 
	d2x.resize(x.size());
	for (int i=0; i&lt;x.size(); i++) {
		double gausx,dgx,d2gx; getdX(x,i,sigma,gausx,dgx,d2gx,g,dg,d2g,isOpen);
		gx[i] = gausx;
		dx[i] = dgx;
		d2x[i] = d2gx;
	}
}
</pre>
<p>The smoothing runs on each of the curves dimensions (i.e. x and y) separately, so I create little helper functions:</p>
<pre class="brush: plain; title: ; notranslate">
template&lt;typename T, typename V&gt;
void PolyLineSplit(const vector&lt;Point_&lt;T&gt; &gt;&amp; pl,vector&lt;V&gt;&amp; contourx, vector&lt;V&gt;&amp; contoury) {
	contourx.resize(pl.size()); 
	contoury.resize(pl.size());
	
	for (int j=0; j&lt;pl.size(); j++) 
	{ 
		contourx[j] = (V)(pl[j].x); 
		contoury[j] = (V)(pl[j].y); 
	}
}

template&lt;typename T, typename V&gt;
void PolyLineMerge(vector&lt;Point_&lt;T&gt; &gt;&amp; pl, const vector&lt;V&gt;&amp; contourx, const vector&lt;V&gt;&amp; contoury) {
	assert(contourx.size()==contoury.size());
	pl.resize(contourx.size());
	for (int j=0; j&lt;contourx.size(); j++) {
		pl[j].x = (T)(contourx[j]);
		pl[j].y = (T)(contoury[j]);
	}
}
</pre>
<p>They also convert to different types if needed.</p>
<p>Smoothing is easy:</p>
<pre class="brush: plain; title: ; notranslate">
vector&lt;Point&gt; curve = ...;

double sigma = 3.0;
int M = round((10.0*sigma+1.0) / 2.0) * 2 - 1;
assert(M % 2 == 1); //M is an odd number

//create kernels
vector&lt;double&gt; g,dg,d2g; getGaussianDerivs(sigma,M,g,dg,d2g);
	
vector&lt;double&gt; curvex,curvey,smoothx,smoothy;
PolyLineSplit(curve,curvex,curvey);

vector&lt;double&gt; X,XX,Y,YY;
getdXcurve(curvex,sigma,smoothx,X,XX,g,dg,d2g,isOpen);
getdXcurve(curvey,sigma,smoothy,Y,YY,g,dg,d2g,isOpen);

PolyLineMerge(curve,smoothx,smoothy);
</pre>
<h2>Resampling</h2>
<p>I implemented my own resampling code, where I sample points on the curve keeping the same regular distance between them. To get the regular distance I simply take the complete length of the original curve and divide by the number of desired points.</p>
<p><img src="http://www.morethantechnical.com/wp-content/uploads/2012/12/resample_curve.png" alt="" title="resample_curve" width="500" class="aligncenter size-full wp-image-1171" /></p>
<p>The implementation is again quite simple:</p>
<pre class="brush: plain; title: ; notranslate">
void ResampleCurve(const vector&lt;double&gt;&amp; curvex, const vector&lt;double&gt;&amp; curvey,
				   vector&lt;double&gt;&amp; resampleX, vector&lt;double&gt;&amp; resampleY,
				   int N,
				   bool isOpen
				   ) {
	assert(curvex.size()&gt;0 &amp;&amp; curvey.size()&gt;0 &amp;&amp; curvex.size()==curvey.size());
	
	vector&lt;Point2d&gt; resamplepl(N); resamplepl[0].x = curvex[0]; resamplepl[0].y = curvey[0];
	vector&lt;Point2i&gt; pl; PolyLineMerge(pl,curvex,curvey);

	double pl_length = arcLength(pl, false);
	double resample_size = pl_length / (double)N;
	int curr = 0;
	double dist = 0.0;
	for (int i=1; i&lt;N; ) {		
		assert(curr &lt; pl.size() - 1);
		double last_dist = norm(pl[curr] - pl[curr+1]);
		dist += last_dist;
//		cout &lt;&lt; curr &lt;&lt; &quot; and &quot; &lt;&lt; curr+1 &lt;&lt; &quot;\t\t&quot; &lt;&lt; last_dist &lt;&lt; &quot; (&quot;&lt;&lt;dist&lt;&lt;&quot;)&quot;&lt;&lt;endl;
		if (dist &gt;= resample_size) {
			//put a point on line
			double _d = last_dist - (dist-resample_size);
			Point2d cp(pl[curr].x,pl[curr].y),cp1(pl[curr+1].x,pl[curr+1].y);
			Point2d dirv = cp1-cp; dirv = dirv * (1.0 / norm(dirv));
//			cout &lt;&lt; &quot;point &quot; &lt;&lt; i &lt;&lt; &quot; between &quot; &lt;&lt; curr &lt;&lt; &quot; and &quot; &lt;&lt; curr+1 &lt;&lt; &quot; remaining &quot; &lt;&lt; dist &lt;&lt; endl;
			assert(i &lt; resamplepl.size());
			resamplepl[i] = cp + dirv * _d;
			i++;
			
			dist = last_dist - _d; //remaining dist			
			
			//if remaining dist to next point needs more sampling... (within some epsilon)
			while (dist - resample_size &gt; 1e-3) {
//				cout &lt;&lt; &quot;point &quot; &lt;&lt; i &lt;&lt; &quot; between &quot; &lt;&lt; curr &lt;&lt; &quot; and &quot; &lt;&lt; curr+1 &lt;&lt; &quot; remaining &quot; &lt;&lt; dist &lt;&lt; endl;
				assert(i &lt; resamplepl.size());
				resamplepl[i] = resamplepl[i-1] + dirv * resample_size;
				dist -= resample_size;
				i++;
			}
		}
		
		curr++;
	}
	
	PolyLineSplit(resamplepl,resampleX,resampleY);
}
</pre>
<p>Essentially I just traverse the original curve, advancing in a regular pace (resample_size) and adding new vertices as long as there is space to so on the current edge. If space to add more vertices on the edge - I move to the next edge and add more vertices there.</p>
<p><img src="http://www.morethantechnical.com/wp-content/uploads/2012/12/Screen-shot-2012-12-07-at-10.07.23-AM.png" alt="" title="Screen shot 2012-12-07 at 10.07.23 AM" width="450" class="aligncenter size-full wp-image-1172" /></p>
<h2>Curvature Scale Space</h2>
<p>The core idea of the CSS image (as shown perhaps best by Mokhtarian and Abbassi in their <a href="http://www.sciencedirect.com/science/article/pii/S0031320301000401" target="_blank">2002 paper</a>) is to smooth the curve by ever increasing gaussian kernels and looking at zero crossings of the 2nd derivative. When you're smoothing the curve you will loose the noise, and be left with only the biggest changes in curvature, and a zero-crossing on the 2nd derivative will indicate a big change in curvature. The invariant points across the different sizes of the gaussian kernel - are the interest points of the curve (sometimes referred to as "affine invariant").</p>
<pre class="brush: plain; title: ; notranslate">
/* compute curvature of curve after gaussian smoothing 
 from &quot;Shape similarity retrieval under affine transforms&quot;, Mokhtarian &amp; Abbasi 2002
 curvex - x position of points
 curvey - y position of points
 kappa - curvature coeff for each point
 sigma - gaussian sigma
 */
void ComputeCurveCSS(const vector&lt;double&gt;&amp; curvex, 
					 const vector&lt;double&gt;&amp; curvey, 
					 vector&lt;double&gt;&amp; kappa, 
					 vector&lt;double&gt;&amp; smoothX, vector&lt;double&gt;&amp; smoothY,
					 double sigma,
					 bool isOpen
					 ) 
{
	int M = round((10.0*sigma+1.0) / 2.0) * 2 - 1;
	assert(M % 2 == 1); //M is an odd number
	
	vector&lt;double&gt; g,dg,d2g; getGaussianDerivs(sigma,M,g,dg,d2g);
	
	vector&lt;double&gt; X,XX,Y,YY;
	getdXcurve(curvex,sigma,smoothX,X,XX,g,dg,d2g,isOpen);
	getdXcurve(curvey,sigma,smoothY,Y,YY,g,dg,d2g,isOpen);
	
	kappa.resize(curvex.size());
	for (int i=0; i&lt;curvex.size(); i++) {
		// Mokhtarian 02' eqn (4)
		kappa[i] = (X[i]*YY[i] - XX[i]*Y[i]) / pow(X[i]*X[i] + Y[i]*Y[i], 1.5);
	}
}

/* find zero crossings on curvature */
vector&lt;int&gt; FindCSSInterestPoints(const vector&lt;double&gt;&amp; kappa) {
	vector&lt;int&gt; crossings;
	for (int i=0; i&lt;kappa.size()-1; i++) {
		if ((kappa[i] &lt; 0 &amp;&amp; kappa[i+1] &gt; 0) || kappa[i] &gt; 0 &amp;&amp; kappa[i+1] &lt; 0) {
			crossings.push_back(i);
		}
	}
	return crossings;
}
</pre>
<p><img src="http://www.morethantechnical.com/wp-content/uploads/2012/12/Screen-shot-2012-12-07-at-10.47.32-AM.png" alt="" title="Screen shot 2012-12-07 at 10.47.32 AM" width="532" height="358" class="aligncenter size-full wp-image-1176" /></p>
<p>The evolution of the curve (iterating through many levels of the gaussian kernel) looks like the following:<br />
<img src="http://www.morethantechnical.com/wp-content/uploads/2012/12/evolution2.gif" alt="" title="evolution" width="350" height="350" class="aligncenter size-full wp-image-1182" /></p>
<h2>Code</h2>
<p>Grab the code: <a href="http://web.media.mit.edu/~roys/src/CurveCSS.zip" target="_blank">http://web.media.mit.edu/~roys/src/CurveCSS.zip</a><br />
(if the hosting dies - let me know)</p>
<p>Thanks for joining in<br />
Roy.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.morethantechnical.com/2012/12/07/resampling-smoothing-and-interest-points-of-curves-via-css-in-opencv-w-code/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
