<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	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/"
	>

<channel>
	<title>Kerry D. Wong</title>
	<atom:link href="http://www.kerrywong.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.kerrywong.com</link>
	<description></description>
	<lastBuildDate>Sat, 04 Jul 2009 01:06:30 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Image Blur Detection via Hough Transform &#8212; IV</title>
		<link>http://www.kerrywong.com/2009/07/03/image-blur-detection-via-hough-transform-iv/</link>
		<comments>http://www.kerrywong.com/2009/07/03/image-blur-detection-via-hough-transform-iv/#comments</comments>
		<pubDate>Sat, 04 Jul 2009 01:06:30 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Blur Detection]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Edge Detection]]></category>
		<category><![CDATA[Hough Transform]]></category>
		<category><![CDATA[Intel IPP]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1277</guid>
		<description><![CDATA[In my previous three articles (1,2,3) I discussed how to use Canny edge detection and Hough transform to identify blur images. Here I will show some results from the algorithm discussed before.
Results
When presented with images that are clear, the algorithm correctly identified most of them (see images below):
















The following images illustrate how the original image [...]]]></description>
			<content:encoded><![CDATA[<p>In my previous three articles (<a href="/2009/06/19/image-blur-detection-via-hough-transform-i/">1</a>,<a href="/2009/06/24/image-blur-detection-via-hough-transform-ii/">2</a>,<a href="/2009/06/27/image-blur-detection-via-hough-transform-iii/">3</a>) I discussed how to use Canny edge detection and Hough transform to identify blur images. Here I will show some results from the algorithm discussed before.<span id="more-1277"></span></p>
<h3>Results</h3>
<p>When presented with images that are clear, the algorithm correctly identified most of them (see images below):</p>
<table>
<tr>
<td>
<div id="attachment_1285" class="wp-caption aligncenter" style="width: 330px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/c1.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/c1.jpg" alt="Building (Microsoft Research Digital Image)" title="Building (Microsoft Research Digital Image)" width="320" height="240" class="size-full wp-image-1285" /></a><p class="wp-caption-text">Building (Microsoft Research Digital Image)</p></div>
</td>
<td>
<div id="attachment_1286" class="wp-caption aligncenter" style="width: 330px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/c2.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/c2.jpg" alt="Street (Microsoft Research Digital Image)" title="Street (Microsoft Research Digital Image)" width="320" height="240" class="size-full wp-image-1286" /></a><p class="wp-caption-text">Street (Microsoft Research Digital Image)</p></div>
</td>
</tr>
</table>
<table>
<tr>
<td>
<div id="attachment_1289" class="wp-caption aligncenter" style="width: 330px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/c5.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/c5.jpg" alt="Sky" title="Sky" width="320" height="240" class="size-full wp-image-1289" /></a><p class="wp-caption-text">Sky</p></div>
</td>
<td>
<div id="attachment_1288" class="wp-caption aligncenter" style="width: 330px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/c4.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/c4.jpg" alt="Flower" title="Flower" width="320" height="240" class="size-full wp-image-1288" /></a><p class="wp-caption-text">Flower</p></div>
</td>
</tr>
</table>
<p>The following images illustrate how the original image (top right) is divided into sub regions. Canny detection is performed on each of the sub images.</p>
<table>
<tr>
<td>
<a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/1.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/1.jpg" alt="1" title="1" width="214" height="160" class="aligncenter size-full wp-image-1300" /></a>
</td>
<td>
<a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/4.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/4.jpg" alt="4" title="4" width="214" height="160" class="aligncenter size-full wp-image-1303" /></a>
</td>
<td>
<a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/7.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/7.jpg" alt="7" title="7" width="214" height="160" class="aligncenter size-full wp-image-1306" /></a>
</td>
</tr>
<tr>
<td>
<a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/2.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/2.jpg" alt="2" title="2" width="214" height="160" class="aligncenter size-full wp-image-1301" /></a>
</td>
<td>
<a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/5.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/5.jpg" alt="5" title="5" width="214" height="160" class="aligncenter size-full wp-image-1304" /></a>
</td>
<td>
<a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/8.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/8.jpg" alt="8" title="8" width="214" height="160" class="aligncenter size-full wp-image-1307" /></a>
</td>
</tr>
<tr>
<td>
<a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/3.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/3.jpg" alt="3" title="3" width="214" height="160" class="aligncenter size-full wp-image-1302" /></a>
</td>
<td>
<a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/6.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/6.jpg" alt="6" title="6" width="214" height="160" class="aligncenter size-full wp-image-1305" /></a>
</td>
<td>
<a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/9.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/9.jpg" alt="9" title="9" width="214" height="160" class="aligncenter size-full wp-image-1331" /></a>
</td>
</tr>
</table>
<p>When performing Hough Transform, I chose to detect up to ten lines in each image, with the following stepping parameter (the detection results are very sensitive to these parameters, the following parameters were chosen based on experiment results):<br />
\[\rho=1, \theta=0.01\]</p>
<p>Out of all the detected lines, a few sections are selected based on line continuity and the calculated average gradients around the detected lines. The following images shows the chosen Hough line segments based on the algorithm. </p>
<table>
<tr>
<td>
<a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/1_o.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/1_o.jpg" alt="1_o" title="1_o" width="214" height="160" class="aligncenter size-full wp-image-1309" /></a>
</td>
<td>
<a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/4_o.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/4_o.jpg" alt="4_o" title="4_o" width="214" height="160" class="aligncenter size-full wp-image-1312" /></a>
</td>
<td>
<a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/7_o.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/7_o.jpg" alt="7_o" title="7_o" width="214" height="160" class="aligncenter size-full wp-image-1315" /></a>
</td>
</tr>
<tr>
<td>
<a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/2_o.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/2_o.jpg" alt="2_o" title="2_o" width="214" height="160" class="aligncenter size-full wp-image-1310" /></a>
</td>
<td>
<a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/5_o.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/5_o.jpg" alt="5_o" title="5_o" width="214" height="160" class="aligncenter size-full wp-image-1313" /></a>
</td>
<td>
<a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/8_o.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/8_o.jpg" alt="8_o" title="8_o" width="214" height="160" class="aligncenter size-full wp-image-1316" /></a>
</td>
</tr>
<tr>
<td>
<a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/3_o.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/3_o.jpg" alt="3_o" title="3_o" width="214" height="160" class="aligncenter size-full wp-image-1311" /></a>
</td>
<td>
<a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/6_o.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/6_o.jpg" alt="6_o" title="6_o" width="214" height="160" class="aligncenter size-full wp-image-1314" /></a>
</td>
<td>
<a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/9_o.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/9_o.jpg" alt="9_o" title="9_o" width="214" height="160" class="aligncenter size-full wp-image-1317" /></a>
</td>
</tr>
</table>
<p>The table below shows the gradient index calculated within each area (the average of the gradients along all the chosen line segments within a sub-image. The result is scaled by 1000, the scale factor is chosen such that for clear images the resulted index is greater than 1 and for blur images the resulted index is less than 1).</p>
<table>
<tr>
<td>1</td>
<td>1.709</td>
</tr>
<tr>
<td>2</td>
<td>2.383</td>
</tr>
<tr>
<td>3</td>
<td>1.012</td>
</tr>
<tr>
<td>4</td>
<td>2.842</td>
</tr>
<tr>
<td>5</td>
<td>3.389</td>
</tr>
<tr>
<td>6</td>
<td>2.419</td>
</tr>
<tr>
<td>7</td>
<td>2.933</td>
</tr>
<tr>
<td>8</td>
<td>2.168</td>
</tr>
<tr>
<td>9</td>
<td>2.534</td>
</tr>
</table>
<p>And the sub images are indexed as follows:</p>
<table>
<tr>
<td>1</td>
<td>4</td>
<td>7</td>
</tr>
<tr>
<td>2</td>
<td>5</td>
<td>8</td>
</tr>
<tr>
<td>3</td>
<td>6</td>
<td>9</td>
</tr>
</table>
<p>The algorithm can also detect images with deliberate blur regions (e.g. <a href="http://en.wikipedia.org/wiki/Bokeh">Bokeh</a>). The results are illustrated below:</p>
<div id="attachment_1287" class="wp-caption aligncenter" style="width: 330px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/c3.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/c3.jpg" alt="Plant (Microsoft Research Digital Image)" title="Plant (Microsoft Research Digital Image)" width="320" height="240" class="size-full wp-image-1287" /></a><p class="wp-caption-text">Plant (Microsoft Research Digital Image)</p></div>
<table>
<tr>
<td>1</td>
<td><font color="red">0.000</font></td>
</tr>
<tr>
<td>2</td>
<td>1.750</td>
</tr>
<tr>
<td>3</td>
<td>1.973</td>
</tr>
<tr>
<td>4</td>
<td>1.595</td>
</tr>
<tr>
<td>5</td>
<td>2.815</td>
</tr>
<tr>
<td>6</td>
<td>3.188</td>
</tr>
<tr>
<td>7</td>
<td><font color="red">0.000</font></td>
</tr>
<tr>
<td>8</td>
<td>1.204</td>
</tr>
<tr>
<td>9</td>
<td>1.308</td>
</tr>
</table>
<p>Note that the 0&#8217;s in the detection results indicate that within those regions, no lines could be reliably detected and thus those regions are considered blurred.<br />
Generally speaking, when an image contains both blurred and clear regions, some of the indexes will be zero and others will be greater than one.</p>
<p>The following images are detected as blurred, with the detected indexes far less than one.</p>
<table>
<tr>
<td>
<div id="attachment_1294" class="wp-caption aligncenter" style="width: 330px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/b3.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/b3.jpg" alt="Boat (Microsoft Research Digital Image)" title="Boat (Microsoft Research Digital Image)" width="320" height="240" class="size-full wp-image-1294" /></a><p class="wp-caption-text">Boat (Microsoft Research Digital Image)</p></div>
</td>
<td>
<div id="attachment_1295" class="wp-caption aligncenter" style="width: 330px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/b4.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/b4.jpg" alt="Candle" title="Candle" width="320" height="427" class="size-full wp-image-1295" /></a><p class="wp-caption-text">Candle</p></div>
</td>
</tr>
</table>
<h3>Limitations</h3>
<p>when image contrast is low, or when objects borders are not clearly defined, the algorithm may have difficulty in distinguishing whether an image is blurred. Take the following two cloud images for instance, the image on the left was correctly classified as a clear image due to the relatively high contrast around the center. But the image to the right was classified as blurred due to its lack of contrast. </p>
<table>
<tr>
<td>
<div id="attachment_1291" class="wp-caption aligncenter" style="width: 330px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/b1.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/b1.jpg" alt="Cloud" title="Cloud" width="320" height="240" class="size-full wp-image-1291" /></a><p class="wp-caption-text">Cloud</p></div>
</td>
<td>
<div id="attachment_1293" class="wp-caption aligncenter" style="width: 330px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/b2.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/b2.jpg" alt="Cloud" title="Cloud" width="320" height="240" class="size-full wp-image-1293" /></a><p class="wp-caption-text">Cloud</p></div>
</td>
</tr>
</table>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/07/03/image-blur-detection-via-hough-transform-iv/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Image Blur Detection via Hough Transform &#8212; III</title>
		<link>http://www.kerrywong.com/2009/06/27/image-blur-detection-via-hough-transform-iii/</link>
		<comments>http://www.kerrywong.com/2009/06/27/image-blur-detection-via-hough-transform-iii/#comments</comments>
		<pubDate>Sun, 28 Jun 2009 01:31:01 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Blur Detection]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Edge Detection]]></category>
		<category><![CDATA[Hough Transform]]></category>
		<category><![CDATA[Intel IPP]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1231</guid>
		<description><![CDATA[I will continue where I left off in my previous post. After performing Hough transform, and extracted the longest sections of lines for each corresponding Hough line detected, we will need to calculate the gradients of the image pixels luminance around the line sections.
Gradient Calculation
If you remember how the Hough parameters were determined (in polar [...]]]></description>
			<content:encoded><![CDATA[<p>I will continue where I left off in my <a href="/2009/06/24/image-blur-detection-via-hough-transform-ii/">previous post</a>. After performing Hough transform, and extracted the longest sections of lines for each corresponding Hough line detected, we will need to calculate the gradients of the image pixels luminance around the line sections.<span id="more-1231"></span></p>
<h3>Gradient Calculation</h3>
<p>If you remember how the Hough parameters were determined (in polar form, see figure below), it is not difficult to obtain the pixel coordinates centered around the points on the detected line. </p>
<div id="attachment_1214" class="wp-caption aligncenter" style="width: 554px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/polar.png"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/polar.png" alt="Region selection for gradient calculation" title="Region selection for gradient calculation" width="544" height="410" class="size-full wp-image-1214" /></a><p class="wp-caption-text">Region selection for gradient calculation</p></div>
<p>In fact, we can formulate a line that is perpendicular to the line section detected during Hough transform, and use the line section that is within a predefined region (e.g. the between the dotted lines) to calculate the gradients of luminance. The following code snippet shows how the perpendicular line&#8217;s parameters are obtained.</p>
<pre class="brush: cpp;">
    /**
     * Get the equation parameters for the line that passes through (x,y) and is perpendicular
     * to the line specified by parameters (p0, theta0) in normal form.
     *
     * @param p0 : distance to line from origin.
     * @param theta0 : the slope of p0.
     * @param x : x coordinate of the point where the perpendicular line passes through
     * @param y : y coordinate of the point where the perpendicular line passes through
     * @param &amp;p : the perpendicular line's distance from origin.
     * @param &amp;theta : the slope of p.
     **/
    void LineUtils::GetPerpendicularLineParameters(float p0, float theta0, float x, float y, float &amp;p, float &amp;theta) {
        float x0 = p0 * cos(theta0);
        float y0 = p0 * sin(theta0);

        p = sqrt((x0 - x)*(x0 - x) + (y0 - y)*(y0 - y));

        float a1 = theta0 - PI / 2.0;
        float a2 = theta0 + PI / 2.0;

        //d=|x0 * cos a + y0 * sin a - p|
        float d1 = abs(x * cos(a1) + y * sin(a1) - p);
        float d2 = abs(x * cos(a2) + y * sin(a2) - p);

        if (d1 &lt; d2)
            theta = a1;
        else
            theta = a2;
    }
</pre>
<p>In an ideal situation, the gradient of the line points obtained via the method above looks like the figures below, where the edges are clearly identified. </p>
<div id="attachment_1254" class="wp-caption aligncenter" style="width: 570px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/edge1.png"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/edge1.png" alt="Edge (dark to bright)" title="Edge (dark to bright)" width="560" height="420" class="size-full wp-image-1254" /></a><p class="wp-caption-text">Edge (dark to bright)</p></div>
<div id="attachment_1255" class="wp-caption aligncenter" style="width: 570px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/edge2.png"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/edge2.png" alt="Edge (dark to bright to dark)" title="Edge (dark to bright to dark)" width="560" height="420" class="size-full wp-image-1255" /></a><p class="wp-caption-text">Edge (dark to bright to dark)</p></div>
<p>Sometimes, when the lighting condition is poor, the image would appear to be &#8220;grainy&#8221;, which sometimes led to poor line detection. For instance, the following figure shows the the gradient when the region around the detected edge is grainy:</p>
<div id="attachment_1258" class="wp-caption aligncenter" style="width: 570px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/noneedge.png"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/noneedge.png" alt="None-Edge" title="None-Edge" width="560" height="420" class="size-full wp-image-1258" /></a><p class="wp-caption-text">None-Edge</p></div>
<p>We use the number of times the luminance increases above or decreases below its mean along the perpendicular line interval as a measure of whether we accept the detection results as gradients or not. Typically when such number of crossings is less than 3 (see the first two images above) the curve is either monotonic or has a single peak, we assume that gradients can be correctly calculated and if the crossings are more than 3 we discard the results. The gradient is calculated as the slope of the curve. In the examples above, we used ten pixels on each side of the Hough line to calculate gradients.</p>
<h3>Image Regions</h3>
<p>For images with complex contents, it becomes difficult for the Hough transform to reliably identify line structures within the image. Future more, certain photography techniques (i.e. <a href="http://en.wikipedia.org/wiki/Bokeh">Bokeh</a>) leave portions of images deliberately blurred. Without dividing image into different sub-regions, the classification results would be compromised.</p>
<p>Thus, images are divided into 9 (3&#215;3) sub-images after Canny edge detection, and Hough transform is performed against each sub-images. The figure below illustrates how an image is divided:<br />
<div id="attachment_1267" class="wp-caption aligncenter" style="width: 654px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/3x3.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/3x3.jpg" alt="Image divided into 3x3 sub-images (Microsoft Research Digital Image)" title="Image divided into 3x3 sub-images (Microsoft Research Digital Image)" width="644" height="482" class="size-full wp-image-1267" /></a><p class="wp-caption-text">Image divided into 3x3 sub-images (Microsoft Research Digital Image)</p></div></p>
<p>This technique is especially useful when portions of images are deliberately blurred, like the image shown above. It also helps the line detection accuracy when the image contains complex scenes. By dividing up the image, each sub area&#8217;s complexity is greatly reduced. Other methods in scene separation might achieve even better results, but it is out of the scope for our discussion here.</p>
<p>In my next post, I will show some results obtained from using the method mentioned in this and the previous articles and will also discuss its limitations.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/06/27/image-blur-detection-via-hough-transform-iii/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Image Blur Detection via Hough Transform &#8212; II</title>
		<link>http://www.kerrywong.com/2009/06/24/image-blur-detection-via-hough-transform-ii/</link>
		<comments>http://www.kerrywong.com/2009/06/24/image-blur-detection-via-hough-transform-ii/#comments</comments>
		<pubDate>Thu, 25 Jun 2009 01:44:44 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Blur Detection]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Edge Detection]]></category>
		<category><![CDATA[Hough Transform]]></category>
		<category><![CDATA[Intel IPP]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1194</guid>
		<description><![CDATA[In my previous post, I briefly discussed the rationale behind automated blur detection in digital imagery and did an overview of an algorithm that could be used to detect blur images. Here I will show some implementation details along with some C++ code snippets.
Experience tells us that blur images tend to contain less details then [...]]]></description>
			<content:encoded><![CDATA[<p>In <a href="/2009/06/19/image-blur-detection-via-hough-transform-i/">my previous post</a>, I briefly discussed the rationale behind automated blur detection in digital imagery and did an overview of an algorithm that could be used to detect blur images. Here I will show some implementation details along with some C++ code snippets.<span id="more-1194"></span></p>
<p>Experience tells us that blur images tend to contain less details then their sharper counterparts. And the areas where <a href="http://en.wikipedia.org/wiki/Intensity">intensity</a> transitions occur (e.g. the border of an object) are more well defined in clear images. Mathematically speaking, the <a href="http://en.wikipedia.org/wiki/Slope">slope</a> of the intensity transition is statistically deeper in clear images than blur ones. Since whether an image is blurred or not is not affected by color space, it is sufficient to perform detection in the <a href="http://en.wikipedia.org/wiki/Luminance">luminance</a> space (i.e. gray scale images):</p>
<p>\[I=0.299R\times0.587G\times0.114B\]</p>
<h3>Canny Edge Detection</h3>
<p>Thus the very first step in deciding whether an image or an area within an image is blurred is to use some sort of edge detection algorithms to obtain a collection of the edges in the image.</p>
<p><a href="http://en.wikipedia.org/wiki/Canny_edge_detector">Canny edge detection</a> is a good candidate since it is optimal in terms of good detection and localization. And hysteresis is used to reduce streaking and thus Canny edge detection achieves relatively continuous edge boundaries comparing to other edge detection methods.</p>
<p>In <a href="/2009/05/07/canny-edge-detection-auto-thresholding/">one of my previous posts</a>, I discussed Canny edge detection using auto thresholding utilizing Intel&#8217;s <a href="http://software.intel.com/en-us/intel-ipp/">Integrated Performance Primitives</a> (IPP). I used the same algorithm here for the image pre-processing process.</p>
<h3>Hough Transform</h3>
<p>In order to analyze the gradients along detected edges, it is necessary to first parameterize them. <a href="http://en.wikipedia.org/wiki/Hough_transform">Hough transform</a> comes in handy for this task. </p>
<p>While Hough transform is capable of identifying arbitrary shapes, for the purpose of detecting image blurs simple line detection is more robust. Besides, IPP has an implementation for line detection using Hough transform out of the box.</p>
<p>Since our goal is to determine the quality of the image within a region of interest, we do not need to analyze all the edges identified within that region. But rather, we could select a few based on some pre-determined criteria that would maximize our ability to correctly determine the luminance gradients.</p>
<p>The following code snippet shows my implementation of the edge parameterization method using IPP:</p>
<pre class="brush: cpp;">
    bool CompareIppiPoint(IppiPoint &amp;p1, IppiPoint &amp;p2) {
        if (p1.x == p2.x) {
            return p1.y &lt; p2.y;
        } else {
            return p1.x &lt; p2.x;
        }
    }

    void IPPGrayImage::HoughLine(IppPointPolar delta, int threshold, int maxLineCount, int* pLineCount, IppPointPolar pLines[], list&lt;IppiPoint&gt; pList[]) {
        IppStatus sts;
        IppiSize roiSize = {_width, _height};

        int bufSize;
        sts = ippiHoughLineGetSize_8u_C1R(roiSize, delta, maxLineCount, &amp;bufSize);
        assert(sts == ippStsNoErr);
        Ipp8u * pBuf = ippsMalloc_8u(bufSize);

        Ipp8u *imgBuf;
        int stepSize;
        imgBuf = ippiMalloc_8u_C1(_width, _height, &amp;stepSize);

        sts = ippiConvert_32f8u_C1R(_imgBuffer, _width * PIXEL_SIZE, imgBuf, _width, roiSize, ippRndNear);
        assert(sts == ippStsNoErr);
        assert(imgBuf != NULL);

        sts = ippiHoughLine_8u32f_C1R(imgBuf, _width, roiSize, delta, threshold, pLines, maxLineCount, pLineCount, pBuf);
        assert(sts == ippStsNoErr);

        //d=|x0 * cos a + y0 * sin a - p|
        int val = 0;
        float d;
        for (int x = 0; x &lt; _width; x++) {
            for (int y = 0; y &lt; _height; y++) {
                if (imgBuf[x + y * _width] &gt; 0) {
                    val = imgBuf[x + y * _width];

                    for (int i = 0; i &lt; *pLineCount; i++) {
                        d = abs((float) cos(pLines[i].theta) * (float) x + (float) sin(pLines[i].theta) * (float) y - abs(pLines[i].rho));
                        if (d &lt; threshold) {
                            IppiPoint p;
                            p.x = x;
                            p.y = y;

                            pList[i].push_back(p);
                        }
                    }
                }
            }
        }

        for (int i = 0; i &lt; *pLineCount; i++) {
            pList[i].sort(CompareIppiPoint);
        }

        ippsFree(pBuf);
        ippiFree(imgBuf);
    }
</pre>
<p>Note that the selection for <em>delta</em> is crucial for the line detection quality. In the code above, up to <em>maxLineCount</em> number of lines are detected and each line&#8217;s parameters are stored in <em>pLines[]</em>. The edge image pixel coordinates within a given range that is less than <em>threshold</em> are collected into the list. Because the Hough detection does not indicate the begin and the end point of a line, we need to iterate through the pixels in <em>pList[]</em> and find the sections that the detected lines pass through. The image below illustrates how the edge regions are chosen based on detected line parameters. Image features within a region between the dotted line are recorded based on the distances to the line defined by:<br />
\[d=\vert x_0cos\alpha+y_0sin\alpha-p\vert\]</p>
<div id="attachment_1214" class="wp-caption aligncenter" style="width: 554px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/polar.png"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/polar.png" alt="Region selection for gradient calculation" title="Region selection for gradient calculation" width="544" height="410" class="size-full wp-image-1214" /></a><p class="wp-caption-text">Region selection for gradient calculation</p></div>
<p>In practice, for each parameterized line I chose to select the longest section where the line approximates a section of the edge. Other line sections can be used as well, but the longest portion tends to offer better classification results. The code is shown below, and the thickened section in the figure above illustrates the selected section.</p>
<pre class="brush: cpp;">
    void LineUtils::GetLongestConnectedLinePoints(IppiPoint points[], int len, int threshold, IppiPoint lpoints[], int &amp;maxLen) {
        int maxIndexEnd = 0, curRunLength = 0, maxRunLength = 0;

        lpoints[curRunLength] = points[0];

        for (int i = 1; i &lt; len; i++) {
            if ((abs(points[i].x - lpoints[curRunLength].x) &gt; threshold) || (abs(points[i].y - lpoints[curRunLength].y) &gt; threshold)) {
                if (curRunLength &gt; maxRunLength) {
                    maxRunLength = curRunLength;
                    maxIndexEnd = i;
                }
                curRunLength = 0;
                lpoints[curRunLength] = points[i];
            } else {
                if (curRunLength &gt;= maxLen) {
                    maxRunLength = maxLen;
                    break;
                }

                curRunLength++;
                lpoints[curRunLength] = points[i];
            }
        }

        for (int i = maxIndexEnd - maxRunLength - 1; i &lt; maxIndexEnd; i++) {
            if (i - (maxIndexEnd - maxRunLength) - 1 &lt; maxRunLength) {
                lpoints[i - (maxIndexEnd - maxRunLength - 1)] = points[i];
            }
        }

        maxLen = maxRunLength;
    }
</pre>
<p>In my next post, I will continue with the gradient calculation and some methods to enhance the detection accuracies.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/06/24/image-blur-detection-via-hough-transform-ii/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Image Blur Detection via Hough Transform &#8212; I</title>
		<link>http://www.kerrywong.com/2009/06/19/image-blur-detection-via-hough-transform-i/</link>
		<comments>http://www.kerrywong.com/2009/06/19/image-blur-detection-via-hough-transform-i/#comments</comments>
		<pubDate>Sat, 20 Jun 2009 02:41:13 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Blur Detection]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Edge Detection]]></category>
		<category><![CDATA[Hough Transform]]></category>
		<category><![CDATA[Intel IPP]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1172</guid>
		<description><![CDATA[It is often necessary to identify and classify images based on their clarities. For instance, it is desirable for an automated process to locate blurred images within a large digitized image library and then automatically sharpen the blurred images via inverse filtering or blind deconvolution. In the following series of articles, I will discuss a [...]]]></description>
			<content:encoded><![CDATA[<p>It is often necessary to identify and classify images based on their clarities. For instance, it is desirable for an automated process to locate blurred images within a large digitized image library and then automatically sharpen the blurred images via inverse filtering or blind deconvolution. In the following series of articles, I will discuss a practical method in detecting blur images using <a href="http://en.wikipedia.org/wiki/Hough_transform">Hough Transform</a>.<span id="more-1172"></span></p>
<h3>Background</h3>
<p>Image blur is typically caused by</p>
<ul>
<li>Motion (e.g. the relative movement between the camera and the object during exposure)</li>
<li>Out-of-focus</li>
<li>Low lighting condition</li>
</ul>
<p>Other types of image blur may also occur in photography (such as <a href="http://en.wikipedia.org/wiki/Bokeh">Bokeh</a>). And it is desirable to be able to automatically distinguish desired image blur (e.g. Bokeh caused by camera lens with a shallow depth of field) from un-intended blur (e.g. out of focus).</p>
<p>When reference images (e.g. a series of images with different focus settings) are present, detecting image blur is a relatively simple task. For instance, in passive auto-focus cameras, a series of scene images are captured with progressive focus settings. And the intensity differences are calculated within the same region across these different images. Thus, the image with the highest intensity difference corresponds to the correct focus setting. In Active-focus cameras, image blur detection problem is circumvented by measuring the distance between the lens and the object.</p>
<p>The problem becomes more difficult if we are only given a single image. Since many parameters that we used above in camera auto-focusing are not present in a single image setting, we could not reliably infer image sharpness by the method used in passive auto-focusing as we do not have sufficient knowledge to re-construct the series of images necessary for comparison.</p>
<p>We can however, tell whether an image is in-focus by calculating the intensity differences along the edges in an image. If the calculated intensity is higher than a predefined threshold, we deduce that the image is sharp. And if the calculated intensity is lower than a predefined threshold, we conclude that the image is blurred. So now we shifted the problem to identifying such optimal regions where the intensities are calculated.</p>
<h3>Algorithm Overview</h3>
<p>In this algorithm, we first use <a href="http://en.wikipedia.org/wiki/Canny_edge_detector">Canny edge detection</a> to obtain the edges in the image. The edges are then parameterized using Hough transform. We then calculate the pixel gradients along the parameterized lines detected and finally we use the gradients to decide whether the image is blurred.</p>
<p>I will discuss some technical and implementation details in the up-coming posts. Stay tuned.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/06/19/image-blur-detection-via-hough-transform-i/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C++ Recursive Directory Search Under Linux</title>
		<link>http://www.kerrywong.com/2009/06/12/c-recursive-directory-search-under-linux/</link>
		<comments>http://www.kerrywong.com/2009/06/12/c-recursive-directory-search-under-linux/#comments</comments>
		<pubDate>Fri, 12 Jun 2009 21:55:29 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Linux/BSD]]></category>
		<category><![CDATA[boost]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1154</guid>
		<description><![CDATA[I was trying to search for some code examples on how to do a recursive directory search under Linux using C++ the other day. But to my surprise, I could not find any place that offers a complete example. So I decided to post my code here after I created my own and hopefully you [...]]]></description>
			<content:encoded><![CDATA[<p>I was trying to search for some code examples on how to do a recursive directory search under Linux using C++ the other day. But to my surprise, I could not find any place that offers a complete example. So I decided to post my code here after I created my own and hopefully you will find it helpful.<span id="more-1154"></span></p>
<p>For those who are impatient, the function to perform recursive directory search is here:</p>
<pre class="brush: cpp;">
#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;dirent.h&gt;
#include &lt;errno.h&gt;
#include &lt;vector&gt;
#include &lt;string&gt;
#include &lt;iostream&gt;
#include &lt;boost/regex.hpp&gt;

void GetFileListing(vector&lt;string&gt; &amp;files, string dir, string filter, bool ignoreCase) {
    DIR *d;
    if ((d = opendir(dir.c_str())) == NULL) return;
    if (dir.at(dir.length() - 1) != '/') dir += &quot;/&quot;;

    struct dirent *dent;
    struct stat st;
    boost::regex exp;

    if (ignoreCase)
        exp.set_expression(filter, boost::regex_constants::icase);
    else
        exp.set_expression(filter);

    while ((dent = readdir(d)) != NULL) {
        string path = dir;

        if (string(dent-&gt;d_name) != &quot;.&quot; &amp;&amp; string(dent-&gt;d_name) != &quot;..&quot;) {
            path += string(dent-&gt;d_name);
            const char *p = path.c_str();
            lstat(p, &amp;st);

            if (S_ISDIR(st.st_mode)) {
                GetFiles(files, (path + string(&quot;/&quot;)).c_str(), filter, ignoreCase);
            } else {
                if (filter == &quot;.*&quot;) {
                    files.push_back(path);
                } else {
                    if (boost::regex_match(string(dent-&gt;d_name), exp)) files.push_back(path);
                }
            }
        }
    }

    closedir(d);
}
</pre>
<p>I used <a href="http://www.boost.org">boost library</a> to perform regular expression matches for file names. If you just want to obtain a listing of all the files, you can do without using the boost library.</p>
<p>The following code snippet demonstrates how to use the function. The results are stored in a vector container passed in. Note that the &#8220;filter&#8221; parameter needs standard regular expressions (so if you are looking for any files, the expression should be  .* instead of just *) to work properly.</p>
<p>The code should be pretty self-explanatory. If <em>ignoreCase</em> is set to true, then the match will be case-insensitive.</p>
<pre class="brush: cpp;">
vector&lt;string&gt; files;

FileUtils::GetFiles(files,&quot;/tmp&quot;, &quot;.*&quot;, true);
for (int i = 0 ; i &lt; files.size(); i++) {
    cout &lt;&lt; files[i] &lt;&lt; endl;
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/06/12/c-recursive-directory-search-under-linux/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>LaTeX Math Equations in WordPress</title>
		<link>http://www.kerrywong.com/2009/06/04/latex-math-equations-in-wordpress/</link>
		<comments>http://www.kerrywong.com/2009/06/04/latex-math-equations-in-wordpress/#comments</comments>
		<pubDate>Thu, 04 Jun 2009 23:43:23 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[jsMath]]></category>
		<category><![CDATA[LaTeX]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1123</guid>
		<description><![CDATA[Getting LaTex style math equations to work in WordPress is actually pretty easy. I followed the advice here and everything seemed to work pretty well.
Besides installing wp-hooks and jsMath I also installed jsMath fonts so that I don&#8217;t have to rely on end users having the correct font installed in order to view the LaTex [...]]]></description>
			<content:encoded><![CDATA[<p>Getting LaTex style math equations to work in WordPress is actually pretty easy. I followed the advice <a href="http://stacyprowell.com/blog/2009/04/20/wordpress-and-jsmath/">here</a> and everything seemed to work pretty well.<span id="more-1123"></span></p>
<p>Besides installing <a href="http://wordpress.org/extend/plugins/wp-hooks/">wp-hooks</a> and <a href="http://www.math.union.edu/~dpvc/jsMath/download/">jsMath</a> I also installed <a href="http://downloads.sourceforge.net/jsmath/jsMath-fonts-1.3.zip">jsMath fonts</a> so that I don&#8217;t have to rely on end users having the correct font installed in order to view the LaTex equations.</p>
<p>Here&#8217;s an example (<i>Schwarz inequality</i>):</p>
<p>\[<br />
\left[\int_a^b x(t)y(t)dt\right]^2\leq\int_a^bx^2(t)dt\int_a^by^2(t)dt<br />
\]</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/06/04/latex-math-equations-in-wordpress/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>My First Few Days With Bing</title>
		<link>http://www.kerrywong.com/2009/06/02/my-first-few-days-with-bing/</link>
		<comments>http://www.kerrywong.com/2009/06/02/my-first-few-days-with-bing/#comments</comments>
		<pubDate>Wed, 03 Jun 2009 01:52:34 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Bing]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Search Engine]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1114</guid>
		<description><![CDATA[So Microsoft&#8217;s new search engine Bing has been available for the general public for a few days. While I have read about Bing here and there, I decided to do some comparison myself between Bing and Google.
The Homepage
Depending on who you ask, you either love Google&#8217;s minimalist search home page or prefer a more colorful [...]]]></description>
			<content:encoded><![CDATA[<p>So Microsoft&#8217;s new search engine <a href="http://www.bing.com">Bing</a> has been available for the general public for a few days. While I have read about Bing here and there, I decided to do some comparison myself between Bing and <a href="http://www.google.com">Google</a>.<span id="more-1114"></span></p>
<h3>The Homepage</h3>
<p>Depending on who you ask, you either love Google&#8217;s minimalist search home page or prefer a more colorful one like Bing. But we need to remember that the primary goal of a search engine is to perform search. Bing&#8217;s home page clearly followed Live&#8217;s footstep and as a result the main page is bloated. The home page for Bing comes at <strong>31 Kb</strong> while Google&#8217;s is just above <strong>4 Kb</strong>. (I used <em>wget</em> on both sites and compared the downloaded html, excluding images).</p>
<p>So Bing is at a disadvantage from the start. For the same data pipe size, Google can serve four times as many requests as Bing could. Put it another way: to achieve the same performance, Microsoft would need more resources to compete with Google.</p>
<h3>Search Experience</h3>
<p>On normal searches, Bing lives largely to the hype generated before its launch. It does a decent job in finding relevant results. Comparing the search results between Google and Bing on the same search terms, they are largely similar in terms of how they rank the pages.</p>
<p>Performance-wise, Bing holds up pretty well in general. But occasionally, you can experience a noticeable delay when returning results. Google on the other hand returns results uniformly fast.</p>
<p>Like its home page, the average size of Bing&#8217;s result pages is much larger than Google&#8217;s. Bing&#8217;s search result page (on search term &#8220;test&#8221;) is almost <strong>40 Kb</strong> in size while Google&#8217;s result page remains under <strong>5 Kb</strong>.</p>
<p>I often use searches on servers with a slow remote session and Bing would perform poorly compared with Google in such an environment (e.g. large page sizes).</p>
<h3>Bing Is No Google</h3>
<p>While for the most part Bing gets pretty good search results, I did find some rather poor results from certain search terms.</p>
<p>Try search the word <a href="http://www.bing.com/search?q=download">download</a> on Bing, here is the result you get:<br />
<a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/bing_search.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/06/bing_search.jpg" alt="Bing Search Result on &quot;Download&quot;" title="Bing Search Result on &quot;Download&quot;" width="600" height="477" class="size-full wp-image-1117" /></a><br />
I don&#8217;t know why the first couple of entries would be for Adobe Acrobat Readers. Google&#8217;s first entry points to CNet&#8217;s download site, which makes a lot more sense.</p>
<p>Now, try <a href="http://www.bing.com/search?q=c--">search &#8220;C&#8211;&#8221;</a> on Bing. C minus minus is no where to be found in the results. </p>
<p>If you wanted to find a little more about the <a href="http://www.bing.com/search?q=tasm">TASM</a> assembler, don&#8217;t count on it returning top on the list using Bing, even though the related searches contains related information.</p>
<p>The same thing goes for searching chemical compounds. Searching <a href="http://www.bing.com/search?q=nh3">NH3</a> doesn&#8217;t return you any information about ammonia from the main search results.</p>
<p>Last but not least, Bing lacks the versatility interpreting mathematical equations. To calculate 2 to the 100 power for instance, one could use either 2^100 or 2**100. But using Bing, you are limited to only the first form.</p>
<p>So, to me it is doubtful that Bing would be help Microsoft increase its share in search in any significant way at least not in the near future.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/06/02/my-first-few-days-with-bing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Timing Methods in C++ Under Linux</title>
		<link>http://www.kerrywong.com/2009/05/28/timing-methods-in-c-under-linux/</link>
		<comments>http://www.kerrywong.com/2009/05/28/timing-methods-in-c-under-linux/#comments</comments>
		<pubDate>Fri, 29 May 2009 01:23:38 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[RDTSC]]></category>
		<category><![CDATA[Timing]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1092</guid>
		<description><![CDATA[Measuring the execution time for code sections can be done in multiple ways in C++. Except for the time resolution issue, different timing methods worked relatively the same in single processor environment. As multi-core processors become more prevalent however, we need to be careful at choosing the correct timing mechanism as not all such routines [...]]]></description>
			<content:encoded><![CDATA[<p>Measuring the execution time for code sections can be done in multiple ways in C++. Except for the time resolution issue, different timing methods worked relatively the same in single processor environment. As multi-core processors become more prevalent however, we need to be careful at choosing the correct timing mechanism as not all such routines measure the wall time elapsed.<span id="more-1092"></span></p>
<p>Here I will examine a few commonly used method in measuring time intervals under Linux. All of the following timing routines are timed against the same OpenMP parallel for loop (on a quad-core CPU, the parallel for will spawn four concurrent threads).</p>
<h3>time()</h3>
<p>The <strong>time()</strong> function returns time with the accuracy to a second. So this function is generally useful for measuring long-running processes. </p>
<h3>clock()</h3>
<p>In single-core systems, <strong>clock()</strong> is often used for time measurements. The resolution of this timer is determined by <strong>CLOCKS_PER_SEC</strong> and is usually a microsecond. Since it determines the number of CPU clock cycles elapsed, it is not particularly useful in measuring time on a multi-core processor system when there are concurrent executing threads as the result of <strong>clock()</strong> function is the accumulation of CPU clocks across all active CPUs. On a quad-core system, if all cores are at full utilization then the result time is roughly four times the wall time.</p>
<h3>gettimeofday()</h3>
<p>Similar to the <strong>clock()</strong> function, <strong>gettimeofday()</strong> has a resolution up to one microsecond. As the function name suggests, <strong>gettimeofday()</strong> measures the wall time and thus is suitable for time measurement in multi-core, multi-cpu systems.</p>
<h3>rdtsc</h3>
<p>The <a href="http://en.wikipedia.org/wiki/Time_Stamp_Counter">time stamp counter</a> is available on most modern CPUs (since Pentium). There are many implementations based on <strong>rdtsc</strong> (e.g. on Windows systems, the Win32 API call <strong>QueryPerformanceCounter</strong>). Implementation based on <strong>rdtsc</strong> is generally very accurate (with resolution up to one nanosecond) but depending on implementation, its accuracy might be susceptible to CPU clock throttling (common in mobile CPUs). In my implementation below, the rdtsc results are divided by the CPU frequency. </p>
<blockquote><p>
grep &#8220;cpu MHz&#8221; /proc/cpuinfo  | cut -d&#8217;:&#8217; -f2
</p></blockquote>
<p>This implementation assumes that CPU frequency remains constant during operations, which could lead to poor accuracy should the CPU frequency change during the measurement. For desktop CPU though, this is less of a concern however.</p>
<h3>clock_gettime</h3>
<p>Like <strong>rdtsc</strong>, this function has a nanosecond accuracy and is available on all POSIX compliant systems.</p>
<p>Intel <a href="http://www.threadingbuildingblocks.org/">Threading Building Block</a> also provides a timer function <strong>tick_count::now()</strong> and the time can easily measured using the code snippet below:</p>
<pre class="brush: cpp;">
    t_start = tick_count::now();
    //statements
    t_end = tick_count::now();
    cout &lt;&lt; (t_end - t_start).seconds() * 1000 &lt;&lt; &quot; ms&quot; &lt;&lt; endl;
</pre>
<p>The following lists the code for time measuring using the methods mentioned above.</p>
<pre class="brush: cpp;">
#include &lt;iostream&gt;
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;sys/time.h&gt;
#include &lt;time.h&gt;
#include &lt;ctime&gt;

using namespace std;

void Foo() {
#pragma omp parallel
    {
        for (long i = 0; i &lt; 50000; i++)
            for (long j = 0; j &lt; 50000; j++);
    }

}

unsigned long long rdtsc() {
    unsigned a, d;

    __asm__ volatile(&quot;rdtsc&quot; : &quot;=a&quot; (a), &quot;=d&quot; (d));

    return ((unsigned long long) a) | (((unsigned long long) d) &lt;&lt; 32);
}

void Time() {
    time_t t1, t2;

    time(&amp;t1);
    Foo();
    time(&amp;t2);

    cout &lt;&lt; &quot;time() : &quot; &lt;&lt; t2 - t1 &lt;&lt; &quot; s&quot; &lt;&lt; endl;
}

void Clock() {
    clock_t c1 = clock();
    Foo();
    clock_t c2 = clock();
    cout &lt;&lt; &quot;clock() : &quot; &lt;&lt; (float) (c2 - c1) / (float) CLOCKS_PER_SEC &lt;&lt; &quot; s&quot; &lt;&lt; endl;
}

void GetTimeOfDay() {
    timeval t1, t2, t;
    gettimeofday(&amp;t1, NULL);
    Foo();
    gettimeofday(&amp;t2, NULL);
    timersub(&amp;t2, &amp;t1, &amp;t);

    cout &lt;&lt; &quot;gettimeofday() : &quot; &lt;&lt; t.tv_sec + t.tv_usec / 1000000.0 &lt;&lt; &quot; s&quot; &lt;&lt; endl;
}

void RDTSC() {
    unsigned long long t1, t2;

    t1 = rdtsc();
    Foo();
    t2 = rdtsc();

    cout &lt;&lt; &quot;rdtsc() : &quot; &lt;&lt; 1.0 * (t2 - t1) / 3199987.0 / 1000.0 &lt;&lt; &quot; s&quot; &lt;&lt; endl;
}

void ClockGettime() {
    timespec res, t1, t2;
    clock_getres(CLOCK_REALTIME, &amp;res);

    clock_gettime(CLOCK_REALTIME, &amp;t1);
    Foo();
    clock_gettime(CLOCK_REALTIME, &amp;t2);

    cout &lt;&lt; &quot;clock_gettime() : &quot;
         &lt;&lt; (t2.tv_sec - t1.tv_sec)  + (float) (t2.tv_nsec - t1.tv_nsec) / 1000000000.0
         &lt;&lt; &quot; s&quot; &lt;&lt; endl;
}

int main() {
    cout.setf(ios::fixed);
    cout.setf(ios::showpoint);
    cout.precision(5);

    Time();
    Clock();
    GetTimeOfDay();

    RDTSC();
    ClockGettime();

    return (EXIT_SUCCESS);
}
</pre>
<p>And here is the output from my quad-core computer in debug mode.</p>
<blockquote><p>
time() :  6 s<br />
clock() : 21.85000 s<br />
gettimeofday() : 5.67368 s<br />
rdtsc() : 5.65957 s<br />
clock_gettime() : 5.65894 s
</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/05/28/timing-methods-in-c-under-linux/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Magick++ Missing Delegate Error</title>
		<link>http://www.kerrywong.com/2009/05/20/magick-missing-delegate-error/</link>
		<comments>http://www.kerrywong.com/2009/05/20/magick-missing-delegate-error/#comments</comments>
		<pubDate>Thu, 21 May 2009 00:24:02 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Magick++]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1084</guid>
		<description><![CDATA[As I wrote last time, I did a clean Ubuntu 9.04 install on my main PC. Everything worked pretty well. But after re-installing all the packages I needed for C++ development, I realized that I still was missing some libraries as I got &#8220;Magick::ErrorMissingDelegate&#8221; exception (ImageMagick: no decode delegate for this image format) when I [...]]]></description>
			<content:encoded><![CDATA[<p>As I wrote <a href="/2009/05/13/ubuntu-904-on-my-main-pc/">last time</a>, I did a clean Ubuntu 9.04 install on my main PC. <span id="more-1084"></span>Everything worked pretty well. But after re-installing all the packages I needed for C++ development, I realized that I still was missing some libraries as I got &#8220;Magick::ErrorMissingDelegate&#8221; exception (ImageMagick: no decode delegate for this image format) when I tried to open JPEG or PNG images from code utilizing Magick++ image library.</p>
<p>After a quick <a href="http://www.imagemagick.org/discourse-server/viewtopic.php?f=1&#038;t=12366">search on ImageMagick&#8217;s site</a> I realized that I was missing the following libraries:</p>
<blockquote><p>
libpng12<br />
libjpeg62
</p></blockquote>
<p><!--more--></p>
<p>Note, that you might want to use the following commands to find out the exact package names:</p>
<blockquote><p>
sudo apt-cache search libpng<br />
sudo apt-cache search libjpeg
</p></blockquote>
<p>sudo apt-cache search libjpeg<br />
And then use the following commands to install the packages:</p>
<blockquote><p>
sudo apt-get install libpng12-0 libpng12-dev<br />
sudo apt-get install libjpeg62 libjpeg62-dev
</p></blockquote>
<p>Note that after that, you will need to re-configure and re-build the Magick++ library (e.g. ./configure, ./make ./make install) so that Magick++ library can be linked correctly with the above libraries. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/05/20/magick-missing-delegate-error/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ubuntu 9.04 on My Main PC</title>
		<link>http://www.kerrywong.com/2009/05/13/ubuntu-904-on-my-main-pc/</link>
		<comments>http://www.kerrywong.com/2009/05/13/ubuntu-904-on-my-main-pc/#comments</comments>
		<pubDate>Wed, 13 May 2009 22:35:07 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Linux/BSD]]></category>
		<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Dual Sound Card]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[WD1001FALS]]></category>
		<category><![CDATA[WD6400AAKS]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1068</guid>
		<description><![CDATA[Last month,I upgraded one of my PCs from Ubuntu 8.10 to Ubuntu 9.04 and everything went rather smoothly. Since my main PC is running Ubuntu 8.04 (LTS) and there is no option to upgrade to 9.04 directly without going through 8.10, so I decided to try a fresh installation.
I have a lot of important programs [...]]]></description>
			<content:encoded><![CDATA[<p>Last month,I <a href="/2009/04/23/the-jaunty-jackalope/">upgraded one of my PCs</a> from Ubuntu 8.10 to Ubuntu 9.04 and everything went rather smoothly. Since my main PC is running Ubuntu 8.04 (LTS) and there is no option to upgrade to 9.04 directly without going through 8.10, so I decided to try a fresh installation.<span id="more-1068"></span></p>
<p>I have a lot of important programs on my main PC and I wanted to be extra cautious, so instead of backing up the working harddrive and install Ubuntu 9.04 on top of it, I decided to install it on a new harddrive. This way, I could always fall back to my currently working Ubuntu 8.04 installation should something not working out the way I wanted.</p>
<p>The drive I chose to install Ubuntu 9.04 on was a <a href="http://www.wdc.com/en/products/products.asp?driveid=488">Western Digital Caviar Black WD1001FALS (1TB)</a>.  The installation went smoothly and ten minutes later I was able to use the brand new Ubuntu 9.04 desktop.</p>
<p>It took me a while to customize the desktop, install the applications I needed and migrate the data over. But everything pretty much worked out-of-box. And it certainly feels a lot faster than Ubuntu 8.04.</p>
<p>The only minor &#8220;glitch&#8221; I ran into was my dual sound card setup. As I <a href="/2008/12/09/a-dual-sound-card-setup/">mentioned in an earlier post</a>, I needed to use a second sound card because my on board Intel sound board does not have a MIDI/Game port. I needed that port to hook up my old MIDI keyboard. After the installation though, the sound playback would only go through the Sound Blaster sound card, not the on board Intel HDA sound card. There are various posts (<a href="http://ubuntuforums.org/showthread.php?t=205449">1</a>,<a href="https://help.ubuntu.com/community/SoundTroubleshooting">2</a>,<a href="http://ubuntuforums.org/showthread.php?t=331072">3</a>,<a href="https://answers.launchpad.net/ubuntu/+question/13897">4</a>,<a href="http://www.linuxquestions.org/questions/ubuntu-63/how-do-you-change-the-default-sound-card-in-kubuntu-499520/">5</a>) suggesting how to fix this issue but unfortunately none of them worked in my case. No matter which sound card I initialized first, I always ended up with the Sound Blaster Live card working but not the on-board Intel sound card. Here is how I fixed it: I removed the Sound Blaster Live card first and booted up with just the on board sound. After making sure that the on board sound worked properly, I plugged in the Sound Blaster PCI card and then everything worked as desired (the sound now comes from the on-board Intel HDA instead of the Sound Blaster card).</p>
<p>As a side note, it seems that WD1001FALS does have some performance advantage over WD6400AAKS (which is the harddrive I run Ubuntu 8.04 on) even though their platter densities are quite comparable (333MB/platter versus 320MB/platter). </p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/05/13/ubuntu-904-on-my-main-pc/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Got Slashdotted</title>
		<link>http://www.kerrywong.com/2009/05/09/got-slashdotted/</link>
		<comments>http://www.kerrywong.com/2009/05/09/got-slashdotted/#comments</comments>
		<pubDate>Sat, 09 May 2009 04:03:13 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1065</guid>
		<description><![CDATA[OK, I admit I was not quite prepared for the traffic I got for my previous post on MS-DEBUG as my website has been overwhelmed by the flood of requests coming in. Yes, I got Slashdotted!
Apparently, I do not have enough memory on the server and the large volume of requests caused the main memory [...]]]></description>
			<content:encoded><![CDATA[<p>OK, I admit I was not quite prepared for the traffic I got for <a href="/2009/05/08/ms-debug-1981-2009/">my previous post on MS-DEBUG</a> as my website has been overwhelmed by the flood of requests coming in. Yes, I got <a href="http://tech.slashdot.org/article.pl?sid=09/05/08/169226">Slashdotted</a>!<span id="more-1065"></span></p>
<p>Apparently, I do not have enough memory on the server and the large volume of requests caused the main memory and the swap space to fill up quickly.  And eventually I got the &#8220;out of memory error&#8221;. So for the majority of the day (from noon on), the server was pretty much inaccessible. I even rebooted the server a couple of times but the situation did not improve much due to the number of requests I was handling. I had to fine tune some Apache settings and wait till the requests die down&#8230; Anyway, I was finally able to login to my own site twelve hours later after the post initially appeared on Slashdot.</p>
<p>Some readers had kindly pointed out that the information I presented was not entirely accurate. I guess that I did not even realize that it is more of a 64bit versus 32bit Windows issue. One would have assumed that the only real difference between the two is the size of the addressable memory. Nevertheless, I was thrilled to hear the kind of nostalgia you have all expressed.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/05/09/got-slashdotted/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MS-DEBUG 1981 &#8211; 2009</title>
		<link>http://www.kerrywong.com/2009/05/08/ms-debug-1981-2009/</link>
		<comments>http://www.kerrywong.com/2009/05/08/ms-debug-1981-2009/#comments</comments>
		<pubDate>Fri, 08 May 2009 15:16:12 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Debug]]></category>
		<category><![CDATA[Windows 7]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1047</guid>
		<description><![CDATA[Earlier this week (May 5) Microsoft Windows 7 Release Candidate was released to the general public and like many technology enthusiasts I downloaded a copy early in the morning hours on Tuesday, shortly after Microsoft made it available on its website.
The RC build of Windows 7 (build 7100) has many tweaks over the previous beta [...]]]></description>
			<content:encoded><![CDATA[<p>Earlier this week (May 5) Microsoft Windows 7 Release Candidate was released to the general public and like many technology enthusiasts I downloaded a copy early in the morning hours on Tuesday, shortly after Microsoft made it available on its website.<span id="more-1047"></span></p>
<p>The RC build of Windows 7 (build 7100) has many tweaks over the previous beta build I have (build 7000) and I have not yet played with it long enough to come up with any meaningful conclusions. However, this is not the point of this article. As you might have noticed from the title of this article, I was not about to talk about my experience with Windows 7 (maybe I will write about it later). What I noticed the first thing in Windows 7 is that the <a href="http://en.wikipedia.org/wiki/DEBUG_(DOS_Command)">DEBUG</a> command is nowhere to be found.</p>
<p>I was just old enough to remember the very early days of DEBUG under <a href="http://en.wikipedia.org/wiki/MS-DOS">MS-DOS</a>. In fact, I was fascinated with such a small and yet powerful tool that came with every version of MS-DOS distribution. the DEBUG command was so powerful that you could do almost anything with your machine with sometimes just a few key strokes.</p>
<p>For a long time, I used DEBUG to learn x86 assembly language and to learn about disk (both floppy disks and harddrives) structures and file systems. And occasionally, I would use DEBUG to edit binary files.</p>
<p>I remembered that I could use commands like</p>
<blockquote><p>
-l 100 0 0 1<br />
-d
</p></blockquote>
<p>to load the boot sector from floppy A and inspect whether the boot sector was infected with any virus and if so, I would find a clean floppy disk and using DEBUG to write its boot sector to the disk that was infected.</p>
<p>And routinely, I would use the following commands to inspect the partition table of my harddrive to make sure that it was free from any infections:</p>
<blockquote><p>
mov ax, 0201<br />
mov bx, 1000<br />
mov cx, 0001<br />
mov dx, 0080<br />
int 13<br />
int 3<br />
-g 100<br />
-d 1000
</p></blockquote>
<p>Remember this one?</p>
<blockquote><p>
jmp ffff:0000
</p></blockquote>
<p>I remembered that someone at my high school used to play the pranks by changing the very first few bytes on floppy disks to EA:00:00:FF and placed the disks in computers in the lab so that whenever someone turned on the computer, it would enter an infinite reboot cycle.</p>
<p>And when <a href="http://en.wikipedia.org/wiki/CIH_virus">CIH</a> stroke in the late nineties, my friends and I would use DEBUG to inspect the virus&#8217;s code to see how the instructions could actually be used to cause real physical damage to the hardware.</p>
<p>After Windows came along, I still used DEBUG often. After all, deep inside Windows (up till Windows ME), there was MS-DOS and for years, user were allowed to operate in <a href="http://en.wikipedia.org/wiki/Real_mode">real mode</a> if they so inclined to. With the advent of Windows 2000 and then later Windows XP people started to forget about DEBUG since the operating system became true 32bit and the DOS prompt became just an emulator. You could still view files and write assembly code within DEBUG, but it was in a protected environment and everything you do was pretty safe and you couldn&#8217;t really do anything harmful to the hardware (of course, you could still overwrite sectors in floppy disks if you wanted to).</p>
<p>Ah, those were the good old days. Just like <a href="http://en.wikipedia.org/wiki/QBasic">QBasic</a> disappeared from later versions MS-DOS, DEBUG has gradually become obsolete. It remained in Windows Vista, but it is no where to be found in Windows 7. At last, Windows has shed one of its last vintage applications from the MS-DOS era.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/05/08/ms-debug-1981-2009/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>Canny Edge Detection Auto Thresholding</title>
		<link>http://www.kerrywong.com/2009/05/07/canny-edge-detection-auto-thresholding/</link>
		<comments>http://www.kerrywong.com/2009/05/07/canny-edge-detection-auto-thresholding/#comments</comments>
		<pubDate>Fri, 08 May 2009 02:15:41 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Linux/BSD]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Image Processing]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=999</guid>
		<description><![CDATA[In the example I gave in &#8220;Interfacing IPP with Magick++&#8220;, I illustrated how to use Intel’s Integrated Performance Primitives (IPP) to perform edge detection. One issue with Canny edge detection algorithm is that we need to specify a high threshold and a low threshold. How to select those threshold values affect the quality of the [...]]]></description>
			<content:encoded><![CDATA[<p>In the example I gave in &#8220;<a href="/2009/03/17/interfacing-ipp-with-magick/">Interfacing IPP with Magick++</a>&#8220;, I illustrated how to use <a href="http://software.intel.com/en-us/intel-ipp/">Intel’s Integrated Performance Primitives (IPP)</a> to perform edge detection. One issue with <a href="http://en.wikipedia.org/wiki/Canny_edge_detector">Canny edge detection</a> algorithm is that we need to specify a high threshold and a low threshold. How to select those threshold values affect the quality of the detected edge greatly. And in my previous example, the threshold values were chosen manually. In this blog post, I will examine a couple of simple methods that can be used to automatically determine the threshold values.<span id="more-999"></span></p>
<p>The simplest way is to use the mean value of the gray scale image pixel values. As a rule of thumb, we set the low threshold to 0.66*[mean value] and set the high threshold to 1.33*[mean value]. Another way is to use the median color in the gray scale image and uses 0.66*[median value] and 1.33*[median value] accordingly. For typical images, these two methods achieve comparable results.</p>
<p>For example, the following shows the picture of a building along with its histogram (original image from <a href="ftp://ftp.research.microsoft.com/pub/download/orid">Microsoft Research Digital Image</a>. Please see <a href="http://research.microsoft.com/en-us/um/people/antcrim/data_objrec/msr%20cambridge%20eula%20for%20digital%20images_download.rtf">Microsoft Research Digital Image License Agreement</a> for more information):</p>
<table>
<tr>
<td>
<div id="attachment_1011" class="wp-caption aligncenter" style="width: 330px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/building_gray.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/building_gray.jpg" alt="Building" title="Building" width="320" height="240" class="size-full wp-image-1011" /></a><p class="wp-caption-text">Building</p></div>
</td>
<td>
<div id="attachment_1012" class="wp-caption aligncenter" style="width: 330px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/building_hist.png"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/building_hist.png" alt="Building Histogram" title="Building Histogram" width="320" height="240" class="size-full wp-image-1012" /></a><p class="wp-caption-text">Building Histogram</p></div>
</td>
</tr>
</table>
<p>The following shows the edge detection results using Canny algorithm (left image uses mean value auto-thresholding, right image uses median value auto-thresholding) and the results exhibit very little visible differences. </p>
<table>
<tr>
<td>
<div id="attachment_1006" class="wp-caption aligncenter" style="width: 330px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/building_canny_mean.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/building_canny_mean.jpg" alt="Building (Canny Mean)" title="Building (Canny Mean)" width="320" height="240" class="size-full wp-image-1006" /></a><p class="wp-caption-text">Building (Canny Mean)</p></div>
</td>
<td>
<div id="attachment_1007" class="wp-caption aligncenter" style="width: 330px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/building_canny_median.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/building_canny_median.jpg" alt="Building (Canny Median)" title="Building (Canny Median)" width="320" height="240" class="size-full wp-image-1007" /></a><p class="wp-caption-text">Building (Canny Median)</p></div>
</td>
</tr>
</table>
<p>However, for images has non-equalized histogram (see the picture of cloud and its histogram below): </p>
<table>
<tr>
<td>
<div id="attachment_1018" class="wp-caption aligncenter" style="width: 250px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/cloud_gray.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/cloud_gray.jpg" alt="Cloud" title="Cloud" width="240" height="320" class="size-full wp-image-1018" /></a><p class="wp-caption-text">Cloud</p></div>
</td>
<td>
<div id="attachment_1019" class="wp-caption aligncenter" style="width: 330px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/cloud_hist.png"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/cloud_hist.png" alt="Cloud Histogram" title="Cloud Histogram" width="320" height="240" class="size-full wp-image-1019" /></a><p class="wp-caption-text">Cloud Histogram</p></div>
</td>
</tr>
</table>
<p>Canny Edge detection result based on mean value auto-thresholding is pretty poor (see image on the left below), while edge detection based on median value auto-thresholding achieved much better result (see image on the right below)</p>
<table>
<tr>
<td>
<div id="attachment_1021" class="wp-caption aligncenter" style="width: 250px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/cloud_canny_mean.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/cloud_canny_mean.jpg" alt="Cloud (Canny Mean)" title="Cloud (Canny Mean)" width="240" height="320" class="size-full wp-image-1021" /></a><p class="wp-caption-text">Cloud (Canny Mean)</p></div>
</td>
<td>
<div id="attachment_1024" class="wp-caption aligncenter" style="width: 250px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/cloud_eq_canny_median.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/cloud_eq_canny_median.jpg" alt="Cloud (Canny Median)" title="Cloud (Canny Median)" width="240" height="320" class="size-full wp-image-1024" /></a><p class="wp-caption-text">Cloud (Canny Median)</p></div>
</td>
</tr>
</table>
<p>Alternatively, we could have performed histogram equalization on the image first before applying Canny edge detection with mean auto-thresholding:</p>
<table>
<tr>
<td>
<div id="attachment_1026" class="wp-caption aligncenter" style="width: 250px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/cloud_eq.png"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/cloud_eq.png" alt="Cloud Equalized" title="Cloud Equalized" width="240" height="320" class="size-full wp-image-1026" /></a><p class="wp-caption-text">Cloud Equalized</p></div>
</td>
<td>
<div id="attachment_1028" class="wp-caption aligncenter" style="width: 330px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/cloud_hist_eq.png"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/cloud_hist_eq.png" alt="Cloud Equalized Histogram" title="Cloud Equalized Histogram" width="320" height="240" class="size-full wp-image-1028" /></a><p class="wp-caption-text">Cloud Equalized Histogram</p></div>
</td>
</tr>
</table>
<p>And after image equalization, both mean and median value auto-thresholding achieved similar results.</p>
<table>
<tr>
<td>
<div id="attachment_1030" class="wp-caption aligncenter" style="width: 250px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/cloud_eq_canny_mean.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/cloud_eq_canny_mean.jpg" alt="Cloud Equalized (Canny Mean)" title="Cloud Equalized (Canny Mean)" width="240" height="320" class="size-full wp-image-1030" /></a><p class="wp-caption-text">Cloud Equalized (Canny Mean)</p></div>
</td>
<td>
<div id="attachment_1031" class="wp-caption aligncenter" style="width: 250px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/cloud_eq_canny_median.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/05/cloud_eq_canny_median.jpg" alt="Cloud Equalized (Canny Median)" title="Cloud Equalized (Canny Median)" width="240" height="320" class="size-full wp-image-1030" /></a><p class="wp-caption-text">Cloud Equalized (Canny Median)</p></div>
</td>
</tr>
</table>
<p>So the Canny edge detection using median value auto-thresholding seems to adapt to different types of images very well (note selecting the median value selection can be thought as equalizing the histogram, except that the pixel values are not changed during such operation).</p>
<p>The following is the code listing for the histogram calculation using IPP (based on the <a href="/2009/04/10/an-image-class-based-on-ipp/">image class I created earlier</a>)</p>
<pre class="brush: cpp;">
/** @brief Get the min max mean value statistics for the current image
 *   @param min, max, mean: these are output parameters that are passed
 *         back by reference.
 */
void IPPGrayImage::MinMaxMean(float&amp; min, float&amp; max, double&amp; mean)
{
    IppStatus sts;
    IppiSize origImgSize = {_width, _height};

    sts = ippiMinMax_32f_C1R(_imgBuffer, _width * PIXEL_SIZE, origImgSize, &amp;min, &amp;max);
    assert(sts == ippStsNoErr);
    sts = ippiMean_32f_C1R(_imgBuffer, _width * PIXEL_SIZE, origImgSize, &amp;mean, ippAlgHintFast);
    assert(sts == ippStsNoErr);
}

/** @brief Calculate the histogram of the image
 *   @param nLevel: the number of bins in the histogram
 *        levels: this is the optional levels user can pass in (histogram will be then
 *                calculated with these levels instead of the uniform levels by default.
 *   @return an integer array which contains the histogram.
 *   @note the histogram is by default calculated using uniform bins across the color range.
 */
unsigned int * IPPGrayImage::GetHistogram(unsigned int nLevel, float levels[])
{
    IppStatus sts;
    Ipp32f* l = new Ipp32f[nLevel];
    IppiSize origImgSize = {_width, _height};

    unsigned int* bins = new unsigned int[nLevel - 1];

    float minVal = 0, maxVal = 0, stepVal = 0;
    double meanVal = 0;
    if (levels != NULL)
    {
        for (unsigned int i = 0; i &lt; nLevel; i++)
        {
            l[i] = levels[i];
        }
    }
    else
    {
        MinMaxMean(minVal, maxVal, meanVal);
        stepVal = (maxVal - minVal) / (float) nLevel;

        for (unsigned int i = 0; i &lt; nLevel; i++)
        {
            l[i] = minVal + stepVal * i;
        }
    }

    sts = ippiHistogramRange_32f_C1R(_imgBuffer, _width * PIXEL_SIZE, origImgSize, (Ipp32s*) bins, (Ipp32f*) l, nLevel);
    return bins;
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/05/07/canny-edge-detection-auto-thresholding/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Kubuntu 9.04 Test Drive</title>
		<link>http://www.kerrywong.com/2009/05/01/kbuntu-904-test-drive/</link>
		<comments>http://www.kerrywong.com/2009/05/01/kbuntu-904-test-drive/#comments</comments>
		<pubDate>Sat, 02 May 2009 02:20:05 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Linux/BSD]]></category>
		<category><![CDATA[Gnome]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[Kubuntu]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=989</guid>
		<description><![CDATA[I was traditionally a KDE user till KDE 4.0 came along. While many users are excited about many of the new features (e.g. Widgets) added in KDE 4, I am simply no big fan of fancy user interfaces. So I have been using GNOME ever since. Of course the beauty of Linux is that running [...]]]></description>
			<content:encoded><![CDATA[<p>I was traditionally a <a href="http://www.kde.org">KDE</a> user till KDE 4.0 came along. While many users are excited about many of the new features (e.g. Widgets) added in KDE 4, I am simply no big fan of fancy user interfaces. So I have been using <a href="http://www.gnome.org/">GNOME</a> ever since. Of course the beauty of Linux is that running one windows manager does not prevent you from running applications native to another windows manager. <span id="more-989"></span></p>
<p>As I mentioned <a href="/2009/04/23/the-jaunty-jackalope/">a few days ago</a>, I installed Ubuntu 9.04 on one of my home machines the day it became available and while no radical new features introduced I liked the improvements over 8.10 and 8.04. Since  haven&#8217;t tried KDE for a while, I decide to download and install the latest Kubuntu 9.04 on VMWare and give it a try.</p>
<p>Kubuntu&#8217;s installation process is as easy as it could be just like installing Ubuntu. It took only a minute or two longer than installing Ubuntu but within 10 minutes I was ready to log in.</p>
<p><strong>What I liked</strong><br />
The new Dolphin file manager is extremely fast and easy to use. I like the the places side bar where you could create shortcuts to your favorite folders. The performance of Dolphin is also much faster than Nautilus in Gnome. For smaller folder sizes (e.g. folders with less than 100 files) there is usually very little noticeable performance issue in either file managers. But with large folders (e.g. folders with a few thousands files), Nautilus becomes unbearably slow. Dolphin seems to have little trouble handling large folders.</p>
<p>I also like the &#8220;filter&#8221; capability in Dolphin. It makes finding files in folders much easier.</p>
<p>The new KDE application launcher is also very pleasant to use and I think it is certainly a big improvement over KDE 3&#8217;s start menu. The main menu usability has almost been my main issue when using GNOME. Even though alternative menus such as Gnome Main Menu and Ubuntu System Panel provide similar functionalities, they lack the polish and stability of KDE&#8217;s application launcher.</p>
<p>The overall performance of KDE 4 seems to be on par if not better than that of KDE 3.</p>
<p><strong>What I didn&#8217;t like</strong><br />
One of the main reasons the KDE community developed the Plasma desktop was to provide users a richer visual experience. Unfortunately I have never been a big fan of any UI visual sugars. Of course, this is totally a personal preference and opinion seems to be evenly divided within the Linux community&#8211;people either loves the new look and feel or think it is too cumbersome. And the borders of default windows are excessively thick which I think it is a waste of screen real estate. </p>
<p>The new task bar is a bit buggy and seems to be too easy to mess up, it would help to have a menu item called &#8220;restore to default layout&#8221;.</p>
<p>One of the problem I ran into was that Kubuntu somehow couldn&#8217;t remember the screen resolution setting under VMWare (by the way, I was using the 64bit version of Kubuntu). And every time after a reboot the screen size got automatically reset to 640&#215;480. I am not sure whether this particular issue is related to just VMWare (6.5.2), but it was very annoying as I had to manually adjust the screen resolution every time. And once the screen resolution is adjusted, font sizes on certain applications got messed up. It seems that the font in Konqueror got scaled up multiple times somehow and looks ridiculously large. </p>
<p>So I guess I will have to stick to my GNOME desktop for a long while&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/05/01/kbuntu-904-test-drive/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Jaunty Jackalope</title>
		<link>http://www.kerrywong.com/2009/04/23/the-jaunty-jackalope/</link>
		<comments>http://www.kerrywong.com/2009/04/23/the-jaunty-jackalope/#comments</comments>
		<pubDate>Thu, 23 Apr 2009 15:14:48 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Linux/BSD]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=975</guid>
		<description><![CDATA[Without much fanfare, Ubuntu 9.04 (Jaunty Jackalope) was released into the wild earlier today. But Ubuntu followers are wasting no time, overloading many of the official downloading sites. 
This kind of enthusiasm is certainly encouraging as Linux matures. And certainly, this kind of enthusiasm is much needed for the open source community in general. Whether [...]]]></description>
			<content:encoded><![CDATA[<p>Without much fanfare, <a href="http://www.ubuntu.com/">Ubuntu 9.04 (Jaunty Jackalope)</a> was released into the wild earlier today. But Ubuntu followers are wasting no time, overloading many of the official downloading sites. <span id="more-975"></span></p>
<p>This kind of enthusiasm is certainly encouraging as Linux matures. And certainly, this kind of enthusiasm is much needed for the open source community in general. Whether it is proprietary software or free software, the community acceptance is definitely key to the success of its future. </p>
<p>I have three systems running on Ubuntu at home right now. My Wordpress server is running Ubuntu 8.04 server (32 bit). One of my working machine is running Ubuntu 8.04 64 bit and the other is running Ubuntu 8.10. For my server, I will stick to the 8.04 as it is an LTS release. But I am thinking of installing the latest Ubuntu desktops onto my workstations in the next couple of weeks&#8230;</p>
<p><strong>Update 1 8:00 PM</strong><br />
I have just installed Ubuntu 9.04 using the ISO image I downloaded earlier onto a VM. The installation was made even easier (the time zone is now selected by default). The default installation took just about five minutes. The boot time is also very impressive. It took just about 20 seconds before showing the login screen, which is a big improvement over my 8.04 installation.</p>
<p><strong>Update 2 9:00 PM</strong><br />
Even though a fresh installation might be ideal, I decided to run the update on my Ubuntu 8.10 machine anyway. This is mainly because it was used as a file and VM server and I had done very little customizations on it besides that. So I think the chances of getting a successful upgrade is pretty high. The distribution upgrade is pretty slow though, and it is downloading at about 30k/s right now&#8230;<br />
<div id="attachment_985" class="wp-caption aligncenter" style="width: 391px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/04/ubuntu904upgrade.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/04/ubuntu904upgrade.jpg" alt="Upgrading from Ubuntu 8.10 to 9.04" title="Upgrading from Ubuntu 8.10 to 9.04" width="381" height="318" class="size-full wp-image-985" /></a><p class="wp-caption-text">Upgrading from Ubuntu 8.10 to 9.04</p></div></p>
<p><strong>Update 3 4/24/2009 7:00 AM</strong><br />
The 8.10 to 9.04 upgrade went surprisingly well. The only problem I had has nothing to do with Ubuntu. </p>
<p>Since the machine I was doing the update on is a file and VMs server, I did not bother attach display or keyboard to it. So when I was doing the update yesterday used an SSH connection and forgot that the updates would need to shutdown SSH and other services in order to install the newer version of the daemons. Anyway, half way through the upgrade, the connection to my server was lost. At first I thought that I could just attach a monitor and keyboard to my server and continue the whole upgrade process. Of course it wouldn&#8217;t work since the upgrade process was tied to that particular terminal. </p>
<p>So I had to reboot the machine. For whatever reason, maybe because the machine was only half upgraded, the normal boot does not work and I could not log in via the graphical login screen. I restarted in &#8220;safe&#8221; mode dropping into a root shell and did a </p>
<blockquote><p>
sudo dpkg &#8211;configure -a
</p></blockquote>
<p>And the upgrade process picked up from where it was left at before. This is truly impressive! After the upgrade process finished, I rebooted into the new 9.04 installation:</p>
<blockquote><p>
sudo lsb_release -a</p>
<p>Distributor ID:	Ubuntu<br />
Description:	Ubuntu 9.04<br />
Release:	9.04<br />
Codename:	jaunty
</p></blockquote>
<p>The only thing that did not work after the upgrade was the VMWare Server (which is totally expected as it needs to link to the correct version of libraries). But after a simple re-config, the VMWare Server came back into life.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/04/23/the-jaunty-jackalope/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C++ IDEs Under Linux</title>
		<link>http://www.kerrywong.com/2009/04/18/c-ides-under-linux/</link>
		<comments>http://www.kerrywong.com/2009/04/18/c-ides-under-linux/#comments</comments>
		<pubDate>Sun, 19 Apr 2009 02:27:04 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Linux/BSD]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Code::Blocks]]></category>
		<category><![CDATA[KDevelop]]></category>
		<category><![CDATA[NetBeans]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=964</guid>
		<description><![CDATA[So far I have been mainly using KDevelop and Code::Blocks as my C++ development IDEs. Recently, I started using NetBeans IDE for C++ and I started to like it quite a bit.
In my opinion, the above three IDEs all have their strengths and weaknesses depending on what kind of project you are working on. Here [...]]]></description>
			<content:encoded><![CDATA[<p>So far I have been mainly using <a href="http://www.kdevelop.org">KDevelop</a> and <a href="http://www.codeblocks.org">Code::Blocks</a> as my C++ development IDEs. Recently, I started using <a href="http://www.netbeans.org/">NetBeans IDE</a> for C++ and I started to like it quite a bit.<span id="more-964"></span></p>
<p>In my opinion, the above three IDEs all have their strengths and weaknesses depending on what kind of project you are working on. Here are some of my observations.<br />
<strong><br />
KDevelop is probably the most comprehensive IDE of the three</strong>. This should not come as a surprise as it has been around for more than 10 years and it bas been the de facto development environment for most of the <a href="http://www.kde.org">KDE</a> development work. It is very feature rich and you can use it to develop many different types of applications natively out of box (e.g. KDE, GTK+, Qt, wxWidgets, etc). If you are developing <a href="http://www.gnu.org">GNU</a> style applications, you will benefit from the Automake project type if provides. Besides the vast functionalities KDevelop provides, it is also very fast, efficient and stable. </p>
<p>Nonetheless, KDevelop is not the most intuitive IDE and does not suit small projects (e.g. prof of concept code) well as the initial project setup can be time consuming.</p>
<p><strong>Code::Blocks is a very capable IDE for C++ development as well</strong>. It offers many project templates even though it does not offer native KDE project types. This should not be a problem to most people however. Among the features I like the most is that it does not require explicit make file configuration and the build dependencies are inferred by default. This makes it very attractive for rapid prototyping. Debugging under Code::Blocks is also a pleasant experience. It also integrates (at least in the later SVN versions) <a href="http://valgrind.org/">Valgrind</a>&#8217;s MemCheck and Cachegrind, which are very useful for detecting memory leaks and tweaking algorithms for the maximum performance.</p>
<p>The latest stable version of Code::Blocks is 8.02, it is a little dated as a lot of functionalities have been added in the later SVN builds. If you do not require the most stability (I have run into <a href="/2009/04/15/how-to-revert-to-a-specific-svn-version-of-codeblocks/">some issues</a> recently), using SVN build should not be a problem. The editor (e.g. syntax highlighting, collapsible regions) is a little bit buggy though and the contextual help does not always work to the level of detail I desired. </p>
<p><strong>NetBeans C++ IDE is probably the most beautiful one among the three</strong>. It offers the most detailed syntax highlighting, and can be configured to display class hierarchy and library function information. The refactor tool works pretty well and is certainly a boon to large scale development. Its contextual help is also of top-notch.</p>
<p>All of these come at a cost of course. NetBeans C++ IDE is the most resource intensive among the three. It can easily use 500 MB memory when doing development and can be sluggish at times. It also comes with a very limited project template (e.g. no out-of-box project templates for Qt, wxWidgets). Certain settings <a href="http://www.netbeans.org/kb/docs/cnd/toolchain.html">are hard to get at</a> as well. Nevertheless, if I am primarily writing back-end code, NetBeans C++ IDE could easily earn my top choice. </p>
<p>Some people like <a href="http://www.anjuta.org">Anjuta</a> and compare it favorably to Code::Blocks. But I haven&#8217;t got a chance to use it yet.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/04/18/c-ides-under-linux/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>How to Revert to a Specific SVN Version of Code::Blocks</title>
		<link>http://www.kerrywong.com/2009/04/15/how-to-revert-to-a-specific-svn-version-of-codeblocks/</link>
		<comments>http://www.kerrywong.com/2009/04/15/how-to-revert-to-a-specific-svn-version-of-codeblocks/#comments</comments>
		<pubDate>Wed, 15 Apr 2009 23:52:45 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Linux/BSD]]></category>
		<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Code::Blocks]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=960</guid>
		<description><![CDATA[I had set up my apt-get source to use latest SVN build of Code::Blocks. Everything has been running pretty smoothly until a couple of days ago when Code::Blocks was updated to SVN 5534. It seemed that for whatever reason, this particular build is extremely unstable on my Ubuntu 8.04 box and it would refuse to [...]]]></description>
			<content:encoded><![CDATA[<p>I had set up my apt-get source to use latest SVN build of Code::Blocks. Everything has been running pretty smoothly until a couple of days ago when Code::Blocks was updated to SVN 5534.<span id="more-960"></span> It seemed that for whatever reason, this particular build is extremely unstable on my Ubuntu 8.04 box and it would refuse to open any projects created prior to SVN 5534.</p>
<p>So naturally, I wanted to revert back to my previous working version (SVN 5489). There are some <a href="http://lgp203.free.fr/spip/spip.php?article1">instructions on lgp203.free.fr</a> that in theory should work to install any revisions of Code::Blocks from SVN. But the script provided there did not work for me as it was complaining about not able to find certain packages. So I decided to do it manually, and here are the steps I took to get SVN 5489 installed.</p>
<p>First, you will need to remove the installed version of Code::Blocks.</p>
<blockquote><p>sudo apt-get remove codeblocks<br />
sudo apt-get remove codeblocks-common</p></blockquote>
<p>Then you will need to install the Debian packages one by one from lgp203.free.fr. using </p>
<blockquote><p>wget http://lgp203.free.fr/pool/codeblocks/wxsmith-headers_8.02svn5489_all.deb<br />
wget http://lgp203.free.fr/pool/codeblocks/libwxsmithlib0_8.02svn5489_amd64.deb<br />
wget http://lgp203.free.fr/pool/codeblocks/codeblocks-headers_8.02svn5489_all.deb<br />
wget http://lgp203.free.fr/pool/codeblocks/libcodeblocks0_8.02svn5489_amd64.deb<br />
wget http://lgp203.free.fr/pool/codeblocks/codeblocks_8.02svn5489_amd64.deb<br />
wget http://lgp203.free.fr/pool/codeblocks/codeblocks-common_8.02svn5489_all.deb<br />
wget http://lgp203.free.fr/pool/codeblocks/codeblocks-contrib_8.02svn5489_amd64.deb<br />
wget http://lgp203.free.fr/pool/codeblocks/codeblocks-contrib-common_8.02svn5489_all.deb</p></blockquote>
<blockquote><p>sudo dpkg -i wxsmith-headers_8.02svn5489_all.deb<br />
sudo dpkg -i libwxsmithlib0_8.02svn5489_amd64.deb<br />
sudo dpkg -i codeblocks-headers_8.02svn5489_all.deb<br />
sudo dpkg -i libcodeblocks0_8.02svn5489_amd64.deb<br />
sudo dpkg -i codeblocks_8.02svn5489_amd64.deb<br />
sudo dpkg -i codeblocks-common_8.02svn5489_all.deb<br />
sudo dpkg -i codeblocks-contrib_8.02svn5489_amd64.deb<br />
sudo dpkg -i codeblocks-contrib-common_8.02svn5489_all.deb
</p></blockquote>
<p>You can find a full list of all the available Code::Blocks&#8217; SVN versions <a href="http://lgp203.free.fr/ubuntu/dists/">here</a>. Now, I am running version 5489 and everything is working again.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/04/15/how-to-revert-to-a-specific-svn-version-of-codeblocks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>On Default Linux IO Priority</title>
		<link>http://www.kerrywong.com/2009/04/14/on-default-linux-io-priority/</link>
		<comments>http://www.kerrywong.com/2009/04/14/on-default-linux-io-priority/#comments</comments>
		<pubDate>Wed, 15 Apr 2009 01:24:02 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Linux/BSD]]></category>
		<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=956</guid>
		<description><![CDATA[If there is any thing I think Linux distributions can definitely improve upon is to reduce the default IO task priorities while running a Windows manager (e.g. GNOME or KDE).
What I have found out over time is that the default IO priorities tend to cause the UI very sluggish when doing heavy IO operations (e.g. [...]]]></description>
			<content:encoded><![CDATA[<p>If there is any thing I think Linux distributions can definitely improve upon is to reduce the default IO task priorities while running a Windows manager (e.g. GNOME or KDE).<span id="more-956"></span></p>
<p>What I have found out over time is that the default IO priorities tend to cause the UI very sluggish when doing heavy IO operations (e.g. copying files between disks, etc.). While this problem is not inherent to Linux (Linux is only the kernel), The default sluggish behavior under heavy IO conditions makes popular Linux distributions (e.g. Ubuntu) less user friendly than it should.</p>
<p>While using <strong>ionice</strong> <a href="http://digg.com/d1AWma">can solve this issue</a>, it isn&#8217;t very continent as it needs to be manually set every time the user performs heavy IO tasks. </p>
<p>It is true that the performance of the main-stream hard drives/and controllers (e.g. SATA) is partially responsible for the sluggishness of the UI response and higher end disk sub-systems like serial attached SCSI alleviate this problem to a certain degree, for Linux to really go main stream nevertheless, this problem should not be overlooked as SATA is the common disk sub-system almost all main-stream users have.</p>
<p>Since copying large files is such a common task nowadays, why couldn&#8217;t we just lower the default IO priority settings instead of relying on user to use <strong>ionice</strong>? In general, most end users care more about the UI responsiveness than the background disk throughput. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/04/14/on-default-linux-io-priority/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>An Image Class Based On IPP</title>
		<link>http://www.kerrywong.com/2009/04/10/an-image-class-based-on-ipp/</link>
		<comments>http://www.kerrywong.com/2009/04/10/an-image-class-based-on-ipp/#comments</comments>
		<pubDate>Sat, 11 Apr 2009 00:34:55 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Linux/BSD]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[FFT]]></category>
		<category><![CDATA[IPP]]></category>
		<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=935</guid>
		<description><![CDATA[A couple of weeks ago, I wrote about how to interface Integrated Performance Primitives (IPP) with Magick++. While IPP offers excellent performance advantages, it does not come with the easiest programming model. Fortunately, it is easy enough to create a C++ wrapper on top of IPP and provide an easier to use programming interface.
In this [...]]]></description>
			<content:encoded><![CDATA[<p>A couple of weeks ago, I wrote about <a href="/2009/03/17/interfacing-ipp-with-magick/">how to interface Integrated Performance Primitives (IPP) with Magick++</a>. While IPP offers excellent performance advantages, it does not come with the easiest programming model. Fortunately, it is easy enough to create a C++ wrapper on top of IPP and provide an easier to use programming interface.<span id="more-935"></span></p>
<p>In this article, I will show a simple example of creating a wrapper class using <a href="http://www.intel.com/cd/software/products/asmo-na/eng/302910.htm">IPP</a> and <a href="http://www.imagemagick.org/Magick%2B%2B/">Magick++</a>. The example I am going to show can be used to calculate the 2-dimensional FFT spectrum of a gray-scale image. This framework can be easily extended to include other algorithms that can be applied to an image using IPP.</p>
<p>Before I show the implementation details, let me first show how easy it is to use the class. The code snippet below shows how to read in an image file, apply 2D FFT with and without a Hamming window and save the results into image files.</p>
<pre class="brush: cpp;">
    IPPGrayImage *img, *img1;

    img = new IPPGrayImage();
    img-&gt;LoadFromFile(IMAGE_FILE);

    img1 = img-&gt;Clone();
    img1 = img1-&gt;FFT(true);
    img1-&gt;SaveToFile(IMAGE_HOME + &quot;/test_fftmag.jpg&quot;);
    img1 = img-&gt;Clone();
    img1 = img-&gt;ApplyHammingWindow();
    img1-&gt;SaveToFile(IMAGE_HOME + &quot;/test_hamming.jpg&quot;);
    img1 = img1-&gt;FFT(true);
    img1-&gt;SaveToFile(IMAGE_HOME + &quot;/test_fftmag_hamming.jpg&quot;);
</pre>
<p>And for the following IMAGE_FILE,<br />
<div id="attachment_941" class="wp-caption aligncenter" style="width: 266px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/04/testimg.jpeg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/04/testimg.jpeg" alt="Test image used for 2D FFT" title="Test Image" width="256" height="256" class="size-full wp-image-941" /></a><p class="wp-caption-text">Test image used for 2D FFT</p></div></p>
<p>Here are the results for FFT spectrum with and without hamming window:<br />
<div id="attachment_943" class="wp-caption aligncenter" style="width: 266px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/04/test_hamming.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/04/test_hamming.jpg" alt="Hamming window applied" title="Hamming window applied" width="256" height="256" class="size-full wp-image-943" /></a><p class="wp-caption-text">Hamming window applied</p></div><br />
<div id="attachment_944" class="wp-caption aligncenter" style="width: 266px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/04/test_fftmag.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/04/test_fftmag.jpg" alt="FFT spectrum (without Hamming window)" title="FFT spectrum (without Hamming window)" width="256" height="256" class="size-full wp-image-944" /></a><p class="wp-caption-text">FFT spectrum (without Hamming window)</p></div><br />
<div id="attachment_945" class="wp-caption aligncenter" style="width: 266px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/04/test_fftmag_hamming.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/04/test_fftmag_hamming.jpg" alt="FFT spectrum with Hamming window" title="FFT spectrum with Hamming window" width="256" height="256" class="size-full wp-image-945" /></a><p class="wp-caption-text">FFT spectrum with Hamming window</p></div></p>
<p>The header file for the class is as follows:</p>
<pre class="brush: cpp;">
#ifndef IPPGRAYIMAGE_H
#define IPPGRAYIMAGE_H

#include &lt;Magick++/Image.h&gt;
#include &lt;Magick++.h&gt;
#include &lt;ipp.h&gt;

using namespace std;
using namespace Magick;

namespace KDW
{
    class IPPGrayImage
    {
    public:
        unsigned int PIXEL_SIZE;

        IPPGrayImage();
        IPPGrayImage(const unsigned int width, const unsigned int height);
        IPPGrayImage(Ipp32f *imgBuffer, const unsigned int width, const unsigned int height);
        IPPGrayImage(const IPPGrayImage&amp; other);
        virtual ~IPPGrayImage();
        IPPGrayImage&amp; operator=(const IPPGrayImage&amp; other);

        void LoadFromFile(string fileName);
        void SaveToFile();
        void SaveToFile(string fileName);

        inline float GetPixel(unsigned int col, unsigned int row) {return _imgBuffer[row * _width + col];}
        inline void SetPixel(unsigned int col, unsigned int row, float clr) {_imgBuffer[row * _width + col] = clr;}

        unsigned int GetWidth() { return _width;}
        unsigned int GetHeight() { return _height;}

        Ipp32f* GetImageBuffer() { return _imgBuffer;}
        Image* GetImage() { return _img;}

        IPPGrayImage* Clone();
        IPPGrayImage* ApplyHammingWindow();
        IPPGrayImage* FFT(bool fftShift = false);
    protected:
    private:
        unsigned int _width;
        unsigned int _height;

        Image* _img;
        Pixels* _view;
        PixelPacket* _pixels;
        Ipp32f* _imgBuffer;
        string _fileName;

        void Init();
    };
}
#endif // IPPGRAYIMAGE_H
</pre>
<p>And here&#8217;s the implementation for the class:</p>
<pre class="brush: cpp;">
#include &lt;assert.h&gt;
#include &lt;math.h&gt;

#include &quot;IPPGrayImage.h&quot;

namespace KDW
{
    /** @brief Constructor()
     *  Initialize image buffer.
     */
    IPPGrayImage::IPPGrayImage()
    {
        Init();
    }

    /** @brief Constructor(width, height)
     *  Initialize an image size of width x height.
     */
    IPPGrayImage::IPPGrayImage(const unsigned int width, const unsigned int height)
    {
        Init();

        _width = width;
        _height = height;

        int stepByte = 0;
        _imgBuffer = ippiMalloc_32f_C1(_width, _height, &amp;stepByte);
    }

    /** @brief Constructor(imgBuffer, width, height)
     *  Initilize from an Ipp32f buffer (width x height)
     */
    IPPGrayImage::IPPGrayImage(Ipp32f *imgBuffer, const unsigned int width, const unsigned int height)
    {
        Init();

        _width = width;
        _height = height;
        _imgBuffer = imgBuffer;
    }

    /** @brief Copy Constructor
     */
    IPPGrayImage::IPPGrayImage(const IPPGrayImage&amp; other)
    {
        _width = other._width;
        _height = other._height;

        int stepByte = 0;

        _imgBuffer = ippiMalloc_32f_C1(_width, _height, &amp;stepByte);

        for (unsigned int row = 0; row &lt; _height ; row++)
        {
            for (unsigned int column = 0; column &lt; _width ; column++)
            {
                _imgBuffer[column + row * _width] =other._imgBuffer[column + row * _width];
            }
        }

        if (other._pixels == NULL) _pixels = NULL;
    }

    /** @brief Overload =
     */
    IPPGrayImage&amp; IPPGrayImage::operator=(const IPPGrayImage&amp; rhs)
    {
        if (this == &amp;rhs) return *this; // handle self assignment

        return *this;
    }

    /**
     * @brief Destructor
     */
    IPPGrayImage::~IPPGrayImage()
    {
        ippFree(_imgBuffer);
        delete _img;
        delete _view;
    }

    /**
     * @brief Common initialization code
     */
    void IPPGrayImage::Init()
    {
        PIXEL_SIZE = sizeof(Ipp32f);
        _pixels = NULL;
        _imgBuffer = NULL;
        _img = NULL;
    }

    /** @brief Load an image from file
      */
    void IPPGrayImage::LoadFromFile(string fileName)
    {
        _img = new Image(fileName);
        Geometry g = _img-&gt;size();

        _width = g.width();
        _height= g.height();

        _view = new Pixels(*_img);
        _pixels = _view-&gt;get(0,0, _width, _height);

        int stepByte = 0;
        _imgBuffer = ippiMalloc_32f_C1(_width, _height, &amp;stepByte);

        for (unsigned int row = 0; row &lt; _height ; row++)
        {
            for (unsigned int column = 0; column &lt; _width ; column++)
            {
                PixelPacket *p = &amp;_pixels[column + row * _width];
                Color c = Color(p-&gt;red, p-&gt;green, p-&gt;blue);
                _imgBuffer[column + row * _width] = c.intensity();
            }
        }
    }

    /** @brief Save the current image buffer to file
      */
    void IPPGrayImage::SaveToFile()
    {
        SaveToFile(&quot;&quot;);
    }

    /** @brief SaveToFile(fileName)
     *  Saves the current image buffer to a file (by file name).
     */
    void IPPGrayImage::SaveToFile(string fileName)
    {
        if (_img != NULL &amp;&amp; _pixels != NULL)
        {
            for (unsigned int y = 0; y&lt; _height ; y++)
            {
                for (unsigned int x = 0; x &lt; _width; x++)
                {
                    float clr = (float) _imgBuffer[x + y * _width];
                    _pixels[x+ y * _width] = Color(clr, clr, clr);
                }
            }
            _view-&gt;sync();
            _img-&gt;syncPixels();

            if (fileName == &quot;&quot;)
            {
                _img-&gt;write(_fileName);
            }
            else
            {
                _img-&gt;write(fileName);
            }
        }
        else
        {
            Image img(Geometry(_width, _height),&quot;white&quot;);

            for (unsigned int y = 0; y&lt; _height ; y++)
            {
                for (unsigned int x = 0; x &lt; _width; x++)
                {
                    Color c;
                    float clr = (float) _imgBuffer[x + y * _width];
                    img.pixelColor(x,y, Color(clr, clr, clr));
                }
            }

            img.write(fileName);
        }
    }

    /** @brief Clone
    *   Duplicate the current image to another IPPGrayImage object.
    *   @return an IPPGrayImage pointer to the cloned image
    */
    IPPGrayImage* IPPGrayImage::Clone()
    {
        IPPGrayImage *newImg;

        newImg = new IPPGrayImage(_width, _height);

        int stepByte = 0;
        newImg-&gt;_imgBuffer = ippiMalloc_32f_C1(_width,_height, &amp;stepByte);

        for (unsigned int y = 0 ; y &lt; _height ; y++)
        {
            for (unsigned int x = 0 ; x &lt; _width ; x++)
            {
                newImg-&gt;_imgBuffer[x + y * _width] = _imgBuffer[x + y * _width];
            }
        }

        return newImg;
    }

    /** @brief Apply Hamming window to the image
     *  @return an IPPGrayImage pointer to the processed image
     */
    IPPGrayImage* IPPGrayImage::ApplyHammingWindow()
    {
        IPPGrayImage *newImg;
        newImg = new IPPGrayImage(_width , _height);
        IppiSize srcImgSize = {_width, _height};

        IppStatus sts;
        int stepByte;
        Ipp32f *imgCache = ippiMalloc_32f_C1(_width , _height , &amp;stepByte);

        sts = ippiWinHamming_32f_C1R(_imgBuffer, _width * PIXEL_SIZE, imgCache, _width * PIXEL_SIZE, srcImgSize);
        assert(sts ==ippStsNoErr);

        for (unsigned int y = 0; y&lt; _height; y++)
        {
            for (unsigned int x = 0; x &lt; _width; x++)
            {
                newImg-&gt;_imgBuffer[x+ y * _width] = imgCache[x + y * _width];
            }
        }

        return newImg;
    }

    /** @brief Perform FFT on the image and returns the magnitude component
     *  @param fftShift: if it is true, the the result is with
     *         zero-frequency component shifted to center of spectrum
     *  @return the magnitude FFT component
     */
    IPPGrayImage* IPPGrayImage::FFT(bool fftShift)
    {
        IPPGrayImage *newImg;
        IppiFFTSpec_R_32f *spec;
        IppStatus sts;

        unsigned int n = (int) (logf((float) _width) / logf(2.0f));
        unsigned int m = (int) (logf((float) _height) / logf(2.0f));

        unsigned int N = pow(2, n);
        unsigned int M = pow(2, m);

        if (N &lt; _width)
        {
            n = n + 1;
            N = pow(2, n);
        }

        if (M &lt; _height)
        {
            m = m + 1;
            M = pow(2, m);
        }

        int stepByte;
        Ipp32f *src = ippiMalloc_32f_C1(M , N , &amp;stepByte);
        Ipp32f *dst = ippiMalloc_32f_C1(M , N , &amp;stepByte);
        Ipp32f *mag = ippiMalloc_32f_C1(M , N , &amp;stepByte);

        IppiSize srcImgSize = {_width, _height};
        IppiSize dstImgSize = {N, M};

        sts = ippiCopyConstBorder_32f_C1R(
                  _imgBuffer, _width * PIXEL_SIZE, srcImgSize,
                  src,  N * PIXEL_SIZE, dstImgSize,
                  0,0,0);
        assert(sts ==ippStsNoErr);

        sts = ippiFFTInitAlloc_R_32f(&amp;spec, n , m, IPP_FFT_DIV_BY_SQRTN, ippAlgHintAccurate);
        assert(sts ==ippStsNoErr);

        sts = ippiFFTFwd_RToPack_32f_C1R(src, N*PIXEL_SIZE, dst, N*PIXEL_SIZE, spec, 0);
        assert(sts ==ippStsNoErr);

        sts = ippiMagnitudePack_32f_C1R(dst, N*PIXEL_SIZE, mag, N*PIXEL_SIZE, dstImgSize);
        assert (sts ==ippStsNoErr);

        newImg = new IPPGrayImage(N , M);

        if (fftShift)
        {
#pragma omp sections
            {
#pragma omp section
                {
                    for (unsigned int y = 0 ; y &lt; M/2; y++)
                    {
                        for (unsigned int x = 0 ; x &lt; N/2; x++)
                        {
                            newImg-&gt;_imgBuffer[x+ y *N] = mag[x + N/2 + (y + M/2) * N];
                        }
                    }
                }
#pragma omp section
                {
                    for (unsigned int y = 0 ; y &lt; M/2; y++)
                    {
                        for (unsigned int x = N/2 ; x &lt; N; x++)
                        {
                            newImg-&gt;_imgBuffer[x+ y *N] = mag[x - N/2 + (y + M/2) * N];
                        }
                    }
                }
#pragma omp section
                {
                    for (unsigned int y = M/2 ; y &lt; M; y++)
                    {
                        for (unsigned int x = 0 ; x &lt; N/2; x++)
                        {
                            newImg-&gt;_imgBuffer[x+ y *N] = mag[x + N/2 + (y - M/2) * N];
                        }
                    }
                }
#pragma omp section
                {
                    for (unsigned int y = M/2 ; y &lt; M; y++)
                    {
                        for (unsigned int x = N/2 ; x &lt; N; x++)
                        {
                            newImg-&gt;_imgBuffer[x+ y *N] = mag[x - N/2 + (y - M/2) * N];
                        }
                    }
                }
            }
        }
        else
        {
            for (unsigned int y = 0; y&lt; M; y++)
            {
                for (unsigned int x = 0; x &lt;N; x++)
                {
                    newImg-&gt;_imgBuffer[x+ y * N] = mag[x + y * N];
                }
            }

        }

        return newImg;
    }
}
</pre>
<p>The above example showed only the FFT function, but virtually all IPP image routines can be accommodated using the wrapper image class above. Intel IPP utilizes many different data types (e.g. Ipp8u, Ipp16s, Ipp32f etc.), but to provide most of the flexibility and compatibility I chose to use only the 32 bit floating data type. For specific implementations, other data types can be used as well.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/04/10/an-image-class-based-on-ipp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Changing SyntaxHighlighter Font Size</title>
		<link>http://www.kerrywong.com/2009/04/05/changing-syntaxhighlighter-font-size/</link>
		<comments>http://www.kerrywong.com/2009/04/05/changing-syntaxhighlighter-font-size/#comments</comments>
		<pubDate>Mon, 06 Apr 2009 00:25:48 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=927</guid>
		<description><![CDATA[After I upgraded to the latest SyntaxHighliger (2.0.296) I noticed that the font size of the code section is a little bit too small to my taste. But there is not an UI option to change it.
So I went to the source code and located the style sheet where the font parameters are set.
To change [...]]]></description>
			<content:encoded><![CDATA[<p>After I upgraded to the <a href="http://alexgorbatchev.com">latest SyntaxHighliger (2.0.296)</a> I noticed that the font size of the code section is a little bit too small to my taste. But there is not an UI option to change it.<span id="more-927"></span></p>
<p>So I went to the source code and located the style sheet where the font parameters are set.</p>
<p>To change the default font-size, you will need to modify the following CSS file: <em>[your WordPress install root path]/wp-content/plugins/syntaxhighlighter/syntaxhighlighter/styles/shCore.css</em>. Locate the following class:</p>
<pre class="brush: css;">
.syntaxhighlighter span

{

	margin: 0 !important;

	padding: 0 !important;

	border: 0 !important;

	outline: 0 !important;

	background: none !important;

	text-align: left !important;

	float: none !important;

	vertical-align: baseline !important;

	position: static !important;

	left: auto !important;

	top: auto !important;

	right: auto !important;

	bottom: auto !important;

	height: auto !important;

	width: auto !important;

	line-height: 1.1em !important;

	font-family: &quot;Consolas&quot;, &quot;Monaco&quot;, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, Courier, monospace !important;

	font-weight: normal !important;

	font-style: normal !important;

	font-size: 1em !important;

}
</pre>
<p>And change the font-size to 1.05em or the size you prefer. Note that this setting is extremely sensitive and typically a 5 percent of increase is enough. Since  prefer the Courier font better, I also swapped it with the default &#8220;Consolas&#8221;. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/04/05/changing-syntaxhighlighter-font-size/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
