<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" gd:etag="W/&quot;DEEFQnwzfyp7ImA9WhRQEUQ.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613</id><updated>2011-12-06T10:36:53.287-08:00</updated><category term="randomness" /><category term="Steganography" /><category term="Lang_Javascript" /><category term="Lang_F#" /><category term="copy-move forgery" /><category term="Pi" /><category term="Lang_Python" /><category term="implosion" /><category term="Sieve of eratosthenes" /><category term="eval" /><category term="contrast detection" /><category term="game theory" /><category term="Lang_J" /><category term="Lang_C#" /><category term="Lang_C" /><category term="information entropy" /><category term="evolution strategy" /><category term="game development" /><category term="vigenere cipher" /><category term="2D graphics" /><category term="Lang_C++" /><category term="Google codejam contest" /><category term="Heat vision" /><category term="Langton's ant" /><category term="IBM ponder this" /><category term="probability theory" /><category term="Binary filter" /><category term="sudoku solver" /><category term="Self-projection" /><category term=".net" /><category term="Project Euler" /><category term="iPhone games" /><category term="Fog" /><category term="gradient" /><category term="Hough transform" /><category term="edge detection" /><category term="digital image forensic" /><category term="Cel Shader" /><category term="codegolf" /><category term="ellipse detection" /><category term="polygon" /><category term="traveler's dilemma" /><category term="Pixel Shader" /><category term="Frosted glass" /><category term="cellular automaton" /><category term="Toon Shader" /><category term="Fractals" /><category term="Pixelation" /><category term="Thermal vision" /><category term="transfer function" /><category term="chart" /><category term="Convolution" /><category term="array programming language" /><category term="Explosion" /><category term="geometry" /><category term="multi-core cpu" /><category term="selfish gene algorithm" /><category term="math expressions" /><category term="Dijkstra's algorithm" /><category term="parallel extensions" /><category term="number of runs" /><category term="Lang_Lua" /><category term="Prime numbers" /><category term="reversing number" /><category term="Sharpness" /><category term="image processing" /><category term="Gaussian blur" /><category term="Emboss" /><category term="DirectX" /><category term="Lang_Objective-C" /><category term="XNA Framework" /><title>Coding experiments</title><subtitle type="html">Coding diary of Agnius Vasiliauskas</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>52</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/Coding-experiments" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="coding-experiments" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;CUABRHcyfCp7ImA9WhdbEEw.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-8735270346209416444</id><published>2011-10-06T10:52:00.000-07:00</published><updated>2011-10-07T11:55:55.994-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-07T11:55:55.994-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Lang_Objective-C" /><category scheme="http://www.blogger.com/atom/ns#" term="game development" /><category scheme="http://www.blogger.com/atom/ns#" term="iPhone games" /><title>iPhone game "Pong Hau K'i" source code</title><content type="html">Have you ever had a dream to write an iPhone board game and wondered where to start from ? Or maybe you wanted some simplistic iPhone game source code to look at and learn from ? Now you have a good opportunity to solve that problem . I've decided to publish my iPhone board game &lt;a href="http://www.1888freeonlinegames.com/iphonegames/pong-hau-k-i-7228.html"&gt;Pong Hau K'i&lt;/a&gt;&lt;br&gt; &lt;a href="https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0BwrFeS7BioZiOWE3MTIyMmYtMGJlNy00MGRhLWEwYWMtYjRkMDdhODlhN2Nk&amp;hl=en_US"&gt;source code &amp; assets&lt;/a&gt;.  Use it for any purpose you wish - be it personal / educational or commercial use ...

HTH !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-8735270346209416444?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/WMhYDd9BaFo6rfQMc1iUT16fnMY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/WMhYDd9BaFo6rfQMc1iUT16fnMY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/WMhYDd9BaFo6rfQMc1iUT16fnMY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/WMhYDd9BaFo6rfQMc1iUT16fnMY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/8735270346209416444/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2011/10/pong-hau-ki-source-code.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/8735270346209416444?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/8735270346209416444?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2011/10/pong-hau-ki-source-code.html" title="iPhone game &quot;Pong Hau K'i&quot; source code" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DEMMQnk-fCp7ImA9WhZVFEU.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-8070906288658271071</id><published>2011-05-27T01:39:00.000-07:00</published><updated>2011-05-27T01:54:43.754-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-27T01:54:43.754-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ellipse detection" /><category scheme="http://www.blogger.com/atom/ns#" term="Hough transform" /><category scheme="http://www.blogger.com/atom/ns#" term="image processing" /><category scheme="http://www.blogger.com/atom/ns#" term="Lang_Python" /><title>Ellipse detection in image by using Hough transform</title><content type="html">How we can detect ellipses in images ? One way is to use &lt;a href="http://en.wikipedia.org/wiki/Hough_transform"&gt;Hough transform&lt;/a&gt;. I will use Hough transform algorithm variant created by &lt;a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.1.8792&amp;rep=rep1&amp;type=pdf"&gt;Yonghong Xie and Qiang Ji&lt;/a&gt;. That algorithm pseudo-code:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;1. Store all edge pixels in a one dimensional array.
2. Clear the accumulator array.
3. For each pixel (x1, y1), carry out the following steps from (4) to (14).
   4. For each other pixel (x2, y2), if the distance between
   (x1, y1) and (x2, y2) is greater than the required least
   distance for a pair of pixels to be considered then
   carry out the following steps from (5) to (14).
      5. From the pair of pixels (x1, y1) and (x2, y2) calculate the center,
      orientation and length of major axis for the assumed ellipse.
      6. For each third pixel (x, y), if the distance between
      (x, y) and (x0, y0) is greater than the required least
      distance for a pair of pixels to be considered then
      carry out the following steps from (7) to (9).
         7. Calculate the length of minor axis.
         8. Increment the accumulator for this length of minor axis by 1.
         9. Loop until all pixels are computed for this pair of pixels.
      10. Find the maximum element in accumulator array. The
      related length is the possible length of minor axis
      for assumed ellipse. If the vote is greater than the
      required least number for assumed ellipse, one
      ellipse is detected.
      11. Output ellipse parameters.
      12. Remove the pixels on the detected ellipse from edge pixel array.
      13. Clear accumulator array.
      14. Loop until all pairs of pixels are computed.
&lt;/pre&gt;&lt;br /&gt;
Proof-of-concept algorithm implementation in Python:&lt;hr&gt;&lt;pre style="color:green"&gt;import sys
from PIL import Image,ImageFilter, ImageDraw
from math import *

# some global constants
EL_COVERAGE_RATIO = 0.9
EL_VERIFICATION_DISTANCE = 1.
EL_PATH_POINTS = 51
MIN_MINOR_FREQUENCY = 30
MIN_HALF_MAJOR = 8
MIN_HALF_MINOR = 6

def distance(p1,p2):
 x1,y1 = p1
 x2,y2 = p2
 return sqrt((x1-x2)**2 + (y1-y2)**2)

def nonnegative(v):
 return v if v &gt;= 0 else 0

def parametricEllipse(center, a, b, angle):
 xc,yc = center
 elx = lambda t: xc + a * cos(t) * cos(angle) - b * sin(t) * sin(angle)
 ely = lambda t: yc + a * cos(t) * sin(angle) + b * sin(t) * cos(angle)
 return [(int(elx(2.*pi*x/float(EL_PATH_POINTS-1))),int(ely(2.*pi*x/float(EL_PATH_POINTS-1)))) for x in range(EL_PATH_POINTS)]

assert len(sys.argv)!=2, "missing input and/or output file !"

im = Image.open(sys.argv[1])
width, height = im.size
io = Image.new('RGB',(width, height),(255,255,255))
draw = ImageDraw.Draw(io)

# converting image to grayscale
im = im.convert('L')

# detecting edge pixels
im = im.filter(ImageFilter.FIND_EDGES)

# converting to binary image
im = im.convert('1')
pixels = im.load()
pxy = []

# extracting binary pixels coordinates
for x in range(width):
 for y in range(height):
  if pixels[x,y]==255:
   pxy.append((x,y))

# applying Hough transform for ellipses detection.
# algorithm is taken from this paper:
# http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.1.8792&amp;rep=rep1&amp;type=pdf
cIx = -1
colors = [(255,0,0),(0,200,0),(0,0,255)]
for x1,y1 in pxy:
  for x2,y2 in pxy:
    bbins = {}
    dist = distance((x1,y1),(x2,y2))
    if dist &gt;= 2*MIN_HALF_MAJOR:
     cent = ((x1+x2)/2.,(y1+y2)/2.)
     a = dist/2. # semi-length of major axis
     alfa = atan2((y2 - y1),(x2 - x1))
     for rx,ry in pxy:
      d = distance((rx,ry),cent)
      if d &gt;= MIN_HALF_MINOR:
       f = distance((rx,ry),(x2,y2))
       cost = (a**2. + d**2. - f**2.)/(0.00001+2.*a*d)
       b = sqrt(nonnegative((a**2. * d**2. * (1.-cost**2.))/(0.00001 + a**2. - d**2. * cost**2.)))  # semi-length of minor axis
       b = int(b)
       if bbins.has_key(b):
        bbins[b]+=1
       elif b &gt; 0:
        bbins[b]=1
     bbins_rev = dict([(v,k) for k,v in bbins.iteritems()])
     max_freq = max(bbins_rev.keys())
     bmax = bbins_rev[max_freq]
     # Did we found probable ellipse ?
     if max_freq &gt;= MIN_MINOR_FREQUENCY and alfa &gt;=0.0 and bmax &gt;= MIN_HALF_MINOR:
      elData = parametricEllipse(cent, a, bmax, alfa)
      supported = []
      supportRatio = 0.0
      # counting how much pixels lies on ellipse path
      for i in range(EL_PATH_POINTS):
       elx,ely = elData[i]
       added = False
       for x,y in pxy:
        if distance((elx,ely),(x,y)) &lt;= EL_VERIFICATION_DISTANCE:
         supported.append((x,y))
         if not added:
          supportRatio += 1./float(EL_PATH_POINTS)
          added = True
      supported = list(set(supported))
      # if number of pixels on ellipse path is big enough
      if supportRatio &gt;= EL_COVERAGE_RATIO:
       cIx = (cIx+1)%3
       print "coverage %.2f" % supportRatio,"frequency ", max_freq, "center ", cent, "angle %.2f" % alfa, "axes (%.2f,%.2f)" % (a, bmax)
       # removing founded ellipse pixels from further analysis
       for p in supported:
        pxy.remove(p)
       # drawing founded ellipse
       for i in range(EL_PATH_POINTS):
        elx,ely = elData[i]
        if i &lt; EL_PATH_POINTS-1:
         draw.line(elData[i] + elData[i+1], fill=colors[cIx])
io.save(sys.argv[2])
print "***************************************************************"
print "************************** DONE *******************************"
print "***************************************************************"
&lt;/pre&gt;&lt;hr&gt;(Prototype algorithm is slow, tested only on 50x50 images). So, by running this algo on this image:
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-0tIJbp27Q1I/Td9h95rFE-I/AAAAAAAAARA/MGg-k2Y6x-8/s1600/atom.jpg" imageanchor="1" style=""&gt;&lt;img border="0" height="50" width="50" src="http://2.bp.blogspot.com/-0tIJbp27Q1I/Td9h95rFE-I/AAAAAAAAARA/MGg-k2Y6x-8/s400/atom.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;we will get such algorithm output:
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-KREri3aXdAE/Td9iLy0FHEI/AAAAAAAAARI/rvysi2Ihef0/s1600/out.png" imageanchor="1" style=""&gt;&lt;img border="0" height="50" width="50" src="http://2.bp.blogspot.com/-KREri3aXdAE/Td9iLy0FHEI/AAAAAAAAARI/rvysi2Ihef0/s400/out.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Have fun in computer vision !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-8070906288658271071?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/9sFrUwsfohWB8zKcZg2-WiVpFYU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/9sFrUwsfohWB8zKcZg2-WiVpFYU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/9sFrUwsfohWB8zKcZg2-WiVpFYU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/9sFrUwsfohWB8zKcZg2-WiVpFYU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/8070906288658271071/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2011/05/ellipse-detection-in-image-by-using.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/8070906288658271071?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/8070906288658271071?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2011/05/ellipse-detection-in-image-by-using.html" title="Ellipse detection in image by using Hough transform" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-0tIJbp27Q1I/Td9h95rFE-I/AAAAAAAAARA/MGg-k2Y6x-8/s72-c/atom.jpg" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;D08MRHw6fCp7ImA9WhZXFks.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-4096821614816885384</id><published>2011-05-06T00:11:00.000-07:00</published><updated>2011-05-06T00:11:25.214-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-06T00:11:25.214-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Lang_Javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="transfer function" /><category scheme="http://www.blogger.com/atom/ns#" term="gradient" /><title>Gradient transfer function</title><content type="html">Suppose we need to draw linear gradient, but in a way which lets us to control color distribution between gradient parts. How to do that ? Answer is - gradient transfer function.&lt;br /&gt;
&lt;br /&gt;
Algorithm is this:&lt;br /&gt;
1. Extract pixel's relative distance [0..1] from the start of gradient.&lt;br /&gt;
2. Update this distance by feeding it to gradient transfer function.&lt;br /&gt;
3. Blend source color with target color using updated distance as blend ratio.&lt;br /&gt;
4. Set calculated color to pixel.&lt;br /&gt;
&lt;br /&gt;
We will use such gradient transfer function:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-D9g6fTjRuRg/TcOU9AUsvtI/AAAAAAAAAQI/JbwaMbmS4lc/s1600/TransferFunction.gif" imageanchor="1" style=""&gt;&lt;img border="0" height="29" width="285" src="http://2.bp.blogspot.com/-D9g6fTjRuRg/TcOU9AUsvtI/AAAAAAAAAQI/JbwaMbmS4lc/s400/TransferFunction.gif" /&gt;&lt;/a&gt;&lt;/div&gt;where x is pixel's relative distance from the start and a,b are some adjustable parameters.&lt;br /&gt;
&lt;br /&gt;
Below is Javascript implementation of this method (your browser must support HTML5 canvas element). You can try to change a,b parameters of transfer function and see what happens to gradient.&lt;script type="text/javascript" src="http://coding-experiments.googlecode.com/svn/trunk/Javascript/jquery.js"&gt;&lt;/script&gt; &lt;br /&gt;
&lt;script type="text/javascript" src="http://coding-experiments.googlecode.com/svn/trunk/Javascript/jquery.flot.js"&gt;&lt;/script&gt; &lt;br /&gt;
&lt;script type="text/javascript" src="http://coding-experiments.googlecode.com/svn/trunk/Javascript/gradTransfer.js"&gt;&lt;/script&gt; &lt;br /&gt;
&lt;br /&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;
&lt;b&gt;a&lt;/b&gt; &lt;input id="rngNonlinearity" type="range" min="0.0" max="1.01" value="0.5" step="0.01" onchange="showValue(this.value,'Nonlinearity')" /&gt;&lt;span id="Nonlinearity"&gt;0.5&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;b&lt;/b&gt; &lt;input id="rngAbruptness" type="range" min="5.0" max="20.00" value="5.00" step="0.01" onchange="showValue(this.value,'Abruptness')" /&gt;&lt;span id="Abruptness"&gt;5.00&lt;/span&gt;&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
&lt;div style="position: relative;"&gt;  &lt;div id="placeholder" style="width:300px; height:300px; "&gt;&lt;/div&gt;  &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;canvas id="canvasGrad" width="274" height="50"
          style="position: absolute; left: 22; top: 305; z-index: 1; border: 1px solid #000000; background-color: #EEEEEE;"&gt;&lt;br /&gt;
  Sorry, canvas not supported!&lt;br /&gt;
  &lt;/canvas&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;!-- On Load --&gt;&lt;br /&gt;
&lt;script type="text/javascript"&gt; $(GeneratePlot()); &lt;/script&gt; &lt;br /&gt;
&lt;br /&gt;
And here is Javascript code which does that (plot is generated with FLOT library):&lt;br /&gt;
&lt;hr&gt;&lt;pre style="color: green"&gt;function showValue(newValue,el)
{
  document.getElementById(el).innerHTML=parseFloat(newValue).toFixed(2);
  GeneratePlot();
}

function Clamp(x,a,b) {
  return Math.min(Math.max(x, a), b);
};

function NonLinearTransfer(x,a,b) {
  return (1-a)*x + a*Math.pow(1+Math.exp(b-2*b*x),-1);
};

function GeneratePlot() {
    var data = [];
    var a =  document.getElementById("rngNonlinearity").value;
    var b =  document.getElementById("rngAbruptness").value;

    for (var i = 0; i &lt;= 1; i += 0.01)
        data.push([i, Clamp(NonLinearTransfer(i,a,b),0,1)]);
    
    $.plot($("#placeholder"),
          [{ data: data, label: "Transfer function"}],
          { 
                xaxes: [ { min: 0, max: 1 }],
                yaxes: [ { min: 0, max: 1 }],
  legend: { position: 'nw' }
           }
          );
    GenerateGrad();
};

function Blend(k,x,y) {
  return (1-k)*x + k*y;
}

function setPixel(imageData, x, y, r, g, b, a) {
    index = (x + y * imageData.width) * 4;
    imageData.data[index+0] = r;
    imageData.data[index+1] = g;
    imageData.data[index+2] = b;
    imageData.data[index+3] = a;
}

