<?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>Tanner Helland (dot) Com &#187; Programming</title>
	<atom:link href="http://www.tannerhelland.com/category/programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.tannerhelland.com</link>
	<description>Home of the award-winning author, VG composer, and programmer</description>
	<lastBuildDate>Thu, 17 May 2012 19:00:10 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Seven grayscale conversion algorithms (in VB6)</title>
		<link>http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/</link>
		<comments>http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/#comments</comments>
		<pubDate>Sat, 01 Oct 2011 19:34:50 +0000</pubDate>
		<dc:creator>Tanner</dc:creator>
				<category><![CDATA[Graphics Code]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[color]]></category>
		<category><![CDATA[GIMP]]></category>
		<category><![CDATA[Graphics]]></category>
		<category><![CDATA[graphics code]]></category>
		<category><![CDATA[graphics programming]]></category>
		<category><![CDATA[grayscale]]></category>
		<category><![CDATA[Photoshop]]></category>
		<category><![CDATA[VB]]></category>
		<category><![CDATA[VB6]]></category>

		<guid isPermaLink="false">http://www.tannerhelland.com/?p=3643</guid>
		<description><![CDATA[At long last, here is the most-requested image processing technique for this site - a comprehensive collection of grayscale conversion techniques.  To my knowledge, this is the only project on the Internet that presents 7+ unique grayscale conversion algorithms, including two written from scratch for this very project.]]></description>
			<content:encoded><![CDATA[<p>I have uploaded a great many image processing demonstrations over the years, but today&#8217;s project &#8211; grayscale conversion techniques &#8211; is actually the image processing technique that generates the most email queries for me.  I&#8217;m glad to finally have an answer for all those emails!</p>
<p>Despite many requests for a grayscale demonstration, I have held off coding anything until I could really present something <em>unique</em>.  I don&#8217;t like adding projects to this site that offer nothing novel or interesting, and there are already hundreds of downloads &#8211; in every programming language &#8211; that demonstrate standard color-to-grayscale conversions.   So rather than add one more &#8220;here&#8217;s a grayscale algorithm&#8221; article, I have spent the past week collecting every known grayscale conversion routine.  To my knowledge, this is the only project on the Internet that presents 7+ unique grayscale conversion algorithms, and at least two of the algorithms &#8211; custom # of grayscale shades with and without dithering &#8211; were written from scratch for this very article.</p>
<p>So without further ado, here are seven unique ways to convert a full-color image to grayscale.  <em>(Note: I highly recommend reading the full article so you understand how the various algorithms work and what their purposes might be, but <strong>if all you want is the source code, you&#8217;ll find it past all the pictures and just above the donation link</strong>.)</em></p>
<p><strong>Grayscale &#8211; An Introduction</strong></p>
<p><a  href="http://en.wikipedia.org/wiki/Monochrome_photography">Black and white (or monochrome) photography</a> dates back to the mid-19th century.  Despite the eventual introduction of color photography, monochromatic photography remains popular.  If anything, the digital revolution has actually <em>increased</em> the popularity of monochromatic photography because any digital camera is capable of taking black-and-white photographs (whereas analog cameras required the use of special monochromatic film).  Monochromatic photography is sometimes considered the &#8220;sculpture&#8221; variety of photographic art.  It tends to abstract the subject, allowing the photographer to focus on form and interpretation instead of simply reproducing reality.</p>
<p>Because the terminology <em>black-and-white</em> is imprecise &#8211; black-and-white photography actually consists of many shades of gray &#8211; I will refer to such images as <em>grayscale</em>.</p>
<p>Several other terms will be used frequently throughout my explanations.  The first is <a  href="http://en.wikipedia.org/wiki/Color_space"><em>color space</em></a>.  A <em>color space</em> is a way to visualize a shape or object that represents all available colors.  Different ways of representing color generate different color spaces.  The <a  href="http://en.wikipedia.org/wiki/RGB_color_space">RGB color space is represented as a cube</a>, <a  href="http://en.wikipedia.org/wiki/HSL_color_space">HSL can be a cylinder, cone, or bicone</a>, <a  href="http://en.wikipedia.org/wiki/YIQ">YIQ</a> and <a  href="http://en.wikipedia.org/wiki/YPbPr">YPbPr</a> have more abstract shapes.  This article will primarily reference the RGB and HSL color spaces.</p>
<p>I will also refer frequently to <em><a  href="http://en.wikipedia.org/wiki/Color_channel">color channels</a>.</em>  Most digital images are comprised of three separate color channels: typically a red channel, a green channel, and a blue channel.  Layering these channels on top of each other creates a full-color image.  Different color models have different channels (sometimes the channels are colors, sometimes they are other values like <em>lightness</em> or <em>saturation</em>), but this article will primarily focus on RGB channels.</p>
<p>On to the algorithms!</p>
<p><strong>Sample Image:</strong></p>
<div id="attachment_3645" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/secret_of_monkey_island/" rel="attachment wp-att-3645"><img class="size-large wp-image-3645" title="Secret_of_Monkey_Island" src="http://www.tannerhelland.com/wp-content/uploads/Secret_of_Monkey_Island-600x375.jpg" alt="Promo art for The Secret of Monkey Island: Special Edition, ©2009 LucasArts" width="600" height="375" /></a><p class="wp-caption-text">This bright, colorful promo art for The Secret of Monkey Island: Special Edition will be used to demonstrate each of our seven unique grayscale algorithms.</p></div>
<p><strong>Method 1 &#8211; Averaging (aka &#8220;quick and dirty&#8221;)</strong></p>
<div id="attachment_3646" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/grayscale_average/" rel="attachment wp-att-3646"><img class="size-large wp-image-3646" title="grayscale_average" src="http://www.tannerhelland.com/wp-content/uploads/grayscale_average-600x375.png" alt="Grayscale - average method" width="600" height="375" /></a><p class="wp-caption-text">Grayscale image generated from the formula: Average(Red, Green, Blue)</p></div>
<p>This method is the most boring, so let&#8217;s address it first.  &#8220;Averaging&#8221; is probably the most common grayscale conversion routine, and it works something like this:</p>
<p><code>Gray = (Red + Green + Blue) / 3</code></p>
<p>Fast, simple &#8211; no wonder this is the go-to grayscale algorithm for rookie programmers.  This formula generates a reasonably nice grayscale equivalent, and its simplicity makes it easy to implement and optimize (<a  href="http://www.tannerhelland.com/43/vb-graphics-programming-4/">look-up tables</a> work quite well).  However, this formula is not without shortcomings &#8211; while fast and simple, it does a poor job of representing shades of gray relative to the way humans perceive luminosity (or brightness).  For that, we need something a bit more complex.</p>
<p><strong>Method 2 &#8211; Correcting for the human eye (sometimes called &#8220;luma&#8221; or &#8220;luminance,&#8221; though <a  href="http://poynton.com/PDFs/YUV_and_luminance_harmful.pdf">such terminology isn&#8217;t really accurate</a>)</strong></p>
<div id="attachment_3647" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/grayscale_humaneye/" rel="attachment wp-att-3647"><img class="size-large wp-image-3647" title="grayscale_humaneye" src="http://www.tannerhelland.com/wp-content/uploads/grayscale_humaneye-600x375.png" alt="Grayscale generated using values related to cone density in the human eye" width="600" height="375" /></a><p class="wp-caption-text">Grayscale generated using a formula similar to (Red * 0.3 + Green * 0.59 + Blue * 0.11)</p></div>
<p>It&#8217;s hard to tell a difference between this image and the one above, so let me provide one more example.  In the image below, method #1 or the &#8220;average method&#8221; covers the top half of the picture, while method #2 covers the bottom half:</p>
<div id="attachment_3648" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/grayscale_average_and_humaneye/" rel="attachment wp-att-3648"><img class="size-large wp-image-3648" title="grayscale_average_and_humaneye" src="http://www.tannerhelland.com/wp-content/uploads/grayscale_average_and_humaneye-600x375.png" alt="Grayscale methods 1 and 2 compared" width="600" height="375" /></a><p class="wp-caption-text">If you look closely, you can see a horizontal line running across the center of the image. The top half (the average method) is more washed-out than the bottom half.  This is especially visible in the middle-left segment of the image, beneath the cheekbone of the background skull.</p></div>
<p>The difference between the two methods is even more pronounced when flipping between them at full-size, as you can do in the provided source code.  Now might be a good time to download my sample project (available at the bottom of this article) so you can compare the various algorithms side-by-side.</p>
<p>This second algorithm plays off the fact that cone density in the human eye is not uniform across colors.  Humans perceive green more strongly than red, and red more strongly than blue.  This makes sense from an evolutionary biology standpoint &#8211; much of the natural world appears in shades of green, so humans have evolved greater sensitivity to green light.  <em>(Note: this is oversimplified, but accurate.)</em></p>
<p>Because humans do not perceive all colors equally, the &#8220;average method&#8221; of grayscale conversion is inaccurate.  Instead of treating red, green, and blue light equally, a good grayscale conversion will weight each color based on how the human eye perceives it.  A common formula in image processors (Photoshop, <a  href="http://gimp-savvy.com/BOOK/index.html?node54.html">GIMP</a>) is:</p>
<p><code>Gray = (Red * 0.3 + Green * 0.59 + Blue * 0.11)</code></p>
<p>It&#8217;s surprising to see such a huge difference between red, green, and blue, isn&#8217;t it?  This formula requires a bit of extra computation, but it results in a more dynamic grayscale image.  Again, downloading the sample program is the best way to appreciate this, so I recommend grabbing the code, experimenting with it, then returning to this article.</p>
<p>It&#8217;s worth noting that there is disagreement on the best formula for this type of grayscale conversion.  In my project, I have chosen to go with the original <a  href="http://en.wikipedia.org/wiki/ITU-R">ITU-R</a> recommendation (BT.709, specifically) which is the historical precedent.  This formula, sometimes called <a  href="http://en.wikipedia.org/wiki/Luma_%28video%29">Luma</a>, looks like this:</p>
<p><code>Gray = (Red * 0.2126 + Green * 0.7152 + Blue * 0.0722)</code></p>
<p>Some modern digital image and video formats use a different recommendation (BT.601), which calls for slightly different coefficients:</p>
<p><code>Gray = (Red * 0.299 + Green * 0.587 + Blue * 0.114)</code></p>
<p>A full discussion of which formula is &#8220;better&#8221; is beyond the scope of this article.  For further reading, I strongly suggest <a  href="http://poynton.com/">the work of Charles Poynton</a>.  For 99.99% of programmers, the difference between these two formulas is irrelevant.  Both are perceptually preferable to the &#8220;average method&#8221; discussed at the top of this article.</p>
<p><strong>Method 3 &#8211; Desaturation</strong></p>
<div id="attachment_3669" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/grayscale_desaturate/" rel="attachment wp-att-3669"><img class="size-large wp-image-3669" title="grayscale_desaturate" src="http://www.tannerhelland.com/wp-content/uploads/grayscale_desaturate-600x375.png" alt="Grayscale generated from a Desaturate algorithm" width="600" height="375" /></a><p class="wp-caption-text">A desaturated image. Desaturating an image takes advantage of the ability to treat the (R, G, B) colorspace as a 3-dimensional cube. Desaturation approximates a luminance value for each pixel by choosing a corresponding point on the neutral axis of the cube.</p></div>
<p>Next on our list of methods is <em>desaturation</em>.</p>
<p>There are various ways to describe the color of a pixel.  Most programmers use the RGB color model, where each color is described by its red, green, and blue components.  While this is a nice way for a machine to describe color, the RGB color space can be difficult for humans to visualize.  If I tell you, &#8220;oh, I just bought a car.  Its color is RGB(122, 0, 255),&#8221; I doubt you can imagine the color I&#8217;m describing.  If, however, I say, &#8220;I just bought a car.  It is a bright, vivid shade of violet,&#8221; you can probably picture <span style="color: #7a00ff;">the color in question</span>.  (Note: this is a hypothetical example.  I do not drive a purple car.  :)</p>
<p>For this reason (among others), <a  href="http://en.wikipedia.org/wiki/HSL_and_HSV">the HSL color space</a> is sometimes used to describe colors.  HSL stands for <em>hue</em>, <em>saturation</em>, <em>lightness</em>.  <em>Hue</em> could be considered the name of the color &#8211; red, green, orange, yellow, etc.  Mathematically, hue is described as an angular dimension on the color wheel (range [0,360]), where pure red occurs at 0°, pure green at 120°, pure blue at 240°, then back to pure red at 360°.  Saturation describes how vivid a color is; a very vivid color has full saturation, while gray has no saturation.  Lightness describes the brightness of a color; black has zero lightness, while white has full lightness.</p>
<p>Desaturating an image works by converting an RGB triplet to an HSL triplet, then forcing the saturation to zero.  Basically, this takes a pixel and converts it to its <em>least-saturated variant</em>.  The mathematics of this conversion are more complex than this article warrants, so I&#8217;ll simply provide the shortcut calculation.  A pixel can be desaturated by finding the midpoint between the maximum of (R, G, B) and the minimum of (R, G, B), like so:</p>
<p><code>(Max(R, G, B) + Min(R, G, B)) / 2</code></p>
<p>In terms of the RGB color space, desaturation forces each pixel to a point along the neutral axis running from (0, 0, 0) to (255, 255, 255).  If that makes no sense, take a moment to read <a  href="http://en.wikipedia.org/wiki/RGB_color_space">this wikipedia article</a> about the RGB color space.</p>
<p>Desaturation results in a flatter, softer grayscale image.  If you compare this desaturated sample to the human-eye-corrected sample (Method #2), you should notice a difference in the contrast of the image.  Method #2 seems more like an <a  href="http://www.anseladams.com/category_s/71.htm">Ansel Adams photograph</a>, while desaturation looks like the kind of grayscale photo you might take with a cheap point-and-shoot camera.  Of the three methods discussed thus far, desaturation results in the flattest (least contrast) and darkest overall image.</p>
<p><strong>Method 4 &#8211; Decomposition (think of it as <em>de-composition</em> &#8211; not the biological process!)</strong></p>
<div id="attachment_3672" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/grayscale_decompose_max/" rel="attachment wp-att-3672"><img class="size-large wp-image-3672" title="grayscale_decompose_max" src="http://www.tannerhelland.com/wp-content/uploads/grayscale_decompose_max-600x375.png" alt="Decomposition - Max Values" width="600" height="375" /></a><p class="wp-caption-text">Decomposition using maximum values</p></div>
<div id="attachment_3673" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/grayscale_decompose_min/" rel="attachment wp-att-3673"><img class="size-large wp-image-3673" title="grayscale_decompose_min" src="http://www.tannerhelland.com/wp-content/uploads/grayscale_decompose_min-600x375.png" alt="Decomposition - Minimum Values" width="600" height="375" /></a><p class="wp-caption-text">Decomposition using minimum values</p></div>
<p>Decomposing an image (sounds gross, doesn&#8217;t it?) could be considered a simpler form of desaturation.  To decompose an image, we force each pixel to the highest (maximum) or lowest (minimum) of its red, green, and blue values.  Note that this is done on a per-pixel basis &#8211; so if we are performing a <em>maximum</em> decompose and pixel #1 is RGB(255, 0, 0) while pixel #2 is RGB(0, 0, 64), we will set pixel #1 to 255 and pixel #2 to 64.  Decomposition only cares about which color value is highest or lowest &#8211; not which channel it comes from.</p>
<p>As you can imagine, a maximum decomposition provides a brighter grayscale image, while a minimum decomposition provides a darker one.</p>
<p>This method of grayscale reduction is typically used for artistic effect.</p>
<p><strong>Method 5 &#8211; Single color channel</strong></p>
<div id="attachment_3680" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/grayscale_rechannel_red/" rel="attachment wp-att-3680"><img class="size-large wp-image-3680" title="grayscale_rechannel_red" src="http://www.tannerhelland.com/wp-content/uploads/grayscale_rechannel_red-600x375.png" alt="Grayscale - red channel only" width="600" height="375" /></a><p class="wp-caption-text">Grayscale generated by using only red channel values.</p></div>
<div id="attachment_3681" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/grayscale_rechannel_green/" rel="attachment wp-att-3681"><img class="size-large wp-image-3681" title="grayscale_rechannel_green" src="http://www.tannerhelland.com/wp-content/uploads/grayscale_rechannel_green-600x375.png" alt="Grayscale - green channel only" width="600" height="375" /></a><p class="wp-caption-text">Grayscale generated by using only green channel values.</p></div>
<div id="attachment_3682" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/grayscale_rechannel_blue/" rel="attachment wp-att-3682"><img class="size-large wp-image-3682" title="grayscale_rechannel_blue" src="http://www.tannerhelland.com/wp-content/uploads/grayscale_rechannel_blue-600x375.png" alt="Grayscale - blue channel only" width="600" height="375" /></a><p class="wp-caption-text">Grayscale generated by using only blue channel values.</p></div>
<p>Finally, we reach the fastest computational method for grayscale reduction &#8211; using data from a single color channel.  Unlike all the methods mentioned so far, this method requires no calcuations.  All it does is pick a single channel and make that the grayscale representation of the images.</p>
<p>Believe it or not, <a  href="http://en.wikipedia.org/wiki/Charge-coupled_device#Color_cameras">this algorithm is the one most digital cameras use for taking &#8220;grayscale&#8221; photos</a>.  CCDs in digital cameras are comprised of a blend of red, green, and blue sensors, and rather than perform the necessary math to convert RGB values to gray ones, they simply grab a single channel (green, for the reasons mentioned in Method #2 &#8211; human eye correction) and call that the grayscale one.  For this reason, most photographers recommend <strong>against</strong> using your camera&#8217;s built-in grayscale option.  Instead, shoot everything in color and then perform the grayscale conversion later, using whatever method leads to the best result!</p>
<p>It is difficult to predict the results of this method of grayscale conversion.  As such, it is usually reserved for artistic effect.</p>
<p><strong>Method 6 &#8211; Custom # of gray shades</strong></p>
<div id="attachment_3683" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/grayscale_4_shades/" rel="attachment wp-att-3683"><img class="size-large wp-image-3683" title="grayscale_4_shades" src="http://www.tannerhelland.com/wp-content/uploads/grayscale_4_shades-600x375.png" alt="Grayscale using only 4 shades" width="600" height="375" /></a><p class="wp-caption-text">Grayscale using only 4 shades - black, dark gray, light gray, and white</p></div>
<p>Now it&#8217;s time for the fun algorithms.  Method #6, which I wrote from scratch for this project, allows the user to specify how many shades of gray the resulting image will use.  Any value between 2 and 256 is accepted; 2 results in a black-and-white image, while 256 gives you an image identical to Method #1 above.  This project only uses 8-bit color channels, but for 16 or 24-bit grayscale images (and their resulting 65,536 and 16,777,216 maximums) this code would work just fine.</p>
<p>The algorithm works by selecting X # of gray values, equally spread (inclusively) between zero luminance &#8211; black &#8211; and full luminance &#8211; white.  The above image uses four shades of gray.  Here is another example, using sixteen shades of gray:</p>
<div id="attachment_3684" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/grayscale_16_shades/" rel="attachment wp-att-3684"><img class="size-large wp-image-3684" title="grayscale_16_shades" src="http://www.tannerhelland.com/wp-content/uploads/grayscale_16_shades-600x375.png" alt="Grayscale using 16 shades of gray" width="600" height="375" /></a><p class="wp-caption-text">In this image, we use 16 shades of gray spanning from black to white</p></div>
<p>I enjoy the artistic possibilities of this algorithm.  The attached source code renders all grayscale images in real-time, so for a better understanding of this algorithm, load up the sample code and rapidly scroll between different numbers of gray shades.</p>
<p><strong>Method 7 &#8211; Custom # of gray shades with dithering (in this example, horizontal error-diffusion dithering)</strong></p>
<div id="attachment_3685" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/grayscale_4_shades_dithered/" rel="attachment wp-att-3685"><img class="size-large wp-image-3685" title="grayscale_4_shades_dithered" src="http://www.tannerhelland.com/wp-content/uploads/grayscale_4_shades_dithered-600x375.png" alt="Grayscale - four shades, dithered" width="600" height="375" /></a><p class="wp-caption-text">This image also uses only four shades of gray (black, dark gray, light gray, white), but it adds full error-diffusion dithering support</p></div>
<p>Our final algorithm is perhaps the strangest one of all.  Like the previous method, it allows the user to specify any value in the [2,256] range, and the algorithm will automatically calculate the best spread of grayscale values for that range.  However, this algorithm also adds full dithering support.</p>
<p>What is dithering, you ask?  In image processing, <a  href="http://en.wikipedia.org/wiki/Dithering#Digital_photography_and_image_processing">dithering uses optical illusions to make an image look more colorful than than it actually is</a>.  Dithering algorithms work by interspersing whatever colors are available into new patterns &#8211; ordered or random &#8211; that fool the human eye into perceiving more colors than are actually present.  If that makes no sense, take a look at <a  href="http://en.wikipedia.org/wiki/Dithering#Algorithms">this gallery of dithered images</a>.</p>
<p>There are many different dithering algorithms.  The one I provide is one of the simpler error-diffusion mechanisms: a one-dimensional diffusion that bleeds color conversion errors from left to right.</p>
<p>If you look at the image above, you&#8217;ll notice that only four colors are present &#8211; black, dark gray, light gray, and white &#8211; but because these colors are mixed together, from a distance this image looks much sharper than the four-color non-dithered image under Method #6.  Here is a side-by-side comparison:</p>
<div id="attachment_3686" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/grayscale_4_shades_sidebyside/" rel="attachment wp-att-3686"><img class="size-large wp-image-3686" title="grayscale_4_shades_sidebyside" src="http://www.tannerhelland.com/wp-content/uploads/grayscale_4_shades_sidebyside-600x375.png" alt="Side-by-side of dithered and non-dithered 4-color grayscale images" width="600" height="375" /></a><p class="wp-caption-text">The left side of the image is a 4-shade non-dithered image; the right side is a 4-shade image WITH dithering</p></div>
<p>When few colors are available, dithering preserves more nuances than a non-dithered image, but the trade-off is a &#8220;dirty,&#8221; speckled look.  Some dithering algorithms are better than others; the one I&#8217;ve used falls somewhere in the middle, which is why I selected it.</p>
<p>As a final example, here is a 16-color grayscale image with full dithering, followed by a side-by-side comparison with the non-dithered version:</p>
<div id="attachment_3687" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/grayscale_16_shades_dithered/" rel="attachment wp-att-3687"><img class="size-large wp-image-3687" title="grayscale_16_shades_dithered" src="http://www.tannerhelland.com/wp-content/uploads/grayscale_16_shades_dithered-600x375.png" alt="Grayscale image, 16 shades, dithered" width="600" height="375" /></a><p class="wp-caption-text">Hard to believe only 16 shades of gray are used in this image, isn&#39;t it?</p></div>
<div id="attachment_3688" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/grayscale_16_shades_sidebyside/" rel="attachment wp-att-3688"><img class="size-large wp-image-3688" title="grayscale_16_shades_sidebyside" src="http://www.tannerhelland.com/wp-content/uploads/grayscale_16_shades_sidebyside-600x375.png" alt="Grayscale, 16 shades, dithered vs non-dithered" width="600" height="375" /></a><p class="wp-caption-text">As the number of colors in an image increases, dithering artifacts become less and less noticeable.  Can you tell which side of the image is dithered and which is not?</p></div>
<p><strong>Conclusion</strong></p>
<p>If you&#8217;re reading this from a slow Internet connection, I apologize for the image-heavy nature of this article.  Unfortunately, the only way to really demonstrate all these grayscale techniques is by showing many examples!</p>
<p>The source code for this project, like all image processing code on this site, runs in real-time.  The GUI is simple and streamlined, automatically hiding and displaying relevant user-adjustable options as you click through the various algorithms:</p>
<div id="attachment_3689" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/grayscale_source_code_gui/" rel="attachment wp-att-3689"><img class="size-large wp-image-3689" title="grayscale_source_code_GUI" src="http://www.tannerhelland.com/wp-content/uploads/grayscale_source_code_GUI-600x344.jpg" alt="GUI of the provided source code" width="600" height="344" /></a><p class="wp-caption-text">GUI of the provided source code. The program also allows you to load your own images.</p></div>
<p>Each algorithm is provided as a stand-alone method, accepting a source and destination picturebox as parameters.  I designed it this way so you can grab whatever algorithms interest you and drop them straight into an existing project, without need for modification.</p>
<p>Comments and suggestions are welcome.  If you know of any interesting grayscale conversion algorithms I might have missed, please let me know.</p>
<p><em>(Fun fact: want to convert a grayscale image back to color?  If so, check out <a  href="http://www.tannerhelland.com/3552/colorize-image-vb6/">my real-time image colorization project</a>.)</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Real-time Diffuse (Spread) Image Filter in VB6</title>
		<link>http://www.tannerhelland.com/3601/realtime-diffuse-spread-image-filter-vb6/</link>
		<comments>http://www.tannerhelland.com/3601/realtime-diffuse-spread-image-filter-vb6/#comments</comments>
		<pubDate>Fri, 01 Jul 2011 23:23:35 +0000</pubDate>
		<dc:creator>Tanner</dc:creator>
				<category><![CDATA[Graphics Code]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[diffuse]]></category>
		<category><![CDATA[GIMP]]></category>
		<category><![CDATA[Graphics]]></category>
		<category><![CDATA[graphics code]]></category>
		<category><![CDATA[graphics programming]]></category>
		<category><![CDATA[Photoshop]]></category>
		<category><![CDATA[spread]]></category>
		<category><![CDATA[VB6]]></category>

		<guid isPermaLink="false">http://www.tannerhelland.com/?p=3601</guid>
		<description><![CDATA[A software-based "diffuse filter" - random displacement of image pixels within a specified radius - was used in a number of SNES, Genesis, and DOS games to simulate an explosion effect.  Today's project provides the source code for generating a diffuse effect in real-time.]]></description>
			<content:encoded><![CDATA[<div id="attachment_3603" class="wp-caption alignright" style="width: 310px"><a  rel="attachment wp-att-3603" href="http://www.tannerhelland.com/3601/realtime-diffuse-spread-image-filter-vb6/camera_diffuse_filters/"><img class="size-full wp-image-3603" title="camera_diffuse_filters" src="http://www.tannerhelland.com/wp-content/uploads/camera_diffuse_filters.jpg" alt="One brand of camera diffusion lenses" width="300" height="300" /></a><p class="wp-caption-text">A set of camera diffusion lenses.</p></div>
<p>In traditional photography and film, a diffusion filter is used to soften light from a flash or stationary lamp.  Specialized lenses are available for this purpose, but the effect can be cheaply replicated by smearing petroleum jelly over the light (<a  title="Wikipedia article on diffusion filters" href="http://en.wikipedia.org/wiki/Diffusion_filter">seriously</a>) or by shooting through a sheet of nylon.</p>
<p>In image processing, a diffusion filter often means something else entirely.  Photoshop&#8217;s &#8220;Diffuse&#8221; filter randomly rearranges pixels within a set radius.  (GIMP can do the same thing, but the effect is more accurately titled &#8220;Spread.&#8221;)  This effect can be animated for a cheap explosion effect &#8211; something a number of SNES, Genesis, and DOS games used to great effect.</p>
<p>This project demonstrates a simple, real-time method for replicating such an effect.  All code is commented and reasonably optimized, and an animated &#8220;special effect&#8221; version is provided for those interested.  Unlike Photoshop, this routine allows you to specify separate horizontal and vertical max random distances, as well as the ability to wrap pixels around image edges.</p>
<div id="attachment_3604" class="wp-caption aligncenter" style="width: 610px"><a  rel="attachment wp-att-3604" href="http://www.tannerhelland.com/3601/realtime-diffuse-spread-image-filter-vb6/lbp/"><img class="size-large wp-image-3604" title="LittleBigPlanet" src="http://www.tannerhelland.com/wp-content/uploads/LBP-600x375.jpg" alt="LittleBigPlanet mini poster" width="600" height="375" /></a><p class="wp-caption-text">Here&#39;s the original image (a poster for LittleBigPlanet)</p></div>
<div id="attachment_3605" class="wp-caption aligncenter" style="width: 610px"><a  rel="attachment wp-att-3605" href="http://www.tannerhelland.com/3601/realtime-diffuse-spread-image-filter-vb6/lbp_diffuse_5/"><img class="size-large wp-image-3605" title="LBP_diffuse_5" src="http://www.tannerhelland.com/wp-content/uploads/LBP_diffuse_5-600x375.jpg" alt="" width="600" height="375" /></a><p class="wp-caption-text">Here is the same image with a diffuse filter applied (max distance=5)</p></div>
<div id="attachment_3606" class="wp-caption aligncenter" style="width: 610px"><a  rel="attachment wp-att-3606" href="http://www.tannerhelland.com/3601/realtime-diffuse-spread-image-filter-vb6/lbp_diffuse_50/"><img class="size-large wp-image-3606" title="LBP_diffuse_50" src="http://www.tannerhelland.com/wp-content/uploads/LBP_diffuse_50-600x375.jpg" alt="" width="600" height="375" /></a><p class="wp-caption-text">...and here is the image again, but with max distance = 50</p></div>
<div id="attachment_3607" class="wp-caption aligncenter" style="width: 610px"><a  rel="attachment wp-att-3607" href="http://www.tannerhelland.com/3601/realtime-diffuse-spread-image-filter-vb6/lbp_diffuse_50_wrap_pixels/"><img class="size-large wp-image-3607" title="LBP_diffuse_50_wrap_pixels" src="http://www.tannerhelland.com/wp-content/uploads/LBP_diffuse_50_wrap_pixels-600x375.jpg" alt="" width="600" height="375" /></a><p class="wp-caption-text">...and one more example.  This time, edge wrapping has been enabled.  Note the bleed of planet pixels at the top and black pixels at the bottom.</p></div>
]]></content:encoded>
			<wfw:commentRss>http://www.tannerhelland.com/3601/realtime-diffuse-spread-image-filter-vb6/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to Colorize an Image (in VB6)</title>
		<link>http://www.tannerhelland.com/3552/colorize-image-vb6/</link>
		<comments>http://www.tannerhelland.com/3552/colorize-image-vb6/#comments</comments>
		<pubDate>Thu, 28 Apr 2011 18:41:36 +0000</pubDate>
		<dc:creator>Tanner</dc:creator>
				<category><![CDATA[Graphics Code]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[colorization]]></category>
		<category><![CDATA[colorize]]></category>
		<category><![CDATA[graphics code]]></category>
		<category><![CDATA[image filters]]></category>
		<category><![CDATA[VB6]]></category>

		<guid isPermaLink="false">http://www.tannerhelland.com/?p=3552</guid>
		<description><![CDATA["Colorization" in image processing can refer to one of several things.  One form of "colorization" is taking any image - including full-color ones - and applying a uniform color for dramatic or artistic effect.  This is the type of colorization filter provided by software like Photoshop and GIMP, and it's also the effect this project implements.]]></description>
			<content:encoded><![CDATA[<p>&#8220;Colorization&#8221; in image processing can refer to one of several things.  Most commonly, to <em>colorize</em> an image is to take an image without color (like a black and white photograph) and artificially apply color to it.  One example of this is the old <a  href="http://en.wikipedia.org/wiki/Three_Stooges">Three Stooges</a> movies which were originally shot in black-and-white, but <a  href="http://en.wikipedia.org/wiki/Film_colorization">re-released several years ago in color</a>.  Colorization of an entire movie is expensive and time-consuming, and a lot of human intervention is required to make things look right.</p>
<p>Another form of &#8220;colorization&#8221; is taking any image &#8211; including full-color ones &#8211; and colorizing the image for dramatic or artistic effect.  This is the type of colorization filter provided by software like Photoshop and GIMP, and it&#8217;s also the effect my source code provides.</p>
<div id="attachment_3553" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3552/colorize-image-vb6/enslaved-odyssey-to-the-west-normal/" rel="attachment wp-att-3553"><img src="http://www.tannerhelland.com/wp-content/uploads/Enslaved-Odyssey-to-the-West-normal-600x375.jpg" alt="Enslaved poster - original" title="Enslaved-Odyssey-to-the-West-normal" width="600" height="375" class="size-large wp-image-3553" /></a><p class="wp-caption-text">Here&#039;s the original image (a poster for Enslaved: Odyssey to the West)</p></div>
<div id="attachment_3554" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3552/colorize-image-vb6/enslaved-odyssey-to-the-west-blue-original-saturation/" rel="attachment wp-att-3554"><img src="http://www.tannerhelland.com/wp-content/uploads/Enslaved-Odyssey-to-the-West-blue-original-saturation-600x375.jpg" alt="Enslaved poster - blue colorization" title="Enslaved-Odyssey-to-the-West-blue-original-saturation" width="600" height="375" class="size-large wp-image-3554" /></a><p class="wp-caption-text">...and here&#039;s the same poster, colorized</p></div>
<p>Colorization works by retaining certain data about each pixel&#8217;s color (luminance and possibly saturation) while ignoring other data about color (hue).  In the demonstration above, each pixel in the second picture has the exact same saturation and luminance as the top picture, but all hue values have been replaced with blue.</p>
<p>Different programs implement colorization differently.  Most require you to specify hue and saturation values, with luminance being optional.  I really like the effect created when you keep the saturation values from the original image.  If you force saturation values to an arbitrary number &#8211; like Photoshop or GIMP &#8211; the colorized image looks either drab or blown-out.</p>
<div id="attachment_3555" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3552/colorize-image-vb6/enslaved-odyssey-to-the-west-orange-original-saturation/" rel="attachment wp-att-3555"><img src="http://www.tannerhelland.com/wp-content/uploads/Enslaved-Odyssey-to-the-West-orange-original-saturation-600x375.jpg" alt="Enslaved poster - orange, original saturation" title="Enslaved-Odyssey-to-the-West-orange-original-saturation" width="600" height="375" class="size-large wp-image-3555" /></a><p class="wp-caption-text">Here&#039;s another colorization - this time to orange.  Saturation values are unchanged.</p></div>
<div id="attachment_3556" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3552/colorize-image-vb6/enslaved-odyssey-to-the-west-orange-saturation-50/" rel="attachment wp-att-3556"><img src="http://www.tannerhelland.com/wp-content/uploads/Enslaved-Odyssey-to-the-West-orange-saturation-50-600x375.jpg" alt="Enslaved poster - orange, 50 percent saturation" title="Enslaved-Odyssey-to-the-West-orange-saturation-50" width="600" height="375" class="size-large wp-image-3556" /></a><p class="wp-caption-text">Here&#039;s the same image, but with saturation forced to 50 percent (Photoshop style).  See how the characters and background blur together?  The nice contrast between the background buildings and the character on the right is no longer present.</p></div>
<div id="attachment_3557" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3552/colorize-image-vb6/enslaved-odyssey-to-the-west-orange-saturation-100/" rel="attachment wp-att-3557"><img src="http://www.tannerhelland.com/wp-content/uploads/Enslaved-Odyssey-to-the-West-orange-saturation-100-600x375.jpg" alt="Enslaved poster - orange, 100 percent saturation" title="Enslaved-Odyssey-to-the-West-orange-saturation-100" width="600" height="375" class="size-large wp-image-3557" /></a><p class="wp-caption-text">...and here&#039;s the image again, but with saturation forced to 100 percent.  This looks terrible, IMO.</p></div>
<p>I think the top image in this set offers the most interesting colorization&#8230; but since I wrote this code, I could be biased&#8230; :)</p>
<p>Full sample code is provided, and &#8211; like all code on this site &#8211; it&#8217;s fast enough to run in real-time.  </p>
<div id="attachment_3558" class="wp-caption aligncenter" style="width: 610px"><a  href="http://www.tannerhelland.com/3552/colorize-image-vb6/colorize-program-screenshot/" rel="attachment wp-att-3558"><img src="http://www.tannerhelland.com/wp-content/uploads/colorize-program-screenshot-600x528.jpg" alt="Colorize program screenshot" title="colorize-program-screenshot" width="600" height="528" class="size-large wp-image-3558" /></a><p class="wp-caption-text">Here&#039;s a screenshot of the GUI attached to the sample code</p></div>
<p>Comments and ideas for improvement are always welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tannerhelland.com/3552/colorize-image-vb6/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Stained Glass Effect (using VB6 and GIMP)</title>
		<link>http://www.tannerhelland.com/2306/stained-glass-image-effect/</link>
		<comments>http://www.tannerhelland.com/2306/stained-glass-image-effect/#comments</comments>
		<pubDate>Wed, 23 Jun 2010 00:26:42 +0000</pubDate>
		<dc:creator>Tanner</dc:creator>
				<category><![CDATA[Graphics Code]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[algorithms]]></category>
		<category><![CDATA[GIMP]]></category>
		<category><![CDATA[post-processing]]></category>
		<category><![CDATA[randomizing]]></category>
		<category><![CDATA[stained glass]]></category>

		<guid isPermaLink="false">http://www.tannerhelland.com/?p=2306</guid>
		<description><![CDATA[I wanted to title this article "a novel method for matrix randomization using polygons and custom differential post-processing blending"... but that was a bit long, even for me...]]></description>
			<content:encoded><![CDATA[<p>I wanted to title this article &#8220;<em>a novel method for matrix randomization using polygons and custom differential post-processing blending</em>&#8220;&#8230; but that was a bit long, even for me.</p>
<p>Why such a complex title?</p>
<p>It all started with a strange idea I had today.  I was thinking of common ways to randomize image data (don&#8217;t ask why), and it struck me that the most common randomization method &#8211; varying RGB data of single pixels &#8211; is not the most interesting way to go about it.   Why not use lines, triangles, or other polygons to randomize an image?   How would that look?</p>
<p>To test my theory, I wrote a quick program that selects two random pixels in an image, averages their colors, then draws a line of that averaged color between the two points.  When repeated over and over again, such an algorithm leads to some interesting effects&#8230;</p>
<div id="attachment_2313" class="wp-caption aligncenter" style="width: 646px"><a  rel="attachment wp-att-2313" href="http://www.tannerhelland.com/2306/stained-glass-image-effect/gow3_original-2/"><img class="size-full wp-image-2313" title="GoW3_original" src="http://www.tannerhelland.com/wp-content/uploads/2010/06/GoW3_original1.jpg" alt="" width="636" height="333" /></a><p class="wp-caption-text">I started with this God of War 3 image...</p></div>
<div id="attachment_2314" class="wp-caption aligncenter" style="width: 646px"><a  rel="attachment wp-att-2314" href="http://www.tannerhelland.com/2306/stained-glass-image-effect/gow3_lines_30/"><img class="size-full wp-image-2314" title="GoW3_lines_30" src="http://www.tannerhelland.com/wp-content/uploads/2010/06/GoW3_lines_30.jpg" alt="" width="636" height="333" /></a><p class="wp-caption-text">...and got this  (100,000 iterations of lines with max length 42).</p></div>
<div id="attachment_2315" class="wp-caption aligncenter" style="width: 646px"><a  rel="attachment wp-att-2315" href="http://www.tannerhelland.com/2306/stained-glass-image-effect/gow3_lines_60/"><img class="size-full wp-image-2315" title="GoW3_lines_60" src="http://www.tannerhelland.com/wp-content/uploads/2010/06/GoW3_lines_60.jpg" alt="" width="636" height="333" /></a><p class="wp-caption-text">Here&#39;s the same image, but with lines of max length 85.</p></div>
<p>Kinda cool.  I&#8217;m not sure what to call this effect&#8230; although it looks &#8220;furry&#8221; to me.  Should we invent a new word &#8211; <em>furrification</em>?</p>
<p>Once I had lines working, my next curiosity involved polygons.  Here&#8217;s the same picture, but with triangle randomization:</p>
<div id="attachment_2316" class="wp-caption aligncenter" style="width: 646px"><a  rel="attachment wp-att-2316" href="http://www.tannerhelland.com/2306/stained-glass-image-effect/gow3_triangles_30/"><img class="size-full wp-image-2316" title="GoW3_triangles_30" src="http://www.tannerhelland.com/wp-content/uploads/2010/06/GoW3_triangles_30.jpg" alt="" width="636" height="333" /></a><p class="wp-caption-text">Same parameters as the first line-based randomization above (100,000 iterations, 42 max length).</p></div>
<div id="attachment_2317" class="wp-caption aligncenter" style="width: 646px"><a  rel="attachment wp-att-2317" href="http://www.tannerhelland.com/2306/stained-glass-image-effect/gow3_triangles_60/"><img class="size-full wp-image-2317" title="GoW3_triangles_60" src="http://www.tannerhelland.com/wp-content/uploads/2010/06/GoW3_triangles_60.jpg" alt="" width="636" height="333" /></a><p class="wp-caption-text">Same parameters as the second line-based image above (100,000 iterations, max length 85)</p></div>
<p>This is also a cool effect, especially when you watch it in action.  (The program refreshes the screen every 100 iterations.)</p>
<p>While I didn&#8217;t go to the trouble of implementing additional polygons, the code is primed and ready for it.  In fact, it would be trivial to draw polygons of any segment count.</p>
<p>Once I had my newly randomized images, I decided to pop into GIMP and do a bit of post-processing.  It was then that I realized this could be used to create pretty sweet stained glass images:</p>
<div id="attachment_2318" class="wp-caption aligncenter" style="width: 646px"><a  rel="attachment wp-att-2318" href="http://www.tannerhelland.com/2306/stained-glass-image-effect/gow3-stained-glass-30/"><img class="size-full wp-image-2318" title="GoW3-stained-glass-30" src="http://www.tannerhelland.com/wp-content/uploads/2010/06/GoW3-stained-glass-30.jpg" alt="" width="636" height="333" /></a><p class="wp-caption-text">Sweet!</p></div>
<p>It&#8217;s trivial to create an image like this &#8211; simply open up your base image, then add a triangle randomized copy over the top as a new layer.  Set the layer mode to &#8220;difference&#8221; and bam: stained glass!</p>
<div id="attachment_2319" class="wp-caption aligncenter" style="width: 646px"><a  rel="attachment wp-att-2319" href="http://www.tannerhelland.com/2306/stained-glass-image-effect/gow3-stained-glass-60/"><img class="size-full wp-image-2319" title="GoW3-stained-glass-60" src="http://www.tannerhelland.com/wp-content/uploads/2010/06/GoW3-stained-glass-60.jpg" alt="" width="636" height="333" /></a><p class="wp-caption-text">Same effect, but with a larger triangle size.</p></div>
<p>Other blending modes provide interesting effects &#8211; for example, multiply:</p>
<div id="attachment_2320" class="wp-caption aligncenter" style="width: 646px"><a  rel="attachment wp-att-2320" href="http://www.tannerhelland.com/2306/stained-glass-image-effect/gow3-multiply-30/"><img class="size-full wp-image-2320" title="GoW3-multiply-30" src="http://www.tannerhelland.com/wp-content/uploads/2010/06/GoW3-multiply-30.jpg" alt="" width="636" height="333" /></a><p class="wp-caption-text">Same two images as the first stained glass example - just the blending mode has changed.</p></div>
<p>Anyway, I thought this was an interesting exploration in using a randomized copy of an image as an overlay.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tannerhelland.com/2306/stained-glass-image-effect/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Generating Emboss / Engrave / Relief Filters (in VB6)</title>
		<link>http://www.tannerhelland.com/2225/generating-emboss-engrave-relief-filters-vb6/</link>
		<comments>http://www.tannerhelland.com/2225/generating-emboss-engrave-relief-filters-vb6/#comments</comments>
		<pubDate>Tue, 15 Jun 2010 02:07:18 +0000</pubDate>
		<dc:creator>Tanner</dc:creator>
				<category><![CDATA[Graphics Code]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[emboss]]></category>
		<category><![CDATA[engrave]]></category>
		<category><![CDATA[image processing]]></category>
		<category><![CDATA[relief]]></category>

		<guid isPermaLink="false">http://www.tannerhelland.com/?p=2225</guid>
		<description><![CDATA[Basic <em>emboss</em> and <em>engrave</em> filters are two of the simplest image processing features to implement. Both operate on the same principle - for each pixel, subtract the RGB values of one or more neighboring pixels in a particular direction. This leads to an image where low-contrast areas are all black, while high-contrast areas (edges) are varying colors of brighter intensity. Most emboss/engrave filters add 127 to the RGB values so that uniformly contrasted areas are gray.  I've added a "color" option to my implementation, so you can emboss/engrave an image to any hue. In the Bayonetta example above, the left side of the picture is embossed to something around #81a3fe...]]></description>
			<content:encoded><![CDATA[<div id="attachment_2226" class="wp-caption aligncenter" style="width: 632px"><a  rel="attachment wp-att-2226" href="http://www.tannerhelland.com/2225/generating-emboss-engrave-relief-filters-vb6/bayonetta_emboss/"><img class="size-full wp-image-2226" title="bayonetta_emboss" src="http://www.tannerhelland.com/wp-content/uploads/2010/06/bayonetta_emboss.jpg" alt="" width="622" height="352" /></a><p class="wp-caption-text">Bayonetta is quite possibly the best action game I&#39;ve ever played - yes, even better than God of War III</p></div>
<p>I&#8217;ve had this code ready for months, but I couldn&#8217;t bring myself to post it until I added something more exciting than just &#8220;emboss&#8221; and &#8220;engrave.&#8221;</p>
<p>Today is that day!</p>
<p>First, let me mention what emboss/engrave actually do.  These are two of the simplest image processing filters, and they can be efficiently implemented in pretty much any programming language.  They both operate on the same principle &#8211; for each pixel, subtract the RGB values of one or more neighboring pixels in a particular direction.  This leads to an image where low-contrast areas are all black, while high-contrast areas (edges) are varying colors of brighter intensity.  Most emboss/engrave filters add 127 to the RGB values so that uniformly contrasted areas are gray.  As a bonus feature, I&#8217;ve added a &#8220;color&#8221; option to this code, so you can emboss/engrave an image to any hue.  In the Bayonetta example above, the left side of the picture is embossed to something around #81a3fe.</p>
<p>Relief is a variation on emboss/engrave, where the base color is not artificially generated but is based off the current pixel.  This acts almost like a sharpen filter, but because the filter doesn&#8217;t operate in all directions, it lends the image a more artificial look.  (Hence the &#8220;relief&#8221; moniker &#8211; on certain images, it looks like an image has been chipped out of stone and then painted.)  Try it on a photo &#8211; they tend to work best!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tannerhelland.com/2225/generating-emboss-engrave-relief-filters-vb6/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Drawing the Mandelbrot Set / Fractal (in VB6)</title>
		<link>http://www.tannerhelland.com/1494/mandelbrot-vb6/</link>
		<comments>http://www.tannerhelland.com/1494/mandelbrot-vb6/#comments</comments>
		<pubDate>Fri, 26 Mar 2010 03:08:20 +0000</pubDate>
		<dc:creator>Tanner</dc:creator>
				<category><![CDATA[Graphics Code]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Fractals]]></category>
		<category><![CDATA[Mandelbrot Set]]></category>

		<guid isPermaLink="false">http://www.tannerhelland.com/?p=1494</guid>
		<description><![CDATA[Today's very cool project demonstrates a proof of concept implementation for rendering the famed Mandelbrot set (or "Mandelbrot fractal") using VB6.  It's a bit of a feat, since VB6 isn't exactly optimized for recursion-heavy calculations...but you know me.  I love making VB do things it was never meant to do!  :)]]></description>
			<content:encoded><![CDATA[<div id="attachment_1496" class="wp-caption aligncenter" style="width: 518px"><a  rel="attachment wp-att-1496" href="http://www.tannerhelland.com/1494/mandelbrot-vb6/mandelbrot_vb6/"><img class="size-large wp-image-1496" title="Mandelbrot_VB6" src="http://www.tannerhelland.com/wp-content/uploads/2010/03/Mandelbrot_VB6-508x600.png" alt="" width="508" height="600" /></a><p class="wp-caption-text">One possible view of the Mandelbrot set (generated with this project)</p></div>
<p>Today&#8217;s very cool project demonstrates a proof of concept implementation for rendering the famed Mandelbrot set (or &#8220;Mandelbrot fractal&#8221;) using VB6.  It&#8217;s a bit of a feat, since VB6 isn&#8217;t exactly optimized for recursion-heavy calculations&#8230;but you know me.  :)  I love making VB do things it was never meant to do!</p>
<p>I&#8217;m very happy with how the project turned out.  It may not be the fastest or prettiest or most accurate implementation (for example, at very high zoom-in you&#8217;ll start to see noticeable quality degradation), but I&#8217;ve  deliberately kept the project as short and sweet as possible to maximize adaptability and learning potential.</p>
<p>To enhance the experience, I&#8217;ve added several user-controlled options to help you get a feel for how the rendering works.  First is the scroll-bar at the top of the screen, which allows you to preferentially set speed or accuracy as the program&#8217;s objective.  (For those familiar with how the Mandelbrot set works, the scroll bar controls the &#8220;escape time&#8221; of the recursive function.)</p>
<p>Another neat option is a click-and-drag feature that allows you to draw new rendering boundaries.  This makes it simple to zoom as deep as you want into the fractal.</p>
<p>Finally, rather than a drab grayscale rendering, I&#8217;ve chosen a more purplish gradient.  The code can be easily modified to favor another color if you so choose.</p>
<p>The code is reasonably optimized, so a complete view should render within several seconds on most modern hardware.  If speed is a concern, note that the white areas of the image take the longest to process &#8211; so <strong>minimizing</strong> the amount of white you select will <strong>maximize</strong> render speed.  Also, due to the inherent limits of the &#8220;Double&#8221; type in VB6, if you zoom in really, really far the program may lock up.  (Simply click the close button to force-terminate the project if this happens.)</p>
<p>The download link can be found below these sample images.</p>
<div class="captionfull">
<a  rel="attachment wp-att-1499" href="http://www.tannerhelland.com/1494/mandelbrot-vb6/mandelbrot_vb6_4/"><img class="aligncenter size-full wp-image-1499" title="Mandelbrot_VB6_4" src="http://www.tannerhelland.com/wp-content/uploads/2010/03/Mandelbrot_VB6_4.png" alt="" width="602" height="602" /></a>
</div>
<div class="captionfull">
<a  rel="attachment wp-att-1500" href="http://www.tannerhelland.com/1494/mandelbrot-vb6/mandelbrot_vb6_5/"><img class="aligncenter size-full wp-image-1500" title="Mandelbrot_VB6_5" src="http://www.tannerhelland.com/wp-content/uploads/2010/03/Mandelbrot_VB6_5.png" alt="" width="603" height="602" /></a>
</div>
<div class="captionfull">
<a  rel="attachment wp-att-1501" href="http://www.tannerhelland.com/1494/mandelbrot-vb6/mandelbrot_vb6_6/"><img class="aligncenter size-full wp-image-1501" title="Mandelbrot_VB6_6" src="http://www.tannerhelland.com/wp-content/uploads/2010/03/Mandelbrot_VB6_6.png" alt="" width="602" height="603" /></a>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.tannerhelland.com/1494/mandelbrot-vb6/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Artificial Life Simulator (in VB6)</title>
		<link>http://www.tannerhelland.com/1399/artificial-life-simulator-vb6/</link>
		<comments>http://www.tannerhelland.com/1399/artificial-life-simulator-vb6/#comments</comments>
		<pubDate>Tue, 22 Dec 2009 06:09:11 +0000</pubDate>
		<dc:creator>Tanner</dc:creator>
				<category><![CDATA[Bioinformatics]]></category>
		<category><![CDATA[Game Code]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[AI]]></category>

		<guid isPermaLink="false">http://www.tannerhelland.com/?p=1399</guid>
		<description><![CDATA[Here you have it: the largest, most complex programming project now available on tannerhelland.com. Originally a final project for a university bioinformatics course, this artificial life simulator has now been completely retooled as a full-blown lesson in evolution and population genetics.  As with most artificial life simulators, a set of simple artificial creatures compete for limited resources.  Each creature has a strand of pseudo-DNA that determines three basic attributes: size, speed, and range (how far it can see)...]]></description>
			<content:encoded><![CDATA[<div class="captionfull"><a  rel="attachment wp-att-1398" href="http://www.tannerhelland.com/1399/artificial-life-simulator-vb6/artificial_life/"><img class="aligncenter size-large wp-image-1398" title="Artificial_Life" src="http://www.tannerhelland.com/wp-content/uploads/2009/12/Artificial_Life-600x467.png" alt="This is what the Artificial Life Simulator looks like in action" width="600" height="467" /></a></div>
<p><strong>The Short Description:</strong></p>
<p>Here you have it: the largest, most complex programming project now available on tannerhelland.com.  Originally a final project for a university bioinformatics course, my artificial life simulator has now been completely retooled as a full-blown lesson in evolution and population genetics.</p>
<p>As with most artificial life simulators, a set of simple artificial creatures compete for limited resources.   Each creature has a strand of pseudo-DNA that determines three basic attributes: size, speed, and range (how far it can see).  When the little critters reproduce (asexually&#8230; unfortunately), mutations may occur.  Over time, this can lead to remarkable changes in gene frequency throughout the population.  Typically the creatures with a balance of speed and range tend to win out over bigger, slower creatures and smaller, faster ones.</p>
<p>The code is well-optimized, so it should run decently on any hardware.   As a bonus, the simulator can be surprisingly addicting &#8211; my longest simulation to date ran for over 500,000 cycles before all the creatures died.   For further analysis of a particular simulation run, all data can be saved to a tab-delimited text file compatible with any major spreadsheet software.</p>
<p><strong>The Long Description:</strong></p>
<p>As you can imagine, a project of this magnitude warrants a fair amount of documentation.  I am currently working on a <em>&#8220;how to use this software to teach evolution and population genetics&#8221;</em> tutorial that educators &#8211; or anyone interested in biology &#8211; can read to see how things like genetic drift, population equilibrium, the &#8220;bottleneck&#8221; effect, and other aspects of a small, closed population work.</p>
<p>Unfortunately, a document like that takes some time to create&#8230; so rather than holding off until I&#8217;ve finished it, I&#8217;ve decided to upload the project for people to start playing with.  If you have any comments or questions, let me know and I&#8217;ll see if I can&#8217;t work answers into the final version of the tutorial.</p>
<p>(If you&#8217;d like to be notified when the documentation is finished, please let me know via the <a  href="http://www.tannerhelland.com/contact/" target="_blank">contact form</a>.  I plan on sending out an email once all updates have been posted.)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tannerhelland.com/1399/artificial-life-simulator-vb6/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Hidden Markov Models, the Viterbi Algorithm, and CpG Islands (in VB6)</title>
		<link>http://www.tannerhelland.com/1187/hidden-markov-models-viterbi-algorithm-cpg-islands-in-vb6/</link>
		<comments>http://www.tannerhelland.com/1187/hidden-markov-models-viterbi-algorithm-cpg-islands-in-vb6/#comments</comments>
		<pubDate>Tue, 18 Aug 2009 02:08:09 +0000</pubDate>
		<dc:creator>Tanner</dc:creator>
				<category><![CDATA[Bioinformatics]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Hidden Markov models]]></category>
		<category><![CDATA[HMM]]></category>
		<category><![CDATA[science is cool]]></category>
		<category><![CDATA[Viterbi algorithm]]></category>

		<guid isPermaLink="false">http://www.tannerhelland.com/?p=1187</guid>
		<description><![CDATA[Today's project is something new to this site - bioinformatics code!  I feel a tad ridiculous that it's taken me so many years to post code related to my field, but hey - better late than never. Read on to discover the awesomeness of Hidden Markov models, the Viterbi algorithm (also known as Viterbi paths), CpG islands, and how these all work together to help scientists locate genes.]]></description>
			<content:encoded><![CDATA[<div id="attachment_1188" class="wp-caption aligncenter" style="width: 480px"><a  href="http://commons.wikimedia.org/wiki/File:3D-SIM-4_Anaphase_3_color.jpg"><img class="size-full wp-image-1188" title="3D-SIM-4_Anaphase_3_color" src="http://www.tannerhelland.com/wp-content/uploads/2009/08/3D-SIM-4_Anaphase_3_color.jpg" alt="Anaphase, courtesy of Lothar Schermelleh" width="470" height="356" /></a><p class="wp-caption-text">Anaphase, courtesy of Lothar Schermelleh</p></div>
<p>Today&#8217;s project is something new to this site &#8211; bioinformatics code!  It&#8217;s unfortunate that it&#8217;s taken me several years to post code related to my field, but hey &#8211; better late than never.  (That seems to be a <a  href="http://www.tannerhelland.com/philosophy/affirmations-skepticism/">recurring</a> <a  href="http://www.tannerhelland.com/site-news/sharing-is-good/">theme</a> on this site&#8230;)</p>
<p>First, a primer.  If you don&#8217;t know what the title of this article references, here are some Wikipedia links to get you started:</p>
<p><a  href="http://en.wikipedia.org/wiki/Hidden_Markov_model" target="_blank">Hidden Markov models (including some examples in Python)</a></p>
<p><a  href="http://en.wikipedia.org/wiki/Viterbi_path" target="_blank">Viterbi algorithm / Viterbi paths (including even more Python examples)</a></p>
<p><a  href="http://en.wikipedia.org/wiki/CpG_islands" target="_blank">CpG islands</a></p>
<p>As a bonus, I&#8217;m including sections from my original write-up on this program (it began as a university project) to help explain the purpose and design of my code.</p>
<p>The algorithm implementations are quite fast, and the visual feedback is a big improvement over traditional command-line tools. I&#8217;ve also included a FASTA file with data from chromosome #1 in the human genome (bases 6000-12000, I believe), which you can use to test the project.</p>
<p><em>(FYI, my original lab assignment link is here: <a  href="http://dna.cs.byu.edu/bio465/Labs/hmm.shtml" target="_blank">http://dna.cs.byu.edu/bio465/Labs/hmm.shtml</a>.  It contains quite a bit of helpful information and links if you&#8217;re looking to write your own HMM implementation.)</em></p>
<p><em>(FYI #2, this project has been cited in the following paper:<a  title="Correlating CpG islands, motifs, and sequence variants in human chromosome 21" href="http://www.biomedcentral.com/1471-2164/12/S2/S10"> Spontaneo L, Cercone N. Correlating CpG islands, motifs, and sequence variants in human chromosome 21. 2011. BMC Genomics 12(Suppl 2):S10</a>.  I recommend it to anyone seeking a more in-depth explanation of this code.)</em></p>
<p><strong>INTRODUCTION</strong></p>
<p>CpG islands are regions of DNA characterized by a large number of adjacent cytosine and guanine nucletoides linked by phosphodiester bonds. Additionally, CpG islands appear in some 70% of promoters of human genes (40% of mammalian genes). Unlike CpG sites in the coding region of a gene, in most instances the CpG sites in CpG islands are unmethylated if genes are expressed. This observation led to the speculation that methylation of CpG sites in the promoter of a gene may inhibit the expression of a gene. (Wikipedia, retrieved Feb 2007)</p>
<p>This project uses a Hidden Markov model to define the relationship between normal states (B) and island states (I) within a region of the human chromosome. Such an implementation is useful for gene finding, as CpG islands tend to appear near the promoters of important mammalian genes. The automation of this process is critical because such islands are impossible to locate by simply looking at a strand of DNA; they may cover several hundred bases and their C/G content may be only slightly higher than expected values.</p>
<p><strong>PROCEDURE</strong></p>
<p>This project is coded in the Microsoft Visual Basic 6.0 programming language. VB6 provides a relevant blend of native-code processing speed (allowing fast implementation of the HMM and associated visualizations) and a simple, flexible GUI. Visual feedback is a key element of this process, as finding CpG islands using HMMs may require some some experimentation with input values to maximize efficiency and accuracy of the algorithm. To my knowledge, previous implementations of HMM-based CpG detection code have been command-line only, making this visual implementation first of its kind. <em>(Additional note: if you are a Linux user, please note that this project works flawlessly under Wine 1.1.27, and likely earlier versions as well.)</em></p>
<p>I will refer to the following screenshot as I walk through my implementation of a HMM.</p>
<div class="captionfull"><img class="aligncenter size-large wp-image-1189" title="HMM_screenshot" src="http://www.tannerhelland.com/wp-content/uploads/2009/08/HMM_screenshot-600x401.png" alt="HMM_screenshot" width="600" height="401" /></div>
<p><span style="text-decoration: underline;">Step 1: Loading a FASTA file</span><br />
This routine isn’t of much interest, except to mention a programming quirk particular to VB6. A, C, G, and T entries from the FASTA file are reassigned into a byte array as the numbers 0, 1, 2, and 3. In VB6, number comparison and processing is generally faster than string comparison and processing.<em> (Additional note: to any VB experts reading this &#8211; please note that I am aware of mechanisms for overcoming this limitation, but such solutions are cumbersome compared to simply rebuilding the FASTA file as a byte array.)</em></p>
<p><span style="text-decoration: underline;">Step 2: HMM Parameters</span><br />
The GUI allows the user to change 14 HMM-related parameters. Additionally, I have added an option to let the program estimate the eight state probabilities. This is a trivial computation to perform, but it helps increase the accuracy of the algorithm. The estimation of A, C, G and T&#8217;s being emitted in a B state is computed by the percentage of occurrences of each of these entries in the original FASTA data. I predict that given the low percentage of I states in a length of DNA, this method of estimating emission probabilities is relatively accurate.</p>
<p>Once these probabilities have been estimated, the I state probabilities are estimated by doubling C and G probabilities and halving the A and T probabilities.</p>
<p><span style="text-decoration: underline;">Step 3: The HMM and Viterbi algorithms</span><br />
This step begins by moving all HMM parameters into look-up tables. The logs of these values are pre-calculated, allowing us to add them (instead of multiplying) for fast HMM calculations.</p>
<p>Next, all HMM probabilities are calculated and stored.</p>
<p>This is followed by a second loop run backward through the data that calculates all data necessary for the Viterbi algorithm.<em> (Additional note: this is not necessarily the most efficient way to do this, but the speed difference is negligible for sequences less than 100,000 bases long.)</em></p>
<p>After all Viterbi data has been pre-calculated, the traceback part of the Viterbi algorithm can be run very quickly.<em> (Additional note: execution speed of this chunk of code is slightly reduced because I translate the states into a string and display that string in the textbox in the upper-right of the program window. This is mainly for convenience and satisfying curiosity. If speed is your goal, it is trivial to disable this part of the code.)</em></p>
<p><span style="text-decoration: underline;">Step 4: The Sliding Window</span><br />
This step is where visual feedback becomes an essential component. In this project, I have chosen to display two graphs built from the HMM data; the top graph displays raw counts of C and G occurrences as compared to the expected value (where 0.5 is used as the expected ratio). The bottom graph displays the ratio of I and B states, and it is this data that is used to predict the location of any CpG islands.</p>
<p>A noteworthy shortcoming of this implementation is that it is designed to only find the <em>most </em>probable CpG island (instead of multiple islands). In a more formal implementation, returning any/all potential CpG island locations would be more useful.</p>
<p><em>(Additional note: this step is my favorite part of the program. I find it to be well-implemented and surprisingly graphically pleasing for a bioinformatics tool. :)</em></p>
<p><strong>RESULTS</strong><br />
By my estimation, the program&#8217;s most accurate CpG prediction for this FASTA file is bases 2018-2045 (which corresponds to bases 6018-6045 in the original data, I believe). Multiple runs with varying parameters generate similar estimates. Adjusting the sliding window size doesn&#8217;t have a large effect on the estimates, although larger windows will unsurprisingly result in larger CpG island predictions. The percentage of I states varies dramatically; certain parameters result in levels as high as 30-40% while others are less than 5%. For my best estimate (above), the percentage of I states was 22%.</p>
<p>Finally, code execution is swift &#8211; typically a matter of seconds &#8211; and if the text display in the top-right is disabled the program runs more-or-less instantaneously on modern hardware.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tannerhelland.com/1187/hidden-markov-models-viterbi-algorithm-cpg-islands-in-vb6/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Sepia / “Antique” Image Effect (in VB6)</title>
		<link>http://www.tannerhelland.com/1138/sepia-antique-effect-vb6/</link>
		<comments>http://www.tannerhelland.com/1138/sepia-antique-effect-vb6/#comments</comments>
		<pubDate>Tue, 04 Aug 2009 02:23:31 +0000</pubDate>
		<dc:creator>Tanner</dc:creator>
				<category><![CDATA[Graphics Code]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[graphics programming]]></category>
		<category><![CDATA[Photoshop]]></category>

		<guid isPermaLink="false">http://www.tannerhelland.com/?p=1138</guid>
		<description><![CDATA[I'm guessing you've seen this style of image before - a sort of pseudo-antique filter than can make any image look like it was taken with a very old camera.  There are many ways to programmatically generate images like this, and in this article I've put together one that does more than just make the image look "brown."  This filter involves several steps (fading, multiplicative brightness, and gamma correction, among others) and results in a conversion that not only adds a sepia coloring, but also gives an image a histogram more in keeping with older photos.]]></description>
			<content:encoded><![CDATA[<div class="captionfull">
<div id="attachment_1141" class="wp-caption aligncenter" style="width: 480px"><img class="size-full wp-image-1141" title="Sepia_Big_Bang_Theory" src="http://www.tannerhelland.com/wp-content/uploads/2009/08/Sepia_Big_Bang_Theory.jpg" alt="&quot;Antiquified&quot; version of a BBT promo photo" width="470" height="353" /><p class="wp-caption-text">&quot;Antiquified&quot; version of a BBT promo photo</p></div>
</div>
<p>I&#8217;m guessing you&#8217;ve seen this style of image before &#8211; a sort of pseudo-antique filter than can make any photo look like it was taken with a very old camera (or even a <a  href="http://en.wikipedia.org/wiki/Daguerreotype" target="_blank">daguerreotype</a> &#8211; how&#8217;s that for a cool word?).  There are many ways to programmatically generate images like this, and in this article I&#8217;ve put together one that does more than just make the image look &#8220;brown.&#8221;  This filter involves several steps (fading, multiplicative brightness, and gamma correction, among others) and results in a conversion that not only adds a sepia coloring, but also gives an image a histogram more in keeping with older photos.</p>
<p>As with all graphics code on this site, the algorithm is fast enough to be applied in real-time.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tannerhelland.com/1138/sepia-antique-effect-vb6/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Nature-Inspired Image Filters (in VB6)</title>
		<link>http://www.tannerhelland.com/1118/nature-inspired-image-effects-vb6/</link>
		<comments>http://www.tannerhelland.com/1118/nature-inspired-image-effects-vb6/#comments</comments>
		<pubDate>Tue, 07 Jul 2009 00:22:21 +0000</pubDate>
		<dc:creator>Tanner</dc:creator>
				<category><![CDATA[Graphics Code]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[graphics programming]]></category>
		<category><![CDATA[Photoshop]]></category>

		<guid isPermaLink="false">http://www.tannerhelland.com/?p=1118</guid>
		<description><![CDATA[Today's article brings a collection of random image effects that can be quickly (and programmatically) generated. In an attempt to give the project some coherency, I've named each effect after something "nature-themed" so as to help distinguish them.  As always, full source code and a sample .exe is provided...]]></description>
			<content:encoded><![CDATA[<p>Today&#8217;s article brings a collection of random image effects that can be quickly (and programmatically) generated.  In an attempt to give the project some coherency, I&#8217;ve named each effect after something &#8220;nature-themed&#8221; so as to help distinguish them.</p>
<p>Below, you can see how each filter looks on a promotional image from <a  href="http://en.wikipedia.org/wiki/Final_Fantasy_Versus_XIII" target="_blank"><em>Final Fantasy Versus XIII</em></a>.</p>
<p>Original:</p>
<div class="captionfull">
<div id="attachment_1115" class="wp-caption aligncenter" style="width: 610px"><img class="size-large wp-image-1115" title="FFVS13" src="http://www.tannerhelland.com/wp-content/uploads/2009/07/FFVS13-600x337.jpg" alt="Final Fantasy Versus XIII" width="600" height="337" /><p class="wp-caption-text">Final Fantasy Versus XIII</p></div>
</div>
<p>Atmosphere:</p>
<div class="captionfull">
<div id="attachment_1116" class="wp-caption aligncenter" style="width: 610px"><img class="size-large wp-image-1116" title="FFVS13_Atmosphere" src="http://www.tannerhelland.com/wp-content/uploads/2009/07/FFVS13_Atmosphere-600x337.jpg" alt="Final Fantasy Versus XIII - Atmosphere Effect" width="600" height="337" /><p class="wp-caption-text">Final Fantasy Versus XIII - Atmosphere Effect</p></div>
</div>
<p>Burn:</p>
<div class="captionfull">
<div id="attachment_1117" class="wp-caption aligncenter" style="width: 610px"><img class="size-large wp-image-1117" title="FFVS13_Burn" src="http://www.tannerhelland.com/wp-content/uploads/2009/07/FFVS13_Burn-600x337.jpg" alt="Final Fantasy Versus XIII - Burn Effect" width="600" height="337" /><p class="wp-caption-text">Final Fantasy Versus XIII - Burn Effect</p></div>
</div>
<p>Fog:</p>
<div class="captionfull">
<div id="attachment_1119" class="wp-caption aligncenter" style="width: 610px"><img class="size-large wp-image-1119" title="FFVS13_Fog" src="http://www.tannerhelland.com/wp-content/uploads/2009/07/FFVS13_Fog-600x337.jpg" alt="Final Fantasy Versus XIII - Fog Effect" width="600" height="337" /><p class="wp-caption-text">Final Fantasy Versus XIII - Fog Effect</p></div>
</div>
<p>Freeze:</p>
<div class="captionfull">
<div id="attachment_1120" class="wp-caption aligncenter" style="width: 610px"><img class="size-large wp-image-1120" title="FFVS13_Freeze" src="http://www.tannerhelland.com/wp-content/uploads/2009/07/FFVS13_Freeze-600x337.jpg" alt="Final Fantasy Versus XIII - Freeze Effect" width="600" height="337" /><p class="wp-caption-text">Final Fantasy Versus XIII - Freeze Effect</p></div>
</div>
<p>Lava:</p>
<div class="captionfull">
<div id="attachment_1121" class="wp-caption aligncenter" style="width: 610px"><img class="size-large wp-image-1121" title="FFVS13_Lava" src="http://www.tannerhelland.com/wp-content/uploads/2009/07/FFVS13_Lava-600x337.jpg" alt="Final Fantasy Versus XIII - Lava Effect" width="600" height="337" /><p class="wp-caption-text">Final Fantasy Versus XIII - Lava Effect</p></div>
</div>
<p>Ocean:</p>
<div class="captionfull">
<div id="attachment_1122" class="wp-caption aligncenter" style="width: 610px"><img class="size-large wp-image-1122" title="FFVS13_Ocean" src="http://www.tannerhelland.com/wp-content/uploads/2009/07/FFVS13_Ocean-600x337.jpg" alt="Final Fantasy Versus XIII - Ocean Effect" width="600" height="337" /><p class="wp-caption-text">Final Fantasy Versus XIII - Ocean Effect</p></div>
</div>
<p>Rainbow:</p>
<div class="captionfull">
<div id="attachment_1123" class="wp-caption aligncenter" style="width: 610px"><img class="size-large wp-image-1123" title="FFVS13_Rainbow" src="http://www.tannerhelland.com/wp-content/uploads/2009/07/FFVS13_Rainbow-600x337.jpg" alt="Final Fantasy Versus XIII - Rainbow Effect" width="600" height="337" /><p class="wp-caption-text">Final Fantasy Versus XIII - Rainbow Effect</p></div>
</div>
<p>Metal:</p>
<div class="captionfull">
<div id="attachment_1124" class="wp-caption aligncenter" style="width: 610px"><img class="size-large wp-image-1124" title="FFVS13_Metal" src="http://www.tannerhelland.com/wp-content/uploads/2009/07/FFVS13_Steel-600x337.jpg" alt="Final Fantasy Versus XIII - Metal Effect" width="600" height="337" /><p class="wp-caption-text">Final Fantasy Versus XIII - Metal Effect</p></div>
</div>
<p>Underwater:</p>
<div class="captionfull">
<div id="attachment_1125" class="wp-caption aligncenter" style="width: 610px"><img class="size-large wp-image-1125" title="FFVS13_Water" src="http://www.tannerhelland.com/wp-content/uploads/2009/07/FFVS13_Water-600x337.jpg" alt="Final Fantasy Versus XIII - Underwater Effect" width="600" height="337" /><p class="wp-caption-text">Final Fantasy Versus XIII - Underwater Effect</p></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.tannerhelland.com/1118/nature-inspired-image-effects-vb6/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

