<?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 &#187; Miscellaneous</title>
	<atom:link href="http://www.kerrywong.com/category/miscellaneous/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.kerrywong.com</link>
	<description></description>
	<lastBuildDate>Fri, 03 Sep 2010 00:51:09 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Weekend Server Upgrade &#8211; Update</title>
		<link>http://www.kerrywong.com/2010/08/02/weekend-server-upgrade-update/</link>
		<comments>http://www.kerrywong.com/2010/08/02/weekend-server-upgrade-update/#comments</comments>
		<pubDate>Tue, 03 Aug 2010 01:30:36 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Ubuntu 10.04 Server]]></category>
		<category><![CDATA[Ubuntu Server]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=2415</guid>
		<description><![CDATA[Well, there is an old saying:&#8220;There&#8217;s no such thing as a free lunch.&#8221; After yesterday&#8217;s server upgrade, everything worked pretty well till sometime late this afternoon. At first I noticed that the database was down, but when I finally got to the console after work, it appeared that the server had crashed for some reason. [...]]]></description>
			<content:encoded><![CDATA[<p>Well, there is an old saying:<em>&#8220;There&#8217;s no such thing as a free lunch.&#8221;</em> After <a href="http://www.kerrywong.com/2010/08/01/weekend-server-upgrade/">yesterday&#8217;s server upgrade</a>, everything worked pretty well till sometime late this afternoon.<span id="more-2415"></span> </p>
<p>At first I noticed that the database was down, but when I finally got to the console after work, it appeared that the server had crashed for some reason. So naturally, I powered down the server and rebooted. But nothing happened, there was no POST message. At first I thought this was just a temporary glitch of some kind, but after repeated reboot attempts it became apparent that something was seriously wrong. I swapped RAM and CPU and tried a few other tricks but the machine refused to show any sign of life&#8230; I guess that somehow the old hand-me-down server had just bit the dust.</p>
<p>I could have just powered back on my old server but since I had intended to upgrade to Ubuntu 10.04 (my old server was running Ubuntu 8.04) I decided to run my server under VMWare for the time being till I get a chance to upgrade my old server to 10.04 first. </p>
<p>I guess I will have to live with my old Pentium III server for a bit longer. But hey, old as it is, it only consumes 40W of power!</p>
<p><em>Update 8/3/2010</em><br />
I have switched back to my old server. As I mentioned yesterday, I upgraded the server to Ubuntu 10.04. So everything is back to normal, at least for now&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2010/08/02/weekend-server-upgrade-update/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Weekend Server Upgrade</title>
		<link>http://www.kerrywong.com/2010/08/01/weekend-server-upgrade/</link>
		<comments>http://www.kerrywong.com/2010/08/01/weekend-server-upgrade/#comments</comments>
		<pubDate>Sun, 01 Aug 2010 23:47:59 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Linux/BSD]]></category>
		<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Ubuntu 10.04 Server]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=2407</guid>
		<description><![CDATA[I have finally got around to upgrade my web server. The server I have been using was an old Pentium III about 10 years old. It had been serving my website quite well over the years till recently. Due to the small amount of RAM (512MB), that server was no longer able to handle the [...]]]></description>
			<content:encoded><![CDATA[<p>I have finally got around to upgrade my web server. The server I have been using was an old Pentium III about 10 years old. It had been serving my website quite well over the years till recently. <span id="more-2407"></span>Due to the small amount of RAM (512MB), that server was no longer able to handle the ever increasing net traffic and had been crashing with out-of-memory errors quite often.</p>
<p>Luckily, I got a fully equipped hand-me-down Compaq (HP) ProLiant DL360 G2 server and I decided to migrate my website over during the weekend.</p>
<p>Even though this server is a few generations behind, it has dual Pentium III S 1.4 GHz processors, 15,000 RMP SCSI harddrive and 4GB of RAM which is more than plenty to meet my near future needs.</p>
<p>Since my web server was running on Ubuntu Server 8.04, this hardware upgrade also gives me an opportunity to upgrade the OS to the latest version of Ubuntu Server (10.04) which is also an LTS version. </p>
<p>With the new hardware and software, the site should be running rather smoothly for the next couple of years&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2010/08/01/weekend-server-upgrade/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>The Case For Using Parallel Programmer</title>
		<link>http://www.kerrywong.com/2010/06/26/the-case-for-using-parallel-programmer/</link>
		<comments>http://www.kerrywong.com/2010/06/26/the-case-for-using-parallel-programmer/#comments</comments>
		<pubDate>Sat, 26 Jun 2010 17:37:58 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[AVR/Arduino]]></category>
		<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Atmega328P]]></category>
		<category><![CDATA[Parallel Programmer]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=2267</guid>
		<description><![CDATA[This is what I ran into for the first time: I was flashing the chip the other day and after many successful runs I encountered the following infamous avrdude error: &#8230; &#8230; &#8230; avrdude: Device signature = 0×000000 &#8230; &#8230; &#8230; Typically when I ran into this problem it was due to loose cable connection [...]]]></description>
			<content:encoded><![CDATA[<p>This is what I ran into for the first time: I was flashing the chip the other day and after many successful runs I encountered the following infamous avrdude error:<span id="more-2267"></span></p>
<blockquote><p>
&#8230; &#8230; &#8230;<br />
avrdude: Device signature = 0×000000<br />
&#8230; &#8230; &#8230;
</p></blockquote>
<p>Typically when I ran into this problem it was due to loose cable connection and I was able to get past it by reconnecting the ICSP header and try again. But this time, the it seems that no matter how many times I tried the problem remained.</p>
<p>I am pretty sure that chip itself was not damaged as it was sitting in the <a href="http://www.kerrywong.com/2010/04/24/an-arduino-icsp-board/">ICSP board I built</a> all the time and I was able to program it successfully many times minutes before this happened. </p>
<p>Here&#8217;s what I have tried and so far had no success:</p>
<ul>
<li>rebooted system</li>
<li>re-seated the IC
<li>changed -B option to allow more delays</li>
<li>changed -b option to different baud rates</li>
<li>tried to use external clock signal from a working ATmega328p</li>
</ul>
<p>And just to be sure nothing was wrong with either the cable or the board itself, I popped in another ATmega328P and everything worked.  So it seems that even though I did not change any fuse settings, and the only command I used was </p>
<blockquote><p>avrdude -V -F -C avrdude.conf -c duemilanove -p m328p -U flash:w:{hex file})</p></blockquote>
<p>I guess that somehow the fuse settings had changed and thus the chip stopped responding to the clock signal.</p>
<p>So, it&#8217;s time for me to try the high voltage parallel programming method (like <a href="http://mightyohm.com/blog/products/avr-hv-rescue-shield/">this one</a>) to see if my theory was correct. </p>
<p>Following the <a href="http://mightyohm.com/blog/products/avr-hv-rescue-shield/">instructions</a>, I built the shield quickly (not very pretty but serves the purpose nevertheless). The none-standard header spacing was not a big issue as it was easy enough to bend the header pins to achieve the desired spacing (see picture below):</p>
<div id="attachment_2282" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2010/06/shield1.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2010/06/shield1-300x225.jpg" alt="Top view" title="Top view" width="300" height="225" class="size-medium wp-image-2282" /></a><p class="wp-caption-text">Top view</p></div>
<div id="attachment_2283" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2010/06/shield2.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2010/06/shield2-300x221.jpg" alt="Bottom View" title="Bottom View" width="300" height="221" class="size-medium wp-image-2283" /></a><p class="wp-caption-text">Bottom View</p></div>
<p>For the high voltage programming enable 12V supply, I chose to use a simply transistor switch instead of the boost converter:</p>
<div id="attachment_2286" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2010/06/HVEnable.png"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2010/06/HVEnable-300x232.png" alt="12V Supply" title="12V Supply" width="300" height="232" class="size-medium wp-image-2286" /></a><p class="wp-caption-text">12V Supply</p></div>
<p>The drawback of this approach is that the output voltage is not as precise and I had to experiment a little bit to obtain the required HV programming voltage The enable signal comes from the Arduino is around 4.5 V which may not be sufficient to put the transistor in the saturated mode and in my case with a 14 Volt supply, I was able to obtain the required 12 V output. Since the control signal is inverted compared to the original schematic in the article, I had to invert all the digitalWrites to the 12V enable pin to make the program work with my version of the shield.</p>
<p>I used the <a href="http://www.engbedded.com/fusecalc/">AVR Fuse calculator</a> to obtain the default fuse settings for ATmega328p:</p>
<blockquote><p>
LFuse = 0&#215;62<br />
HFuse = 0xD9<br />
EFuse = 0xFF
</p></blockquote>
<p> And it brought the &#8220;bricked&#8221; ATmega328p back to life with the first try! So I guess a parallel mode programmer can come in handy in situations like this. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2010/06/26/the-case-for-using-parallel-programmer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google PAC-MAN</title>
		<link>http://www.kerrywong.com/2010/05/21/google-pac-man/</link>
		<comments>http://www.kerrywong.com/2010/05/21/google-pac-man/#comments</comments>
		<pubDate>Fri, 21 May 2010 15:35:17 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Google]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=2146</guid>
		<description><![CDATA[The Google PAC-MAN logo is actually a live game! I really admire Google&#8217;s creativity and it is actually quite impressive to cramp such a game into just 58K of javascript (http://www.google.com/logos/js/pacman10-hp.2.js) and a small PNG file:]]></description>
			<content:encoded><![CDATA[<p>The Google PAC-MAN logo is actually a live game! <span id="more-2146"></span><br />
<div id="attachment_2147" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2010/05/google_pacman.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2010/05/google_pacman-300x222.jpg" alt="Google PAC-MAN" title="Google PAC-MAN" width="300" height="222" class="size-medium wp-image-2147" /></a><p class="wp-caption-text">Google PAC-MAN</p></div></p>
<p>I really admire Google&#8217;s creativity and it is actually quite impressive to cramp such a game into just 58K of javascript (<a href="http://www.google.com/logos/js/pacman10-hp.2.js">http://www.google.com/logos/js/pacman10-hp.2.js</a>) and a small PNG file:</p>
<div id="attachment_2149" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2010/05/google_pacman_png.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2010/05/google_pacman_png-300x158.jpg" alt="Google PAC-MAN (behind the scene)" title="Google PAC-MAN (behind the scene)" width="300" height="158" class="size-medium wp-image-2149" /></a><p class="wp-caption-text">Google PAC-MAN (behind the scene)</p></div>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2010/05/21/google-pac-man/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A Parallel Port Stepper Motor Driver With Discrete Components</title>
		<link>http://www.kerrywong.com/2010/02/20/a-parallel-port-stepper-motor-driver-with-discrete-components/</link>
		<comments>http://www.kerrywong.com/2010/02/20/a-parallel-port-stepper-motor-driver-with-discrete-components/#comments</comments>
		<pubDate>Sun, 21 Feb 2010 01:31:13 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[MOSFET]]></category>
		<category><![CDATA[Parallel Port]]></category>
		<category><![CDATA[Stepper Motor]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1636</guid>
		<description><![CDATA[Using PC&#8217;s parallel port is a convenient way to control a stepper motor. For unipolar stepper motors, up to two motors can be controlled with the 8bit data line. The standard way of connecting a unipolar stepper motor to the parallel port is to use a Darlington driver such as ULN2003 and there are already [...]]]></description>
			<content:encoded><![CDATA[<p>Using PC&#8217;s <a href="http://en.wikipedia.org/wiki/Parallel_port">parallel port</a> is a convenient way to control a stepper motor. For unipolar stepper motors, up to two motors can be controlled with the 8bit data line.<span id="more-1636"></span></p>
<p>The standard way of connecting a <a href="http://en.wikipedia.org/wiki/Stepper_motor">unipolar stepper motor</a> to the parallel port is to use a <a href="http://en.wikipedia.org/wiki/Darlington_transistor">Darlington</a> driver such as <a href="http://www.st.com/stonline/books/pdf/docs/5279.pdf">ULN2003</a> and there are already <a href="http://www.google.com/#hl=en&#038;q=parallel+port+stepper+motor&#038;aq=f&#038;aqi=g1&#038;oq=&#038;fp=79a46ede2c2a175d">many examples</a> out there on how to do this. In this post, I will show you how to build a simple stepper motor driver using discrete <a href="http://en.wikipedia.org/wiki/MOSFET">MOSFET</a>s.</p>
<p>In the circuit diagram below, you will find that the four power MOSFETs are used as switches for each coil in the stepper motor (the stepper motor I used in this example is a <a href="http://www.mitsumi.co.jp/Catalog/pdf/motor_m35sp_9_e.pdf">MITSUMI M35SP-9</a>. In theory, any uni-polar stepper motors should work with this circuit). A pull-down resistor is attached to the gate of each MOSFET. This is important as otherwise the interference from the port would prevent the MOSFET from switching reliably.<br />
<div id="attachment_1648" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2010/02/controllercircuit.png"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2010/02/controllercircuit-300x145.png" alt="Controller Circuit" title="Controller Circuit" width="300" height="145" class="size-medium wp-image-1648" /></a><p class="wp-caption-text">Controller Circuit</p></div></p>
<p>The benefit of using discrete MOSFET is that they can handle extremely high current loads. Using <a href="http://pdf1.alldatasheet.com/datasheet-pdf/view/96663/IRF/IRFZ22.html">IRFZ22</a>, the coil current can be as high as 10 Amp.<br />
<div id="attachment_1657" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2010/02/steppermotorctrl.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2010/02/steppermotorctrl-300x225.jpg" alt="Stepper Motor Controller" title="Stepper Motor Controller" width="300" height="225" class="size-medium wp-image-1657" /></a><p class="wp-caption-text">Stepper Motor Controller</p></div></p>
<p>The following C code sets the data port (pin 2, 3, 4, 5) to high in order so that the stepper motor would rotate clockwise. If you want the motor to rotate counter-clockwise, simply change the output order to 8,4,2,1.</p>
<pre class="brush: cpp;">
#include &lt;sys/io.h&gt;

#define PAR_PORT 0x378 

void main()
{
	while (1)
	{
		outb(1, PAR_PORT);
		outb(2, PAR_PORT);
		outb(4, PAR_PORT);
		outb(8, PAR_PORT);
	}
}                                            
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2010/02/20/a-parallel-port-stepper-motor-driver-with-discrete-components/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>An Isolated MOSFET Serial Port Relay Controller</title>
		<link>http://www.kerrywong.com/2010/02/04/an-isolated-mosfet-serial-port-relay-controller/</link>
		<comments>http://www.kerrywong.com/2010/02/04/an-isolated-mosfet-serial-port-relay-controller/#comments</comments>
		<pubDate>Fri, 05 Feb 2010 01:48:26 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[MOSFET]]></category>
		<category><![CDATA[RS232]]></category>
		<category><![CDATA[Serial Port]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1618</guid>
		<description><![CDATA[Using DTR (data terminal ready) and RTS (request to send) pins of a PC serial port (RS-232) without actually using the serial data pins, we can interface at least two relay devices with a computer. Windmeadow Labs has an excellent article on how to achieve this using a bipolar transistor (BJT). Here I will show [...]]]></description>
			<content:encoded><![CDATA[<p>Using DTR (data terminal ready) and RTS (request to send) pins of a PC serial port (RS-232) without actually using the serial data pins, we can interface at least two relay devices with a computer.  <a href="http://www.windmeadow.com/node/4">Windmeadow Labs has an excellent article</a> on how to achieve this using a <a href="http://en.wikipedia.org/wiki/Bipolar_junction_transistor">bipolar transistor</a> (BJT). Here I will show you a similar relay control circuit built using an <a href="http://en.wikipedia.org/wiki/Opto-isolator">opto-isolator</a> and a <a href="http://en.wikipedia.org/wiki/MOSFET">MOSFET</a>. <span id="more-1618"></span></p>
<p>Here is the circuit diagram:<br />
<div id="attachment_1624" class="wp-caption aligncenter" style="width: 1023px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2010/02/serialportctrl.png"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2010/02/serialportctrl.png" alt="" title="An Isolated MOSFET Serial Port Relay Controller" width="1013" height="498" class="size-full wp-image-1624" /></a><p class="wp-caption-text">An Isolated MOSFET Serial Port Relay Controller</p></div></p>
<p>The benefit of using an opto-isolator is that the rest of the controller circuit is totally isolated from the serial port and thus prevents the port from accidentally being damaged by wrong wiring or current surge due to a failed component. And by replacing the drive circuitry from using a BJT to a MOSFET, the switching capability is improved dramatically, making switching higher current load more reliable and more efficient.</p>
<p>Here is a picture of the finished board:<br />
<div id="attachment_1632" class="wp-caption aligncenter" style="width: 810px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2010/02/serialportctrlboard.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2010/02/serialportctrlboard.jpg" alt="Circuit Board" title="Circuit Board" width="800" height="600" class="size-full wp-image-1632" /></a><p class="wp-caption-text">Circuit Board</p></div></p>
<p>And here is a simple program that toggles the relay on and off at an interval of 0.5 second. </p>
<pre class="brush: cpp;">
#include &lt;sys/ioctl.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;stdlib.h&gt;

#define _SERIAL_PORT &quot;/dev/ttyS0&quot;

int main(int argc, char **argv)
{
        int fd, status = 0, cmd = 0;

        if ((fd = open(_SERIAL_PORT, O_RDWR | O_NDELAY)) &lt; 0)  exit(1);

        while(1) {
                if (cmd) cmd = 0;  else cmd = TIOCM_DTR;

                ioctl(fd, TIOCMSET, &amp;cmd);
                ioctl(fd, TIOCMGET, &amp;status);

                if (status &amp; TIOCM_DTR) puts(&quot;ON&quot;); else puts(&quot;OFF&quot;);
                usleep(500000l);
        }

        close(fd);
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2010/02/04/an-isolated-mosfet-serial-port-relay-controller/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Building a Degaussing Coil</title>
		<link>http://www.kerrywong.com/2010/01/18/building-a-degaussing-coil/</link>
		<comments>http://www.kerrywong.com/2010/01/18/building-a-degaussing-coil/#comments</comments>
		<pubDate>Tue, 19 Jan 2010 02:27:50 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Electronics]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1605</guid>
		<description><![CDATA[One of my older CRT TVs does not have a built-in degauss button and after sitting in the corner of the basement for a couple of years, it somehow got magnetized pretty badly. The top two-thirds became totally disclorored with the &#8220;rainbow&#8221; effect.Since the TV works excellent otherwise, I decided to fix the screen magnetization [...]]]></description>
			<content:encoded><![CDATA[<p>One of my older CRT TVs does not have a built-in degauss button and after sitting in the corner of the basement for a couple of years, it somehow got magnetized pretty badly. The top two-thirds became totally disclorored with the &#8220;rainbow&#8221; effect.<span id="more-1605"></span>Since the TV works excellent otherwise, I decided to fix the screen magnetization issue with a <a href="http://en.wikipedia.org/wiki/Degaussing">degaussing</a> coil.</p>
<p>The basic operation principal of a degaussing coil is using a strong and gradual fading magnetic field which has an initial magnetic field many times stronger than the magnetization within the tube (typically in the shadow mask or the supporting frame). To produce such a strong magnetic field, we would need a very strong electromagnet. The simplest way is to find a pre-wound spool of <a href="http://en.wikipedia.org/wiki/Magnet_wire">magnetic wire</a> and connect it to an <a href="http://en.wikipedia.org/wiki/Alternating_current">AC</a> source.</p>
<p>I bought a spool of 28 AWG magnetic wire which is roughly 1000ft. The spool has an inner diameter of roughly 1 inch. To increase the inductance of the coil and make it suitable for use with 110V main power, I added a steel rod as the core (the steel rod came from a used printer which was just a tad thinner than 1 inch). Here&#8217;s a picture of the degaussing coil I built:</p>
<div id="attachment_1609" class="wp-caption aligncenter" style="width: 392px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2010/01/degaussingcoil.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2010/01/degaussingcoil.jpg" alt="Degaussing Coil" title="Degaussing Coil" width="382" height="237" class="size-full wp-image-1609" /></a><p class="wp-caption-text">Degaussing Coil</p></div>
<p>To test the coil, you will have to be careful about the maximum current the magnetic wire coil can carry. Excessive current can cause the coil to melt and possibly burn! If you are unsure about the inductance of the coil, you probably want to use an <a href="http://en.wikipedia.org/wiki/Autotransformer">autotransformer (Variac)</a> and a AC current meter to determine what is the optimal operation voltage for your coil. Or, if you don&#8217;t have such tools, you will at least want to add a 100W light bulb between the coil and the power to limit the maximum current. If the light is dim when you power on the coil, then it indicates that your coil has sufficient inductance to operate using 110V AC power. If the light is very bright, you will have to adjust your design (i.e., adding a core with higher permissibility or add more turns to the winding).</p>
<p>If your construct is the same as mine, then the coil can operate at 110V AC with no overheating issue (current is at roughly 0.35 A when connected).</p>
<div id="attachment_1612" class="wp-caption aligncenter" style="width: 351px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2010/01/degaussingcircuit.png"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2010/01/degaussingcircuit.png" alt="Degaussing Circuit" title="Degaussing Circuit" width="341" height="182" class="size-full wp-image-1612" /></a><p class="wp-caption-text">Degaussing Circuit</p></div>
<p>When degaussing, connect the power and move the coil slowly away from the TV screen to a few feet away in a gradual and circular motion. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2010/01/18/building-a-degaussing-coil/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>The Simplest MOSFET On/Off Switch</title>
		<link>http://www.kerrywong.com/2010/01/06/the-simplest-mosfet-onoff-switch/</link>
		<comments>http://www.kerrywong.com/2010/01/06/the-simplest-mosfet-onoff-switch/#comments</comments>
		<pubDate>Wed, 06 Jan 2010 23:46:10 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[MOSFET]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1597</guid>
		<description><![CDATA[A touch sensitive on/off switch can be made with a single MOSFET. The following schematics illustrate such a switch using only a power MOSFET (IRFZ22). In this example, the switching capability is achieved by the dielectric nature of MOSFET&#8217;s gate. Since the gate is insulated from other device regions, the leakage current is relatively small [...]]]></description>
			<content:encoded><![CDATA[<p>A touch sensitive on/off switch can be made with a single <a href="http://en.wikipedia.org/wiki/MOSFET">MOSFET</a>. The following schematics illustrate such a switch using only a power MOSFET (<a href="http://www.alldatasheet.com/datasheet-pdf/pdf/96663/IRF/IRFZ22.html">IRFZ22</a>).<span id="more-1597"></span></p>
<div id="attachment_1598" class="wp-caption aligncenter" style="width: 507px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2010/01/mosfetswitch.gif"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2010/01/mosfetswitch.gif" alt="Simplest Switch using MOSFET" title="Simplest Switch using MOSFET" width="497" height="319" class="size-full wp-image-1598" /></a><p class="wp-caption-text">Simplest Switch using MOSFET</p></div>
<p>In this example, the switching capability is achieved by the dielectric nature of MOSFET&#8217;s gate. Since the gate is insulated from other device regions, the leakage current is relatively small and thus the capacitor can hold its charge for a relatively long period of time.</p>
<p>When the gate and the positive lead are touched, the relatively small gate capacitor is rapidly charged (dry skin has a resistance of several mega-ohm) and the switch turns on. And when the gate and the ground are touched the gate capacitor quickly discharges and the switch turns off.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2010/01/06/the-simplest-mosfet-onoff-switch/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>My First Few Days With Chrome for Linux Beta</title>
		<link>http://www.kerrywong.com/2009/12/13/my-first-few-days-with-chrome-for-linux-beta/</link>
		<comments>http://www.kerrywong.com/2009/12/13/my-first-few-days-with-chrome-for-linux-beta/#comments</comments>
		<pubDate>Mon, 14 Dec 2009 02:02:50 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1584</guid>
		<description><![CDATA[When Google Chrome beta for Windows was first released last September, I tested it briefly on a Windows XP box and was quite impressed by its speed and simplistic user interface. But it would have been too early to tell how the future lies for Google&#8217;s budding browser platform without first seeing it running on [...]]]></description>
			<content:encoded><![CDATA[<p>When <a href="http://www.google.com/chrome/">Google Chrome</a> beta for Windows was first released last September, I tested it briefly on a Windows XP box and was quite impressed by its speed and simplistic user interface.<span id="more-1584"></span></p>
<p>But it would have been too early to tell how the future lies for Google&#8217;s budding browser platform without first seeing it running on other platforms, particularly on Linux. Although the market share for Linux has been a distant third comparing to Windows and Mac OS (depending on how the market share is calculated the figure goes anywhere between less than 1% to a few percentages), it is a sign of serious commitment when we see the support for Linux finally comes. To be honest, the developer build Chrome for Linux had been around for a while now, but the release of Beta last week was the first official release from Google.</p>
<p>Before I started using it, I wasn&#8217;t keeping my hopes very high. I was prepared to experience some glitches as after all it is still in its early Beta stage and comparing to Firefox, Chrome is only in its infant stage. But the result is much beyond my expectations.</p>
<p>The installation process was pretty much flawless. Google provides both Debian and RPM packages (Chrome 4.0.249.30) and installing on 64bit Ubuntu (9.10) was as simple as any other Ubuntu packages. And upon starting for the first time, it offered to import my favorites from my current Firefox installations. Unfortunately, I had my Firefox sessions open at the time, and it was unable to import the settings. But it was easy enough to manually import all my favorites ones I started using it.</p>
<p>My first impression is that the user interface is very pleasant. It is clean, minimal and almost barren. Like the simple design of its homepage, Google wanted to emphasize on the content and rather the shell. This clean design is also a necessity given Google&#8217;s intension of a Chrome based web-centric OS. Serving as the desktop surface, every square inch of client usable screen real estate counts. This philosophy virtually dictated every aspect of the Chrome browser. When maximized, borders are gone. The top border was shrunk down further&#8211;an other nice touch&#8211;as users do not need to move the window when the browser is maximized. Even the status area is not permanently utilized. It only appears when there is message to display.<br />
All of these efforts add up to give users the maximum screen space.</p>
<p>Another well thought behavior was the slight delay when closing tabs. When you have dozens of open tabs, the tab sizes were adjusted dynamically to accommodate the limited screen width. If you try to close these tabs one by one, it would be annoying if you had to constantly adjust your mouse to find the &#8220;close&#8221; icon of the tab. Google realized this, and designed Chrome such that as long as mouse remains in the tabbing area, the tab sizes do not change. So that closing multiple consecutive windows is a simple matter of multiple mouse clicks, without the need to move or adjust. The tab sizes are only adjusted after a brief delay when the mouse moves out of the &#8220;tabbing&#8221; area (see screen shot below).</p>
<div id="attachment_1589" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/12/chrome_closingtabs.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/12/chrome_closingtabs-300x29.jpg" alt="Tab closing behavior" title="Tab closing behavior" width="300" height="29" class="size-medium wp-image-1589" /></a><p class="wp-caption-text">Tab closing behavior</p></div>
<p>Chrome is also a full-fledged web development environment. It has many handy tools (developer->developer tools menu) you would need to inspect/debug your web pages. It even provides a task manager, listing the resources each web page utilizes. Presumably, being an OS rather than a simple browser means that it has to have a task manager of some sort.</p>
<p>Needless to say, page loading in Chrome is generally noticeably faster than that in Firefox. Fast page loading is extremely important for concurrently loading multiple pages (for example, opening a folder of favorites). If a browser is slow, many pages will time out due to the limited rendering capability of the browser. When I loaded a set of a couple dozen or so sites in both Firefox and Chrome, only a couple of sites failed to load properly in Chrome, where as in Firefox as many as ten sites were timed out.</p>
<p>Sites with Flash also worked flawlessly. While this has less to do with Google than Adobe, supporting Flash out-of-box is certainly a nice thought as users generally assume that a web site should just work, regardless of what plug-in is required.</p>
<p>And of course, Chrome is standard compliant. It passes even the most stringent ACID3 browser test. The only gripe I had was the lack of a bookmark menu icon when bookmark bar is not used. In this case, you will have to open the bookmark manager in order to retrieve bookmarked items.</p>
<p>Remember though, this is only a beta browser and it&#8217;s not near its completion by any means. I am sure there would be more pleasant surprises down the pipeline. </p>
<p>Whether or not the Chrome OS lives up to its hype, Chrome as a browser is certainly a serious and credible challenge to Microsoft Internet Explorer and it is here to stay. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/12/13/my-first-few-days-with-chrome-for-linux-beta/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A Hall Effect Magnetic Field Polarity Detector</title>
		<link>http://www.kerrywong.com/2009/12/05/a-hall-effect-magnetic-field-polarity-detector/</link>
		<comments>http://www.kerrywong.com/2009/12/05/a-hall-effect-magnetic-field-polarity-detector/#comments</comments>
		<pubDate>Sun, 06 Dec 2009 00:42:00 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Brushless Motor]]></category>
		<category><![CDATA[Hall Effect]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1563</guid>
		<description><![CDATA[Hall effect sensors can be found in many common household gadgets. Most brushless DC motors for instance, like those used in computer cooling fans, contain Hall effect sensors in the driving circuits. I recently replaced one of the cooling fans in my computer and decided to do some experiments with the Hall effect sensor in [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://en.wikipedia.org/wiki/Hall_effect">Hall effect</a> sensors can be found in many common household gadgets. Most <a href="(http://en.wikipedia.org/wiki/Brushless_DC_electric_motor">brushless DC motors</a> for instance, like those used in computer cooling fans, contain Hall effect sensors in the driving circuits.<span id="more-1563"></span> I recently replaced one of the cooling fans in my computer and decided to do some experiments with the Hall effect sensor in that old fan.</p>
<p>After removing the fan rotor you can see the stator and the control circuits. This particular fan is driven by a single chip ATS 277<a href="http://www.datasheetcatalog.org/datasheet2/a/0awqfy74tj776gp8g4esy438whwy.pdf">(the data sheet can be found here)</a>, which is a complementary output Hall effect latch. It turns on and off the alternate side of the poles depending on the rotor&#8217;s position. </p>
<div id="attachment_1565" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/12/stator.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/12/stator-300x228.jpg" alt="The stator of a cooling fan" title="The stator of a cooling fan" width="300" height="228" class="size-medium wp-image-1565" /></a><p class="wp-caption-text">The stator of a cooling fan</p></div>
<p>So, using this Hall effect latch IC, we can build a simply electronic circuit that can be used to detect the polarity of a magnet (the magnetic field has to be strong enough to trigger the sensor due to its limited sensitivity).  </p>
<p>Here is the schematics I used to build such a detector:</p>
<div id="attachment_1568" class="wp-caption aligncenter" style="width: 291px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/12/PolarityDetector.gif"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/12/PolarityDetector-281x300.gif" alt="Magnetic Polarity Detector Schematic" title="Magnetic Polarity Detector Schematic" width="281" height="300" class="size-medium wp-image-1568" /></a><p class="wp-caption-text">Magnetic Polarity Detector Schematic</p></div>
<p>and here is a picture of the detector after it was built.</p>
<div id="attachment_1571" class="wp-caption aligncenter" style="width: 289px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/12/detector.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/12/detector-279x300.jpg" alt="The assembled detector" title="The assembled detector" width="279" height="300" class="size-medium wp-image-1571" /></a><p class="wp-caption-text">The assembled detector</p></div>
<p>When the circuit is powered on, one of the two output will be latched at low and thus the LED connected to that pin will light up: </p>
<div id="attachment_1572" class="wp-caption aligncenter" style="width: 255px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/12/led1on.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/12/led1on-245x300.jpg" alt="Activated with one side of the magnet" title="Activated with one side of the magnet" width="245" height="300" class="size-medium wp-image-1572" /></a><p class="wp-caption-text">Activated with one side of the magnet</p></div>
<p>If the Hall sensor detects a strong enough magnetic field, the original pin with the low output will turn high and the other pin will turn low. Thus the blue LED will be off and the red LED will be turned on (see the picture below, note that the red LED is illuminated albeit it is a little dark compared to the blue one).<br />
<div id="attachment_1573" class="wp-caption aligncenter" style="width: 281px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/12/led2on.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/12/led2on-271x300.jpg" alt="Activated with the other side of the magnet" title="Activated with the other side of the magnet" width="271" height="300" class="size-medium wp-image-1573" /></a><p class="wp-caption-text">Activated with the other side of the magnet</p></div></p>
<p>By alternating the polarity of the magnetic field (e.g. use the opposite side of the magnet), the LEDs will alternate between blue and red, depending on the polarity used.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/12/05/a-hall-effect-magnetic-field-polarity-detector/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A Simple Program for Finding Palindromic Prime Numbers</title>
		<link>http://www.kerrywong.com/2009/11/15/a-simple-program-for-finding-palindromic-prime-numbers/</link>
		<comments>http://www.kerrywong.com/2009/11/15/a-simple-program-for-finding-palindromic-prime-numbers/#comments</comments>
		<pubDate>Mon, 16 Nov 2009 01:49:08 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Palindromic Prime Number]]></category>
		<category><![CDATA[Palprime]]></category>
		<category><![CDATA[Prime Number]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1527</guid>
		<description><![CDATA[A palindromic prime (palprime) is a prime number that is also palindromic. So out of curiosity I wrote a simple program a few days ago that can find the palindromic numbers within a given range. Here is the code in C++: #include &#60;stdio.h&#62; #include &#60;stdlib.h&#62; #include &#60;limits.h&#62; #include &#60;math.h&#62; #include &#60;iostream&#62; using namespace std; bool [...]]]></description>
			<content:encoded><![CDATA[<p>A <a href="http://mathworld.wolfram.com/PalindromicPrime.html">palindromic prime</a> (palprime) is a prime number that is also palindromic. So out of curiosity I wrote a simple program a few days ago that can find the palindromic numbers within a given range. Here is the code in C++:<span id="more-1527"></span></p>
<pre class="brush: cpp;">
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;limits.h&gt;
#include &lt;math.h&gt;
#include &lt;iostream&gt;

using namespace std;

bool IsPrime(unsigned long long n) {
	bool r = true;

	for (unsigned long long i = 3; i &lt; sqrt((double) n) + 1; i+= 2)
	{
		if (n % i ==0) {
			r = false;
			break;
		}
	}

	return r;
}

bool IsPalindrome(unsigned long long n) {
	bool r = true;
	char s[30];
	int l = sprintf(s, &quot;%llu&quot;, n);

	if (l == 1 &amp;&amp; n != 1) {
		r = true;
	} else	{
		for (int i = 0; i &lt; l/2; i++) {
			if (s[i] != s[l-i-1]) {
				r = false;
				break;
			}
		}
	}

	return r;
}

/*
 * usage: palprime [lbound] [ubound]
 */
int main(int argc, char** argv) {
	unsigned long long beginNum = 3;
	unsigned long long endNum = 3;

	if (argc == 2) { // lbound default to 3
#ifdef _WIN32
		endNum = _strtoui64(argv[1], NULL, 10);
#else
		endNum = strtoull(argv[1], NULL, 10);
#endif

	} else if (argc == 3) {
#ifdef _WIN32
		beginNum = _strtoui64(argv[1], NULL, 10);
		endNum = _strtoui64(argv[2], NULL, 10);
#else
		beginNum = strtoull(argv[1], NULL, 10);
		endNum = strtoull(argv[2], NULL, 10);
#endif
	}

        unsigned long long i = beginNum;

        while (i &lt; endNum) {
                char s[30];
                int l = sprintf(s, &quot;%llu&quot;, i);

		//length cannot be even as even length palindrome numbers
		//can be divided by 11.
                if (l % 2 == 0) {
                    i = ((unsigned long long) (i / 10)) * 100 + 1;
                    continue;
                }

		if (IsPalindrome(i)) {
			if (IsPrime(i)) {
				cout &lt;&lt; i &lt;&lt; endl;
			}
		}

                i+=2;

                if (s[0] % 2 == 0) {
                    i+=pow(10, l-1);

		    //leading/ending number cannot be 5
                    if (((int) (s[0] - '0')) + 1 == 5) {
                        i += 2 * pow(10, l-1);
                    }
                }
	}
	return (EXIT_SUCCESS);
}
</pre>
<p>At first, I was trying to find all the palprimes that can be represented by 64 bit integers. But soon I realized that it would take months to do so using the code above with a quad-core PC (using 4 processes with different ranges). Anyway, here&#8217;s the last few palindromic primes less than 10,000,000,000,000:</p>
<blockquote><p>
9999899989999<br />
9999901099999<br />
9999907099999<br />
9999913199999<br />
9999919199999<br />
9999938399999<br />
9999961699999<br />
9999970799999<br />
9999980899999<br />
9999987899999
</p></blockquote>
<p>And here are a few interesting ones:</p>
<blockquote><p>
11357975311<br />
1112345432111<br />
1300000000031<br />
1700000000071<br />
1900000000091<br />
7900000000097<br />
9200000000029<br />
1357900097531
</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/11/15/a-simple-program-for-finding-palindromic-prime-numbers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CFL Capacitor Problem</title>
		<link>http://www.kerrywong.com/2009/11/08/cfl-capacitor-problem/</link>
		<comments>http://www.kerrywong.com/2009/11/08/cfl-capacitor-problem/#comments</comments>
		<pubDate>Mon, 09 Nov 2009 02:03:01 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Compact Fluorescent Lamp]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1511</guid>
		<description><![CDATA[Many of you may still remember the capacitor plague that caused massive motherboard failures back in the early 2000s. While the practice of using cheap and unreliable electrolytic capacitors in computer components has largely died down nowadays, it seems that the issue has cropped up elsewhere. This time, the issue is with cheap capacitors used [...]]]></description>
			<content:encoded><![CDATA[<p>Many of you may still remember the <a href="http://en.wikipedia.org/wiki/Capacitor_plague">capacitor plague</a> that caused massive motherboard failures back in the early 2000s. While the practice of using cheap and unreliable <a href="http://en.wikipedia.org/wiki/Electrolytic_capacitor">electrolytic capacitors</a> in computer components has largely died down nowadays, it seems that the issue has cropped up elsewhere. <span id="more-1511"></span></p>
<p>This time,  the issue is with cheap capacitors used in some compact fluorescent light (CFL) bulbs. The following photo is taken from the electronic ballast of a CFL that failed during the first year of its use:<br />
<div id="attachment_1516" class="wp-caption aligncenter" style="width: 330px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/11/badcap.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/11/badcap.jpg" alt="Bad Capacitor in CFL electronic ballast" title="Bad Capacitor in CFL electronic ballast" width="320" height="398" class="size-full wp-image-1516" /></a><p class="wp-caption-text">Bad Capacitor in CFL electronic ballast</p></div></p>
<p>As you can see that the bulging top clearly shows signs of leakage. The capacitor used in this particular CFL is rated 22uf/200V with a maximum operating temperature of 105 degree (Celsius). Under normal conditions, this capacitor should be fine. But with a lot of interior light fixtures that are recessed into the ceiling, the heat generated during normal operation can easily approach this limit and causes the CFL to fail prematurely. Many failed CFLs I had over the past few years exhibited similar capacitor problems. And apparently, the general quality issue of CFLs <a href="http://www.nytimes.com/2009/03/28/business/energy-environment/28bulbs.html">has been concerning</a>.</p>
<p>It seems to me though that the easiest way to fix this issue is for manufacturers to use electrolytic capacitors with higher operating temperature rating and lower <a href="http://en.wikipedia.org/wiki/Equivalent_series_resistance">ESR</a>. Since the majority of CFL electronic ballasts utilize only one electrolytic capacitor, the increase in cost should be minimum.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/11/08/cfl-capacitor-problem/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>An Alternative Illustration of Prime Number Distribution</title>
		<link>http://www.kerrywong.com/2009/09/06/an-alternative-illustration-of-prime-number-distribution/</link>
		<comments>http://www.kerrywong.com/2009/09/06/an-alternative-illustration-of-prime-number-distribution/#comments</comments>
		<pubDate>Sun, 06 Sep 2009 14:40:04 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Distribution]]></category>
		<category><![CDATA[Histogram]]></category>
		<category><![CDATA[Prime Number]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1441</guid>
		<description><![CDATA[Prime number theorem dictates the asymptotic behavior of prime number distributions. In layman terms, the distance between prime numbers increases at a logarithmic pace. This gives the familiar logarithm figure. Alternatively, if we “bin” the prime numbers according to the differences (gaps) between two consecutive prime numbers, we would yield another logarithmic distribution: the histogram [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://en.wikipedia.org/wiki/Prime_number_theorem">Prime number theorem</a> dictates the asymptotic behavior of prime number distributions. In layman terms, the distance between prime numbers increases at a logarithmic pace. This gives the familiar logarithm figure.<span id="more-1441"></span></p>
<p>Alternatively, if we “bin” the prime numbers according to the differences (gaps) between two consecutive prime numbers, we would yield another logarithmic distribution: the histogram of such differences will be logarithmic as well.</p>
<p>So, take the following sequence of prime numbers for example:</p>
<blockquote><p>2, 3, 5, 7, 11, 13, 17, 19, 23, 29&#8230;</p></blockquote>
<p>The distances between the consecutive numbers in the above sequence are:</p>
<blockquote><p>
3-2 = 1<br />
5-3 = 2<br />
7-5 = 2<br />
11-7 = 4<br />
19-17 = 2<br />
23-19 = 4<br />
29-23 = 6
</p></blockquote>
<p>We then calculate the histogram based on the gaps. </p>
<p>Denote the histogram bin index as<br />
\[i = \lfloor\frac{d}{2}\rfloor\]</p>
<p>For the example above, we get the following distributions for H[i]:<br />
\[H[0] = 1, H[1] = 3 H[2]=2, H[3]=1\]</p>
<p>Now we calculate the distribution (H[i]) described above using prime numbers within the following interval (for all prime numbers up to 4,294,967,291):<br />
\[[2^0, 2^{32}]\]</p>
<p>We can obtain the following plot for the histogram (H[i]):<br />
<div id="attachment_1474" class="wp-caption aligncenter" style="width: 610px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/09/hist.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/09/hist.jpg" alt="Prime number distribution" title="Prime number distribution" width="600" height="450" class="size-full wp-image-1474" /></a><p class="wp-caption-text">Prime number distribution</p></div></p>
<p>To illustrate that the distribution is indeed around a logarithm curve, we take the logrithms of the values for each H[i] and get the following figure:</p>
<div id="attachment_1475" class="wp-caption aligncenter" style="width: 610px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/09/hist_log.jpg"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/09/hist_log.jpg" alt="Prime number distribution" title="Prime number distribution" width="600" height="450" class="size-full wp-image-1475" /></a><p class="wp-caption-text">Prime number distribution</p></div>
<p>As you can see, the distribution is around a straight line.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/09/06/an-alternative-illustration-of-prime-number-distribution/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Why Current EVs Do Not Make Sense From Economical And Environmental View Points</title>
		<link>http://www.kerrywong.com/2009/08/15/why-current-evs-do-not-make-sense-from-economical-and-environmental-view-points/</link>
		<comments>http://www.kerrywong.com/2009/08/15/why-current-evs-do-not-make-sense-from-economical-and-environmental-view-points/#comments</comments>
		<pubDate>Sat, 15 Aug 2009 23:32:49 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Electric Vehicle]]></category>
		<category><![CDATA[Hybrid Car]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1432</guid>
		<description><![CDATA[About two years ago, I blogged about why hybrids were not saving us any energy by taking into consideration the amount of energy needed to produce the vast battery packs and the inherent low efficiencies in battery technologies. Now, two years later after crude oil price peeked and then stabilized amidst the economic turmoil, the [...]]]></description>
			<content:encoded><![CDATA[<p>About two years ago, I blogged about <a href="/2007/04/30/do-hybrid-cars-really-save-energy/">why hybrids were not saving us any energy</a> by taking into consideration the amount of energy needed to produce the vast battery packs and the inherent low efficiencies in battery technologies.<span id="more-1432"></span></p>
<p>Now, two years later after crude oil price peeked and then stabilized amidst the economic turmoil, the main reason for companies from Toyota and GM alike to push for new electric and hybrid vehicles seems to me is to show case their technological capabilities and ride along the buzz generated many years ago when the first generation Prius first hit the road. Using the technologies available to us today and in the immediate future, the advantage in terms of environmental impacts of these alternative vehicles such as the hybrid and electric cars remains unclear. And at their current state, it is doubtful that these alternative drivetrains make any economical sense.</p>
<p>Take electric cars for example. From an environmental point of view, while electrical vehicles by themselves do not generate any greenhouse emissions like their gasoline and diesel counterparts, the manufacturing process of the batteries that go into these EVs are likely to have a high environmental impact. The extraction of precious metals and the creation of some of the chemical compounds that used in these high energy density battery packs are likely to consume more energy than the well established process for engine manufacturing. And much of that energy is coming from electrical power plants that use fossil fuel for electricity generation. The “cleaner” nature of EVs is merely because of the redistribution of pollution over different stages of their life cycles and over different geographic areas.</p>
<p>From an economical stand point, today’s manufacturing processes to produce batteries used in the electrical vehicles remain very expensive and the cost of which constitutes a significant portion of the overall cost of the vehicle. And because batteries must be plugged into the grid for charging, it relies on the cost of electricity in order to make economical sense. It seems funny to me that at a time when people prefer natural gas based heating system and shy away from electrical baseboards due to cost considerations, it would somehow be cheaper to charge the EVs off the grid on a daily basis. We know that the power requirement for the electrical vehicles dwarfs some of the most power hungry household electrical systems. Until we are further removed from fossil fuels in our electricity generation process, the cost saving of using EVs is hardly justified. We are having the illusion of savings due to government subsidy and the lower day-to-day operating expenses. The initial investment buying an EV, however, is likely to be much bigger than that of a traditional gasoline counterpart.</p>
<p>Reliability remains a big concern for EVs and hybrids, particularly for EVs. As I discussed <a href="/2007/04/30/do-hybrid-cars-really-save-energy/">before</a>, given the complexity of the hybrid powertrains and the inherent reliability issues of the battery banks, it remains unknown how the long-term reliability (e.g. over a time span of 20 years) of these EVs compare against that of the more traditional vehicles. So even though electric motors are generally much more reliable than gasoline engines, the current state of battery technology significantly limits the overall reliability of these battery powered vehicles.</p>
<p>Another not-so-obvious problem of EVs is related to the power-hungry auxiliary systems (e.g. Heater, air conditioner, audio amplifier, etc). Using these systems will significantly shorten the advertised range and EVs may have to rely on an alternative power-generating unit (e.g. a regular gas powered motor) to generate the additional power needed while using these auxiliary systems. </p>
<p>To improve EV performance, companies have invested heavily and concentrated on reducing the overall weight of the vehicles by using lighter materials such as carbon fibers for the body frames. If we were to adopt a similar approach in today’s gasoline car manufacturing process and reduce the weight of the vehicles, we would significantly reduce the power requirement and thus be able to reduce the engine sizes and ultimately reduce emissions as well.</p>
<p>So, the long term viability of the current electrical vehicles remains to be seen.</p>
<h3>References:</h3>
<ul>
<li>
<a href="http://money.cnn.com/2009/08/11/autos/volt_mpg/index.htm?postversion=2009081108">Chevy volt to get 230 mpg rating</a>
</li>
<li>
<a href="http://tech.slashdot.org/comments.pl?sid=1332901">Slashdot comments</a> on Chevy Volt Rated At 230 mpg In the City
</li>
<li>
<a href="http://www.evworld.com/article.cfm?storyid=1361">Electric Vehicles and the Environment</a>
</li>
<li>
<a href="http://www.typesofenergy.co.uk/electric-vehicles-environment.html">http://www.typesofenergy.co.uk/electric-vehicles-environment.html</a>
</li>
<li>
<a href="http://agmetalminer.com/2009/08/12/a-different-take-on-the-gm-volt-announcement/">A Different Take on the GM Volt Announcement</a>
</li>
<li>
<a href="http://clipmarks.forbes.com/2009/08/11/chevy-volt-part-ii-mileage-but-at-what-cost/">Chevy Volt (part II): 230 MPG, but at what cost?</a>
</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/08/15/why-current-evs-do-not-make-sense-from-economical-and-environmental-view-points/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Strange Windows Authentication Behavior</title>
		<link>http://www.kerrywong.com/2009/07/30/strange-windows-authentication-behavior/</link>
		<comments>http://www.kerrywong.com/2009/07/30/strange-windows-authentication-behavior/#comments</comments>
		<pubDate>Thu, 30 Jul 2009 12:13:59 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[SQL Server]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1429</guid>
		<description><![CDATA[I was writing an ASP.Net 2.0 web application using Windows authentication (since I needed to capture users’ credentials). The web application saves data into a MS SQL 2005 database using a SQL server account. While developing this application, I ran into a very strange issue. Since the database access is using a SQL Server account [...]]]></description>
			<content:encoded><![CDATA[<p>I was writing an ASP.Net 2.0 web application using Windows authentication (since I needed to capture users’ credentials). The web application saves data into a MS SQL 2005 database using a SQL server account. While developing this application, I ran into a very strange issue.<span id="more-1429"></span></p>
<p>Since the database access is using a SQL Server account rather than integrated authentication, in theory the database access code should not be affected by whether I use Forms authentication or Windows authentication in the web application. </p>
<p>However, the problem I ran into was that if I use Forms authentication mode, everything works fine. But if I switch the authentication mode to Windows, I would get the following error message emitted from the data access layer after the application was deployed to the server:</p>
<blockquote><p>A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 &#8211; Could not open a connection to SQL Server) </p></blockquote>
<p>What is weirder is that if I tried to use the application locally on the web server after deployment, everything would work fine. And after &#8220;touching&#8221; the deployed website on the server, the web pages can then be remotely accessed via client browser for a while (10 minutes maybe) but after that the same error would occur again.</p>
<p>So I searched many forums but could not find any conclusive explanations or remedies.</p>
<h3>The Not So Satisfying Solution</h3>
<p>One of my coworkers took a look at my code and confirmed that there were no coding errors but noticed that I did not have port information in the connection string (Note, even though we use non-standard ports, this has never been necessary). So as he suggested, I plugged in the port number and it worked!</p>
<p>Clearly, I am still as confused as before. The authentication modes differences must have somehow affected the way the connection string is interpreted&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/07/30/strange-windows-authentication-behavior/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Monodevelop on Ubuntu 9.04</title>
		<link>http://www.kerrywong.com/2009/07/22/monodevelop-on-ubuntu-9-04/</link>
		<comments>http://www.kerrywong.com/2009/07/22/monodevelop-on-ubuntu-9-04/#comments</comments>
		<pubDate>Wed, 22 Jul 2009 04:00:04 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Linux/BSD]]></category>
		<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[C Sharp (C#)]]></category>
		<category><![CDATA[Mono]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1408</guid>
		<description><![CDATA[I am running Ubuntu 9.04 64bit. One thing I noticed is that the integrated debugger is behaving quite flaky for the included Monodevelop 2.0 package. After some research, it turned out that a lot of people are having similar issues. So I followed the instructions given in these two blogs: Install Mono 2.4 on Ubuntu, [...]]]></description>
			<content:encoded><![CDATA[<p>I am running Ubuntu 9.04 64bit. One thing I noticed is that the integrated debugger is behaving quite flaky for the included <a href="http://monodevelop.com/">Monodevelop 2.0</a> package. After some research, it turned out that a lot of people are having similar issues.<span id="more-1408"></span></p>
<p>So I followed the instructions given in these two blogs: <a href="http://blog.ruski.co.za/page/Install-Mono-on-Ubuntu.aspx">Install Mono 2.4 on Ubuntu</a>,<br />
<a href="http://synpl.blogspot.com/2009/07/building-mono-and-monodevelop-from.html">Building Mono and MonoDevelop from source on Ubuntu 9.04 64bit</a> to re-install Monodevelop 2.0 and its dependencies from the source. </p>
<p>One thing you will need to pay special attention to is that for the monodevelop-debugger-mdb-2.0 to compile successfully, you will need mono-debugger version 2.4, instead of the latest version 2.4.1. Otherwise you will receive an error on <em>Thread.AbortInvocation</em> as there is a breaking change in mono-debugger 2.4.1 which added a parameter to the method (see <a href="http://lists.ximian.com/pipermail/mono-patches/2009-May/149225.html">mono debugger 2.4.1 change log</a>).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/07/22/monodevelop-on-ubuntu-9-04/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google Finance Down Earlier Today</title>
		<link>http://www.kerrywong.com/2009/07/06/google-finance-down-earlier-today/</link>
		<comments>http://www.kerrywong.com/2009/07/06/google-finance-down-earlier-today/#comments</comments>
		<pubDate>Tue, 07 Jul 2009 01:43:56 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Cloud Computing]]></category>

		<guid isPermaLink="false">http://www.kerrywong.com/?p=1368</guid>
		<description><![CDATA[It appeared that Google Finance was down for at least half an hour (from before 9:30 EST till after 10:00 EST) today. I captured this screen-shot during the outage: This is just the latest one of a string of high-profile outages from large corporations like Google (here&#8217;s an other outage less than two months ago) [...]]]></description>
			<content:encoded><![CDATA[<p>It appeared that Google Finance was down for at least half an hour (from before 9:30 EST till after 10:00 EST) today. I captured this screen-shot during the outage:<span id="more-1368"></span></p>
<div id="attachment_1369" class="wp-caption aligncenter" style="width: 686px"><a href="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/googlefinanceerror1.gif"><img src="http://www.kerrywong.com/blog/wp-content/uploads/2009/07/googlefinanceerror1.gif" alt="Google Finance Error" title="Google Finance Error" width="676" height="445" class="size-full wp-image-1369" /></a><p class="wp-caption-text">Google Finance Error</p></div>
<p>This is just the latest one of a string of high-profile outages from large corporations like Google (<a href="http://news.cnet.com/widespread-google-outages-rattle-users/">here&#8217;s an other outage less than two months ago</a>) and Microsoft (<a href="http://news.cnet.com/8301-1023_3-10279084-93.html">this outage</a> was on July 3, due to fire at a data center in Seattle).</p>
<p>It certainly does not bode well for those who tout <a href="http://en.wikipedia.org/wiki/Cloud_computing">cloud computing</a>. While in theory, larger cloud service providers like Google and Microsoft have the resources and capabilities to make their cloud services much more reliable. In practice, it doesn&#8217;t help when the services are down at the most unfortunate time when you need them the most.</p>
<p>I could see some benefits of using cloud computing in some non-essential business scenarios, but I doubt that any business would shift its core applications into the cloud. The reason is quite simple: For the bread-and-butter business applications, we need to know with confidence when the system will be down. When you host your own application, even if you don&#8217;t have control over everything (e.g. hardware failure) you at least can control when you implement changes. So while your applications might not be up 99% of the time, you could carefully plan the outage windows for the necessary maintenances to minimize any side effects to the normal business operations. </p>
<p>Of course, there are many other reasons why companies should not en-thrust their core businesses to the cloud. Some of the reasons are physical (e.g. a web service call will always be magnitudes slower than a in-process function call. And Internet speed will always be slower than intranet and significantly slower than memory speed), and some are philosophical. Like <a href="http://en.wikipedia.org/wiki/Richard_Stallman">Richard Stallman</a> once <a href="http://www.guardian.co.uk/technology/2008/sep/29/cloud.computing.richard.stallman">put it</a>:</p>
<blockquote><p>&#8220;One reason you should not use web applications to do your computing is that you lose control. It&#8217;s just as bad as using a proprietary program. Do your own computing on your own computer with your copy of a freedom-respecting program. If you use a proprietary program or somebody else&#8217;s web server, you&#8217;re defenseless. You&#8217;re putty in the hands of whoever developed that software.&#8221;</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/07/06/google-finance-down-earlier-today/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<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 [...]]]></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&#8242;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>
<h3>Update (7/12/2010)</h3>
<p>A few readers requested the code for calculating gradients. The method I used was quite simple, please see the LineUtils code below:</p>
<pre class="brush: cpp;">
/*
 * File:   lineutils.cpp
 * Author: kwong
 *
 * Created on June 5, 2009, 8:47 PM
 */

#include &quot;LineUtils.h&quot;

#include &lt;math.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;iostream&gt;
#include &lt;ios&gt;

using namespace std;

namespace KDW {
    const float PI = 3.14159265358979;
    const float Epsilon = 1e-5;
    const float MaxGradient = 1e6;

    LineUtils::LineUtils() {
    }

    LineUtils::LineUtils(const LineUtils&amp; orig) {
    }

    LineUtils::~LineUtils() {
    }

    /**
     * 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;
    }

    /**
     * Get a line segement's coordinates. The segement is centered at x0, y0.
     *
     * @param p : distance to line from origin.
     * @param theta : the slope of p.
     * @param x0 : x coordinate of the segement center.
     * @param y0 : y coordinate of the segement center.
     * @param numOfPoints : the number of coordinate points to collect at either side
     *                      of (x0, y0)
     * @param points[] : returns the x,y coordinates of the points on the line segement in IppiPoint.
     **/
    void LineUtils::GetLineIntervalPoints(float p, float theta, float x0, float y0, int numOfPoints, IppiPoint points[]) {
        if (abs(sin(theta)) &lt; Epsilon) {
            for (int xp = x0 - numOfPoints; xp &lt;= x0 + numOfPoints; xp++) {
                points[(int) (xp + numOfPoints - x0)].x = xp;
                points[(int) (xp + numOfPoints - x0)].y = y0;
            }
        } else if (abs(cos(theta)) &lt; Epsilon) {
            for (int yp = y0 - numOfPoints; yp &lt;= y0 + numOfPoints; yp++) {
                points[(int) (yp + numOfPoints - y0)].y = yp;
                points[(int) (yp + numOfPoints - y0)].x = x0;
            }
        } else if ((abs(theta) &gt; 0 &amp;&amp; abs(theta) &lt;= 0.25 * PI) ||
                (abs(theta) &gt; 0.75 * PI &amp;&amp; abs(theta) &lt;= PI) ||
                (theta &gt; PI &amp;&amp; theta &lt;= 1.25 * PI) ||
                (theta &gt; 1.75 * PI and theta &lt;= 2.0 * PI)) {
            for (int xp = x0 - numOfPoints; xp &lt;= x0 + numOfPoints; xp++) {
                points[(int) (xp + numOfPoints - x0)].x = xp;
                points[(int) (xp + numOfPoints - x0)].y = (int) ((p - points[(int) (xp + numOfPoints - x0)].x * cos(theta)) / sin(theta));
            }
        } else {
            for (int yp = y0 - numOfPoints; yp &lt;= y0 + numOfPoints; yp++) {
                points[(int) (yp + numOfPoints - y0)].y = yp;
                points[(int) (yp + numOfPoints - y0)].x = (p - points[(int) (yp + numOfPoints - y0)].y * sin(theta)) / cos(theta);
            }
        }
    }

    /**
     * Get a line segement's coordinates. The segement is centered at x0, y0.
     *
     * @param points[] : the x,y coordinate of the input points (ordered).
     * @param threashold : the threashold of disconnected points before a line is considered no
     *              longer connected.
     * @param lpoints[] : the x,y coordinates of the points in the detected longest connected line.
     * @param &amp;maxLen : the maximum length of the output array, addtional line points
     *                  will be discarded if exceed this limit.
     **/
    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 - points[i - 1].x) &gt; threshold) || (abs(points[i].y - points[i - 1].y) &gt; threshold)) {
            if ((abs(points[i].x - lpoints[curRunLength].x) &gt; threshold) || (abs(points[i].y - lpoints[curRunLength].y) &gt; threshold)) {
                //if (curRunLength &gt; maxRunLength) {
                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;
    }

    bool LineUtils::GetMinMaxIndicies(float pixels[], int len, int &amp;minIndex, int &amp;maxIndex) {
        bool isEdge = false;
        bool isPositive = true;

        int numCrossings = 0;

        minIndex = 0;
        maxIndex = 0;

        float avg = 0;

        for (int i = 0; i &lt; len; i++) {
            avg += pixels[i];
        }

        avg = avg / (float) len;        

        if (pixels[0] &gt; avg)
            isPositive = true;
        else
            isPositive = false;

        for (int i = 0; i &lt; len; i++) {
            if (pixels[i] &lt; pixels[minIndex]) {
                minIndex = i;
            } else if (pixels[i] &gt; pixels[maxIndex]) {
                maxIndex = i;
            }

            if (isPositive &amp;&amp; pixels[i] &lt; avg) {
                isPositive = false;
                numCrossings++;
            } else if (!isPositive &amp;&amp; pixels[i] &gt; avg) {
                isPositive = true;
                numCrossings++;
            }
        }

        if (numCrossings &lt; 3)
            return true;
        else
            return false;
    }

    float LineUtils::CalculateGradient(IppiPoint points[], float pixels[], int len, int minIndex, int maxIndex) {
        float lAvg = 0;
        float hAvg = 0;

        if (minIndex &gt; 0 &amp;&amp; minIndex &lt; len - 1) {
            lAvg = (pixels[minIndex] + pixels[minIndex - 1] + pixels[minIndex + 1]) / 3.0;
        } else if (minIndex &gt; 1) {
            lAvg = (pixels[minIndex] + pixels[minIndex - 1] + pixels[minIndex - 2]) / 3.0;
        } else if (minIndex &lt; len - 2) {
            lAvg = (pixels[minIndex] + pixels[minIndex + 1] + pixels[minIndex + 2]) / 3.0;
        } else {
            lAvg = pixels[minIndex];
        }

        if (maxIndex &gt; 0 &amp;&amp; maxIndex &lt; len - 1) {
            hAvg = (pixels[maxIndex] + pixels[maxIndex - 1] + pixels[maxIndex + 1]) / 3.0;
        } else if (maxIndex &gt; 1) {
            hAvg = (pixels[maxIndex] + pixels[maxIndex - 1] + pixels[maxIndex - 2]) / 3.0;
        } else if (maxIndex &lt; len - 2) {
            hAvg = (pixels[maxIndex] + pixels[maxIndex + 1] + pixels[maxIndex + 2]) / 3.0;
        } else {
            hAvg = pixels[maxIndex];
        }

        float h = hAvg - lAvg;
        float t = abs(h / (float) (points[maxIndex].x - points[minIndex].x));

        if (t &gt; 0)
            return t &gt; MaxGradient ? MaxGradient : t;
        else
            return MaxGradient;
    }

    float LineUtils::GetAverage(float gradients[], int count) {
        int zerosCount = 0;
        int minValIndex = 0, maxValIndex = 0;

        for (int i = 0; i &lt; count; i++) {
            if (gradients[i] == 0)
                zerosCount++;

            if (gradients[i] &gt; gradients[maxValIndex])
                maxValIndex = i;
            else if (gradients[i] &lt; gradients[minValIndex])
                minValIndex = i;
        }

        gradients[minValIndex] = 0;
        gradients[maxValIndex] = 0;

        zerosCount += 2;

        if (zerosCount &lt; 6) {
            for (int i = 0; i &lt; count; i++) {
                if (gradients[i] &gt; gradients[maxValIndex])
                    maxValIndex = i;
                else if (gradients[i] &lt; gradients[minValIndex])
                    minValIndex = i;
            }
        }

        gradients[minValIndex] = 0;
        gradients[maxValIndex] = 0;

        zerosCount += 2;

        if (zerosCount &lt; 6) {
            for (int i = 0; i &lt; count; i++) {
                if (gradients[i] &gt; gradients[maxValIndex])
                    maxValIndex = i;
                else if (gradients[i] &lt; gradients[minValIndex])
                    minValIndex = i;
            }
        }

        gradients[minValIndex] = 0;
        gradients[maxValIndex] = 0;

        float r = 0;
        zerosCount = 0;
        for (int i = 0; i &lt; count; i++) {
            if (gradients[i] &gt; 0) {
                r += gradients[i];
                zerosCount++;
            }
        }

        if (zerosCount == 0)
            return 0;
        else
            return r / (float) zerosCount;
    }
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/07/03/image-blur-detection-via-hough-transform-iv/feed/</wfw:commentRss>
		<slash:comments>6</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 [...]]]></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>1</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 [...]]]></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>
	</channel>
</rss>