function GenerateGrad() {

element = document.getElementById("canvasGrad");
c = element.getContext("2d");

width = parseInt(element.getAttribute("width"));
height = parseInt(element.getAttribute("height"));

imageData = c.createImageData(width, height);

scolor = [0,255,0];
tcolor = [0,0,255];
c1 =  document.getElementById("rngNonlinearity").value;
c2 =  document.getElementById("rngAbruptness").value;

// draw gradient
for (x = 0; x &lt; width; x++) {
  k = x/width;
  k = NonLinearTransfer(k,c1,c2);
  r = Blend(k,scolor[0],tcolor[0]);
  g = Blend(k,scolor[1],tcolor[1]);
  b = Blend(k,scolor[2],tcolor[2]);
  for (y = 0; y &lt; height; y++) {
    setPixel(imageData, x, y, r, g, b, 0xff);
  }
}

c.putImageData(imageData, 0, 0);
}
&lt;/pre&gt;
&lt;hr&gt;Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-4096821614816885384?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/VXhDkoVnJWpXCQW7sSrHzMEMusg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/VXhDkoVnJWpXCQW7sSrHzMEMusg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/VXhDkoVnJWpXCQW7sSrHzMEMusg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/VXhDkoVnJWpXCQW7sSrHzMEMusg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/4096821614816885384/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2011/05/gradient-transfer-function.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/4096821614816885384?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/4096821614816885384?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2011/05/gradient-transfer-function.html" title="Gradient transfer function" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-D9g6fTjRuRg/TcOU9AUsvtI/AAAAAAAAAQI/JbwaMbmS4lc/s72-c/TransferFunction.gif" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;Dk4DQnY_eSp7ImA9Wx9WGEQ.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-4976374382208944513</id><published>2011-01-24T09:27:00.000-08:00</published><updated>2011-01-24T10:49:33.841-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-24T10:49:33.841-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="contrast detection" /><category scheme="http://www.blogger.com/atom/ns#" term="Lang_C" /><category scheme="http://www.blogger.com/atom/ns#" term="image processing" /><title>Algorithm to determine image contrast</title><content type="html">How to determine image contrast ? More specifically - How to determine that image contrast is low and it needs automatic contrast adjustment through histogram equalization method ?&lt;br /&gt;&lt;br /&gt;Algorithm is this:&lt;br /&gt;   1. Calculate cumulative histogram of image.&lt;br /&gt;   2. Make linear regression of cumulative histogram in the form freq(x) = A*x + B.&lt;br /&gt;   3. Calculate RMSE of real_cumulative_frequency(x)-freq(x).&lt;br /&gt;   4. If that RMSE is close to zero - image is already equalized and should be in good contrast. (That means for equalized images cumulative histograms must be linear)&lt;br /&gt;&lt;br /&gt;Now fun part - C code which opens image in PGM format with ASCII encoding and detects if image needs contrast adjustment or not.&lt;br /&gt;&lt;pre style="color: green"&gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;#include &amp;lt;math.h&amp;gt;&lt;br /&gt;&lt;br /&gt;#define PGM_FILE "test3.pgm"&lt;br /&gt;&lt;br /&gt;typedef struct {&lt;br /&gt; int Width;&lt;br /&gt; int Height;&lt;br /&gt; int max_value;&lt;br /&gt; int ** data;&lt;br /&gt;} PGMdata;&lt;br /&gt;&lt;br /&gt;PGMdata PGMdata_ReadPgmFile(char* fileName) {&lt;br /&gt; FILE * pFile;&lt;br /&gt; char line[1000];&lt;br /&gt; char* res;&lt;br /&gt; int lineNum = 0;&lt;br /&gt; PGMdata pgmOut = {0,0,0,NULL};&lt;br /&gt;&lt;br /&gt; if ((pFile = fopen(fileName , "r")) == NULL) &lt;br /&gt;  printf("Error opening file %s \n", fileName);&lt;br /&gt; else {&lt;br /&gt;  while ((res = fgets(line, 100, pFile)) != NULL) {&lt;br /&gt;  lineNum++;&lt;br /&gt;  // max value of pixel&lt;br /&gt;  if (lineNum==4)&lt;br /&gt;   sscanf(line,"%i",&amp;amp;pgmOut.max_value);&lt;br /&gt;  // width and height of image&lt;br /&gt;  if (lineNum==3) {&lt;br /&gt;   int i;&lt;br /&gt;   sscanf(line,"%i %i",&amp;amp;pgmOut.Width, &amp;amp;pgmOut.Height);&lt;br /&gt;   pgmOut.data = (int**) malloc(pgmOut.Height*sizeof(int*));&lt;br /&gt;   for (i=0; i &amp;lt; pgmOut.Height; i++) {&lt;br /&gt;    pgmOut.data[i] = (int*) malloc(pgmOut.Width*sizeof(int));&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;  // load real pixels&lt;br /&gt;  if (lineNum &amp;gt; 4) {&lt;br /&gt;   int ix = lineNum - 5;&lt;br /&gt;   int row = ix/pgmOut.Width;&lt;br /&gt;   int col = ix - row*pgmOut.Width;&lt;br /&gt;   sscanf(line,"%i", &amp;amp;pgmOut.data[row][col]);&lt;br /&gt;  }&lt;br /&gt;  }&lt;br /&gt;  fclose(pFile);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt; return pgmOut;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void PGMdata_freeMemory(PGMdata* image) {&lt;br /&gt; int i;&lt;br /&gt; for (i=0; i &amp;lt; image-&amp;gt;Height; i++) {&lt;br /&gt;  free(image-&amp;gt;data[i]);&lt;br /&gt; }&lt;br /&gt; free(image-&amp;gt;data);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void CumulativeHistogram(PGMdata* image, double* hist) {&lt;br /&gt; int i,j;&lt;br /&gt; double dp = 1.0/((double) image-&amp;gt;Width*image-&amp;gt;Height);&lt;br /&gt;&lt;br /&gt; // initializing histogram bins to zero&lt;br /&gt; for (i=0; i&amp;lt;256; i++) {&lt;br /&gt;  hist[i] = 0.0;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; // calculating histogram&lt;br /&gt; for (i=0; i&amp;lt;image-&amp;gt;Width; i++) {&lt;br /&gt;  for (j=0; j&amp;lt;image-&amp;gt;Height; j++) {&lt;br /&gt;   hist[image-&amp;gt;data[j][i]] += dp;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; // making histogram cumulative&lt;br /&gt; for (i=0; i&amp;lt;255; i++) {&lt;br /&gt;  hist[i+1] += hist[i];&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void CreateXmatrix(double mat[256][2]) {&lt;br /&gt; int i;&lt;br /&gt; for (i=0; i&amp;lt;256; i++) {&lt;br /&gt;   mat[i][0] = 1;&lt;br /&gt;   mat[i][1] = i;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void TransposeMatrix(double mat[256][2], double tmat[2][256]) {&lt;br /&gt; int i,j;&lt;br /&gt; for (i=0; i&amp;lt;2; i++) {&lt;br /&gt;  for (j=0; j&amp;lt;256; j++) {&lt;br /&gt;   tmat[i][j] = mat[j][i];&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;double MultiplyMatrixes(double A[2][256], double B[256][2], int row, int col) {&lt;br /&gt; int i;&lt;br /&gt; double sum = 0.0;&lt;br /&gt;&lt;br /&gt; for (i=0; i&amp;lt;256; i++) {&lt;br /&gt;  sum += A[row][i]*B[i][col];&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; return sum;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;double MultiplyMatrixAndVector(double A[2][256], double Y[256], int row) {&lt;br /&gt; int i;&lt;br /&gt; double sum = 0.0;&lt;br /&gt;&lt;br /&gt; for (i=0; i&amp;lt;256; i++) {&lt;br /&gt;  sum += A[row][i]*Y[i];&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; return sum;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;double HistogramPredicted(double c0, double c1, double level) {&lt;br /&gt; return c0 + c1*level;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;double RootMeanSquare(double* hist, double c0, double c1) {&lt;br /&gt; double rms = 0.0;&lt;br /&gt; int i;&lt;br /&gt;&lt;br /&gt; for (i=0; i&amp;lt;256; i++) {&lt;br /&gt;  rms += pow(hist[i]-HistogramPredicted(c0,c1,i),2.0);&lt;br /&gt; }&lt;br /&gt; rms /= 256.0;&lt;br /&gt;&lt;br /&gt; return sqrt(rms);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void LinearLeastSquares(double* hist, double* c0, double* c1) {&lt;br /&gt; double X[256][2];&lt;br /&gt; double tX[2][256];&lt;br /&gt; double a1,a2,a3,a4;&lt;br /&gt; double b1, b2;&lt;br /&gt;&lt;br /&gt; // create matrix X composed of x'es&lt;br /&gt; CreateXmatrix(X);&lt;br /&gt;&lt;br /&gt; // transpose X matrix&lt;br /&gt; TransposeMatrix(X,tX);&lt;br /&gt;&lt;br /&gt; // calculate tX*X matrix which is&lt;br /&gt; // [a1 a2]&lt;br /&gt; // [a3 a4]&lt;br /&gt;&lt;br /&gt; a1 = MultiplyMatrixes(tX,X,0,0);&lt;br /&gt; a2 = MultiplyMatrixes(tX,X,0,1);&lt;br /&gt; a3 = MultiplyMatrixes(tX,X,1,0);&lt;br /&gt; a4 = MultiplyMatrixes(tX,X,1,1);&lt;br /&gt;&lt;br /&gt; // calculate tX*Y  (Y=HISTOGRAM) which is&lt;br /&gt; // [b1]&lt;br /&gt; // [b2]&lt;br /&gt;&lt;br /&gt; b1 = MultiplyMatrixAndVector(tX,hist,0);&lt;br /&gt; b2 = MultiplyMatrixAndVector(tX,hist,1);&lt;br /&gt;&lt;br /&gt; // solve matrix equation by using elimination of variables method&lt;br /&gt; // [a1 a2]   [c0]   [b1]&lt;br /&gt; //         *      = &lt;br /&gt; // [a3 a4]   [c1]   [b2]&lt;br /&gt; &lt;br /&gt; *c1 = (a1*b2-a3*b1)/(a1*a4-a2*a3);&lt;br /&gt; *c0 = (b1-a2*(*c1))/a1;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main () {&lt;br /&gt; int i;&lt;br /&gt; double hist[256];&lt;br /&gt; PGMdata image;&lt;br /&gt; double c0=0.0, c1=0.0;&lt;br /&gt; double rms;&lt;br /&gt;&lt;br /&gt; // read grayscale image from PGM format&lt;br /&gt; if ((image = PGMdata_ReadPgmFile(PGM_FILE)).data==NULL)&lt;br /&gt;  return;&lt;br /&gt;&lt;br /&gt; // create cumulative histogram&lt;br /&gt; CumulativeHistogram(&amp;amp;image, hist);&lt;br /&gt;&lt;br /&gt; // least mean squares method, to find c0,c1 coefficents in equation:&lt;br /&gt; // c0 + c1*gray_level = Frequency&lt;br /&gt; LinearLeastSquares(hist,&amp;amp;c0,&amp;amp;c1);&lt;br /&gt;&lt;br /&gt; // calculate RMS of Frequency[bin]-predicted_Frequency(bin)&lt;br /&gt; rms = RootMeanSquare(hist,c0,c1);&lt;br /&gt;&lt;br /&gt; // Low RMS shows that histogram frequencies are distributed in linear fashion&lt;br /&gt; // between bins. This means that histogram equalization was performed on image&lt;br /&gt; // and/or that global image contrast is good.&lt;br /&gt; if (rms &amp;lt;= 0.01)&lt;br /&gt;  printf("image contrast is OK\n");&lt;br /&gt; else&lt;br /&gt;  printf("image contrast is BAD, please perform histogram equalization on image...\n");&lt;br /&gt;&lt;br /&gt; // free used memory&lt;br /&gt; PGMdata_freeMemory(&amp;amp;image);&lt;br /&gt;&lt;br /&gt; return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you want to test this algorithm on ASCII PGM image - you better covert image to PGM format with GIMP 2.6.11, because it was only tested in this way.&lt;br /&gt;So by running this C code on below image (after converting it to PGM)&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hTm-LSlj8U4/TT3EuV1SDiI/AAAAAAAAAP8/j3AAwgs55zY/s1600/land.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 300px; height: 200px;" src="http://3.bp.blogspot.com/_hTm-LSlj8U4/TT3EuV1SDiI/AAAAAAAAAP8/j3AAwgs55zY/s400/land.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5565821014913453602" /&gt;&lt;/a&gt;&lt;br /&gt;we get algorithm output&lt;br /&gt;"&lt;span style="font-weight:bold;"&gt;image contrast is BAD, please perform histogram equalization on image...&lt;/span&gt;" :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-4976374382208944513?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/f1idgDjjel5VMYtkQiBBz18jZ4o/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/f1idgDjjel5VMYtkQiBBz18jZ4o/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/f1idgDjjel5VMYtkQiBBz18jZ4o/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/f1idgDjjel5VMYtkQiBBz18jZ4o/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/4976374382208944513/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2011/01/algorithm-to-determine-image-contrast.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/4976374382208944513?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/4976374382208944513?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2011/01/algorithm-to-determine-image-contrast.html" title="Algorithm to determine image contrast" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_hTm-LSlj8U4/TT3EuV1SDiI/AAAAAAAAAP8/j3AAwgs55zY/s72-c/land.jpg" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DU8GSX47fyp7ImA9Wx9WFU8.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-864908922800941224</id><published>2011-01-15T09:03:00.000-08:00</published><updated>2011-01-20T04:50:28.007-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-20T04:50:28.007-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Toon Shader" /><category scheme="http://www.blogger.com/atom/ns#" term="Pixel Shader" /><category scheme="http://www.blogger.com/atom/ns#" term="Cel Shader" /><title>Toon pixel shader</title><content type="html">How to make pixel shader which performs 'basic' toon shading operation on images ? &lt;br /&gt;&lt;br /&gt;Algorithm is following:&lt;br /&gt;1. Convert pixel from RGB to HSV color space.&lt;br /&gt;2. Map H,S,V values to some pre-defined set of H,S,V values.&lt;br /&gt;3. Convert back from HSV to RGB.&lt;br /&gt;4. Calculate if pixel is on edge, if so - ignore above calculated pixel color and place some pre-defined edge color instead.&lt;br /&gt;&lt;br /&gt;That's it. You will have image converted to toon-shaded variant :-)&lt;br /&gt;&lt;br /&gt;Here is GLSL code, which performs toon shading on image:&lt;hr&gt;&lt;pre style="color: green"&gt;&lt;br /&gt;#version 150&lt;br /&gt;uniform sampler2D Texture0;&lt;br /&gt;varying vec2 texCoord;&lt;br /&gt;&lt;br /&gt;#define HueLevCount 6&lt;br /&gt;#define SatLevCount 7&lt;br /&gt;#define ValLevCount 4&lt;br /&gt;float[HueLevCount] HueLevels = float[] (0.0,80.0,160.0,240.0,320.0,360.0);&lt;br /&gt;float[SatLevCount] SatLevels = float[] (0.0,0.15,0.3,0.45,0.6,0.8,1.0);&lt;br /&gt;float[ValLevCount] ValLevels = float[] (0.0,0.3,0.6,1.0);&lt;br /&gt;&lt;br /&gt;vec3 RGBtoHSV( float r, float g, float b) {&lt;br /&gt;   float minv, maxv, delta;&lt;br /&gt;   vec3 res;&lt;br /&gt;&lt;br /&gt;   minv = min(min(r, g), b);&lt;br /&gt;   maxv = max(max(r, g), b);&lt;br /&gt;   res.z = maxv;            // v&lt;br /&gt;   &lt;br /&gt;   delta = maxv - minv;&lt;br /&gt;&lt;br /&gt;   if( maxv != 0.0 )&lt;br /&gt;      res.y = delta / maxv;      // s&lt;br /&gt;   else {&lt;br /&gt;      // r = g = b = 0      // s = 0, v is undefined&lt;br /&gt;      res.y = 0.0;&lt;br /&gt;      res.x = -1.0;&lt;br /&gt;      return res;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   if( r == maxv )&lt;br /&gt;      res.x = ( g - b ) / delta;      // between yellow &amp; magenta&lt;br /&gt;   else if( g == maxv )&lt;br /&gt;      res.x = 2.0 + ( b - r ) / delta;   // between cyan &amp; yellow&lt;br /&gt;   else&lt;br /&gt;      res.x = 4.0 + ( r - g ) / delta;   // between magenta &amp; cyan&lt;br /&gt;&lt;br /&gt;   res.x = res.x * 60.0;            // degrees&lt;br /&gt;   if( res.x &lt; 0.0 )&lt;br /&gt;      res.x = res.x + 360.0;&lt;br /&gt;      &lt;br /&gt;   return res;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;vec3 HSVtoRGB(float h, float s, float v ) {&lt;br /&gt;   int i;&lt;br /&gt;   float f, p, q, t;&lt;br /&gt;   vec3 res;&lt;br /&gt;&lt;br /&gt;   if( s == 0.0 ) {&lt;br /&gt;      // achromatic (grey)&lt;br /&gt;      res.x = v;&lt;br /&gt;      res.y = v;&lt;br /&gt;      res.z = v;&lt;br /&gt;      return res;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   h /= 60.0;         // sector 0 to 5&lt;br /&gt;   i = int(floor( h ));&lt;br /&gt;   f = h - float(i);         // factorial part of h&lt;br /&gt;   p = v * ( 1.0 - s );&lt;br /&gt;   q = v * ( 1.0 - s * f );&lt;br /&gt;   t = v * ( 1.0 - s * ( 1.0 - f ) );&lt;br /&gt;&lt;br /&gt;   switch( i ) {&lt;br /&gt;      case 0:&lt;br /&gt;         res.x = v;&lt;br /&gt;         res.y = t;&lt;br /&gt;         res.z = p;&lt;br /&gt;         break;&lt;br /&gt;      case 1:&lt;br /&gt;         res.x = q;&lt;br /&gt;         res.y = v;&lt;br /&gt;         res.z = p;&lt;br /&gt;         break;&lt;br /&gt;      case 2:&lt;br /&gt;         res.x = p;&lt;br /&gt;         res.y = v;&lt;br /&gt;         res.z = t;&lt;br /&gt;         break;&lt;br /&gt;      case 3:&lt;br /&gt;         res.x = p;&lt;br /&gt;         res.y = q;&lt;br /&gt;         res.z = v;&lt;br /&gt;         break;&lt;br /&gt;      case 4:&lt;br /&gt;         res.x = t;&lt;br /&gt;         res.y = p;&lt;br /&gt;         res.z = v;&lt;br /&gt;         break;&lt;br /&gt;      default:      // case 5:&lt;br /&gt;         res.x = v;&lt;br /&gt;         res.y = p;&lt;br /&gt;         res.z = q;&lt;br /&gt;         break;&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   return res;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;float nearestLevel(float col, int mode) {&lt;br /&gt;   int levCount;&lt;br /&gt;   if (mode==0) levCount = HueLevCount;&lt;br /&gt;   if (mode==1) levCount = SatLevCount;&lt;br /&gt;   if (mode==2) levCount = ValLevCount;&lt;br /&gt;   &lt;br /&gt;   for (int i =0; i&amp;lt;levCount-1; i++ ) {&lt;br /&gt;     if (mode==0) {&lt;br /&gt;        if (col &gt;= HueLevels[i] &amp;&amp; col &lt;= HueLevels[i+1]) {&lt;br /&gt;          return HueLevels[i+1];&lt;br /&gt;        }&lt;br /&gt;     }&lt;br /&gt;     if (mode==1) {&lt;br /&gt;        if (col &gt;= SatLevels[i] &amp;&amp; col &lt;= SatLevels[i+1]) {&lt;br /&gt;          return SatLevels[i+1];&lt;br /&gt;        }&lt;br /&gt;     }&lt;br /&gt;     if (mode==2) {&lt;br /&gt;        if (col &gt;= ValLevels[i] &amp;&amp; col &lt;= ValLevels[i+1]) {&lt;br /&gt;          return ValLevels[i+1];&lt;br /&gt;        }&lt;br /&gt;     }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// averaged pixel intensity from 3 color channels&lt;br /&gt;float avg_intensity(vec4 pix) {&lt;br /&gt; return (pix.r + pix.g + pix.b)/3.;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;vec4 get_pixel(vec2 coords, float dx, float dy) {&lt;br /&gt; return texture2D(Texture0,coords + vec2(dx, dy));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// returns pixel color&lt;br /&gt;float IsEdge(in vec2 coords){&lt;br /&gt;  float dxtex = 1.0 /float(textureSize(Texture0,0)) ;&lt;br /&gt;  float dytex = 1.0 /float(textureSize(Texture0,0));&lt;br /&gt;  float pix[9];&lt;br /&gt;  int k = -1;&lt;br /&gt;  float delta;&lt;br /&gt;&lt;br /&gt;  // read neighboring pixel intensities&lt;br /&gt;  for (int i=-1; i&lt;2; i++) {&lt;br /&gt;   for(int j=-1; j&lt;2; j++) {&lt;br /&gt;    k++;&lt;br /&gt;    pix[k] = avg_intensity(get_pixel(coords,float(i)*dxtex,&lt;br /&gt;                                          float(j)*dytex));&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // average color differences around neighboring pixels&lt;br /&gt;  delta = (abs(pix[1]-pix[7])+&lt;br /&gt;          abs(pix[5]-pix[3]) +&lt;br /&gt;          abs(pix[0]-pix[8])+&lt;br /&gt;          abs(pix[2]-pix[6])&lt;br /&gt;           )/4.;&lt;br /&gt;&lt;br /&gt;  return clamp(5.5*delta,0.0,1.0);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void main(void)&lt;br /&gt;{&lt;br /&gt;    vec4 colorOrg = texture2D( Texture0, texCoord );&lt;br /&gt;    vec3 vHSV =  RGBtoHSV(colorOrg.r,colorOrg.g,colorOrg.b);&lt;br /&gt;    vHSV.x = nearestLevel(vHSV.x, 0);&lt;br /&gt;    vHSV.y = nearestLevel(vHSV.y, 1);&lt;br /&gt;    vHSV.z = nearestLevel(vHSV.z, 2);&lt;br /&gt;    float edg = IsEdge(texCoord);&lt;br /&gt;    vec3 vRGB = (edg &gt;= 0.3)? vec3(0.0,0.0,0.0):HSVtoRGB(vHSV.x,vHSV.y,vHSV.z);&lt;br /&gt;    gl_FragColor = vec4(vRGB.x,vRGB.y,vRGB.z,1.0);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;hr&gt;&lt;br /&gt;&lt;br /&gt;So from this car&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hTm-LSlj8U4/TTHWsM-crwI/AAAAAAAAAPs/B-e9sUFX7Ho/s1600/car.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 255px;" src="http://4.bp.blogspot.com/_hTm-LSlj8U4/TTHWsM-crwI/AAAAAAAAAPs/B-e9sUFX7Ho/s400/car.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5562463069665013506" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;we will get this toon-car after shader is applied:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hTm-LSlj8U4/TTHXHLttwCI/AAAAAAAAAP0/JosHXP0AF4A/s1600/toonCar.bmp"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 253px;" src="http://1.bp.blogspot.com/_hTm-LSlj8U4/TTHXHLttwCI/AAAAAAAAAP0/JosHXP0AF4A/s400/toonCar.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5562463533182861346" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Have a fun with shaders !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-864908922800941224?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/FZtdRH5fmXB9I4bPhzSot9L9Hf0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FZtdRH5fmXB9I4bPhzSot9L9Hf0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/FZtdRH5fmXB9I4bPhzSot9L9Hf0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FZtdRH5fmXB9I4bPhzSot9L9Hf0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/864908922800941224/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2011/01/toon-pixel-shader.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/864908922800941224?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/864908922800941224?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2011/01/toon-pixel-shader.html" title="Toon pixel shader" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_hTm-LSlj8U4/TTHWsM-crwI/AAAAAAAAAPs/B-e9sUFX7Ho/s72-c/car.jpg" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;C0MBRns_eip7ImA9Wx9SGE4.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-2053322882986640506</id><published>2010-12-08T09:16:00.000-08:00</published><updated>2010-12-08T10:04:17.542-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-12-08T10:04:17.542-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Lang_F#" /><category scheme="http://www.blogger.com/atom/ns#" term="Project Euler" /><title>Project Euler, problem 26</title><content type="html">Problem is stated as following:&lt;hr&gt;&lt;pre&gt;&lt;br /&gt;A unit fraction contains 1 in the numerator. The decimal representation of the unit &lt;br /&gt;fractions with denominators 2 to 10 are given:&lt;br /&gt;&lt;br /&gt;    1/2  =  0.5&lt;br /&gt;    1/3  =  0.(3)&lt;br /&gt;    1/4  =  0.25&lt;br /&gt;    1/5  =  0.2&lt;br /&gt;    1/6  =  0.1(6)&lt;br /&gt;    1/7  =  0.(142857)&lt;br /&gt;    1/8  =  0.125&lt;br /&gt;    1/9  =  0.(1)&lt;br /&gt;    1/10 =  0.1&lt;br /&gt;&lt;br /&gt;Where 0.1(6) means 0.166666..., and has a 1-digit recurring cycle. It can be seen&lt;br /&gt;that 1/7 has a 6-digit recurring cycle.&lt;br /&gt;&lt;br /&gt;Find the value of d &lt; 1000 for which 1/d contains the longest recurring cycle in &lt;br /&gt;its decimal fraction part.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;Solution is based on idea that longest recurring cycle should have 1/p form, where p - prime number. After quick look at wikipedia about &lt;a href="http://en.wikipedia.org/wiki/Repeating_decimal#Fractions_with_prime_denominators"&gt;repeating decimals&lt;/a&gt; I thought that I should just search biggest prime, but at closer examination of wiki, I understood that not necessary biggest prime would result in biggest recurring cycle of 1/prime. So for the sake of mathematical integrity, I decided to implement 'correct' search of biggest recurring cycle, which is based on calculating multiplicative order of 10 modulo prime. Solution also is pretty fast - executes in about 130 ms. Below is solution code in language F#:&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;pre style="color: green"&gt;&lt;br /&gt;open System.Diagnostics&lt;br /&gt;&lt;br /&gt;// http://en.wikipedia.org/wiki/Modular_exponentiation&lt;br /&gt;let modular_exponent b e m =&lt;br /&gt;    let rec modular_exponent0 b e e0 m c0 = &lt;br /&gt;        match () with&lt;br /&gt;        | _ when e0 &gt;= e -&gt; c0&lt;br /&gt;        | _  -&gt; let e1 = e0 + 1 in&lt;br /&gt;                let c1 = (c0 * b) % m in&lt;br /&gt;                modular_exponent0 b e e1 m c1&lt;br /&gt;    modular_exponent0 b e 0 m 1&lt;br /&gt;&lt;br /&gt;// http://en.wikipedia.org/wiki/Multiplicative_order&lt;br /&gt;let multiplicative_order a n =&lt;br /&gt;    let rec multiplicative_order0 a n k0 = &lt;br /&gt;        let me = modular_exponent a k0 n in&lt;br /&gt;            match me with&lt;br /&gt;            | 1 -&gt; k0&lt;br /&gt;            | _ -&gt; let k1 = k0 + 1 in&lt;br /&gt;                   multiplicative_order0 a n k1&lt;br /&gt;    multiplicative_order0 a n 1&lt;br /&gt;&lt;br /&gt;// http://en.wikipedia.org/wiki/Repeating_decimal#Fractions_with_prime_denominators&lt;br /&gt;let period_of_1divp p = multiplicative_order 10 p&lt;br /&gt;&lt;br /&gt;// http://en.wikipedia.org/wiki/Prime_number#Verifying_primality&lt;br /&gt;let is_prime x = &lt;br /&gt;    let rec is_prime0 x d0 = &lt;br /&gt;        match () with&lt;br /&gt;        | _ when d0 &gt; int (sqrt (float x)) -&gt; true&lt;br /&gt;        | _ when x % d0 = 0 -&gt; false&lt;br /&gt;        | _ -&gt; let d1 = d0 + 1 in&lt;br /&gt;               is_prime0 x d1&lt;br /&gt;    is_prime0 x 2&lt;br /&gt;&lt;br /&gt;let main = let stopwatch = new Stopwatch()&lt;br /&gt;           stopwatch.Start()&lt;br /&gt;           let prime,max_period = &lt;br /&gt;               [ for x in 6..999 do if is_prime x then yield x,period_of_1divp x ] |&gt; &lt;br /&gt;               Seq.fold (fun (a,b) (x,y) -&gt; if y &gt; b then (x,y) else (a,b)) (0,0)&lt;br /&gt;           stopwatch.Stop()&lt;br /&gt;           printfn "Fraction with greatest period of %d is 1/%d, calculated in %d ms" &lt;br /&gt;                    max_period&lt;br /&gt;                    prime&lt;br /&gt;                    stopwatch.ElapsedMilliseconds&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;Have fun with Project Euler and F# !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-2053322882986640506?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Jq9Csvvcu3KNOH9SaBF3pfdcfVk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Jq9Csvvcu3KNOH9SaBF3pfdcfVk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Jq9Csvvcu3KNOH9SaBF3pfdcfVk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Jq9Csvvcu3KNOH9SaBF3pfdcfVk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/2053322882986640506/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2010/12/project-euler-problem-26.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/2053322882986640506?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/2053322882986640506?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2010/12/project-euler-problem-26.html" title="Project Euler, problem 26" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DUcGSHY9fSp7ImA9Wx5UFkg.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-158357136811857068</id><published>2010-10-21T02:58:00.000-07:00</published><updated>2010-10-21T03:30:29.865-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-10-21T03:30:29.865-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Thermal vision" /><category scheme="http://www.blogger.com/atom/ns#" term="Heat vision" /><category scheme="http://www.blogger.com/atom/ns#" term="Pixel Shader" /><title>Thermal vision pixel shader</title><content type="html">This is how we can get thermal vision pixel shader:&lt;br /&gt;1. Make some gradient (here we will use blue-yellow-red gradient).&lt;br /&gt;2. Make thermal map texture (here we will substitute pixel luminance value for temperature)&lt;br /&gt;3. Get pixel's temperature from thermal map texture and map it to gradient value.&lt;br /&gt;&lt;br /&gt;GLSL code&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;pre style="color: green"&gt;&lt;br /&gt;#version 120&lt;br /&gt;&lt;br /&gt;uniform sampler2D tex;&lt;br /&gt;&lt;br /&gt;void main()&lt;br /&gt;{&lt;br /&gt; vec4 pixcol = texture2D(tex, gl_TexCoord[0].xy);&lt;br /&gt; vec4 colors[3];&lt;br /&gt; colors[0] = vec4(0.,0.,1.,1.);&lt;br /&gt; colors[1] = vec4(1.,1.,0.,1.);&lt;br /&gt; colors[2] = vec4(1.,0.,0.,1.);&lt;br /&gt; float lum = (pixcol.r+pixcol.g+pixcol.b)/3.;&lt;br /&gt; int ix = (lum &lt; 0.5)? 0:1;&lt;br /&gt; vec4 thermal = mix(colors[ix],colors[ix+1],(lum-float(ix)*0.5)/0.5);&lt;br /&gt; gl_FragColor = thermal;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;Tank&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hTm-LSlj8U4/TMAS-aqX7QI/AAAAAAAAAPQ/lK2hur9sHAg/s1600/tank_night.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://3.bp.blogspot.com/_hTm-LSlj8U4/TMAS-aqX7QI/AAAAAAAAAPQ/lK2hur9sHAg/s400/tank_night.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5530441205929209090" /&gt;&lt;/a&gt;&lt;br /&gt;and after thermal vision shader applied:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hTm-LSlj8U4/TMAT9w2oeLI/AAAAAAAAAPY/pqT9HWZkteo/s1600/tank_thermal.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 398px;" src="http://2.bp.blogspot.com/_hTm-LSlj8U4/TMAT9w2oeLI/AAAAAAAAAPY/pqT9HWZkteo/s400/tank_thermal.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5530442294217963698" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-158357136811857068?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/FjpU_htXdmjqjKpOLUG3nHEmNOQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FjpU_htXdmjqjKpOLUG3nHEmNOQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/FjpU_htXdmjqjKpOLUG3nHEmNOQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FjpU_htXdmjqjKpOLUG3nHEmNOQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/158357136811857068/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2010/10/thermal-vision-pixel-shader.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/158357136811857068?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/158357136811857068?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2010/10/thermal-vision-pixel-shader.html" title="Thermal vision pixel shader" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_hTm-LSlj8U4/TMAS-aqX7QI/AAAAAAAAAPQ/lK2hur9sHAg/s72-c/tank_night.png" height="72" width="72" /><thr:total>1</thr:total></entry><entry gd:etag="W/&quot;Ck8CSXc6eip7ImA9Wx5TEEo.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-7631278101008970485</id><published>2010-07-11T02:52:00.000-07:00</published><updated>2010-07-25T08:14:28.912-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-07-25T08:14:28.912-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Sharpness" /><category scheme="http://www.blogger.com/atom/ns#" term="Convolution" /><category scheme="http://www.blogger.com/atom/ns#" term="Pixel Shader" /><category scheme="http://www.blogger.com/atom/ns#" term="Gaussian blur" /><category scheme="http://www.blogger.com/atom/ns#" term="Emboss" /><category scheme="http://www.blogger.com/atom/ns#" term="edge detection" /><title>Convolution Pixel Shader</title><content type="html">What is convolution ? Simply speaking convolution is weighted sum of pixel values around target pixel. If those weights are put into vector &lt;b&gt;W&lt;/b&gt; and pixel values around x,y are put in vector &lt;b&gt;P&lt;/b&gt;, then in linear algebra terms convolution at x,y is nothing more than dot product of vectors &lt;b&gt;W&lt;/b&gt;,&lt;b&gt;P&lt;/b&gt;. More precisely:&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;Convolution(x,y) = (&lt;b&gt;W&lt;/b&gt;*&lt;b&gt;P&lt;/b&gt;)/denominator + offset&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;This &lt;b&gt;W&lt;/b&gt; vector is called &lt;i&gt;kernel&lt;/i&gt;. (Also formula can be re-written for matrix case, in that case W and P would be matrix). So by using different &lt;i&gt;kernels&lt;/i&gt; we could achieve different image convolution effects. Several common convolution kernels:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Gaussian Blur kernel&lt;/i&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;1., 2., 1.,&lt;br /&gt;2., 4., 2.,&lt;br /&gt;1., 2., 1.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;i&gt;Sharpness kernel&lt;/i&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-1., -1., -1.,&lt;br /&gt;-1.,  9., -1.,&lt;br /&gt;-1., -1., -1.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;i&gt;Edge detection kernel&lt;/i&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-1./8., -1./8., -1./8.,&lt;br /&gt;-1./8.,  1.,    -1./8.,&lt;br /&gt;-1./8., -1./8., -1./8.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;i&gt;Emboss kernel&lt;/i&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;2.,  0.,  0.,&lt;br /&gt;0., -1.,  0.,&lt;br /&gt;0.,  0., -1.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now, GLSL pixel shader code which performs convolution with all these kernels =&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="color: green"&gt;&lt;br /&gt;#version 150&lt;br /&gt;&lt;br /&gt;uniform sampler2D Texture0;&lt;br /&gt;&lt;br /&gt;vec4 get_pixel(in vec2 coords, in float dx, in float dy) { &lt;br /&gt;   return texture2D(Texture0,coords + vec2(dx, dy));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;float Convolve(in float[9] kernel, in float[9] matrix, &lt;br /&gt;               in float denom, in float offset) {&lt;br /&gt;   float res = 0.0;&lt;br /&gt;   for (int i=0; i&lt;9; i++) {&lt;br /&gt;      res += kernel[i]*matrix[i];&lt;br /&gt;   }&lt;br /&gt;   return clamp(res/denom + offset,0.0,1.0);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;float[9] GetData(in int channel) {&lt;br /&gt;   float dxtex = 1.0 / float(textureSize(Texture0,0));  &lt;br /&gt;   float dytex = 1.0 / float(textureSize(Texture0,0));&lt;br /&gt;   float[9] mat;&lt;br /&gt;   int k = -1;&lt;br /&gt;   for (int i=-1; i&lt;2; i++) {   &lt;br /&gt;      for(int j=-1; j&lt;2; j++) {    &lt;br /&gt;         k++;    &lt;br /&gt;         mat[k] = get_pixel(gl_TexCoord[0].xy,float(i)*dxtex,&lt;br /&gt;                            float(j)*dytex)[channel];&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;   return mat;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;float[9] GetMean(in float[9] matr, in float[9] matg, in float[9] matb) {&lt;br /&gt;   float[9] mat;&lt;br /&gt;   for (int i=0; i&lt;9; i++) {&lt;br /&gt;      mat[i] = (matr[i]+matg[i]+matb[i])/3.;&lt;br /&gt;   }&lt;br /&gt;   return mat;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void main(void)&lt;br /&gt;{&lt;br /&gt;   float[9] kerEmboss = float[] (2.,0.,0.,&lt;br /&gt;                                 0., -1., 0.,&lt;br /&gt;                                 0., 0., -1.);&lt;br /&gt;&lt;br /&gt;   float[9] kerSharpness = float[] (-1.,-1.,-1.,&lt;br /&gt;                                    -1., 9., -1.,&lt;br /&gt;                                    -1., -1., -1.);&lt;br /&gt;&lt;br /&gt;   float[9] kerGausBlur = float[]  (1.,2.,1.,&lt;br /&gt;                                    2., 4., 2.,&lt;br /&gt;                                    1., 2., 1.);&lt;br /&gt;&lt;br /&gt;   float[9] kerEdgeDetect = float[] (-1./8.,-1./8.,-1./8.,&lt;br /&gt;                                     -1./8., 1., -1./8.,&lt;br /&gt;                                     -1./8., -1./8., -1./8.);&lt;br /&gt;&lt;br /&gt;   float matr[9] = GetData(0);&lt;br /&gt;   float matg[9] = GetData(1);&lt;br /&gt;   float matb[9] = GetData(2);&lt;br /&gt;   float mata[9] = GetMean(matr,matg,matb);&lt;br /&gt;&lt;br /&gt;   // Sharpness kernel&lt;br /&gt;   //gl_FragColor = vec4(Convolve(kerSharpness,matr,1.,0.),&lt;br /&gt;   //                    Convolve(kerSharpness,matg,1.,0.),&lt;br /&gt;   //                    Convolve(kerSharpness,matb,1.,0.),1.0);&lt;br /&gt;&lt;br /&gt;   // Gaussian blur kernel&lt;br /&gt;   //gl_FragColor = vec4(Convolve(kerGausBlur,matr,16.,0.),&lt;br /&gt;   //                    Convolve(kerGausBlur,matg,16.,0.),&lt;br /&gt;   //                    Convolve(kerGausBlur,matb,16.,0.),1.0);&lt;br /&gt;&lt;br /&gt;   // Edge Detection kernel&lt;br /&gt;   //gl_FragColor = vec4(Convolve(kerEdgeDetect,mata,0.1,0.),&lt;br /&gt;   //                    Convolve(kerEdgeDetect,mata,0.1,0.),&lt;br /&gt;   //                    Convolve(kerEdgeDetect,mata,0.1,0.),1.0);&lt;br /&gt;&lt;br /&gt;   // Emboss kernel&lt;br /&gt;   gl_FragColor = vec4(Convolve(kerEmboss,mata,1.,1./2.),&lt;br /&gt;                       Convolve(kerEmboss,mata,1.,1./2.),&lt;br /&gt;                       Convolve(kerEmboss,mata,1.,1./2.),1.0);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;What's left ? Results of course :)&lt;br /&gt;Here is original image&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_hTm-LSlj8U4/TDmhQksZWrI/AAAAAAAAAOM/ArstEfAfJG4/s1600/tarant.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 296px;" src="http://3.bp.blogspot.com/_hTm-LSlj8U4/TDmhQksZWrI/AAAAAAAAAOM/ArstEfAfJG4/s400/tarant.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5492598526654896818" /&gt;&lt;/a&gt;&lt;br /&gt;convolution with Gaussian Blur kernel&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_hTm-LSlj8U4/TDmhnXSQ22I/AAAAAAAAAOU/PKv-fSF1DjM/s1600/tarantGaussBlur.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 292px;" src="http://1.bp.blogspot.com/_hTm-LSlj8U4/TDmhnXSQ22I/AAAAAAAAAOU/PKv-fSF1DjM/s400/tarantGaussBlur.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5492598918192618338" /&gt;&lt;/a&gt;&lt;br /&gt;convolution with Sharpness kernel&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_hTm-LSlj8U4/TDmh0hwqcoI/AAAAAAAAAOc/MVzxkxrtKmE/s1600/tarantSharpness.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 292px;" src="http://4.bp.blogspot.com/_hTm-LSlj8U4/TDmh0hwqcoI/AAAAAAAAAOc/MVzxkxrtKmE/s400/tarantSharpness.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5492599144342778498" /&gt;&lt;/a&gt;&lt;br /&gt;convolution with Edge detection kernel&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_hTm-LSlj8U4/TDmiCRlYoDI/AAAAAAAAAOk/acZLd7fI1Lw/s1600/tarantEdgeDet.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 292px;" src="http://1.bp.blogspot.com/_hTm-LSlj8U4/TDmiCRlYoDI/AAAAAAAAAOk/acZLd7fI1Lw/s400/tarantEdgeDet.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5492599380518674482" /&gt;&lt;/a&gt;&lt;br /&gt;convolution with Emboss kernel&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_hTm-LSlj8U4/TDmiTZrcE8I/AAAAAAAAAOs/QBajXZhi3Lg/s1600/tarantEmboss.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 292px;" src="http://1.bp.blogspot.com/_hTm-LSlj8U4/TDmiTZrcE8I/AAAAAAAAAOs/QBajXZhi3Lg/s400/tarantEmboss.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5492599674749326274" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-7631278101008970485?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/SZNwPQa8wblF34WsTZljfmQ2uBA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/SZNwPQa8wblF34WsTZljfmQ2uBA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/SZNwPQa8wblF34WsTZljfmQ2uBA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/SZNwPQa8wblF34WsTZljfmQ2uBA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/7631278101008970485/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2010/07/convolution.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/7631278101008970485?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/7631278101008970485?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2010/07/convolution.html" title="Convolution Pixel Shader" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_hTm-LSlj8U4/TDmhQksZWrI/AAAAAAAAAOM/ArstEfAfJG4/s72-c/tarant.jpg" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;C0YCRXo4fCp7ImA9Wx5TEEo.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-5821650164887558530</id><published>2010-06-25T07:50:00.000-07:00</published><updated>2010-07-25T08:19:24.434-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-07-25T08:19:24.434-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Pixel Shader" /><category scheme="http://www.blogger.com/atom/ns#" term="Steganography" /><title>Steganography Pixel Shader</title><content type="html">Steganography is method for hidding secret message in covert message. In this case I mean hidding secret image into covert image. So, sometimes What You See Is NOT What You Get :) How can we hide secret 3-bit image into other 24-bit image ?&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Encoding procedure&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;1.&lt;br /&gt;secret 3-bit image means that we can hide 2^3 = 8 color palette image.&lt;br /&gt;So at first we need to map these 8 colors to 3-bit pattern. Lets use such mappings:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;--------------------------&lt;br /&gt;  RGB       | Bit pattern&lt;br /&gt;--------------------------&lt;br /&gt;2,2,2       | 0,0,0&lt;br /&gt;38,38,38    | 0,0,1&lt;br /&gt;74,74,74    | 0,1,0&lt;br /&gt;110,110,110 | 1,0,0&lt;br /&gt;146,146,146 | 0,1,1&lt;br /&gt;182,182,182 | 1,1,0&lt;br /&gt;218,218,218 | 1,0,1&lt;br /&gt;254,254,254 | 1,1,1&lt;br /&gt;--------------------------&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;2.&lt;br /&gt;Now as we have color table, we just need to get 3-bit image required pixel and encode it's 3-bit pattern into covert RGB image. One way of doing this is to define secret bit meaning as follows: 0 means covert RBG byte is even, 1 means - odd.&lt;br /&gt;So according to this definition we adjust covert image RGB bytes to be even or odd - depending to required 3-bit secret pattern. For example-&lt;br /&gt;if 3-bit pattern is (1,0,1) and covert RGB pixel is (140,39,16) - then it will be converted to (141,40,17).&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Decoding procedure&lt;/strong&gt;&lt;br /&gt;Secret image extraction from covert image procedure is a reversal of encoding:&lt;br /&gt;1. Check covert RGB bytes are even or odd.&lt;br /&gt;2. From that extract 3-bit pattern.&lt;br /&gt;3. Map this 3-bit pattern to 8 color palette.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Properties of this image hidding method&lt;/strong&gt;&lt;br /&gt;1. Can be used in image formats which doesn't support alpha (transparency) channel.&lt;br /&gt;2. Original image looses only 3/24 = 12.5 percents of quality, which means that it is hard or impossible to spot by eyes that something is wrong with covert image.&lt;br /&gt;3. Regardless of good image quality after conversion, image histogram can show some signs of payload image. Because in some cases histogram is modulated after conversion.&lt;br /&gt;&lt;br /&gt;Now code examples. Encoding part is left as exercise to the reader :) But here it is payload image extraction code (as always in GLSL shader language):&lt;br /&gt;a) Vertex Shader (we need it for correct sampling of texels)&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;pre style="color: green"&gt;&lt;br /&gt;varying vec2 texCoord;&lt;br /&gt;&lt;br /&gt;void main(void)&lt;br /&gt;{&lt;br /&gt;   gl_Position = vec4(gl_Vertex.xy, 0.0, 1.0 );&lt;br /&gt;   texCoord = 0.5 * gl_Position.xy + vec2(0.5);     &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;br /&gt;b) Pixel Shader (real program doing payload image extraction)&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;pre style="color: green"&gt;&lt;br /&gt;#version 120&lt;br /&gt;uniform sampler2D Texture0;&lt;br /&gt;varying vec2 texCoord;&lt;br /&gt;&lt;br /&gt;int binaryToDecimal(in int d1, in int d2, in int d3) {&lt;br /&gt;   return 4*d1+2*d2+d3;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void fillColors(inout float[8] colors) {&lt;br /&gt;   colors[0] = 2./255.;&lt;br /&gt;   colors[1] = 38./255.;&lt;br /&gt;   colors[2] = 74./255.;&lt;br /&gt;   colors[3] = 146./255.;&lt;br /&gt;   colors[4] = 110./255.;&lt;br /&gt;   colors[5] = 218./255.;&lt;br /&gt;   colors[6] = 182./255.;&lt;br /&gt;   colors[7] = 254./255.;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int Odd(in float num) {&lt;br /&gt;   return int(mod(num,2.)!=0.);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void main()&lt;br /&gt;{   &lt;br /&gt;   float colTable[8];&lt;br /&gt;   fillColors(colTable);&lt;br /&gt;   vec4 col = texture2D(Texture0, texCoord);&lt;br /&gt;   int d1 = Odd(col.r*255.);&lt;br /&gt;   int d2 = Odd(col.g*255.);&lt;br /&gt;   int d3 = Odd(col.b*255.);&lt;br /&gt;   float level = colTable[binaryToDecimal(d1,d2,d3)];&lt;br /&gt;   gl_FragColor = vec4(level,level,level,1.0);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;strong&gt;NOTE: When using this GLSL shader for image below - make sure that covert texture is rendered to screen aligned quad of EXACTLY 512x512 pixel dimensions. Otherwise you will not get hidden image, but instead you will get just noise because of incorrect pixel/texel samplings !!!&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Finally,- results. This is covert image:&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_hTm-LSlj8U4/TCTtEiYr_fI/AAAAAAAAAN8/hR8H2rf215s/s1600/sheep.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://4.bp.blogspot.com/_hTm-LSlj8U4/TCTtEiYr_fI/AAAAAAAAAN8/hR8H2rf215s/s400/sheep.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5486770908249718258" /&gt;&lt;/a&gt;&lt;br /&gt;and this is payload image extracted from above image (after extraction GLSL shader applied):&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_hTm-LSlj8U4/TCTt2_dkZ1I/AAAAAAAAAOE/wJJESxjc1kc/s1600/hiddenWolf.PNG"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://2.bp.blogspot.com/_hTm-LSlj8U4/TCTt2_dkZ1I/AAAAAAAAAOE/wJJESxjc1kc/s400/hiddenWolf.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5486771775048279890" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Have fun in making/analyzing covert images !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-5821650164887558530?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/w1DC_8-x8xHWXltpiQLLg1I4h5Q/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/w1DC_8-x8xHWXltpiQLLg1I4h5Q/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/w1DC_8-x8xHWXltpiQLLg1I4h5Q/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/w1DC_8-x8xHWXltpiQLLg1I4h5Q/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/5821650164887558530/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2010/06/steganography.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/5821650164887558530?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/5821650164887558530?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2010/06/steganography.html" title="Steganography Pixel Shader" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_hTm-LSlj8U4/TCTtEiYr_fI/AAAAAAAAAN8/hR8H2rf215s/s72-c/sheep.png" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;C0UDQng5fCp7ImA9Wx5TEEo.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-6886223609859506494</id><published>2010-06-17T06:33:00.000-07:00</published><updated>2010-07-25T08:21:13.624-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-07-25T08:21:13.624-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Pixel Shader" /><category scheme="http://www.blogger.com/atom/ns#" term="Binary filter" /><title>Binary filter Pixel Shader</title><content type="html">Binary image is image composed only from 2 colors. Typical conversion algorithm to binary image is this -&gt; If pixel's averaged intensity is greater than threshold - draw pixel in first color, otherwise- draw it in second color. But you can define other methods of conversion to binary as well. &lt;br /&gt;For example another method can be - If pixel's color is near target color (within error bounds) - draw pixel in first color, otherwise - draw it in second. This conversion rule is implemented in following GLSL pixel shader code:&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;pre style="color: green"&gt;&lt;br /&gt;uniform sampler2D tex;&lt;br /&gt;&lt;br /&gt;bool nearColor(in vec4 col, in vec4 tcol, in float error) {&lt;br /&gt; return abs(col.r-tcol.r) &lt; error &amp;&amp;&lt;br /&gt;    abs(col.g-tcol.g) &lt; error &amp;&amp;&lt;br /&gt;    abs(col.b-tcol.b) &lt; error ;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void main()&lt;br /&gt;{&lt;br /&gt; vec4 xcol = texture2D(tex, gl_TexCoord[0].xy);&lt;br /&gt; vec4 scol = vec4(0.737,0.506,0.404,1.0);&lt;br /&gt; if (nearColor(xcol,scol,0.085))&lt;br /&gt;  gl_FragColor = scol;&lt;br /&gt; else&lt;br /&gt;  gl_FragColor = vec4(0.0,0.0,0.0,1.0);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;Image&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hTm-LSlj8U4/TBopPQ1oD4I/AAAAAAAAANs/FlNSbSigV0s/s1600/vikinglander.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://2.bp.blogspot.com/_hTm-LSlj8U4/TBopPQ1oD4I/AAAAAAAAANs/FlNSbSigV0s/s400/vikinglander.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5483740838471667586" /&gt;&lt;/a&gt;&lt;br /&gt;converted to binary mode:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hTm-LSlj8U4/TBophOOY4BI/AAAAAAAAAN0/tvJGpwSoD2M/s1600/vikinglander_binary.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 399px; height: 400px;" src="http://1.bp.blogspot.com/_hTm-LSlj8U4/TBophOOY4BI/AAAAAAAAAN0/tvJGpwSoD2M/s400/vikinglander_binary.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5483741147007868946" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-6886223609859506494?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/8arfDK_MwEG1DjaJxX_q-IAFa2A/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/8arfDK_MwEG1DjaJxX_q-IAFa2A/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/8arfDK_MwEG1DjaJxX_q-IAFa2A/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/8arfDK_MwEG1DjaJxX_q-IAFa2A/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/6886223609859506494/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2010/06/binary-filter.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/6886223609859506494?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/6886223609859506494?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2010/06/binary-filter.html" title="Binary filter Pixel Shader" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_hTm-LSlj8U4/TBopPQ1oD4I/AAAAAAAAANs/FlNSbSigV0s/s72-c/vikinglander.jpg" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;C0UNQnk_eip7ImA9Wx5TEEo.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-7859761065660525565</id><published>2010-06-15T01:55:00.000-07:00</published><updated>2010-07-25T08:21:33.742-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-07-25T08:21:33.742-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Pixel Shader" /><category scheme="http://www.blogger.com/atom/ns#" term="Self-projection" /><title>Self-projection Pixel Shader</title><content type="html">Image is several times scaled and projected on itself. This concrete GLSL pixel shader projects image on itself 2 times:&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;pre style="color: green"&gt;&lt;br /&gt;uniform sampler2D tex;&lt;br /&gt;&lt;br /&gt;bool inRectangle(in vec2 xloc, in vec2 loc, in vec2 size) {&lt;br /&gt;  return xloc[0] &gt;= loc[0] &amp;&amp; &lt;br /&gt;  xloc[1] &gt;= loc[1] &amp;&amp; &lt;br /&gt;  xloc[0] &lt;= loc[0]+size[0] &amp;&amp; &lt;br /&gt;  xloc[1] &lt;= loc[1]+size[1];&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void main()&lt;br /&gt;{&lt;br /&gt; vec2 start1 = vec2(0.19,0.11);&lt;br /&gt; vec2 size1 = vec2(0.495,0.285);&lt;br /&gt; vec2 start2 = start1 + start1*size1; &lt;br /&gt; vec2 size2 = size1*size1;&lt;br /&gt; if (inRectangle(gl_TexCoord[0].xy, start2, size2))&lt;br /&gt;   gl_FragColor = texture2D(tex, (gl_TexCoord[0].xy - start2)/size2);&lt;br /&gt; else if (inRectangle(gl_TexCoord[0].xy, start1, size1))&lt;br /&gt;   gl_FragColor = texture2D(tex, (gl_TexCoord[0].xy - start1)/size1);&lt;br /&gt; else&lt;br /&gt;   gl_FragColor = texture2D(tex, gl_TexCoord[0].xy);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;Image&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hTm-LSlj8U4/TBdByUEh07I/AAAAAAAAANc/dYkdL3ToNTo/s1600/tv.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://4.bp.blogspot.com/_hTm-LSlj8U4/TBdByUEh07I/AAAAAAAAANc/dYkdL3ToNTo/s400/tv.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5482923403983836082" /&gt;&lt;/a&gt;&lt;br /&gt;and self-projected version of it&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hTm-LSlj8U4/TBdCJLugF1I/AAAAAAAAANk/ks9vaaZ9DPQ/s1600/tv_selfprojected.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://2.bp.blogspot.com/_hTm-LSlj8U4/TBdCJLugF1I/AAAAAAAAANk/ks9vaaZ9DPQ/s400/tv_selfprojected.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5482923796880955218" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-7859761065660525565?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/HYRt52zrpUc2PYi1hPui2pbmPz0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/HYRt52zrpUc2PYi1hPui2pbmPz0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/HYRt52zrpUc2PYi1hPui2pbmPz0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/HYRt52zrpUc2PYi1hPui2pbmPz0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/7859761065660525565/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2010/06/self-projection.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/7859761065660525565?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/7859761065660525565?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2010/06/self-projection.html" title="Self-projection Pixel Shader" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_hTm-LSlj8U4/TBdByUEh07I/AAAAAAAAANc/dYkdL3ToNTo/s72-c/tv.jpg" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;C0QGRX85eSp7ImA9Wx5TEEo.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-5295281652476648587</id><published>2010-06-14T01:17:00.000-07:00</published><updated>2010-07-25T08:22:04.121-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-07-25T08:22:04.121-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Pixelation" /><category scheme="http://www.blogger.com/atom/ns#" term="Pixel Shader" /><title>Pixelation Pixel Shader</title><content type="html">Pixelation is process when pixel at x,y is duplicated into x+dx,y+dy rectangle. Pixelation GLSL fragment code:&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;pre style="color: green"&gt;&lt;br /&gt;uniform sampler2D tex;&lt;br /&gt;&lt;br /&gt;void main()&lt;br /&gt;{&lt;br /&gt; float dx = 15.*(1./512.);&lt;br /&gt; float dy = 10.*(1./512.);&lt;br /&gt; vec2 coord = vec2(dx*floor(gl_TexCoord[0].x/dx),&lt;br /&gt;                   dy*floor(gl_TexCoord[0].y/dy));&lt;br /&gt; gl_FragColor = texture2D(tex, coord);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;Smart&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hTm-LSlj8U4/TBXnDYJes4I/AAAAAAAAANM/FIQ7I1ZMjeo/s1600/smart.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://3.bp.blogspot.com/_hTm-LSlj8U4/TBXnDYJes4I/AAAAAAAAANM/FIQ7I1ZMjeo/s400/smart.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5482542166601282434" /&gt;&lt;/a&gt;&lt;br /&gt;and pixelated version of it&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hTm-LSlj8U4/TBXnUM5oDoI/AAAAAAAAANU/O7ra35CXizE/s1600/smart_pixelated.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 398px;" src="http://4.bp.blogspot.com/_hTm-LSlj8U4/TBXnUM5oDoI/AAAAAAAAANU/O7ra35CXizE/s400/smart_pixelated.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5482542455639772802" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-5295281652476648587?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/BuoYPenzekK7RcitELEnCrckklU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/BuoYPenzekK7RcitELEnCrckklU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/BuoYPenzekK7RcitELEnCrckklU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/BuoYPenzekK7RcitELEnCrckklU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/5295281652476648587/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2010/06/pixelation.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/5295281652476648587?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/5295281652476648587?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2010/06/pixelation.html" title="Pixelation Pixel Shader" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_hTm-LSlj8U4/TBXnDYJes4I/AAAAAAAAANM/FIQ7I1ZMjeo/s72-c/smart.jpg" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;C0MHSX06fip7ImA9Wx5TEEo.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-1946262272145903345</id><published>2010-06-11T06:03:00.001-07:00</published><updated>2010-07-25T08:23:58.316-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-07-25T08:23:58.316-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Fog" /><category scheme="http://www.blogger.com/atom/ns#" term="Pixel Shader" /><title>Fog Pixel Shader</title><content type="html">Each pixel is blended with fog color. The bigger pixel distance from observer location - the more pixel color approaches fog color. GLSL fragment code:&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;pre style="color: green"&gt;&lt;br /&gt;&lt;br /&gt;uniform sampler2D tex;&lt;br /&gt;&lt;br /&gt;void main()&lt;br /&gt;{&lt;br /&gt; float FogDensity = 10.;&lt;br /&gt; vec4 FogColor = vec4(0.4,0.2,0.2,1.0);&lt;br /&gt; vec4 CurrentColor = texture2D(tex, gl_TexCoord[0].xy);&lt;br /&gt;&lt;br /&gt;  // distance to target&lt;br /&gt; float FogDistance = distance(vec2(0.49,0.46),gl_TexCoord[0].xy);&lt;br /&gt; &lt;br /&gt; // fog factor&lt;br /&gt; float FogFactor = exp(-abs(FogDistance * FogDensity));&lt;br /&gt;&lt;br /&gt; // linear blend between fog color and pixel color&lt;br /&gt; gl_FragColor = mix(FogColor,CurrentColor,FogFactor);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;br /&gt;Image&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hTm-LSlj8U4/TBI2BlNbDGI/AAAAAAAAAM4/IJPVWv2FETw/s1600/clock_prague.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://2.bp.blogspot.com/_hTm-LSlj8U4/TBI2BlNbDGI/AAAAAAAAAM4/IJPVWv2FETw/s400/clock_prague.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5481503097259494498" /&gt;&lt;/a&gt;&lt;br /&gt;and after fog shader applied:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hTm-LSlj8U4/TBI2tLgnR1I/AAAAAAAAANA/TwyGey9cC8k/s1600/clock_prague_fog.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://4.bp.blogspot.com/_hTm-LSlj8U4/TBI2tLgnR1I/AAAAAAAAANA/TwyGey9cC8k/s400/clock_prague_fog.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5481503846274910034" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-1946262272145903345?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Oon0XwInZTHROHxpwQ_5I4P02yI/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Oon0XwInZTHROHxpwQ_5I4P02yI/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Oon0XwInZTHROHxpwQ_5I4P02yI/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Oon0XwInZTHROHxpwQ_5I4P02yI/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/1946262272145903345/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2010/06/fog.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/1946262272145903345?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/1946262272145903345?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2010/06/fog.html" title="Fog Pixel Shader" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_hTm-LSlj8U4/TBI2BlNbDGI/AAAAAAAAAM4/IJPVWv2FETw/s72-c/clock_prague.jpg" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;C0IFQHY6cCp7ImA9Wx5TEEo.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-5856252972916704193</id><published>2010-06-09T07:31:00.001-07:00</published><updated>2010-07-25T08:25:11.818-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-07-25T08:25:11.818-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Pixel Shader" /><category scheme="http://www.blogger.com/atom/ns#" term="Frosted glass" /><title>Frosted glass Pixel Shader</title><content type="html">We can get frosted glass effect by shifting pixel location with pseudo-random vector, such as after shift respective pattern emerges. Frosted glass GLSL pixel shader code:&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;pre style="color: green"&gt;&lt;br /&gt;uniform sampler2D tex;&lt;br /&gt;&lt;br /&gt;float rand(vec2 co){&lt;br /&gt;  return fract(sin(dot(co.xy ,vec2(92.,80.))) + &lt;br /&gt;                  cos(dot(co.xy ,vec2(41.,62.))) * 5.1);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void main()&lt;br /&gt;{&lt;br /&gt;  vec2 rnd = vec2(rand(gl_TexCoord[0].xy),rand(gl_TexCoord[0].xy));&lt;br /&gt;  gl_FragColor = texture2D(tex, gl_TexCoord[0].xy+rnd*0.05);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;br /&gt;Original image &lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hTm-LSlj8U4/TA-qEnNbweI/AAAAAAAAAMo/0jpieaUER1E/s1600/Boxer_dog.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://3.bp.blogspot.com/_hTm-LSlj8U4/TA-qEnNbweI/AAAAAAAAAMo/0jpieaUER1E/s400/Boxer_dog.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5480786267754709474" /&gt;&lt;/a&gt;&lt;br /&gt;and processed with frosted glass filter&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hTm-LSlj8U4/TA-q0nguvMI/AAAAAAAAAMw/Dr4mXcH1-z8/s1600/Boxer_dog_frosted.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 398px; height: 400px;" src="http://2.bp.blogspot.com/_hTm-LSlj8U4/TA-q0nguvMI/AAAAAAAAAMw/Dr4mXcH1-z8/s400/Boxer_dog_frosted.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5480787092469365954" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-5856252972916704193?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/2ry4fAaxvj1i6ZdAH0VWYjVizA8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/2ry4fAaxvj1i6ZdAH0VWYjVizA8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/2ry4fAaxvj1i6ZdAH0VWYjVizA8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/2ry4fAaxvj1i6ZdAH0VWYjVizA8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/5856252972916704193/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2010/06/frosted-glass.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/5856252972916704193?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/5856252972916704193?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2010/06/frosted-glass.html" title="Frosted glass Pixel Shader" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_hTm-LSlj8U4/TA-qEnNbweI/AAAAAAAAAMo/0jpieaUER1E/s72-c/Boxer_dog.jpg" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;C0IHQHczfyp7ImA9Wx5TEEo.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-5551418438210604407</id><published>2010-06-07T04:17:00.001-07:00</published><updated>2010-07-25T08:25:31.987-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-07-25T08:25:31.987-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Explosion" /><category scheme="http://www.blogger.com/atom/ns#" term="implosion" /><category scheme="http://www.blogger.com/atom/ns#" term="Pixel Shader" /><title>Explosion and implosion Pixel Shader</title><content type="html">Explosion/Implosion filter can be modeled by shifting pixel outwards/towards the center of image by value which is proportional to pixel distance from the center of image.&lt;br /&gt;Explosion/Implosion pixel shader code in GLSL:&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;pre style="color: green"&gt;&lt;br /&gt;uniform sampler2D tex;&lt;br /&gt;&lt;br /&gt;void main()&lt;br /&gt;{&lt;br /&gt; vec2 cen = vec2(0.5,0.5) - gl_TexCoord[0].xy;&lt;br /&gt; vec2 mcen = - // delete minus for implosion effect&lt;br /&gt;      0.07*log(length(cen))*normalize(cen);&lt;br /&gt; gl_FragColor = texture2D(tex, gl_TexCoord[0].xy+mcen);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;br /&gt;By applying this filter to image below&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hTm-LSlj8U4/TAzX1P0gfkI/AAAAAAAAAMQ/KD2Nn50I10A/s1600/power.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 366px;" src="http://3.bp.blogspot.com/_hTm-LSlj8U4/TAzX1P0gfkI/AAAAAAAAAMQ/KD2Nn50I10A/s400/power.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5479992156382854722" /&gt;&lt;/a&gt;&lt;br /&gt;we get such explosion effect&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hTm-LSlj8U4/TAzYY7WbH-I/AAAAAAAAAMY/JzvQqgEG3-U/s1600/power_exp.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 399px; height: 400px;" src="http://1.bp.blogspot.com/_hTm-LSlj8U4/TAzYY7WbH-I/AAAAAAAAAMY/JzvQqgEG3-U/s400/power_exp.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5479992769363255266" /&gt;&lt;/a&gt;&lt;br /&gt;and such implosion effect&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hTm-LSlj8U4/TAzYr5NzD-I/AAAAAAAAAMg/YH74eggnT0I/s1600/power_imp.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://1.bp.blogspot.com/_hTm-LSlj8U4/TAzYr5NzD-I/AAAAAAAAAMg/YH74eggnT0I/s400/power_imp.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5479993095207718882" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-5551418438210604407?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/1ssm1ZL0DtY7RrDjaGk7NvI5WWo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/1ssm1ZL0DtY7RrDjaGk7NvI5WWo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/1ssm1ZL0DtY7RrDjaGk7NvI5WWo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/1ssm1ZL0DtY7RrDjaGk7NvI5WWo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/5551418438210604407/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2010/06/explosion-and-implosion.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/5551418438210604407?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/5551418438210604407?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2010/06/explosion-and-implosion.html" title="Explosion and implosion Pixel Shader" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_hTm-LSlj8U4/TAzX1P0gfkI/AAAAAAAAAMQ/KD2Nn50I10A/s72-c/power.jpg" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;C0AFRXwyfSp7ImA9Wx5TEEo.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-7290657190259591016</id><published>2010-06-03T23:56:00.001-07:00</published><updated>2010-07-25T08:28:34.295-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-07-25T08:28:34.295-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Pixel Shader" /><category scheme="http://www.blogger.com/atom/ns#" term="edge detection" /><title>Edge detection Pixel Shader</title><content type="html">This time i will write short edge detection tutorial for OpenGL GLSL language. Suppose we have 9 pixels such as below :&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hTm-LSlj8U4/TAimHrrMJKI/AAAAAAAAALw/lHT8epk6tBA/s1600/edge_pix.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 200px; height: 200px;" src="http://1.bp.blogspot.com/_hTm-LSlj8U4/TAimHrrMJKI/AAAAAAAAALw/lHT8epk6tBA/s400/edge_pix.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5478811597609378978" /&gt;&lt;/a&gt;&lt;br /&gt;We want to find out intensity of pixel I_x after applying edge detection filter. In simple edge detection model intensity I_x can be defined as:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hTm-LSlj8U4/TAipzN9e1rI/AAAAAAAAAL4/5z-69472yLk/s1600/edge_form.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 361px; height: 42px;" src="http://1.bp.blogspot.com/_hTm-LSlj8U4/TAipzN9e1rI/AAAAAAAAAL4/5z-69472yLk/s400/edge_form.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5478815644082165426" /&gt;&lt;/a&gt;&lt;br /&gt;That is - for being able to calculate pixel intensity we need to find out intensity differences between neighboring pixels and average them. Pixel shader program which implements this idea is given below (In GLSL language):&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;pre style="color: green"&gt;&lt;br /&gt;uniform sampler2D tex;&lt;br /&gt;&lt;br /&gt;float threshold(in float thr1, in float thr2 , in float val) {&lt;br /&gt; if (val &lt; thr1) {return 0.0;}&lt;br /&gt; if (val &gt; thr2) {return 1.0;}&lt;br /&gt; return val;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// averaged pixel intensity from 3 color channels&lt;br /&gt;float avg_intensity(in vec4 pix) {&lt;br /&gt; return (pix.r + pix.g + pix.b)/3.;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;vec4 get_pixel(in vec2 coords, in float dx, in float dy) {&lt;br /&gt; return texture2D(tex,coords + vec2(dx, dy));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// returns pixel color&lt;br /&gt;float IsEdge(in vec2 coords){&lt;br /&gt;  float dxtex = 1.0 / 512.0 /*image width*/;&lt;br /&gt;  float dytex = 1.0 / 512.0 /*image height*/;&lt;br /&gt;  float pix[9];&lt;br /&gt;  int k = -1;&lt;br /&gt;  float delta;&lt;br /&gt;&lt;br /&gt;  // read neighboring pixel intensities&lt;br /&gt;  for (int i=-1; i&lt;2; i++) {&lt;br /&gt;   for(int j=-1; j&lt;2; j++) {&lt;br /&gt;    k++;&lt;br /&gt;    pix[k] = avg_intensity(get_pixel(coords,float(i)*dxtex,&lt;br /&gt;                                          float(j)*dytex));&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // average color differences around neighboring pixels&lt;br /&gt;  delta = (abs(pix[1]-pix[7])+&lt;br /&gt;          abs(pix[5]-pix[3]) +&lt;br /&gt;          abs(pix[0]-pix[8])+&lt;br /&gt;          abs(pix[2]-pix[6])&lt;br /&gt;           )/4.;&lt;br /&gt;&lt;br /&gt;  return threshold(0.25,0.4,clamp(1.8*delta,0.0,1.0));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void main()&lt;br /&gt;{&lt;br /&gt;  vec4 color = vec4(0.0,0.0,0.0,1.0);&lt;br /&gt;  color.g = IsEdge(gl_TexCoord[0].xy);&lt;br /&gt;  gl_FragColor = color;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;So by using this shader this image =&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hTm-LSlj8U4/TAitFw1cwpI/AAAAAAAAAMA/Ooclrjg-G-o/s1600/astronaut.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://2.bp.blogspot.com/_hTm-LSlj8U4/TAitFw1cwpI/AAAAAAAAAMA/Ooclrjg-G-o/s400/astronaut.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5478819261216244370" /&gt;&lt;/a&gt;&lt;br /&gt;is transformed into this =&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hTm-LSlj8U4/TAitqE9F25I/AAAAAAAAAMI/S326OGOjTBQ/s1600/astronaut_edges.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 398px;" src="http://4.bp.blogspot.com/_hTm-LSlj8U4/TAitqE9F25I/AAAAAAAAAMI/S326OGOjTBQ/s400/astronaut_edges.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5478819885092297618" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;For more advanced algorithms on edge detection - start &lt;a href="http://en.wikipedia.org/wiki/Edge_detection"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Have fun with pixel shaders !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-7290657190259591016?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/B4Gl0u_vo9kphrQxsQJX8iWS22c/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/B4Gl0u_vo9kphrQxsQJX8iWS22c/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/B4Gl0u_vo9kphrQxsQJX8iWS22c/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/B4Gl0u_vo9kphrQxsQJX8iWS22c/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/7290657190259591016/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2010/06/edge-detection.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/7290657190259591016?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/7290657190259591016?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2010/06/edge-detection.html" title="Edge detection Pixel Shader" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_hTm-LSlj8U4/TAimHrrMJKI/AAAAAAAAALw/lHT8epk6tBA/s72-c/edge_pix.png" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CkEERHk8cSp7ImA9Wx9UF0U.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-4688707806740687254</id><published>2010-05-21T02:35:00.000-07:00</published><updated>2011-02-15T06:36:45.779-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-15T06:36:45.779-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="game development" /><category scheme="http://www.blogger.com/atom/ns#" term="iPhone games" /><title>Pong Hau K'i</title><content type="html">My first iPhone app is on App Store now. It is a Chinese board game Pong Hau K'i. You can check my game at App Store &lt;a href="http://itunes.apple.com/us/app/pong-hau-ki/id372394156?mt=8"&gt;here&lt;/a&gt;. If you want - you can see a &lt;a href="http://www.youtube.com/watch?v=Q5lhKyfPRC8"&gt;gameplay&lt;/a&gt; of Pong Hau K'i.&lt;br /&gt;Here are some promotional codes for the first lucky players ;) -&gt;&lt;br /&gt;&lt;br /&gt;EKWKYHAPNL6X&lt;br /&gt;HH9RAXLWPRJP&lt;br /&gt;T7JNHRFEHXAM&lt;br /&gt;467PEPJRWRN9&lt;br /&gt;JXT93WN9RXJP&lt;br /&gt;4JLN4M9EYX73&lt;br /&gt;EWXALNN676WP&lt;br /&gt;F6XHNXEE9Y4K&lt;br /&gt;J9JH3EEPPL9J&lt;br /&gt;HTJFK9R7RKMJ&lt;br /&gt;&lt;br /&gt;Have a nice play !&lt;br /&gt;&lt;br /&gt;p.s.&lt;br /&gt;If you will use promo code - please write customer review for this game on iTunes.&lt;br /&gt;Thanks!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-4688707806740687254?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/A1YLnS8zdBkJlmoOoUNCm6L-KJE/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/A1YLnS8zdBkJlmoOoUNCm6L-KJE/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/A1YLnS8zdBkJlmoOoUNCm6L-KJE/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/A1YLnS8zdBkJlmoOoUNCm6L-KJE/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/4688707806740687254/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2010/05/pong-hau-ki.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/4688707806740687254?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/4688707806740687254?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2010/05/pong-hau-ki.html" title="Pong Hau K'i" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DkcNQno-fip7ImA9WxBbFUs.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-2082551091863490230</id><published>2010-03-12T07:26:00.000-08:00</published><updated>2010-03-14T03:54:53.456-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-03-14T03:54:53.456-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Lang_Lua" /><category scheme="http://www.blogger.com/atom/ns#" term="Fractals" /><title>Design your own fractal</title><content type="html">After I found &lt;a href="http://mypages.iit.edu/~krawczyk/fract01.pdf"&gt;this&lt;/a&gt; interesting paper - I decided to write some sort of fractal generation program that tests that paper idea of different generators and initiators. Basic fractal generation algorithm is this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;1. Draw initiator shape (triangle, rectangle, or other polygon)&lt;br /&gt;2. Draw generator polyline&lt;br /&gt;3. Set initial fractal to initiator shape&lt;br /&gt;4. For each iteration&lt;br /&gt;      For each fractal line&lt;br /&gt;         Replace line with generator polyline&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Thats it. After some iterations new fractal figure will emerge. Of cource "real" fractal generation agorithm is a bit more complex - there will be generator polyline scaling / rotation / translation operations, but lets not focus on details :-) If you will want my program you can download it and check all details. In my program you can draw generator as well as initiator and see resulting fractal (calculated in 6 iterations). You can download my program from &lt;a href="http://someblogfiles.googlegroups.com/web/Fractals.zip?gda=lBv__z8AAABl5m-847h8m0JnFYu-FhHoSOXEbl8NR8yN4zMOzM2QNOuAJOM504tsTlmAausKPreccyFKn-rNKC-d1pM_IdV0"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;strong&gt;Known issues:&lt;/strong&gt;&lt;br /&gt;&lt;em&gt;Please use not more than 8 lines for generator or initiator. Otherwise fractal generation process can hang-up because of too many intermediate steps involved.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;NOTE: This program is coded in Lua language,- by using free &lt;a href="http://love2d.org/"&gt;2D game engine&lt;/a&gt;,- so to be able to run my program you need to install above mentioned 2D game engine and after that you can extract Fractals.zip archive and run "Fractals.love" program. If you need to see Lua program code - then just rename "Fractals.love" to some *.zip file, extract it and you can see file "main.lua" - source code. BTW, &lt;a href="http://www.lua.org/"&gt;Lua&lt;/a&gt; is great scripting language, which programs on average &lt;a href="http://shootout.alioth.debian.org/u32/benchmark.php?test=all&amp;lang=lua&amp;lang2=python3"&gt;runs faster&lt;/a&gt; than Ruby or Python scripts and Lua core is very lightweight - that is why Lua is very suitable for embedding purposes,- such as &lt;a href="http://en.wikipedia.org/wiki/Category:Lua-scripted_video_games"&gt;scripting language for game engines&lt;/a&gt;. Also I want to praise love 2D game engine. It is very good for game/animation prototyping tasks. Also has good learning curve. So if you need rapid prototyping of games - you can use love 2D engine with Lua. Enough rants, lets see some resulting fractals :-). At first some classic ones.&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Koch_snowflake"&gt;Koch snowflake:&lt;/a&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_hTm-LSlj8U4/S5p-RYhRn_I/AAAAAAAAAKQ/-ximQ_CFMyA/s1600-h/frac1.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 298px;" src="http://3.bp.blogspot.com/_hTm-LSlj8U4/S5p-RYhRn_I/AAAAAAAAAKQ/-ximQ_CFMyA/s400/frac1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5447805536362930162" /&gt;&lt;/a&gt;&lt;br /&gt;Modified &lt;a href="http://mathworld.wolfram.com/KochAntisnowflake.html"&gt;Koch antisnowflake:&lt;/a&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_hTm-LSlj8U4/S5p_ZVodoHI/AAAAAAAAAKY/3A949R2n3J0/s1600-h/frac2.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 287px;" src="http://3.bp.blogspot.com/_hTm-LSlj8U4/S5p_ZVodoHI/AAAAAAAAAKY/3A949R2n3J0/s400/frac2.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5447806772538351730" /&gt;&lt;/a&gt;&lt;br /&gt;Structure composed of &lt;a href="http://en.wikipedia.org/wiki/Sierpinski_triangle"&gt;Sierpinski triangles:&lt;/a&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_hTm-LSlj8U4/S5qAlYUrnpI/AAAAAAAAAKg/QJGRS0YT5iM/s1600-h/frac3.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 315px;" src="http://1.bp.blogspot.com/_hTm-LSlj8U4/S5qAlYUrnpI/AAAAAAAAAKg/QJGRS0YT5iM/s400/frac3.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5447808078930747026" /&gt;&lt;/a&gt;&lt;br /&gt;This remainds to me &lt;a href="http://en.wikipedia.org/wiki/Dragon_curve"&gt;dragon curve:&lt;/a&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_hTm-LSlj8U4/S5qBoZaihFI/AAAAAAAAAKo/_Sw3edh_dv0/s1600-h/frac4.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 337px;" src="http://4.bp.blogspot.com/_hTm-LSlj8U4/S5qBoZaihFI/AAAAAAAAAKo/_Sw3edh_dv0/s400/frac4.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5447809230274987090" /&gt;&lt;/a&gt;&lt;br /&gt;And now, more bizarre fractals.&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_hTm-LSlj8U4/S5qCRJaq_HI/AAAAAAAAAKw/nFusf2q5oGs/s1600-h/frac5.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 373px;" src="http://3.bp.blogspot.com/_hTm-LSlj8U4/S5qCRJaq_HI/AAAAAAAAAKw/nFusf2q5oGs/s400/frac5.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5447809930355211378" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_hTm-LSlj8U4/S5qCiR08R3I/AAAAAAAAAK4/4nHLcsAtrE4/s1600-h/frac6.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 328px;" src="http://2.bp.blogspot.com/_hTm-LSlj8U4/S5qCiR08R3I/AAAAAAAAAK4/4nHLcsAtrE4/s400/frac6.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5447810224670656370" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_hTm-LSlj8U4/S5qCvzc2KLI/AAAAAAAAALA/8jN9YP3unZo/s1600-h/frac7.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 326px;" src="http://2.bp.blogspot.com/_hTm-LSlj8U4/S5qCvzc2KLI/AAAAAAAAALA/8jN9YP3unZo/s400/frac7.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5447810457034696882" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_hTm-LSlj8U4/S5qC7vsm8RI/AAAAAAAAALI/-h7fngDniKk/s1600-h/frac8.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 384px;" src="http://1.bp.blogspot.com/_hTm-LSlj8U4/S5qC7vsm8RI/AAAAAAAAALI/-h7fngDniKk/s400/frac8.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5447810662185496850" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_hTm-LSlj8U4/S5qDHsfCiOI/AAAAAAAAALQ/_7U44wumQSs/s1600-h/frac9.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 336px;" src="http://1.bp.blogspot.com/_hTm-LSlj8U4/S5qDHsfCiOI/AAAAAAAAALQ/_7U44wumQSs/s400/frac9.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5447810867481708770" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_hTm-LSlj8U4/S5qDbwkaPHI/AAAAAAAAALY/EtMXKhMQPBU/s1600-h/frac10.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 321px;" src="http://2.bp.blogspot.com/_hTm-LSlj8U4/S5qDbwkaPHI/AAAAAAAAALY/EtMXKhMQPBU/s400/frac10.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5447811212175359090" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_hTm-LSlj8U4/S5qDv1Czv6I/AAAAAAAAALg/xGs7PGD8xtA/s1600-h/frac11.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 383px;" src="http://3.bp.blogspot.com/_hTm-LSlj8U4/S5qDv1Czv6I/AAAAAAAAALg/xGs7PGD8xtA/s400/frac11.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5447811556973985698" /&gt;&lt;/a&gt;&lt;br /&gt;Now my favorite one :-)&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_hTm-LSlj8U4/S5qEJRrMrgI/AAAAAAAAALo/FdeuLq5HJL8/s1600-h/frac12.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 319px;" src="http://2.bp.blogspot.com/_hTm-LSlj8U4/S5qEJRrMrgI/AAAAAAAAALo/FdeuLq5HJL8/s400/frac12.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5447811994156314114" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;strong&gt;Conclusions:&lt;/strong&gt;&lt;br /&gt;Seems there is a lot of space for experimenting with different types of generator/initiator.&lt;br /&gt;&lt;br /&gt;Have fun with fractals and Lua !!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-2082551091863490230?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/FpCzaPziK5cExs4U60qqoW79oBg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FpCzaPziK5cExs4U60qqoW79oBg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/FpCzaPziK5cExs4U60qqoW79oBg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FpCzaPziK5cExs4U60qqoW79oBg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/2082551091863490230/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2010/03/design-your-own-fractal.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/2082551091863490230?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/2082551091863490230?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2010/03/design-your-own-fractal.html" title="Design your own fractal" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_hTm-LSlj8U4/S5p-RYhRn_I/AAAAAAAAAKQ/-ximQ_CFMyA/s72-c/frac1.jpg" height="72" width="72" /><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;C0UAQ3k-eCp7ImA9Wx9UF0U.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-4784635941914832888</id><published>2010-02-05T10:34:00.000-08:00</published><updated>2011-02-15T06:47:22.750-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-15T06:47:22.750-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Lang_C++" /><category scheme="http://www.blogger.com/atom/ns#" term="game development" /><category scheme="http://www.blogger.com/atom/ns#" term="DirectX" /><title>Carousel - fishing card game</title><content type="html">This time I was trying to learn C++ and DirectX and in the process of that to make some card game. So finally here it is - approximatelly 2500 lines of C++ code and game is finished and running (without bugs I suppose ) :-). You can download this card game from &lt;a href="http://docs.google.com/leaf?id=0BwrFeS7BioZiMGYwNjQ3OGItNjUyOS00MDg5LTg2NjUtYTE4ZjgxNDEwOGQz&amp;hl=en"&gt;here (3.7 Mb)&lt;/a&gt;&lt;br /&gt;and source code &lt;a href="http://docs.google.com/leaf?id=0BwrFeS7BioZiZTlkZmQ2NzItMTQ2Mi00OTYyLWIwYjQtODAxMjAzYzQyMDJm&amp;hl=en"&gt;from here&lt;/a&gt;.&lt;br /&gt;You can use source as you wish - no restrictions applied :-)&lt;br /&gt;&lt;br /&gt;Here are some screeshots to stimulate your appetite :-) =&gt;&lt;br /&gt;Game menu screen:&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_hTm-LSlj8U4/S2xsZpeNNXI/AAAAAAAAAKA/UTg_1Rm1pUg/s1600-h/game_menu.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_hTm-LSlj8U4/S2xsZpeNNXI/AAAAAAAAAKA/UTg_1Rm1pUg/s400/game_menu.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5434838038214423922" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Playing screen:&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_hTm-LSlj8U4/S2xslNEY--I/AAAAAAAAAKI/tWo9-M1qZnM/s1600-h/Carousel.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_hTm-LSlj8U4/S2xslNEY--I/AAAAAAAAAKI/tWo9-M1qZnM/s400/Carousel.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5434838236748381154" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Known issues:&lt;/strong&gt;&lt;br /&gt;1. &lt;br /&gt;If after execution of Carousel.exe you get error something like "&lt;strong&gt;this application has failed to start because d3dx9_41.dll was not found&lt;/strong&gt;" - this means that you need to update your DirectX runtime. Go to microsoft site and get latest DirectX runtime.&lt;br /&gt;&lt;br /&gt;2. If after execution you get "&lt;strong&gt;CreateDevice() - FAILED&lt;/strong&gt;" check what video card you have. There is great possibility that game will not run on integrated grapchics cards. Sorry :-)&lt;br /&gt;&lt;br /&gt;Enjoy !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-4784635941914832888?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Zf8tgqgmvbPAw7BlYPa8yCIxqFM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Zf8tgqgmvbPAw7BlYPa8yCIxqFM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Zf8tgqgmvbPAw7BlYPa8yCIxqFM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Zf8tgqgmvbPAw7BlYPa8yCIxqFM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/4784635941914832888/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2010/02/carousel-fishing-card-game.html#comment-form" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/4784635941914832888?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/4784635941914832888?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2010/02/carousel-fishing-card-game.html" title="Carousel - fishing card game" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_hTm-LSlj8U4/S2xsZpeNNXI/AAAAAAAAAKA/UTg_1Rm1pUg/s72-c/game_menu.jpg" height="72" width="72" /><thr:total>4</thr:total></entry><entry gd:etag="W/&quot;DEQNQHk5eip7ImA9Wx5TEEQ.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-932890935397528562</id><published>2009-12-01T12:59:00.000-08:00</published><updated>2010-07-25T15:19:51.722-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-07-25T15:19:51.722-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Lang_C" /><category scheme="http://www.blogger.com/atom/ns#" term="probability theory" /><title>Three doors problem</title><content type="html">There is very interesting problem which solution seems unintuitive, but indeed is correct. Also problem is called &lt;a href="http://en.wikipedia.org/wiki/Monty_Hall_problem"&gt;Monty Hall paradox&lt;/a&gt;. Problem definition is this:&lt;br /&gt;-------------------------------------------------------------&lt;br /&gt;Suppose you're on a game show and you're given the choice of three doors. Behind one door is a car; behind the others, goats [that is, booby prizes]. The car and the goats were placed randomly behind the doors before the show. The rules of the game show are as follows: After you have chosen a door, the door remains closed for the time being. The game show host, Monty Hall, who knows what is behind the doors, now has to open one of the two remaining doors, and the door he opens must have a goat behind it. If both remaining doors have goats behind them, he chooses one randomly. After Monty Hall opens a door with a goat, he will ask you to decide whether you want to stay with your first choice or to switch to the last remaining door. Imagine that you chose Door 1 and the host opens Door 3, which has a goat. He then asks you "Do you want to switch to Door Number 2?" Is it to your advantage to change your choice?&lt;br /&gt;-------------------------------------------------------------&lt;br /&gt;Now what is probability that switching to last remaining door will reveal a car ?&lt;br /&gt;This probability is 2/3. I will not explain it here, because it is very well explained in wikipedia site. It is more interesting to note that problem solution gets somewhat different when one must taken into account host bias. That is - what if host will have freedom to offer (or not) switching door ? If we define probability of host offering door switch when one looses (chooses door with goat) as &lt;span style="font-weight:bold;"&gt;Pol&lt;/span&gt;, and probability of host offering door switch when one wins (chooses door with car) as &lt;span style="font-weight:bold;"&gt;Pow&lt;/span&gt;. Then we can relate these two probabilities as &lt;span style="color:#990000;"&gt;&lt;br /&gt;Pow=1-Pol&lt;/span&gt; and define host bias, which is &lt;span style="color:#990000;"&gt;bias=Pol-Pow&lt;/span&gt;.&lt;br /&gt;So now we have required information and we can conduct experiment/simulation which will reveal host bias impact on probability that door switching wins.&lt;br /&gt;&lt;br /&gt;Experiment algorithm is as follows - &lt;br /&gt;1. Take some bias from the range [-1;1]&lt;br /&gt;2. Calculate Pow,Pol according this bias.&lt;br /&gt;3. Simulate 500 000 games with this bias.&lt;br /&gt;3a.  According to these probabilities Pow,Pol - offer (or not) door change to player.&lt;br /&gt;3b.  If switch was offered and switching win the car - increase won games.&lt;br /&gt;4. Calculate win probability when switching doors, with current host bias.&lt;br /&gt;5. Repeat everything from 1. until bias range is covered.&lt;br /&gt;&lt;br /&gt;Code which did these measurements is this (this time coded in plain good C):&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;pre style="color: green"&gt;&lt;br /&gt;#include &amp;#60;stdio.h&amp;#62;&lt;br /&gt;#include &amp;#60;stdlib.h&amp;#62;&lt;br /&gt;#include &amp;#60;time.h&amp;#62;&lt;br /&gt;&lt;br /&gt;struct Game {&lt;br /&gt; int PrizeDoor;&lt;br /&gt; int ChosenDoor;&lt;br /&gt; int RevealDoor;&lt;br /&gt; int OtherDoor;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;// Reveal one empty door and calculate what door left for changing&lt;br /&gt;void OpenDoor(struct Game *gm) {&lt;br /&gt; for (int i=0; i!=3; ++i) {&lt;br /&gt;  if (i!=gm-&gt;ChosenDoor &amp;&amp; i!=gm-&gt;PrizeDoor ) {&lt;br /&gt;   gm-&gt;RevealDoor = i;&lt;br /&gt;   gm-&gt;OtherDoor = 3 - (gm-&gt;ChosenDoor + gm-&gt;RevealDoor);&lt;br /&gt;   break;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Calculate probability that changing door wins a prize.&lt;br /&gt;// This probability is dependent on host bias towards the fair play.&lt;br /&gt;// Bias +1 - host only offers to change door when one looses.&lt;br /&gt;// Bias  0 - host offers to change door when one looses or wins.&lt;br /&gt;// Bias -1 - host only offers to change door when one wins.&lt;br /&gt;float ProbabilityChangeWins(float bias, int games) {&lt;br /&gt; float Pol, Pow, Prob, ProbChangeWins ;&lt;br /&gt; int TotalWins = 0, gamesWithOffers = 0;&lt;br /&gt; struct Game gm;&lt;br /&gt;&lt;br /&gt; Pol = (bias+1.0)/2.0;&lt;br /&gt; Pow = 1.0-Pol;&lt;br /&gt; srand(time(NULL));&lt;br /&gt;&lt;br /&gt; // Main game test loop. The doors are numbered as 0,1,2.&lt;br /&gt; for (int i=0; i!=games; ++i) {&lt;br /&gt;  gm.PrizeDoor  = rand()%3;&lt;br /&gt;  gm.ChosenDoor = rand()%3;&lt;br /&gt;  Prob = (gm.PrizeDoor == gm.ChosenDoor) ? Pow : Pol; &lt;br /&gt;  // host offers to change doors based on his bias.&lt;br /&gt;  if (((float)rand()/RAND_MAX) &lt; Prob) {&lt;br /&gt;   gamesWithOffers++;&lt;br /&gt;   OpenDoor(&amp;gm);&lt;br /&gt;   TotalWins += (gm.OtherDoor == gm.PrizeDoor);&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; ProbChangeWins = ((float)TotalWins)/gamesWithOffers;&lt;br /&gt;&lt;br /&gt; return ProbChangeWins;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main(void)&lt;br /&gt;{&lt;br /&gt; for (float i = -1.0; i &lt; 1.05; i+=0.05)&lt;br /&gt;  printf("Bias = %1.2f | ProbabilityOfChangeWins = %1.2f\n",&lt;br /&gt;      i,ProbabilityChangeWins(i,500000));&lt;br /&gt; &lt;br /&gt; return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;Results of this experiment is graph plotted as switch win probability dependence on host bias:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hTm-LSlj8U4/SxWsouKvoEI/AAAAAAAAAJw/0pJSk-b4OIQ/s1600/3doors.PNG"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 294px;" src="http://1.bp.blogspot.com/_hTm-LSlj8U4/SxWsouKvoEI/AAAAAAAAAJw/0pJSk-b4OIQ/s400/3doors.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5410420342943359042" /&gt;&lt;/a&gt;&lt;br /&gt;Results is interesting and can be seen that host bias can shift "standard" problem solution very much.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Conclusions&lt;/span&gt;&lt;br /&gt;1. Host can affect game outcome in such a way that switching doors always looses game or always wins game - in the case of marginal host bias values -1/+1.&lt;br /&gt;2. If host is neutral (bias=0) then problem solution becomes the same as in "standard" way - swithing doors wins with the 2/3 probability.&lt;br /&gt;3. Even if host is slightly shifted toward negative bias, that is bias &gt; -0.3, switching doors is still beneficial.&lt;br /&gt;4. What is more interesting that host bias can be established from the probability of win when switching doors. This means that from people who participated in that game and switched doors we can deduce host bias and tell if the game was fair or in what "amount" it was fair.&lt;br /&gt;&lt;br /&gt;Have fun with probabilities and three door problem !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-932890935397528562?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Go45ug-8UVsaxxy50eRODw8VFns/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Go45ug-8UVsaxxy50eRODw8VFns/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Go45ug-8UVsaxxy50eRODw8VFns/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Go45ug-8UVsaxxy50eRODw8VFns/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/932890935397528562/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2009/12/three-doors-problem.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/932890935397528562?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/932890935397528562?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2009/12/three-doors-problem.html" title="Three doors problem" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_hTm-LSlj8U4/SxWsouKvoEI/AAAAAAAAAJw/0pJSk-b4OIQ/s72-c/3doors.PNG" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;D0UCQ3YycCp7ImA9WxBUEUs.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-8587457769872882861</id><published>2009-10-02T10:34:00.000-07:00</published><updated>2010-02-25T22:21:02.898-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-25T22:21:02.898-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Lang_F#" /><category scheme="http://www.blogger.com/atom/ns#" term="math expressions" /><category scheme="http://www.blogger.com/atom/ns#" term="eval" /><title>Evaluating math expressions in F#</title><content type="html">This time we will try to write math expressions evaluator in F#. At first - why we need that ? Well, math expressions evaluator is useful in computer algebra systems - for evaluating some equations. Also such evaluator may be useful for financial institutions where also some kind of formula computation/evaluation is needed and etc. It`s a pitty that such eval function is not implemented in F# language. Possible reasons is that F# is compiled language... Anyway we will try to write such universal eval function which accepts arbitrary math expression and returns result to the user. So what are possible ways of implementing such function in F# ?&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;br /&gt; - by writing so called domain-specific language - math expressions compiler. This is achieved by using some tools such as fsyacc and fslex. Defining custom tokens and etc.&lt;br /&gt;&lt;br /&gt; - by using .NET System.CodeDom.Compiler libraries. This is achieved by generating class definition "on the fly" and with the help of CodeDom - compiling this class in memory.&lt;br /&gt;&lt;br /&gt; - another different approach - is try to write F# script which recursively analyzes math expression and evaluates it piece by piece until it finds the answer. This solution does not use tools mentioned above.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So the last approach will be discussed here. Main algorithm of evaluating math expressions is displayed below:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hTm-LSlj8U4/SsZLF6W1kXI/AAAAAAAAAHs/svR3bAFxuRM/s1600-h/eval_diag.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 307px; height: 400px;" src="http://1.bp.blogspot.com/_hTm-LSlj8U4/SsZLF6W1kXI/AAAAAAAAAHs/svR3bAFxuRM/s400/eval_diag.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5388076569131848050" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;F# code which implements this idea is &lt;a href="http://code.google.com/p/coding-experiments/source/browse/trunk/Fsharp/MathEvaluator.fs"&gt;placed here&lt;/a&gt;.&lt;br /&gt;There are also some eval() function tests implemented in this code. So that after executing this script you will get output something like:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hTm-LSlj8U4/SsZOJNBfCPI/AAAAAAAAAH0/lEuY2kxr9sw/s1600-h/eval_tests.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 229px;" src="http://4.bp.blogspot.com/_hTm-LSlj8U4/SsZOJNBfCPI/AAAAAAAAAH0/lEuY2kxr9sw/s400/eval_tests.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5388079924217055474" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Conclusions:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It is possible to generalize eval() function algorithm in about 90~ lines of F# code without using CodeDom model or fsyacc/fslex tools. This makes solution pretty much "homogeneous" which can be useful in some situations. Also this eval() implementation takes as input arbitrary math expression. As for the bad side - solution is very slow (can be hundreds of times slower than plain F# function call), because of joining/spliting lists constantly. So if you need fast implementation of eval - you should optimize/rewrite this code if possible or take a look in other above mentioned solutions. But in systems where speed issues are not critical - this solution may be OK.&lt;br /&gt;&lt;br /&gt;Have fun with F# and eval !!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-8587457769872882861?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/t2QR7Zlylm2iDW151WhTFhsg8oA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/t2QR7Zlylm2iDW151WhTFhsg8oA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/t2QR7Zlylm2iDW151WhTFhsg8oA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/t2QR7Zlylm2iDW151WhTFhsg8oA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/8587457769872882861/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2009/10/evaluating-math-expressions-in-f.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/8587457769872882861?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/8587457769872882861?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2009/10/evaluating-math-expressions-in-f.html" title="Evaluating math expressions in F#" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_hTm-LSlj8U4/SsZLF6W1kXI/AAAAAAAAAHs/svR3bAFxuRM/s72-c/eval_diag.png" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CU8NSHc8fSp7ImA9Wx5TEEQ.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-8809298968180742603</id><published>2009-09-17T23:07:00.000-07:00</published><updated>2010-07-25T14:38:19.975-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-07-25T14:38:19.975-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="XNA Framework" /><category scheme="http://www.blogger.com/atom/ns#" term="Lang_C#" /><category scheme="http://www.blogger.com/atom/ns#" term="polygon" /><category scheme="http://www.blogger.com/atom/ns#" term="2D graphics" /><category scheme="http://www.blogger.com/atom/ns#" term="geometry" /><title>XNA quest for centroid of polygon</title><content type="html">Now we will talk about XNA Framework and How to find geometrical center of polygon (aka. so called centroid). At first - Why do we need centroid at all ? Well... for example - for some graphics applications we may want drag&amp;drop shape by it`s centroid. Or maybe in some game applications we may need to find shape`s center of gravity, for simulating physics of balancing objects around center of gravity. And in cases when shape material density is uniform (the same over shape) then shape geometrical center (centroid) is also center of gravity (or center of mass). So lets begin search of centroid...&lt;br /&gt;For this you will need:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;- Visual Studio 2008&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;- XNA 3.1 Framework&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;First - some notes about XNA framework. It`s a pitty that such great 2D/3D .NET library doesn`t have 2D primitives drawing routines. Well, actually it has some, but for being able to draw some 2D primitives like points and lines, you should dig deeply in 3D knowledge - for drawing mentioned primitives in MSDN way you should define 3D vectors and 3D viewports !! What the hell ? If user only wants 2D stuff, it means that all 3D stuff should be abstracted out of the view. So that at the end, framework should have separate levels of abstraction into 2D and 3D. But this is not the case about drawing 2D primtives... So one way of drawing point in non-MSDN way is to generate small rectangle texture in run-time and draw this generated texture on screen. Next thing is drawing a simple line in non-MSDN way. Recipe for that - we take generated 2D rectangle texture earlier and draw it as line by scaling and rotating it as needed. After defining this stuff we have all prerequisites for target problem.&lt;br /&gt;Now- How we will find centroid of polygon ? This is not that hard. According to wikipedia &lt;a href="http://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon"&gt;centroid formulas&lt;/a&gt; can be computed simply, assuming we have polygon vertex coordinates and assuming polygon is not complex.&lt;br /&gt;So centroid computation algorithm in C# is this:&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;pre style="color: green"&gt;&lt;br /&gt;public static Vector2 CalculateCentroid(Vector2[] points, &lt;br /&gt;                                        int lastPointIndex)&lt;br /&gt;{&lt;br /&gt;    float area = 0.0f;&lt;br /&gt;    float Cx = 0.0f;&lt;br /&gt;    float Cy = 0.0f;&lt;br /&gt;    float tmp = 0.0f;&lt;br /&gt;    int k;&lt;br /&gt;&lt;br /&gt;    for (int i = 0; i &lt;= lastPointIndex; i++)&lt;br /&gt;    {&lt;br /&gt;        k = (i + 1) % (lastPointIndex + 1);&lt;br /&gt;        tmp = points[i].X * points[k].Y - &lt;br /&gt;              points[k].X * points[i].Y;&lt;br /&gt;        area += tmp;&lt;br /&gt;        Cx += (points[i].X + points[k].X) * tmp;&lt;br /&gt;        Cy += (points[i].Y + points[k].Y) * tmp;&lt;br /&gt;    }&lt;br /&gt;    area *= 0.5f;&lt;br /&gt;    Cx *= 1.0f / (6.0f * area);&lt;br /&gt;    Cy *= 1.0f / (6.0f * area);&lt;br /&gt;&lt;br /&gt;    return new Vector2(Cx, Cy);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;NOTE: this algorithm doesn`t apply for complex polygons&lt;/span&gt;. &lt;br /&gt;But How simply check that polygon is not complex, or not self-intersecting ? One way of doing this is brute-force way -&gt; we can check every polygon edge pair for intersection. If there are some edges which intersects, then polygon is complex, otherwise - simple. So by using this brute-force solution, complex polygon check simplifies to lines self-intersection problem. And How do we check if lines self-intersects ? One way is to find-out 2 linear equations of these lines: y = a1*x + b1 ; y = a2*x + b2.&lt;br /&gt;Then self-intersection point is simply where these equations equals:&lt;br /&gt;a1*x + b1 = a2*x + b2  --&gt; x_intersection = (b2-b1)/(a1-a2). Substituting into any of these two equations we get y_intersection = (a1*b2-a2*b1)/(a1-a2).&lt;br /&gt;Next step - we need to check does lines segments intersects, not the whole lines. This is done just comparing does x_intersection is within x_min,x_max of both lines, the similar check apply for y_intersection. So line intersection check simplifies to finding linear equations slope and intercept constants. This is one way of self-intersection test of lines. But there is also other way to do it (if we don`t need exact intersection point) - suppose we have line1 with end-points l1p1,l1p2 and line2 with end-points l2p1,l2p2. Define function DIRECTION(point1,point2,point3) which returns the direction [CLOCKWISE,COUNTER_CLOCKWISE,LINE] in which we traverse path point1-&gt;point2-&gt;point3. By having such function we can easily define when 2 line segments intersects. Below are one example when lines intersects:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hTm-LSlj8U4/SrOeeJIz7HI/AAAAAAAAAHc/2u3WumvY4tI/s1600-h/intersecting.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 207px;" src="http://1.bp.blogspot.com/_hTm-LSlj8U4/SrOeeJIz7HI/AAAAAAAAAHc/2u3WumvY4tI/s400/intersecting.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5382820220324015218" /&gt;&lt;/a&gt;&lt;br /&gt;Another example when lines do not intersects:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hTm-LSlj8U4/SrOfWqM0YmI/AAAAAAAAAHk/9x-snmrqr0I/s1600-h/non-intersecting.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 265px;" src="http://4.bp.blogspot.com/_hTm-LSlj8U4/SrOfWqM0YmI/AAAAAAAAAHk/9x-snmrqr0I/s400/non-intersecting.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5382821191271866978" /&gt;&lt;/a&gt;&lt;br /&gt;So lines intersects when :&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;direction(l1p1,l1p2,l2p1) != direction(l1p1,l1p2,l2p2) AND &lt;br /&gt;direction(l2p1,l2p2,l1p1) != direction(l2p1,l2p2,l1p2)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This type of lines intersection test is implemented in polygon self-intersection test. So you can download &lt;a href="http://coding-experiments.googlecode.com/svn/trunk/Csharp/Centroid.zip"&gt;centroid XNA 3.1 project&lt;/a&gt; and try experimenting by drawing various polygons and seeing where centroid is computed.&lt;br /&gt;Final part - some results from this project (centroid is draw as black pixel):&lt;br /&gt;Some convex polygons:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hTm-LSlj8U4/SrOBxVCrP2I/AAAAAAAAAGc/dTA3Jmm1kgk/s1600-h/triangle.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 225px; height: 115px;" src="http://2.bp.blogspot.com/_hTm-LSlj8U4/SrOBxVCrP2I/AAAAAAAAAGc/dTA3Jmm1kgk/s320/triangle.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5382788664099815266" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hTm-LSlj8U4/SrOCJiWyZEI/AAAAAAAAAGk/oI-Wai96S_A/s1600-h/trapezoid.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 218px; height: 74px;" src="http://2.bp.blogspot.com/_hTm-LSlj8U4/SrOCJiWyZEI/AAAAAAAAAGk/oI-Wai96S_A/s320/trapezoid.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5382789079990690882" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hTm-LSlj8U4/SrOCzHfBigI/AAAAAAAAAGs/9yPtnfqVPWI/s1600-h/parallelogram.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 166px; height: 87px;" src="http://3.bp.blogspot.com/_hTm-LSlj8U4/SrOCzHfBigI/AAAAAAAAAGs/9yPtnfqVPWI/s320/parallelogram.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5382789794331986434" /&gt;&lt;/a&gt;&lt;br /&gt;Now, more interesting -&gt; concave polygons:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hTm-LSlj8U4/SrOD5kFnvnI/AAAAAAAAAG0/bC4xmzd7eLg/s1600-h/concave1.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 203px; height: 194px;" src="http://3.bp.blogspot.com/_hTm-LSlj8U4/SrOD5kFnvnI/AAAAAAAAAG0/bC4xmzd7eLg/s320/concave1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5382791004600909426" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hTm-LSlj8U4/SrOEObDPDJI/AAAAAAAAAG8/VAsUFwqMOuk/s1600-h/concave2.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 157px; height: 126px;" src="http://2.bp.blogspot.com/_hTm-LSlj8U4/SrOEObDPDJI/AAAAAAAAAG8/VAsUFwqMOuk/s320/concave2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5382791362952236178" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hTm-LSlj8U4/SrOEp36MYNI/AAAAAAAAAHE/6ILQFinwcwQ/s1600-h/concave3.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 166px; height: 189px;" src="http://1.bp.blogspot.com/_hTm-LSlj8U4/SrOEp36MYNI/AAAAAAAAAHE/6ILQFinwcwQ/s320/concave3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5382791834555408594" /&gt;&lt;/a&gt;&lt;br /&gt;From the concave polygon examples (especially from first concave) can be seen that centroid is not the average of (max,min) coordinates in shape. However in some cases it can be that centroid coincides with AVERAGE(Min,Max) of figure (for example for rectangle). But in general - it not. If to talk informally, then centroid is simply the average of ALL points coordinates in shape.&lt;br /&gt;Finally just some examples of complex polygons - as evidence that application detects complex (or self-intersecting) polygons :-) :&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hTm-LSlj8U4/SrOFtACNUrI/AAAAAAAAAHM/SYrXg9Re-jY/s1600-h/complex1.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 108px;" src="http://3.bp.blogspot.com/_hTm-LSlj8U4/SrOFtACNUrI/AAAAAAAAAHM/SYrXg9Re-jY/s320/complex1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5382792987787743922" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hTm-LSlj8U4/SrOGKvdMXQI/AAAAAAAAAHU/as2gJjJLmJM/s1600-h/complex2.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 97px;" src="http://4.bp.blogspot.com/_hTm-LSlj8U4/SrOGKvdMXQI/AAAAAAAAAHU/as2gJjJLmJM/s320/complex2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5382793498733600002" /&gt;&lt;/a&gt;&lt;br /&gt;Actually we can also compute centroids of complex polygon by using info from above mentioned wikipedia site. That is - to get centroid of complex polygon we need:&lt;br /&gt;1. Decompose complex polygon into N simple polygons.&lt;br /&gt;2. Compute area and centroid of each simple polygon by method already explained in this article.&lt;br /&gt;3. Average computed centroids by &lt;a href="http://en.wikipedia.org/wiki/Centroid#Centroid_by_geometric_decomposition"&gt;some formula&lt;/a&gt;.&lt;br /&gt;The main task is number 1. - How effectively split complex polygon into simple ones.&lt;br /&gt;This task is left as exercise to the reader :-)&lt;br /&gt;&lt;br /&gt;Have fun with centroids, polygons, XNA and 2D/3D programming in general !!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-8809298968180742603?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/YxbxAvjAwVatMlYyEh-0lwAOe18/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/YxbxAvjAwVatMlYyEh-0lwAOe18/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/YxbxAvjAwVatMlYyEh-0lwAOe18/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/YxbxAvjAwVatMlYyEh-0lwAOe18/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/8809298968180742603/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2009/09/xna-quest-for-centroid-of-polygon.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/8809298968180742603?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/8809298968180742603?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2009/09/xna-quest-for-centroid-of-polygon.html" title="XNA quest for centroid of polygon" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_hTm-LSlj8U4/SrOeeJIz7HI/AAAAAAAAAHc/2u3WumvY4tI/s72-c/intersecting.png" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CUEGQnY8eip7ImA9Wx5TEEQ.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-4150397248595649036</id><published>2009-06-21T12:23:00.000-07:00</published><updated>2010-07-25T14:33:43.872-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-07-25T14:33:43.872-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Langton's ant" /><category scheme="http://www.blogger.com/atom/ns#" term="Lang_Python" /><category scheme="http://www.blogger.com/atom/ns#" term="cellular automaton" /><title>Langton's ant Or order out of chaos</title><content type="html">This time we will talk about &lt;a href="http://en.wikipedia.org/wiki/Langton%27s_ant"&gt;Langton's ant&lt;/a&gt; - the simple system of simple rules, but with complex behavior. Simple system of Langton`s ant is defined as :&lt;br /&gt;    * At a white square, turn 90° left,  flip the color of the square, move forward one unit&lt;br /&gt;    * At a black square, turn 90° right, flip the color of the square, move forward one unit&lt;br /&gt;This is so called L/R system. But what if for the one color we will have not the one direction, but the direction chain ? That is- for the white squares we will have some chain of 'LRLRR...' events and for the black squares we will have another chain of 'RRLRRL...' events ?? Then we will get so called &lt;a href="http://en.wikipedia.org/wiki/Turmite"&gt;turmite&lt;/a&gt; - a 2D turing machine. So this experiment tests this turmite idea of multiple direction row for the same color. Experiment python script is this:&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;pre style="color: green"&gt;&lt;br /&gt;from Tkinter import *&lt;br /&gt;&lt;br /&gt;rs = raw_input("Enter rule set (e.g.: L/R) =&gt; ")&lt;br /&gt;str0 = rs.split('/')[0]&lt;br /&gt;str1 = rs.split('/')[1]   &lt;br /&gt;i0, i1 = -1, -1&lt;br /&gt;w,h = 500, 500&lt;br /&gt;lx,ly = w/2, h/2&lt;br /&gt;dirx,diry = 0,-1&lt;br /&gt;&lt;br /&gt;# defining absolute directions&lt;br /&gt;vec = {&lt;br /&gt;    (0,1,'L'):(1,0),&lt;br /&gt;    (1,0,'L'):(0,-1),&lt;br /&gt;    (0,-1,'L'):(-1,0),&lt;br /&gt;    (-1,0,'L'):(0,1),&lt;br /&gt;    (0,1,'R'):(-1,0),&lt;br /&gt;    (1,0,'R'):(0,1),&lt;br /&gt;    (0,-1,'R'):(1,0),&lt;br /&gt;    (-1,0,'R'):(0,-1)&lt;br /&gt;    }&lt;br /&gt;mod = 2&lt;br /&gt;grid = dict([((x,y),0) for y in range(0,h,mod) for x in range(0,w,mod)])&lt;br /&gt;&lt;br /&gt;# Initialize Tk window&lt;br /&gt;root = Tk()&lt;br /&gt;ant = Canvas(root,width=w, height=h, bg='white')&lt;br /&gt;ant.pack(fill=BOTH)&lt;br /&gt;&lt;br /&gt;while 1:&lt;br /&gt;    if lx &lt; w and ly &lt; h and lx &gt; 0 and ly &gt; 0:&lt;br /&gt;      if grid[(lx,ly)] == 0:&lt;br /&gt;        i0 = (i0+1)%len(str0)&lt;br /&gt;        rdir = str0[i0]&lt;br /&gt;      elif grid[(lx,ly)] == 1:&lt;br /&gt;        i1 = (i1+1)%len(str1)&lt;br /&gt;        rdir = str1[i1]&lt;br /&gt;      dirx, diry = vec[(dirx,diry,rdir)]&lt;br /&gt;      grid[(lx,ly)] = grid[(lx,ly)]^1&lt;br /&gt;      col = "white" if grid[(lx,ly)] == 0 else "darkorange"&lt;br /&gt;    ant.delete("current")&lt;br /&gt;    ant.create_rectangle(lx, ly, lx+mod-1, ly+mod-1, fill="black",outline="black",tags="current")&lt;br /&gt;    ant.update()&lt;br /&gt;    ant.delete((lx,ly))&lt;br /&gt;    ant.create_rectangle(lx, ly, lx+mod-1, ly+mod-1, fill=col,outline=col,tags=(lx,ly))&lt;br /&gt;    lx,ly = lx+dirx*mod, ly+diry*mod&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;Results are somewhat interesting. At first, the classic Langton`s ant example-&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://coding-experiments.googlecode.com/svn/trunk/Data/L_R.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 247px; height: 180px;" src="http://coding-experiments.googlecode.com/svn/trunk/Data/L_R.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;Can we have system with shorter steps to "highway" ? Seems - yes we can. This is it:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://coding-experiments.googlecode.com/svn/trunk/Data/L_LRL.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 205px; height: 163px;" src="http://coding-experiments.googlecode.com/svn/trunk/Data/L_LRL.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;But this is not the end. There is system which is almost "highway" from the scratch:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://coding-experiments.googlecode.com/svn/trunk/Data/L_RLL.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 223px; height: 168px;" src="http://coding-experiments.googlecode.com/svn/trunk/Data/L_RLL.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And finally- some exotic general Langton`s ant systems:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://coding-experiments.googlecode.com/svn/trunk/Data/LLR_LLRR.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 259px; height: 147px;" src="http://coding-experiments.googlecode.com/svn/trunk/Data/LLR_LLRR.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://coding-experiments.googlecode.com/svn/trunk/Data/LRL_RL.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 328px; height: 109px;" src="http://coding-experiments.googlecode.com/svn/trunk/Data/LRL_RL.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://coding-experiments.googlecode.com/svn/trunk/Data/LRR_LRRR.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 330px; height: 157px;" src="http://coding-experiments.googlecode.com/svn/trunk/Data/LRR_LRRR.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://coding-experiments.googlecode.com/svn/trunk/Data/L_LLRLLRR.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 225px; height: 189px;" src="http://coding-experiments.googlecode.com/svn/trunk/Data/L_LLRLLRR.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://coding-experiments.googlecode.com/svn/trunk/Data/L_LLRRR.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 145px; height: 248px;" src="http://coding-experiments.googlecode.com/svn/trunk/Data/L_LLRRR.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://coding-experiments.googlecode.com/svn/trunk/Data/L_LRRR.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 181px; height: 234px;" src="http://coding-experiments.googlecode.com/svn/trunk/Data/L_LRRR.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Conclusion&lt;/b&gt;&lt;br /&gt;Seems that systems L/R and L/LRL is unstable and switches to stable system L/RLL.&lt;br /&gt;Another conclusion is that there are some other systems that gets to the different types of "highway" - the order out of chaos.&lt;br /&gt;&lt;br /&gt;Have fun with Langton`s ant !!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-4150397248595649036?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/rmAATm_U6mg74YsUp2gKFd3wYXU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/rmAATm_U6mg74YsUp2gKFd3wYXU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/rmAATm_U6mg74YsUp2gKFd3wYXU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/rmAATm_U6mg74YsUp2gKFd3wYXU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/4150397248595649036/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2009/06/langtons-ant-or-order-out-of-chaos.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/4150397248595649036?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/4150397248595649036?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2009/06/langtons-ant-or-order-out-of-chaos.html" title="Langton's ant Or order out of chaos" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;DE8EQH0yeyp7ImA9WxBUFU4.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-7382489815428621600</id><published>2009-03-15T10:13:00.000-07:00</published><updated>2010-03-02T05:33:21.393-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-03-02T05:33:21.393-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="image processing" /><category scheme="http://www.blogger.com/atom/ns#" term="Lang_Python" /><category scheme="http://www.blogger.com/atom/ns#" term="digital image forensic" /><category scheme="http://www.blogger.com/atom/ns#" term="copy-move forgery" /><title>Detecting copy-move forgery in images</title><content type="html">This time I`ll talk about digital image forensic and how to detect copy-move forgery in images. I`ve implemented some &lt;a href="http://code.google.com/p/coding-experiments/source/browse/trunk/Python/detect_copymove.py"&gt;ad-hoc algorithm&lt;/a&gt; for detection of this kind of forgeries. Algorithm is robust, so it can detect forgeries in lossy image formats- such as JPEG. Please keep in mind - this algorithm is experimental toy, if you want more general solutions - you should read &lt;a href="http://www.ws.binghamton.edu/fridrich/Research/copymove.pdf"&gt;this paper&lt;/a&gt; or &lt;a href="http://www.ists.dartmouth.edu/library/102.pdf"&gt;maybe this&lt;/a&gt; to get some ideas in the field. BTW, this algorithm is only tested with Python 2.6, so you better install Python 2.6.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Robust detection algorithm steps&lt;/b&gt;&lt;br /&gt;1. Blur image for eliminating image details&lt;br /&gt;2. Convert image to degraded palette&lt;br /&gt;3. Decompose image into small NxN pixel blocks&lt;br /&gt;4. Alphabetically order these blocks by their pixel values&lt;br /&gt;5. Extract only these adjacent blocks which have small absolute color difference&lt;br /&gt;6. Cluster these blocks into clusters by intersection area among blocks&lt;br /&gt;7. Extract only these clusters which are bigger than block size&lt;br /&gt;8. Extract only these clusters which have similar cluster, by using some sort of similarity function (in this case Hausdorff distance between clusters)&lt;br /&gt;9. Draw discovered similar clusters on image&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Copy-move detection script usage instructions&lt;/b&gt;&lt;br /&gt;Run script from the command line - cmd in Windows or terminal in Linux.&lt;br /&gt;1. At first try to execute script with default parameters-&lt;br /&gt;&lt;i&gt;python detect_copymove.py image_file.jpg&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;2. Then try to lower block color deviation threshold-&lt;br /&gt;&lt;i&gt;python detect_copymove.py image_file.jpg --blcoldev=0.05&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;3. Finally - run script in manual mode and try to spot similar regions by eyes-&lt;br /&gt;&lt;i&gt;python detect_copymove.py image_file.jpg --blcoldev=0.05 --imauto=0&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;If by trying all 3 steps - no copy-move tamperings revealed - there is a good chance that really there are no such tamperings in image. BTW, script has more parameters, full list of them - &lt;br /&gt;&lt;i&gt;python detect_copymove.py --help&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Experiments - object cloning forgery&lt;/b&gt;&lt;br /&gt;This type of forgery tries to deceive viewer that there were more objects than really was.&lt;br /&gt;Original picture:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hTm-LSlj8U4/Sb1HH5u5vxI/AAAAAAAAAFE/FVOBu956tK4/s1600-h/parade_org.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 232px;" src="http://4.bp.blogspot.com/_hTm-LSlj8U4/Sb1HH5u5vxI/AAAAAAAAAFE/FVOBu956tK4/s320/parade_org.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5313481336449253138" /&gt;&lt;/a&gt;&lt;br /&gt;Doctored image:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hTm-LSlj8U4/Sb1IAcy2MKI/AAAAAAAAAFM/qOCk_NV_Phg/s1600-h/parade_doc.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 232px;" src="http://3.bp.blogspot.com/_hTm-LSlj8U4/Sb1IAcy2MKI/AAAAAAAAAFM/qOCk_NV_Phg/s320/parade_doc.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5313482307933712546" /&gt;&lt;/a&gt;&lt;br /&gt;Copy-move script output:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hTm-LSlj8U4/Sb1IiFG3b1I/AAAAAAAAAFU/PIAWsXNTpIE/s1600-h/parade_doc_analyzed.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 232px;" src="http://3.bp.blogspot.com/_hTm-LSlj8U4/Sb1IiFG3b1I/AAAAAAAAAFU/PIAWsXNTpIE/s320/parade_doc_analyzed.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5313482885690781522" /&gt;&lt;/a&gt;&lt;br /&gt;As you see script detected cloning of one tank, but did not detected cloning of tank in further row. This can be because of small size of that tank and because that tank is on boundary of image.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Experiments - object hiding forgery&lt;/b&gt;&lt;br /&gt;In this type of forgery viewer is deceived that there were less objects than in reality was.&lt;br /&gt;Original image:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hTm-LSlj8U4/Sb1LIJMgVRI/AAAAAAAAAFc/qL7xTgvBylc/s1600-h/dune_org.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://4.bp.blogspot.com/_hTm-LSlj8U4/Sb1LIJMgVRI/AAAAAAAAAFc/qL7xTgvBylc/s320/dune_org.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5313485738646459666" /&gt;&lt;/a&gt;&lt;br /&gt;Doctored image:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hTm-LSlj8U4/Sb1Ld0ZkH5I/AAAAAAAAAFk/DXXU35tkp6o/s1600-h/dune_doc.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_hTm-LSlj8U4/Sb1Ld0ZkH5I/AAAAAAAAAFk/DXXU35tkp6o/s320/dune_doc.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5313486111021211538" /&gt;&lt;/a&gt;&lt;br /&gt;Copy-move script output:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hTm-LSlj8U4/Sb1MJPD9IaI/AAAAAAAAAFs/ptuZLsTN11A/s1600-h/dune_doc_analyzed.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_hTm-LSlj8U4/Sb1MJPD9IaI/AAAAAAAAAFs/ptuZLsTN11A/s320/dune_doc_analyzed.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5313486856912708002" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Experiments - mixed type forgery&lt;/b&gt;&lt;br /&gt;In this type of forgery some objects was hidden, some - cloned.&lt;br /&gt;Original picture:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hTm-LSlj8U4/Sb1Nb85ImLI/AAAAAAAAAF0/VGFZPpNoRp4/s1600-h/dogs_org.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 214px;" src="http://3.bp.blogspot.com/_hTm-LSlj8U4/Sb1Nb85ImLI/AAAAAAAAAF0/VGFZPpNoRp4/s320/dogs_org.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5313488277964626098" /&gt;&lt;/a&gt;&lt;br /&gt;Doctored image:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hTm-LSlj8U4/Sb1NlZ61hCI/AAAAAAAAAF8/8JH8K1FB1Hw/s1600-h/dogs_doc.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 214px;" src="http://2.bp.blogspot.com/_hTm-LSlj8U4/Sb1NlZ61hCI/AAAAAAAAAF8/8JH8K1FB1Hw/s320/dogs_doc.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5313488440375215138" /&gt;&lt;/a&gt;&lt;br /&gt;Copy-move script output:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hTm-LSlj8U4/Sb1Nzw_jxlI/AAAAAAAAAGE/ePEP4LTOJ4g/s1600-h/dogs_doc_analyzed.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 214px;" src="http://2.bp.blogspot.com/_hTm-LSlj8U4/Sb1Nzw_jxlI/AAAAAAAAAGE/ePEP4LTOJ4g/s320/dogs_doc_analyzed.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5313488687087208018" /&gt;&lt;/a&gt;&lt;br /&gt;As you see script detected 2 forgeries - cloning of dog, and cloning of background (which was done with intention to hide other dog)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Conclusions&lt;/b&gt;&lt;br /&gt;Copy-move forgery detection script works not bad. However it is also not perfect of course (may not detect all tamperings, so called false negative rate is not zero of course). And I`ve not tested very well, but I suppose script also have false positive rate - i.e. can detect areas which actually was not tampered. But all in all - I think this algorithm is pretty obvious and can be simply implemented and used as first line of defense against copy-move forgeries.&lt;br /&gt;&lt;br /&gt;Have fun in copy-move forgeries hunting !!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-7382489815428621600?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/R5IOvBkuPzbrTK9J7M3At3kddKc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/R5IOvBkuPzbrTK9J7M3At3kddKc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/R5IOvBkuPzbrTK9J7M3At3kddKc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/R5IOvBkuPzbrTK9J7M3At3kddKc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/7382489815428621600/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2009/03/detecting-copy-move-forgery-in-images.html#comment-form" title="12 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/7382489815428621600?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/7382489815428621600?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2009/03/detecting-copy-move-forgery-in-images.html" title="Detecting copy-move forgery in images" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_hTm-LSlj8U4/Sb1HH5u5vxI/AAAAAAAAAFE/FVOBu956tK4/s72-c/parade_org.jpg" height="72" width="72" /><thr:total>12</thr:total></entry><entry gd:etag="W/&quot;D0MAR30yeyp7ImA9WxBUEUs.&quot;"><id>tag:blogger.com,1999:blog-7408569574805188613.post-467893408170205033</id><published>2009-02-21T10:32:00.000-08:00</published><updated>2010-02-25T22:24:06.393-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-25T22:24:06.393-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="selfish gene algorithm" /><category scheme="http://www.blogger.com/atom/ns#" term="Lang_Python" /><category scheme="http://www.blogger.com/atom/ns#" term="evolution strategy" /><title>Evolving first lady of the internet</title><content type="html">At last I ported &lt;a href="http://code.google.com/p/coding-experiments/source/browse/trunk/Python/sga.py"&gt;selfish gene algorithm&lt;/a&gt; into Python. This algorithm pseudo-code is:&lt;br /&gt;1. Encode some solution into set of genes.&lt;br /&gt;2. Set default probability for each gene.&lt;br /&gt;3. Generate 2 random solutions, according to genes probability.&lt;br /&gt;4. Compare these 2 solutions:&lt;br /&gt;  for better solution- increase it`s genes probability by some value&lt;br /&gt;  for worse solution- decrease it`s genes probability by some value&lt;br /&gt;5. Repeat everything from 3, until needed.&lt;br /&gt;&lt;br /&gt;Now, interesting part. What can we do with selfish gene algorithm ? After seeing &lt;a href="http://rogeralsing.com/2008/12/07/genetic-programming-evolution-of-mona-lisa/"&gt;this post&lt;/a&gt; about genetic programming and evolutionary art, I`ve decided to try something similar. But only by using selfish gene algorithm. I`ve tried 2 experiments - tried to evolve picture of &lt;a href="http://en.wikipedia.org/wiki/Lenna"&gt;first lady of the internet&lt;/a&gt; composed of polygons. And second experiment - lenna picture is evolved as some number of lines.&lt;br /&gt;So experiment idea is to generate 2 random images, composed of random polygons (or lines in other experiment) and to compare these 2 images. For image which is more similar to original lenna picture - we increase polygons probability, for other picture - decrease polygons probability. In the long run - "good polygons" tends to group together.&lt;br /&gt;Below are the results of these experiments. Evolved pictures of lenna are compiled as frames of animated GIF image. N - is the iteration number (starting from zero):&lt;br /&gt;&lt;b&gt;&lt;br /&gt;Lena evolved as set of polygons&lt;br /&gt;&lt;/b&gt;&lt;table style="width: 422px; height: 373px;" border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Original Lena&lt;/td&gt;&lt;td&gt;Lena evolution:&lt;br /&gt;39614 iterations&lt;br /&gt;100 polygons&lt;br /&gt;3.5 hours&lt;br /&gt;&lt;a href="http://code.google.com/p/coding-experiments/source/browse/trunk/Python/lena_poly.py"&gt;experiment code&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://coding-experiments.googlecode.com/svn/trunk/Data/LenaC.png"&gt;&lt;img style="cursor: pointer; width: 200px; height: 200px;" src="http://coding-experiments.googlecode.com/svn/trunk/Data/LenaC.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://coding-experiments.googlecode.com/svn/trunk/Data/LenaPolyEvolution.gif"&gt;&lt;img style="cursor: pointer; width: 200px; height: 200px;" src="http://coding-experiments.googlecode.com/svn/trunk/Data/LenaPolyEvolution.gif" alt="" border="0" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Lena evolved as set of lines&lt;/b&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Original Lena&lt;/td&gt;&lt;td&gt;Lena evolution:&lt;br /&gt;69471 iterations&lt;br /&gt;200 lines&lt;br /&gt;2.5 hours&lt;br /&gt;&lt;a href="http://code.google.com/p/coding-experiments/source/browse/trunk/Python/lena_line.py"&gt;experiment code&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://coding-experiments.googlecode.com/svn/trunk/Data/LenaG.png"&gt;&lt;img style="cursor: pointer; width: 200px; height: 200px;" src="http://coding-experiments.googlecode.com/svn/trunk/Data/LenaG.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://coding-experiments.googlecode.com/svn/trunk/Data/LenaLineEvolution.gif"&gt;&lt;img style="cursor: pointer; width: 200px; height: 200px;" src="http://coding-experiments.googlecode.com/svn/trunk/Data/LenaLineEvolution.gif" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Conclusions:&lt;/b&gt;&lt;br /&gt;Selfish gene algorithm (sort of evolution strategy algorithm) is suitable for solving search and optimization problems, including generation of evolutionary art :-)&lt;br /&gt;Below are final iteration pictures better quality than gif:&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://coding-experiments.googlecode.com/svn/trunk/Data/LenaPolyFinal.png"&gt;&lt;img style="cursor: pointer; width: 200px; height: 200px;" src="http://coding-experiments.googlecode.com/svn/trunk/Data/LenaPolyFinal.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://coding-experiments.googlecode.com/svn/trunk/Data/LenaLineFinal.png"&gt;&lt;img style="cursor: pointer; width: 200px; height: 200px;" src="http://coding-experiments.googlecode.com/svn/trunk/Data/LenaLineFinal.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Have fun with selfish gene algorithm, genetic algorithms and evolution art !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7408569574805188613-467893408170205033?l=coding-experiments.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Hik-FSyjDFt_1S7Nk2yvTMutJPE/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Hik-FSyjDFt_1S7Nk2yvTMutJPE/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Hik-FSyjDFt_1S7Nk2yvTMutJPE/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Hik-FSyjDFt_1S7Nk2yvTMutJPE/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://coding-experiments.blogspot.com/feeds/467893408170205033/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://coding-experiments.blogspot.com/2009/02/evolving-first-lady-of-internet.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/467893408170205033?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7408569574805188613/posts/default/467893408170205033?v=2" /><link rel="alternate" type="text/html" href="http://coding-experiments.blogspot.com/2009/02/evolving-first-lady-of-internet.html" title="Evolving first lady of the internet" /><author><name>Agnius Vasiliauskas</name><uri>http://www.blogger.com/profile/10940660947742989178</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry></feed>

