tag:blogger.com,1999:blog-14951233555364062022024-03-13T07:30:30.600+02:00PopscanLife as it is.
<br>
Pop culture as I see it.Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.comBlogger78125tag:blogger.com,1999:blog-1495123355536406202.post-64987437785528058102014-12-07T13:16:00.000+02:002014-12-09T09:09:49.975+02:00Superpixel algorithm implemented in JavaThis Superpixel code has been stored on my hard drive for a year. Too bad, I have only very little time for my recreational image processing programming.<br />
<br />
But here is my interpretation for Superpixel algorithm in Java programming language. The computational process itself is iterative, but I am using the Cluster objects to make the algorithm slightly easier to understand and follow. Without objects, it could be slightly faster, I have not tried to code that kind of version myself.<br />
<br />
<br />
<b>Interesting things to try:</b><br />
<ul>
<li>change the proximity modifier 'm' from small to large</li>
<li>change the cell size 'S' from small to large </li>
</ul>
<br />
<b>Notes </b><br />
<ol>
<li>The algorithm does not ensure superpixel connectivity, thus the result may have orphan pixels from 'wrong' cluster inside of other cluster.</li>
<li>This algorithm works in RGB color space, some other color space (Lab for example) could give you better end results.</li>
<li>The distance calculation can be done also using "approximated" distance without square root calculations, for performance reasons. </li>
</ol>
<b>Links</b><br />
Image segmentation in Wikipedia: <a href="http://en.wikipedia.org/wiki/Image_segmentation">http://en.wikipedia.org/wiki/Image_segmentation</a> <br />
SLIC Superpixels - <a href="http://ivrg.epfl.ch/research/superpixels" target="_blank">http://ivrg.epfl.ch/research/superpixels </a><br />
jSLIC code in the GitHub - <a href="https://github.com/Borda/ij-CMP-BIA">https://github.com/Borda/ij-CMP-BIA</a><br />
<br />
<br />
<b>Example images</b><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOdrCGJw7w1-_dGa3h_KZ9Hv_hGXa9HXawKTGKGIdTwbe9FKJe_U3nah80vNlKzvmJP1L8XG8XmsGxroM2veekDcnSznno2a4sQnEG8-OQA6LjemTE6F3jOeQcmCZ93vJ4wdpo9qK6WRCp/s1600/popscan_blogspot_com_superpixel_01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOdrCGJw7w1-_dGa3h_KZ9Hv_hGXa9HXawKTGKGIdTwbe9FKJe_U3nah80vNlKzvmJP1L8XG8XmsGxroM2veekDcnSznno2a4sQnEG8-OQA6LjemTE6F3jOeQcmCZ93vJ4wdpo9qK6WRCp/s1600/popscan_blogspot_com_superpixel_01.jpg" height="206" width="320" /></a></div>
<div style="text-align: center;">
Values used: left S=16, m=130, right S=24, m=130 </div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzceCKqgXJ1IGOVqdTO4kUPEa_tvca2F7PW2kZCpah5AjhyphenhyphenTbywi4oVj3906Sw8VhrODoqKPMGzxp-Ok5TKHNiOiLpyg_pEApMgIzWfLiCPuUoxVfkKStQuUnfPzm3nJwelRTQX0x-zU9z/s1600/popscan_blogspot_com_superpixel_02.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzceCKqgXJ1IGOVqdTO4kUPEa_tvca2F7PW2kZCpah5AjhyphenhyphenTbywi4oVj3906Sw8VhrODoqKPMGzxp-Ok5TKHNiOiLpyg_pEApMgIzWfLiCPuUoxVfkKStQuUnfPzm3nJwelRTQX0x-zU9z/s1600/popscan_blogspot_com_superpixel_02.jpg" height="206" width="320" /></a></div>
<div style="text-align: center;">
Values used: left S=16, m=130, right S=24, m=130</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJ7qiZq4neZqoaopfwu0R14z5x9TROuEwbJ15GPB2xu_QZCFKan8dZ8KpVLl6UL26v0VWsuuKRRyKlCjmuLs4dxaUHpdAYSgvphjRctAjfNO9oNO7_kSkBdv0Go1yJtaCt-ybRiP2Gp4fe/s1600/popscan_blogspot_com_superpixel_03.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJ7qiZq4neZqoaopfwu0R14z5x9TROuEwbJ15GPB2xu_QZCFKan8dZ8KpVLl6UL26v0VWsuuKRRyKlCjmuLs4dxaUHpdAYSgvphjRctAjfNO9oNO7_kSkBdv0Go1yJtaCt-ybRiP2Gp4fe/s1600/popscan_blogspot_com_superpixel_03.jpg" height="206" width="320" /></a></div>
<div style="text-align: center;">
Values used: left S=16, m=130, right S=24, m=130</div>
<br />
<b>Example usage</b><br />
Using command line <b><br /></b><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;">java popscan.Superpixel "C:\java\flamingo.png" c:\java\sp_flamingo.png 16 130</span></span><br />
<br />
<b>Source
</b><br />
<br />
<style>tr { color: #888888; }h3 { font-family: Verdana,Arial,Serif; border-width: 3px; color: #000000; font-size: 8pt; }p { font-family: Verdana,Arial,Serif; color: #000000; font-size: 8pt; }tr { font-family: Courier,Georgia,Serif; font-size: 8pt; }span.comment { font-weight:bold; color: #008800; font-size: 8pt;}span.cc { font-weight:bold; color: #5555ee; font-size: 8pt; }span.b { font-weight:bold; color: #000000; font-size: 8pt; }span.o { color: #008800; font-size: 8pt; }span.kw { color: #0000aa; font-weight: bold; font-size: 8pt; }div#destination { border-style:solid; border-width:2px; border-color: #555555; background-color: #fefefe; }</style>
<br />
<table cellpadding="0" cellspacing="0"><tbody>
<tr bgcolor="#f0f0f0"><td><span class="kw">package</span> popscan; </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td><span class="kw">import</span> java.awt.<span class="cc">Color</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="kw">import</span> java.awt.image.<span class="cc">BufferedImage</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="kw">import</span> java.io.<span class="cc">File</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="kw">import</span> java.util.<span class="cc">Arrays</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="kw">import</span> java.util.<span class="cc">Vector</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="kw">import</span> javax.imageio.<span class="cc">ImageIO</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td><span class="comment">/**</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> * @author tejopa, 2014</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> * @version 1</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> * http://popscan.blogspot.com</span> </td></tr>
<tr bgcolor="#ffffff"><td> */ </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="kw">public</span><span class="kw"> class </span><span class="cc">Superpixel</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // arrays to store values during process</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">double</span><span class="b">[</span><span class="b">]</span> distances; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span><span class="b">[</span><span class="b">]</span> labels; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span><span class="b">[</span><span class="b">]</span> reds; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span><span class="b">[</span><span class="b">]</span> greens; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span><span class="b">[</span><span class="b">]</span> blues; </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">Cluster</span><span class="b">[</span><span class="b">]</span> clusters; </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // in case of instable clusters, max number of loops</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> maxClusteringLoops = 50; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> /**</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> * @param args</span> </td></tr>
<tr bgcolor="#ffffff"><td> */ </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">public</span> <span class="kw">static</span> <span class="kw">void</span> main<span class="b">(</span><span class="cc">String</span><span class="b">[</span><span class="b">]</span> args<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>args.length!=4<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">System</span>.out.println<span class="b">(</span>"<span class="cc">Usage</span>: java popscan.<span class="cc">Superpixel</span>" </td></tr>
<tr bgcolor="#ffffff"><td> + " <span class="b">[</span>source image filename<span class="b">]</span>" </td></tr>
<tr bgcolor="#f0f0f0"><td> + " <span class="b">[</span>destination image filename<span class="b">]</span>" </td></tr>
<tr bgcolor="#ffffff"><td> + " <span class="b">[</span>cell width <span class="cc">S</span> <span class="b">(</span>1-255<span class="b">)</span><span class="b">]</span>" </td></tr>
<tr bgcolor="#f0f0f0"><td> + " <span class="b">[</span>proximity modifier m <span class="b">(</span>1-255<span class="b">)</span>"<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">return</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // parse arguments</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">String</span> src = args<span class="b">[</span>0<span class="b">]</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">String</span> dst = args<span class="b">[</span>1<span class="b">]</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">double</span> <span class="cc">S</span> = <span class="cc">Integer</span>.parseInt<span class="b">(</span>args<span class="b">[</span>2<span class="b">]</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">double</span> m = <span class="cc">Double</span>.parseDouble<span class="b">(</span>args<span class="b">[</span>3<span class="b">]</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">BufferedImage</span> img = loadImage<span class="b">(</span>src<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">Superpixel</span> sp = <span class="kw">new</span> <span class="cc">Superpixel</span><span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">BufferedImage</span> dstImage = sp.calculate<span class="b">(</span>img,<span class="cc">S</span>,m<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // save the resulting image</span> </td></tr>
<tr bgcolor="#ffffff"><td> saveImage<span class="b">(</span>dst, dstImage<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">public</span> <span class="cc">Superpixel</span><span class="b">(</span><span class="b">)</span> <span class="b">{</span> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">public</span> <span class="cc">BufferedImage</span> calculate<span class="b">(</span><span class="cc">BufferedImage</span> image, </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">double</span> <span class="cc">S</span>, <span class="kw">double</span> m<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> w = image.getWidth<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> h = image.getHeight<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">BufferedImage</span> result = <span class="kw">new</span> <span class="cc">BufferedImage</span><span class="b">(</span>w, h, </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">BufferedImage</span>.<span class="cc">TYPE_INT_RGB</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">long</span> start = <span class="cc">System</span>.currentTimeMillis<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // get the image pixels</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span><span class="b">[</span><span class="b">]</span> pixels = image.getRGB<span class="b">(</span>0, 0, w, h, null, 0, w<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // create and fill lookup tables</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> distances = <span class="kw">new</span> <span class="kw">double</span><span class="b">[</span>w*h<span class="b">]</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">Arrays</span>.fill<span class="b">(</span>distances, <span class="cc">Integer</span>.<span class="cc">MAX_VALUE</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> labels = <span class="kw">new</span> <span class="kw">int</span><span class="b">[</span>w*h<span class="b">]</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">Arrays</span>.fill<span class="b">(</span>labels, -1<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // split rgb-values to own arrays</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> reds = <span class="kw">new</span> <span class="kw">int</span><span class="b">[</span>w*h<span class="b">]</span>; </td></tr>
<tr bgcolor="#ffffff"><td> greens = <span class="kw">new</span> <span class="kw">int</span><span class="b">[</span>w*h<span class="b">]</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> blues = <span class="kw">new</span> <span class="kw">int</span><span class="b">[</span>w*h<span class="b">]</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> y=0;y<h;y++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> x=0;x<w;x++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> pos = x+y*w; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> color = pixels<span class="b">[</span>pos<span class="b">]</span>; </td></tr>
<tr bgcolor="#ffffff"><td> reds<span class="b">[</span>pos<span class="b">]</span> = color>>16&0x000000FF; </td></tr>
<tr bgcolor="#f0f0f0"><td> greens<span class="b">[</span>pos<span class="b">]</span> = color>> 8&0x000000FF; </td></tr>
<tr bgcolor="#ffffff"><td> blues<span class="b">[</span>pos<span class="b">]</span> = color>> 0&0x000000FF; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // create clusters</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> createClusters<span class="b">(</span>image, <span class="cc">S</span>, m<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // loop until all clusters are stable!</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> loops = 0; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">boolean</span> pixelChangedCluster = true; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">while</span> <span class="b">(</span>pixelChangedCluster&&loops<maxClusteringLoops<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> pixelChangedCluster = false; </td></tr>
<tr bgcolor="#ffffff"><td> loops++; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // for each cluster center C </span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> i=0;i<clusters.length;i++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">Cluster</span> c = clusters<span class="b">[</span>i<span class="b">]</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // for each pixel i in 2S region around</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // cluster center</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> xs = <span class="cc">Math</span>.max<span class="b">(</span><span class="b">(</span><span class="kw">int</span><span class="b">)</span><span class="b">(</span>c.avg_x-<span class="cc">S</span><span class="b">)</span>,0<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> ys = <span class="cc">Math</span>.max<span class="b">(</span><span class="b">(</span><span class="kw">int</span><span class="b">)</span><span class="b">(</span>c.avg_y-<span class="cc">S</span><span class="b">)</span>,0<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> xe = <span class="cc">Math</span>.min<span class="b">(</span><span class="b">(</span><span class="kw">int</span><span class="b">)</span><span class="b">(</span>c.avg_x+<span class="cc">S</span><span class="b">)</span>,w<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> ye = <span class="cc">Math</span>.min<span class="b">(</span><span class="b">(</span><span class="kw">int</span><span class="b">)</span><span class="b">(</span>c.avg_y+<span class="cc">S</span><span class="b">)</span>,h<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> y=ys;y<ye;y++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> x=xs;x<xe;x++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> pos = x+w*y; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">double</span> <span class="cc">D</span> = c.distance<span class="b">(</span>x, y, reds<span class="b">[</span>pos<span class="b">]</span>, </td></tr>
<tr bgcolor="#f0f0f0"><td> greens<span class="b">[</span>pos<span class="b">]</span>, </td></tr>
<tr bgcolor="#ffffff"><td> blues<span class="b">[</span>pos<span class="b">]</span>, </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">S</span>, m, w, h<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span><span class="b">(</span><span class="cc">D</span><distances<span class="b">[</span>pos<span class="b">]</span><span class="b">)</span>&&<span class="b">(</span>labels<span class="b">[</span>pos<span class="b">]</span>!=c.id<span class="b">)</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> distances<span class="b">[</span>pos<span class="b">]</span> = <span class="cc">D</span>; </td></tr>
<tr bgcolor="#ffffff"><td> labels<span class="b">[</span>pos<span class="b">]</span> = c.id; </td></tr>
<tr bgcolor="#f0f0f0"><td> pixelChangedCluster = true; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> <span class="b">}</span> // end for x</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> <span class="b">}</span> // end for y</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> <span class="b">}</span> // end for clusters</span> </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // reset clusters</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> index=0;index<clusters.length;index++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> clusters<span class="b">[</span>index<span class="b">]</span>.reset<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // add every pixel to cluster based on label</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> y=0;y<h;y++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> x=0;x<w;x++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> pos = x+y*w; </td></tr>
<tr bgcolor="#ffffff"><td> clusters<span class="b">[</span>labels<span class="b">[</span>pos<span class="b">]</span><span class="b">]</span>.addPixel<span class="b">(</span>x, y, </td></tr>
<tr bgcolor="#f0f0f0"><td> reds<span class="b">[</span>pos<span class="b">]</span>, greens<span class="b">[</span>pos<span class="b">]</span>, blues<span class="b">[</span>pos<span class="b">]</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // calculate centers</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> index=0;index<clusters.length;index++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> clusters<span class="b">[</span>index<span class="b">]</span>.calculateCenter<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // Create output image with pixel edges </span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> y=1;y<h-1;y++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> x=1;x<w-1;x++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> id1 = labels<span class="b">[</span>x+y*w<span class="b">]</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> id2 = labels<span class="b">[</span><span class="b">(</span>x+1<span class="b">)</span>+y*w<span class="b">]</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> id3 = labels<span class="b">[</span>x+<span class="b">(</span>y+1<span class="b">)</span>*w<span class="b">]</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>id1!=id2||id1!=id3<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> result.setRGB<span class="b">(</span>x, y, 0x000000<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> //result.setRGB<span class="b">(</span>x-1, y, 0x000000<span class="b">)</span>;</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> //result.setRGB<span class="b">(</span>x, y-1, 0x000000<span class="b">)</span>;</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> //result.setRGB<span class="b">(</span>x-1, y-1, 0x000000<span class="b">)</span>;</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> <span class="kw">else</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> result.setRGB<span class="b">(</span>x, y, image.getRGB<span class="b">(</span>x, y<span class="b">)</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // mark superpixel <span class="b">(</span>cluster<span class="b">)</span> centers with red pixel </span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> i=0;i<clusters.length;i++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">Cluster</span> c = clusters<span class="b">[</span>i<span class="b">]</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> //result.setRGB<span class="b">(</span><span class="b">(</span>int<span class="b">)</span>c.avg_x, <span class="b">(</span>int<span class="b">)</span>c.avg_y, </span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> //Color.red.getRGB<span class="b">(</span><span class="b">)</span><span class="b">)</span>;</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">long</span> end = <span class="cc">System</span>.currentTimeMillis<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">System</span>.out.println<span class="b">(</span>"<span class="cc">Clustered</span> to "+clusters.length </td></tr>
<tr bgcolor="#ffffff"><td> + " superpixels in "+loops </td></tr>
<tr bgcolor="#f0f0f0"><td> +" loops in "+<span class="b">(</span>end-start<span class="b">)</span>+" ms."<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">return</span> result; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> /*</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> * Create initial clusters.</span> </td></tr>
<tr bgcolor="#ffffff"><td> */ </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">public</span> <span class="kw">void</span> createClusters<span class="b">(</span><span class="cc">BufferedImage</span> image, </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">double</span> <span class="cc">S</span>, <span class="kw">double</span> m<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">Vector</span><<span class="cc">Cluster</span>> temp = <span class="kw">new</span> <span class="cc">Vector</span><<span class="cc">Cluster</span>><span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> w = image.getWidth<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> h = image.getHeight<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">boolean</span> even = false; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">double</span> xstart = 0; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> id = 0; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">double</span> y=<span class="cc">S</span>/2;y<h;y+=<span class="cc">S</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // alternate clusters x-position</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // to create nice hexagon grid</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>even<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> xstart = <span class="cc">S</span>/2.0; </td></tr>
<tr bgcolor="#ffffff"><td> even = false; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> <span class="kw">else</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> xstart = <span class="cc">S</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> even = true; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">double</span> x=xstart;x<w;x+=<span class="cc">S</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> pos = <span class="b">(</span><span class="kw">int</span><span class="b">)</span><span class="b">(</span>x+y*w<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">Cluster</span> c = <span class="kw">new</span> <span class="cc">Cluster</span><span class="b">(</span>id, </td></tr>
<tr bgcolor="#ffffff"><td> reds<span class="b">[</span>pos<span class="b">]</span>, greens<span class="b">[</span>pos<span class="b">]</span>, blues<span class="b">[</span>pos<span class="b">]</span>, </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">(</span><span class="kw">int</span><span class="b">)</span>x, <span class="b">(</span><span class="kw">int</span><span class="b">)</span>y, <span class="cc">S</span>, m<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> temp.add<span class="b">(</span>c<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> id++; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> clusters = <span class="kw">new</span> <span class="cc">Cluster</span><span class="b">[</span>temp.size<span class="b">(</span><span class="b">)</span><span class="b">]</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> i=0;i<temp.size<span class="b">(</span><span class="b">)</span>;i++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> clusters<span class="b">[</span>i<span class="b">]</span> = temp.elementAt<span class="b">(</span>i<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> /**</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> * @param filename</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> * @param image</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> */ </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">public</span> <span class="kw">static</span> <span class="kw">void</span> saveImage<span class="b">(</span><span class="cc">String</span> filename, </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">BufferedImage</span> image<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">File</span> file = <span class="kw">new</span> <span class="cc">File</span><span class="b">(</span>filename<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">try</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">ImageIO</span>.write<span class="b">(</span>image, "png", file<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> <span class="kw">catch</span> <span class="b">(</span><span class="cc">Exception</span> e<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">System</span>.out.println<span class="b">(</span>e.toString<span class="b">(</span><span class="b">)</span>+" <span class="cc">Image</span> '"+filename </td></tr>
<tr bgcolor="#f0f0f0"><td> +"' saving failed."<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> /**</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> * @param filename</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> * @return</span> </td></tr>
<tr bgcolor="#ffffff"><td> */ </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">public</span> <span class="kw">static</span> <span class="cc">BufferedImage</span> loadImage<span class="b">(</span><span class="cc">String</span> filename<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">BufferedImage</span> result = null; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">try</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> result = <span class="cc">ImageIO</span>.read<span class="b">(</span><span class="kw">new</span> <span class="cc">File</span><span class="b">(</span>filename<span class="b">)</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> <span class="kw">catch</span> <span class="b">(</span><span class="cc">Exception</span> e<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">System</span>.out.println<span class="b">(</span>e.toString<span class="b">(</span><span class="b">)</span>+" <span class="cc">Image</span> '" </td></tr>
<tr bgcolor="#f0f0f0"><td> +filename+"' not found."<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">return</span> result; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td> class <span class="cc">Cluster</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> id; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> double inv = 0; // inv variable for optimization</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> double pixelCount; // pixels in this cluster</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> double avg_red; // average red value</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> double avg_green; // average green value</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> double avg_blue; // average blue value</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> double sum_red; // sum red values</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> double sum_green; // sum green values</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> double sum_blue; // sum blue values</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> double sum_x; // sum x</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> double sum_y; // sum y</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> double avg_x; // average x</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> double avg_y; // average y</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">public</span> <span class="cc">Cluster</span><span class="b">(</span><span class="kw">int</span> id, <span class="kw">int</span> in_red, <span class="kw">int</span> in_green, </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> in_blue, <span class="kw">int</span> x, <span class="kw">int</span> y, </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">double</span> <span class="cc">S</span>, <span class="kw">double</span> m<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // inverse for distance calculation</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">this</span>.inv = 1.0 / <span class="b">(</span><span class="b">(</span><span class="cc">S</span> / m<span class="b">)</span> * <span class="b">(</span><span class="cc">S</span> / m<span class="b">)</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">this</span>.id = id; </td></tr>
<tr bgcolor="#f0f0f0"><td> addPixel<span class="b">(</span>x, y, in_red, in_green, in_blue<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // calculate center with initial one pixel</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> calculateCenter<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">public</span> <span class="kw">void</span> reset<span class="b">(</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> avg_red = 0; </td></tr>
<tr bgcolor="#ffffff"><td> avg_green = 0; </td></tr>
<tr bgcolor="#f0f0f0"><td> avg_blue = 0; </td></tr>
<tr bgcolor="#ffffff"><td> sum_red = 0; </td></tr>
<tr bgcolor="#f0f0f0"><td> sum_green = 0; </td></tr>
<tr bgcolor="#ffffff"><td> sum_blue = 0; </td></tr>
<tr bgcolor="#f0f0f0"><td> pixelCount = 0; </td></tr>
<tr bgcolor="#ffffff"><td> avg_x = 0; </td></tr>
<tr bgcolor="#f0f0f0"><td> avg_y = 0; </td></tr>
<tr bgcolor="#ffffff"><td> sum_x = 0; </td></tr>
<tr bgcolor="#f0f0f0"><td> sum_y = 0; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> /*</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> * Add pixel color values to sum of previously added</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> * color values.</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> */ </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">void</span> addPixel<span class="b">(</span><span class="kw">int</span> x, <span class="kw">int</span> y, <span class="kw">int</span> in_red, </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> in_green, <span class="kw">int</span> in_blue<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> sum_x+=x; </td></tr>
<tr bgcolor="#f0f0f0"><td> sum_y+=y; </td></tr>
<tr bgcolor="#ffffff"><td> sum_red += in_red; </td></tr>
<tr bgcolor="#f0f0f0"><td> sum_green+= in_green; </td></tr>
<tr bgcolor="#ffffff"><td> sum_blue += in_blue; </td></tr>
<tr bgcolor="#f0f0f0"><td> pixelCount++; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">public</span> <span class="kw">void</span> calculateCenter<span class="b">(</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // Optimization: using "inverse"</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // to change divide to multiply</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">double</span> inv = 1/pixelCount; </td></tr>
<tr bgcolor="#ffffff"><td> avg_red = sum_red*inv; </td></tr>
<tr bgcolor="#f0f0f0"><td> avg_green = sum_green*inv; </td></tr>
<tr bgcolor="#ffffff"><td> avg_blue = sum_blue*inv; </td></tr>
<tr bgcolor="#f0f0f0"><td> avg_x = sum_x*inv; </td></tr>
<tr bgcolor="#ffffff"><td> avg_y = sum_y*inv; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">double</span> distance<span class="b">(</span><span class="kw">int</span> x, <span class="kw">int</span> y, </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> red, <span class="kw">int</span> green, <span class="kw">int</span> blue, </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">double</span> <span class="cc">S</span>, <span class="kw">double</span> m, <span class="kw">int</span> w, <span class="kw">int</span> h<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // power of color difference between </span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // given pixel and cluster center</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">double</span> dx_color = <span class="b">(</span>avg_red-red<span class="b">)</span>*<span class="b">(</span>avg_red-red<span class="b">)</span> </td></tr>
<tr bgcolor="#ffffff"><td> + <span class="b">(</span>avg_green-green<span class="b">)</span>*<span class="b">(</span>avg_green-green<span class="b">)</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> + <span class="b">(</span>avg_blue-blue<span class="b">)</span>*<span class="b">(</span>avg_blue-blue<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // power of spatial difference between</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // given pixel and cluster center</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">double</span> dx_spatial = <span class="b">(</span>avg_x-x<span class="b">)</span>*<span class="b">(</span>avg_x-x<span class="b">)</span>+<span class="b">(</span>avg_y-y<span class="b">)</span>*<span class="b">(</span>avg_y-y<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // Calculate approximate distance D</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // double D = dx_color+dx_spatial*inv;</span> </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // Calculate squares to get more accurate results</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">double</span> <span class="cc">D</span> = <span class="cc">Math</span>.sqrt<span class="b">(</span>dx_color<span class="b">)</span>+<span class="cc">Math</span>.sqrt<span class="b">(</span>dx_spatial*inv<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">return</span> <span class="cc">D</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
</tbody></table>
Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com2tag:blogger.com,1999:blog-1495123355536406202.post-13009817196378430102014-06-17T10:40:00.000+03:002014-06-17T10:40:01.165+03:00Problem connecting to Netflix - my solutionRecently I encountered an error when trying to open Netflix app on my Lenovo Android tablet. Netflix used to work flawlessly, but suddenly it stopped working on just one of my devices.<br />
<br />
When trying to login, an error message appeared. The message was "<i>There is a problem connecting to Netflix. Please try again later. If the
problem persists, check that your device has the correct date and time
and restart the Netflix application.</i>"<br />
<br />
Actually, as the device is in Finnish locale, the message was "<span class="NF_ERROR"><i>Netflix-yhteyden luomisessa oli ongelma. Yritä
myöhemmin uudelleen. Jos ongelma ei poistu, tarkista että laitteessasi
on oikea päivämäärä ja aika ja käynnistä Netflix-sovellus uudelleen.</i>"</span><br />
<br />
<span class="NF_ERROR">I tried to reset my router, set the time and date for my router and devices etc, nothing helped. I removed Netflix app and reinstalled it. Everything else was working perfectly (net, games, etc) but still I was not able to connect to Netflix. And my kids were getting angry.</span><br />
<br />
<span class="NF_ERROR">Finally I tried to check the DNS settings on my tablet. They pointed to my router, where I have Google's servers configured. Well, I thought, why not set the same IPs to the tablet as well.</span><br />
<br />
<span class="NF_ERROR">So, I set up the Google name server IPs as DNS servers... and Netflix started to work again.</span><br />
<span class="NF_ERROR"><br /></span>
<b><span class="NF_ERROR">Steps to set up the DNS in Android 4.x devices:</span></b><br />
<span class="NF_ERROR">1. Select "Settings"</span><br />
<span class="NF_ERROR">2. Select "Wi-Fi"</span><br />
<span class="NF_ERROR">3. Long tap your wifi network item - a pop up chooser will appear</span><br />
<span class="NF_ERROR">4. Select "Modify network config"</span><br />
<span class="NF_ERROR">5. Select "Show advanced options" - new options will appear</span><br />
<span class="NF_ERROR">6. Select "IP settings" - select "Static" from drop down menu</span><br />
<span class="NF_ERROR">7. Set "DNS1" to "8.8.8.8" (write down the original IP, in case you need it later)</span><br />
<span class="NF_ERROR">8. Set "DNS2" to "8.8.4.4" (write down the original IP, in case you need it later)</span><br />
<span class="NF_ERROR">9. Select "Save"</span><br />
<span class="NF_ERROR">10. Start watching Netflix ;)</span><br />
<span class="NF_ERROR"><br /></span>
<span class="NF_ERROR"><br /></span>
<span class="NF_ERROR"><br /></span>Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com0tag:blogger.com,1999:blog-1495123355536406202.post-56917235892090942142014-04-20T13:55:00.000+03:002014-04-25T15:59:16.226+03:00Watershed image segmentation algorithm with JavaI am very interested in image segmentation, that is why the watershed segmentation caught my attention this time. People are using the watershed algorithm at least in the medical imaging applications, and the F. Meyer's algorithm was mentioned to be "one of the most common" one [1]. It also looked like it is quite easy to implement.<br />
<br />
My favorite method for studying and understanding algorithms is to actually implement the algorithm. During the implementation, you really have to understand what is happening in each step. Also the produced images (in image algorithms) during the development process are helpful. It is fun to analyze the errors and what causes the artifacts in the image. So, the result for my studies is here: the watershed image segmentation algorithm implemented with Java.<br />
<br />
<h4>
<b>Watershed algorithm explained </b>(italics are from Wikipedia):</h4>
<br />
1. <i>"A set of markers, pixels where the flooding shall start, are chosen. Each is given a different label."</i><br />
<ul>
<li>Find all the minimum points from the image. This means that you need to loop through pixels and find the darkest pixel which has not been already selected and which is not close to already selected minimum pixel. You can find as many minimums you like or only selected count of minimums. These minimums are the lowest points of the "basins" which will be flooded.</li>
<li>The label can be for example the index numbering or color values from a known premade palette.</li>
</ul>
<br />
2. <i>"The neighboring pixels of each marked area are inserted into a priority
queue with a priority level corresponding to the gray level of the
pixel."</i><br />
<ul>
<li>For each found minimum point, add the surrounding pixels to the priority queue. Set the initial labels to the label table (result image). Sort the priority queue from dark to light pixels. Now you can start the flooding.</li>
</ul>
<br />
3. <i>"The pixel with the highest priority level is extracted from the priority
queue. If the neighbors of the extracted pixel that have already been
labeled all have the same label, then the pixel is labeled with their
label. All non-marked neighbors that are not yet in the priority queue
are put into the priority queue."</i><b> </b><br />
<ul>
<li>Take out the first pixel (the darkest one) from the priority queue. Check the neighboring pixels for that pixel. If all the labeled pixels are having the same label, label the current pixel with the same label; the current pixel is "inside" of the basin. Remember, there has to be at least one labeled pixel; the one that was previously next to the current pixel. </li>
<li>If there are at least two pixels with different label, it means that we have found a boundary between two different flood basins. We can mark this pixel then as an "edge" pixel. </li>
<li>Finally, add all those neighboring pixels that do not have label to the priority queue.</li>
</ul>
<br />
4. <i>"Redo step 3 until the priority queue is empty."</i><br />
<ul>
<li>Loop until there are no pixels left in the priority queue. When the priority queue is empty, all the pixels from the image are processed. </li>
</ul>
<h4>
<b> </b></h4>
<h4>
<b>Sample images</b></h4>
<h4>
<b> </b></h4>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtSkbTTlQyD190FjP21X9HL6k5XgiKosxFwl2yt5LjcFWzQfxnfMtPEawf2bVdvGAqsf59SBc_FB8ONfmW1AdGNLC6aTR-ykP4U1V0Ao7OKrPojJVSQhuxMYe6-HQqSrOU1Dnk5NbDfvQt/s1600/watershed_sample_source.png" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtSkbTTlQyD190FjP21X9HL6k5XgiKosxFwl2yt5LjcFWzQfxnfMtPEawf2bVdvGAqsf59SBc_FB8ONfmW1AdGNLC6aTR-ykP4U1V0Ao7OKrPojJVSQhuxMYe6-HQqSrOU1Dnk5NbDfvQt/s1600/watershed_sample_source.png" /></a></div>
<div style="text-align: center;">
<span style="font-size: x-small;"><b>Image 1.</b> This is the sample image I have been using for testing. I created it myself with GIMP.</span></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirkyy4WHEBwmTuDPOJtyOfUVIRrBHwbFo5Y_eu_1xiGExzH4s32afd8y9QM9HYoM1Wx132WjiupL4Y9-fTI4o0IT-6j6rp0IADJ5hBbXe7_vzxxIPHjK4MfJhu9snu6pcVEqqFboZunwhq/s1600/watershed_sample_boundaries.png" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirkyy4WHEBwmTuDPOJtyOfUVIRrBHwbFo5Y_eu_1xiGExzH4s32afd8y9QM9HYoM1Wx132WjiupL4Y9-fTI4o0IT-6j6rp0IADJ5hBbXe7_vzxxIPHjK4MfJhu9snu6pcVEqqFboZunwhq/s1600/watershed_sample_boundaries.png" /></a></div>
<div style="text-align: center;">
<span style="font-size: x-small;"><b>Image 2.</b> This is the result after executing the Watershed algorithm to the sample
image. Red squares are the found minimums and the white borders are the
basins edges.</span></div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBjFTrdn9ouH6kmjlt2A3yaNQp8h1vTRy4KqvYmr3ndKYqq2cDHS3cp2o5Ka29g-ua_dswmfC_xjo6QCLbCXICWOpkbLnq3G3vW4C0GaDR50D7B2g6G5kEaPnlM_Z3wAiRhD_Bc38KovAp/s1600/watershed_sample_combined.png" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBjFTrdn9ouH6kmjlt2A3yaNQp8h1vTRy4KqvYmr3ndKYqq2cDHS3cp2o5Ka29g-ua_dswmfC_xjo6QCLbCXICWOpkbLnq3G3vW4C0GaDR50D7B2g6G5kEaPnlM_Z3wAiRhD_Bc38KovAp/s1600/watershed_sample_combined.png" /></a></div>
<div style="text-align: center;">
<span style="font-size: x-small;"><b>Image 3.</b> Here are the sample image and the result image combined in a same image. The boundaries have been colored to green.</span></div>
<br />
<h4>
Notes:</h4>
<ul>
<li>In this implementation, the minimums are found by "sweeping" the pixels from top-left to bottom-right. This way the found minimum is always the "first" one with the lowest value. That is why the minimum centers (the red squares) are not in the exact center of the darkest area. </li>
<li>If you rotate the source image, the result will be different, that is because the minimum locations are changing (see the note above) and <a href="http://imagej.1557.x6.nabble.com/Watershed-Algorithm-source-bug-td3685192.html" target="_blank">this discussion </a><a href="https://www.blogger.com/null" target="_blank">[2]</a>.</li>
<li>After segmentation, you probably need the remove the "background" pixels. What you need to do might change per application. See more examples for fine tuning the Watershed algorithm from <a href="http://cmm.ensmp.fr/~beucher/wtshed.html" target="_blank">http://cmm.ensmp.fr/~beucher/wtshed.html</a> [3].</li>
</ul>
<h3>
</h3>
<h4>
The Java source </h4>
<br />
<b>Implementation notes:</b><br />
<ul>
<li>To find more speed in the pixel sorting, I implemented a crude SortedVector, which uses insertion sort like algorithm to keep the inserted pixels (FloodPoints) in sorted order.</li>
<li>I am disabling the pixels from a rectangle shaped area around the minimum. A circle shape should work better in some cases.</li>
<li>The source contains commented code for saving the image in different steps of the process. Just uncomment the lines to get the images saved on your drive.</li>
<li>The source contains commented code for real time view of the process. Just uncomment the parts where the JFrame is accessed to see the final image being built. You should try that, it looks nice! :)</li>
<li>You can run the code in 4-connected pixels or 8-connected pixels mode. The results are slightly different. You should try them both. </li>
</ul>
<i>Please let me know if you spot errors or have any other comments. Thanks! </i><br />
<ul>
</ul>
<h4>
Usage</h4>
<br />
<span style="font-weight: normal;"><span style="font-family: "Courier New",Courier,monospace;">java Watershed [source file] [result file] [number of segments, 1-256] [minimum window width, 8-256] [connected pixels, 4|8] </span></span><br />
<br />
<span style="font-weight: normal;"><b>For example:</b> </span><br />
<span style="font-weight: normal;"><span style="font-size: small;"><span style="font-family: "Courier New",Courier,monospace;">java Watershed sample_image.png result.png 22 60 8</span></span></span><br />
<h4>
</h4>
<h4>
SortedVector.java</h4>
<style>tr { color: #888888; }h3 { font-family: Verdana,Arial,Serif; border-width: 3px; color: #000000; font-size: 8pt; }p { font-family: Verdana,Arial,Serif; color: #000000; font-size: 8pt; }tr { font-family: Courier,Georgia,Serif; font-size: 8pt; }span.comment { font-weight:bold; color: #008800; font-size: 8pt;}span.cc { font-weight:bold; color: #5555ee; font-size: 8pt; }span.b { font-weight:bold; color: #000000; font-size: 8pt; }span.o { color: #008800; font-size: 8pt; }span.kw { color: #0000aa; font-weight: bold; font-size: 8pt; }div#destination { border-style:solid; border-width:2px; border-color: #555555; background-color: #fefefe; }</style>
<br />
<table cellpadding="0" cellspacing="0"><tbody>
<tr bgcolor="#f0f0f0"><td><span class="kw">import</span> java.util.<span class="cc">Vector</span>; </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td><span class="kw">public</span><span class="kw"> class </span><span class="cc">SortedVector</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">Vector</span><<span class="cc">Comparable</span><<span class="cc">Object</span>>> data; </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">public</span> <span class="cc">SortedVector</span><span class="b">(</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> data = <span class="kw">new</span> <span class="cc">Vector</span><<span class="cc">Comparable</span><<span class="cc">Object</span>>><span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">public</span> <span class="kw">void</span> add<span class="b">(</span><span class="cc">Object</span> o<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>o <span class="kw">instanceof</span> <span class="cc">Comparable</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> insert<span class="b">(</span><span class="b">(</span><span class="cc">Comparable</span><<span class="cc">Object</span>><span class="b">)</span>o<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> <span class="kw">else</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">throw</span> <span class="kw">new</span> <span class="cc">IllegalArgumentException</span><span class="b">(</span>"<span class="cc">Object</span> " + </td></tr>
<tr bgcolor="#ffffff"><td> "must implement <span class="cc">Comparable</span> <span class="kw">interface</span>."<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">private</span> <span class="kw">void</span> insert<span class="b">(</span><span class="cc">Comparable</span><<span class="cc">Object</span>> o<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">if</span> <span class="b">(</span>data.size<span class="b">(</span><span class="b">)</span>==0<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> data.add<span class="b">(</span>o<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> middle = 0; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> left = 0; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> right = data.size<span class="b">(</span><span class="b">)</span>-1; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">while</span> <span class="b">(</span>left < right<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> middle = <span class="b">(</span>left+right<span class="b">)</span>/2; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">if</span> <span class="b">(</span>data.elementAt<span class="b">(</span>middle<span class="b">)</span>.compareTo<span class="b">(</span>o<span class="b">)</span>==-1<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> left = middle + 1; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> <span class="kw">else</span> <span class="kw">if</span> <span class="b">(</span>data.elementAt<span class="b">(</span>middle<span class="b">)</span>.compareTo<span class="b">(</span>o<span class="b">)</span>==1<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> right = middle - 1; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> <span class="kw">else</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // position found, insert here</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // break out while</span> </td></tr>
<tr bgcolor="#ffffff"><td> left = data.size<span class="b">(</span><span class="b">)</span>+1; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> data.add<span class="b">(</span>middle, o<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">public</span> <span class="kw">int</span> size<span class="b">(</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">return</span> data.size<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">public</span> <span class="cc">Object</span> elementAt<span class="b">(</span><span class="kw">int</span> index<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">return</span> data.elementAt<span class="b">(</span>index<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">public</span> <span class="cc">Object</span> remove<span class="b">(</span><span class="kw">int</span> position<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">return</span> data.remove<span class="b">(</span>position<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td><span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
</tbody></table>
<br />
<h4>
Watershed.java</h4>
<style>tr { color: #888888; }h3 { font-family: Verdana,Arial,Serif; border-width: 3px; color: #000000; font-size: 8pt; }p { font-family: Verdana,Arial,Serif; color: #000000; font-size: 8pt; }tr { font-family: Courier,Georgia,Serif; font-size: 8pt; }span.comment { font-weight:bold; color: #008800; font-size: 8pt;}span.cc { font-weight:bold; color: #5555ee; font-size: 8pt; }span.b { font-weight:bold; color: #000000; font-size: 8pt; }span.o { color: #008800; font-size: 8pt; }span.kw { color: #0000aa; font-weight: bold; font-size: 8pt; }div#destination { border-style:solid; border-width:2px; border-color: #555555; background-color: #fefefe; }</style>
<br />
<table cellpadding="0" cellspacing="0"><tbody>
<tr bgcolor="#f0f0f0"><td><span class="kw">import</span> java.awt.<span class="cc">Color</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="kw">import</span> java.awt.<span class="cc">Graphics</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="kw">import</span> java.awt.image.<span class="cc">BufferedImage</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="kw">import</span> java.io.<span class="cc">File</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="kw">import</span> java.util.<span class="cc">Arrays</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="kw">import</span> java.util.<span class="cc">Vector</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="kw">import</span> javax.imageio.<span class="cc">ImageIO</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="kw">import</span> javax.swing.JFrame; </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td><span class="comment">/**</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> * @author tejopa / http://popscan.blogspot.com</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> * @date 2014-04-20</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> */ </td></tr>
<tr bgcolor="#ffffff"><td><span class="kw">public</span><span class="kw"> class </span><span class="cc">Watershed</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> //JFrame frame;</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> g_w; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> g_h; </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">public</span> <span class="kw">static</span> <span class="kw">void</span> main<span class="b">(</span><span class="cc">String</span><span class="b">[</span><span class="b">]</span> args<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">if</span> <span class="b">(</span>args.length!=5<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">System</span>.out.println<span class="b">(</span>"<span class="cc">Usage</span>: java popscan.<span class="cc">Watershed</span>" </td></tr>
<tr bgcolor="#f0f0f0"><td> + " <span class="b">[</span>source image filename<span class="b">]</span>" </td></tr>
<tr bgcolor="#ffffff"><td> + " <span class="b">[</span>destination image filename<span class="b">]</span>" </td></tr>
<tr bgcolor="#f0f0f0"><td> + " <span class="b">[</span>flood point count <span class="b">(</span>1-256<span class="b">)</span><span class="b">]</span>" </td></tr>
<tr bgcolor="#ffffff"><td> + " <span class="b">[</span>minimums window width <span class="b">(</span>8-256<span class="b">)</span><span class="b">]</span>" </td></tr>
<tr bgcolor="#f0f0f0"><td> + " <span class="b">[</span>connected pixels <span class="b">(</span>4 or 8<span class="b">)</span><span class="b">]</span>" </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">return</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">String</span> src = args<span class="b">[</span>0<span class="b">]</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">String</span> dst = args<span class="b">[</span>1<span class="b">]</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> floodPoints = <span class="cc">Integer</span>.parseInt<span class="b">(</span>args<span class="b">[</span>2<span class="b">]</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> windowWidth = <span class="cc">Integer</span>.parseInt<span class="b">(</span>args<span class="b">[</span>3<span class="b">]</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> connectedPixels = <span class="cc">Integer</span>.parseInt<span class="b">(</span>args<span class="b">[</span>4<span class="b">]</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">Watershed</span> watershed = <span class="kw">new</span> <span class="cc">Watershed</span><span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">long</span> start = <span class="cc">System</span>.currentTimeMillis<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">BufferedImage</span> dstImage = watershed.calculate<span class="b">(</span>loadImage<span class="b">(</span>src<span class="b">)</span>, </td></tr>
<tr bgcolor="#ffffff"><td> floodPoints,windowWidth,connectedPixels<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">long</span> end = <span class="cc">System</span>.currentTimeMillis<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // save the resulting image</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">long</span> totalms = <span class="b">(</span>end-start<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">System</span>.out.println<span class="b">(</span>"<span class="cc">Took</span>: "+totalms+" milliseconds"<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> saveImage<span class="b">(</span>dst, dstImage<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">private</span> <span class="cc">BufferedImage</span> calculate<span class="b">(</span><span class="cc">BufferedImage</span> image, </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> floodPoints, <span class="kw">int</span> windowWidth, </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> connectedPixels<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> /*</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // frame for real time view for the process</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> frame = new JFrame<span class="b">(</span><span class="b">)</span>;</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> frame.setSize<span class="b">(</span>image.getWidth<span class="b">(</span><span class="b">)</span>,image.getHeight<span class="b">(</span><span class="b">)</span><span class="b">)</span>;</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> frame.setVisible<span class="b">(</span>true<span class="b">)</span>;</span> </td></tr>
<tr bgcolor="#ffffff"><td> */ </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td> g_w = image.getWidth<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> g_h = image.getHeight<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // height map is the gray color image</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span><span class="b">[</span><span class="b">]</span> map = image.getRGB<span class="b">(</span>0, 0, g_w, g_h, null, 0, g_w<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // LUT is the lookup table for the processed pixels</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span><span class="b">[</span><span class="b">]</span> lut = <span class="kw">new</span> <span class="kw">int</span><span class="b">[</span>g_w*g_h<span class="b">]</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // fill LUT with ones</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">Arrays</span>.fill<span class="b">(</span>lut, 1<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">Vector</span><<span class="cc">FloodPoint</span>> minimums = <span class="kw">new</span> <span class="cc">Vector</span><<span class="cc">FloodPoint</span>><span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // loop all the pixels of the image until</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // a<span class="b">)</span> all the required minimums have been found</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // OR</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // b<span class="b">)</span> there are no more unprocessed pixels left </span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> foundMinimums = 0; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">while</span> <span class="b">(</span>foundMinimums<floodPoints<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> minimumValue = 256; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> minimumPosition = -1; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> i=0;i<lut.length;i++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span><span class="b">(</span>lut<span class="b">[</span>i<span class="b">]</span>==1<span class="b">)</span>&&<span class="b">(</span>map<span class="b">[</span>i<span class="b">]</span><minimumValue<span class="b">)</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> minimumPosition = i; </td></tr>
<tr bgcolor="#ffffff"><td> minimumValue = map<span class="b">[</span>i<span class="b">]</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // check if minimum was found</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>minimumPosition!=-1<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // add minimum to found minimum vector</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> x = minimumPosition%g_w; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> y = minimumPosition/g_w; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> grey = map<span class="b">[</span>x+g_w*y<span class="b">]</span>&0xff; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> label = foundMinimums; </td></tr>
<tr bgcolor="#ffffff"><td> minimums.add<span class="b">(</span><span class="kw">new</span> <span class="cc">FloodPoint</span><span class="b">(</span>x,y, </td></tr>
<tr bgcolor="#f0f0f0"><td> label,grey<span class="b">)</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // remove pixels around so that the next minimum</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // must be at least windowWidth/2 distance from</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // this minimum <span class="b">(</span>using square, could be circle...<span class="b">)</span></span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> half = windowWidth/2; </td></tr>
<tr bgcolor="#ffffff"><td> fill<span class="b">(</span>x-half,y-half,x+half,y+half,lut,0<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> lut<span class="b">[</span>minimumPosition<span class="b">]</span> = 0; </td></tr>
<tr bgcolor="#ffffff"><td> foundMinimums++; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> <span class="kw">else</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // stop while loop</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">System</span>.out.println<span class="b">(</span>"<span class="cc">Out</span> of pixels. <span class="cc">Found</span> " </td></tr>
<tr bgcolor="#ffffff"><td> + minimums.size<span class="b">(</span><span class="b">)</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> + " minimums of requested " </td></tr>
<tr bgcolor="#ffffff"><td> + floodPoints+"."<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">break</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> /*</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // create image with minimums only</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> for <span class="b">(</span>int i=0;i<minimums.size<span class="b">(</span><span class="b">)</span>;i++<span class="b">)</span> <span class="b">{</span></span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> FloodPoint p = minimums.elementAt<span class="b">(</span>i<span class="b">)</span>;</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> Graphics g = image.getGraphics<span class="b">(</span><span class="b">)</span>;</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> g.setColor<span class="b">(</span>Color.red<span class="b">)</span>;</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> g.drawRect<span class="b">(</span>p.x, p.y, 2, 2<span class="b">)</span>;</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> <span class="b">}</span></span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> saveImage<span class="b">(</span>"minimums.png", image<span class="b">)</span>;</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> */ </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // start flooding from minimums</span> </td></tr>
<tr bgcolor="#ffffff"><td> lut = flood<span class="b">(</span>map,minimums,connectedPixels<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // return flooded image</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> image.setRGB<span class="b">(</span>0, 0, g_w, g_h, lut, 0, g_w<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> /*// create image with boundaries also</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> i=0;i<minimums.size<span class="b">(</span><span class="b">)</span>;i++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">FloodPoint</span> p = minimums.elementAt<span class="b">(</span>i<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">Graphics</span> g = image.getGraphics<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> g.setColor<span class="b">(</span><span class="cc">Color</span>.red<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> g.drawRect<span class="b">(</span>p.x, p.y, 2, 2<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> saveImage<span class="b">(</span>"minimums_and_boundaries.png", image<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> */ </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">return</span> image; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">private</span> <span class="kw">int</span><span class="b">[</span><span class="b">]</span> flood<span class="b">(</span><span class="kw">int</span><span class="b">[</span><span class="b">]</span> map, <span class="cc">Vector</span><<span class="cc">FloodPoint</span>> minimums, </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> connectedPixels<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">SortedVector</span> queue = <span class="kw">new</span> <span class="cc">SortedVector</span><span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> //BufferedImage result = new BufferedImage<span class="b">(</span>g_w, g_h,</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // BufferedImage.TYPE_INT_RGB<span class="b">)</span>;</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span><span class="b">[</span><span class="b">]</span> lut = <span class="kw">new</span> <span class="kw">int</span><span class="b">[</span>g_w*g_h<span class="b">]</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span><span class="b">[</span><span class="b">]</span> inqueue = <span class="kw">new</span> <span class="kw">int</span><span class="b">[</span>g_w*g_h<span class="b">]</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // not processed = -1, processed >= 0</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">Arrays</span>.fill<span class="b">(</span>lut, -1<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">Arrays</span>.fill<span class="b">(</span>inqueue, 0<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // Initialize queue with each found minimum</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> i=0;i<minimums.size<span class="b">(</span><span class="b">)</span>;i++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">FloodPoint</span> p = minimums.elementAt<span class="b">(</span>i<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> label = p.label; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // insert starting pixels around minimums</span> </td></tr>
<tr bgcolor="#ffffff"><td> addPoint<span class="b">(</span>queue, inqueue, map, p.x, p.y-1, label<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> addPoint<span class="b">(</span>queue, inqueue, map, p.x+1, p.y, label<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> addPoint<span class="b">(</span>queue, inqueue, map, p.x, p.y+1, label<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> addPoint<span class="b">(</span>queue, inqueue, map, p.x-1, p.y, label<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>connectedPixels==8<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> addPoint<span class="b">(</span>queue, inqueue, map, p.x-1, p.y-1, label<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> addPoint<span class="b">(</span>queue, inqueue, map, p.x+1, p.y-1, label<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> addPoint<span class="b">(</span>queue, inqueue, map, p.x+1, p.y+1, label<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> addPoint<span class="b">(</span>queue, inqueue, map, p.x-1, p.y+1, label<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> pos = p.x+p.y*g_w; </td></tr>
<tr bgcolor="#f0f0f0"><td> lut<span class="b">[</span>pos<span class="b">]</span> = label; </td></tr>
<tr bgcolor="#ffffff"><td> inqueue<span class="b">[</span>pos<span class="b">]</span> = 1; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // start flooding</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">while</span> <span class="b">(</span>queue.size<span class="b">(</span><span class="b">)</span>>0<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // find minimum</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">FloodPoint</span> extracted = null; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // remove the minimum from the queue</span> </td></tr>
<tr bgcolor="#ffffff"><td> extracted = <span class="b">(</span><span class="cc">FloodPoint</span><span class="b">)</span>queue.remove<span class="b">(</span>0<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> x = extracted.x; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> y = extracted.y; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> label = extracted.label; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // check pixels around extracted pixel</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span><span class="b">[</span><span class="b">]</span> labels = <span class="kw">new</span> <span class="kw">int</span><span class="b">[</span>connectedPixels<span class="b">]</span>; </td></tr>
<tr bgcolor="#ffffff"><td> labels<span class="b">[</span>0<span class="b">]</span> = getLabel<span class="b">(</span>lut,x,y-1<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> labels<span class="b">[</span>1<span class="b">]</span> = getLabel<span class="b">(</span>lut,x+1,y<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> labels<span class="b">[</span>2<span class="b">]</span> = getLabel<span class="b">(</span>lut,x,y+1<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> labels<span class="b">[</span>3<span class="b">]</span> = getLabel<span class="b">(</span>lut,x-1,y<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>connectedPixels==8<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> labels<span class="b">[</span>4<span class="b">]</span> = getLabel<span class="b">(</span>lut,x-1,y-1<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> labels<span class="b">[</span>5<span class="b">]</span> = getLabel<span class="b">(</span>lut,x+1,y-1<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> labels<span class="b">[</span>6<span class="b">]</span> = getLabel<span class="b">(</span>lut,x+1,y+1<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> labels<span class="b">[</span>7<span class="b">]</span> = getLabel<span class="b">(</span>lut,x-1,y+1<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">boolean</span> onEdge = isEdge<span class="b">(</span>labels,extracted<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">if</span> <span class="b">(</span>onEdge<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // leave edges without label</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> <span class="kw">else</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // set pixel with label</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> lut<span class="b">[</span>x+g_w*y<span class="b">]</span> = extracted.label; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">if</span> <span class="b">(</span>!inQueue<span class="b">(</span>inqueue,x,y-1<span class="b">)</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> addPoint<span class="b">(</span>queue, inqueue, map, x, y-1, label<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>!inQueue<span class="b">(</span>inqueue,x+1,y<span class="b">)</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> addPoint<span class="b">(</span>queue, inqueue, map, x+1, y, label<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">if</span> <span class="b">(</span>!inQueue<span class="b">(</span>inqueue,x,y+1<span class="b">)</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> addPoint<span class="b">(</span>queue, inqueue, map, x, y+1, label<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>!inQueue<span class="b">(</span>inqueue,x-1,y<span class="b">)</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> addPoint<span class="b">(</span>queue, inqueue, map, x-1, y, label<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">if</span> <span class="b">(</span>connectedPixels==8<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>!inQueue<span class="b">(</span>inqueue,x-1,y-1<span class="b">)</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> addPoint<span class="b">(</span>queue, inqueue, map, x-1, y-1, label<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">if</span> <span class="b">(</span>!inQueue<span class="b">(</span>inqueue,x+1,y-1<span class="b">)</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> addPoint<span class="b">(</span>queue, inqueue, map, x+1, y-1, label<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>!inQueue<span class="b">(</span>inqueue,x+1,y+1<span class="b">)</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> addPoint<span class="b">(</span>queue, inqueue, map, x+1, y+1, label<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">if</span> <span class="b">(</span>!inQueue<span class="b">(</span>inqueue,x-1,y+1<span class="b">)</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> addPoint<span class="b">(</span>queue, inqueue, map, x-1, y+1, label<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // draw the current pixel set to frame, WARNING: slow...</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> //result.setRGB<span class="b">(</span>0, 0, g_w, g_h, lut, 0, g_w<span class="b">)</span>;</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> //frame.getGraphics<span class="b">(</span><span class="b">)</span>.drawImage<span class="b">(</span>result, </span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // 0, 0, g_w, g_h, null<span class="b">)</span>;</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">return</span> lut; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">private</span> <span class="kw">boolean</span> inQueue<span class="b">(</span><span class="kw">int</span><span class="b">[</span><span class="b">]</span> inqueue, <span class="kw">int</span> x, <span class="kw">int</span> y<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>x<0||x>=g_w||y<0||y>=g_h<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">return</span> false; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">if</span> <span class="b">(</span>inqueue<span class="b">[</span>x+g_w*y<span class="b">]</span> == 1<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">return</span> true; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">return</span> false; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">private</span> <span class="kw">boolean</span> isEdge<span class="b">(</span><span class="kw">int</span><span class="b">[</span><span class="b">]</span> labels, <span class="cc">FloodPoint</span> extracted<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> i=0;i<labels.length;i++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">if</span> <span class="b">(</span>labels<span class="b">[</span>i<span class="b">]</span>!=extracted.label&&labels<span class="b">[</span>i<span class="b">]</span>!=-1<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">return</span> true; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">return</span> false; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">private</span> <span class="kw">int</span> getLabel<span class="b">(</span><span class="kw">int</span><span class="b">[</span><span class="b">]</span> lut, <span class="kw">int</span> x, <span class="kw">int</span> y<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">if</span> <span class="b">(</span>x<0||x>=g_w||y<0||y>=g_h<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">return</span> -2; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">return</span> lut<span class="b">[</span>x+g_w*y<span class="b">]</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">private</span> <span class="kw">void</span> addPoint<span class="b">(</span><span class="cc">SortedVector</span> queue, </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span><span class="b">[</span><span class="b">]</span> inqueue, <span class="kw">int</span><span class="b">[</span><span class="b">]</span> map, </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> x, <span class="kw">int</span> y, <span class="kw">int</span> label<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>x<0||x>=g_w||y<0||y>=g_h<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">return</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> queue.add<span class="b">(</span><span class="kw">new</span> <span class="cc">FloodPoint</span><span class="b">(</span>x,y,label,map<span class="b">[</span>x+g_w*y<span class="b">]</span>&0xff<span class="b">)</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> inqueue<span class="b">[</span>x+g_w*y<span class="b">]</span> = 1; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">private</span> <span class="kw">void</span> fill<span class="b">(</span><span class="kw">int</span> x1, <span class="kw">int</span> y1, <span class="kw">int</span> x2, <span class="kw">int</span> y2, </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span><span class="b">[</span><span class="b">]</span> array, <span class="kw">int</span> value<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> y=y1;y<y2;y++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> x=x1;x<x2;x++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // clip to boundaries</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>y>=0&&x>=0&&y<g_h&&x<g_w<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> array<span class="b">[</span>x+g_w*y<span class="b">]</span> = value; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">public</span> <span class="kw">static</span> <span class="kw">void</span> saveImage<span class="b">(</span><span class="cc">String</span> filename, </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">BufferedImage</span> image<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">File</span> file = <span class="kw">new</span> <span class="cc">File</span><span class="b">(</span>filename<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">try</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">ImageIO</span>.write<span class="b">(</span>image, "png", file<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> <span class="kw">catch</span> <span class="b">(</span><span class="cc">Exception</span> e<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">System</span>.out.println<span class="b">(</span>e.toString<span class="b">(</span><span class="b">)</span>+" <span class="cc">Image</span> '"+filename </td></tr>
<tr bgcolor="#ffffff"><td> +"' saving failed."<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">public</span> <span class="kw">static</span> <span class="cc">BufferedImage</span> loadImage<span class="b">(</span><span class="cc">String</span> filename<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">BufferedImage</span> result = null; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">try</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> result = <span class="cc">ImageIO</span>.read<span class="b">(</span><span class="kw">new</span> <span class="cc">File</span><span class="b">(</span>filename<span class="b">)</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> <span class="kw">catch</span> <span class="b">(</span><span class="cc">Exception</span> e<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">System</span>.out.println<span class="b">(</span>e.toString<span class="b">(</span><span class="b">)</span>+" <span class="cc">Image</span> '" </td></tr>
<tr bgcolor="#ffffff"><td> +filename+"' not found."<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">return</span> result; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td> class <span class="cc">FloodPoint</span> <span class="kw">implements</span> <span class="cc">Comparable</span><<span class="cc">Object</span>> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> x; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> y; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> label; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> grey; </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">public</span> <span class="cc">FloodPoint</span><span class="b">(</span><span class="kw">int</span> x, <span class="kw">int</span> y, <span class="kw">int</span> label, <span class="kw">int</span> grey<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">this</span>.x = x; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">this</span>.y = y; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">this</span>.label = label; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">this</span>.grey = grey; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td> @<span class="cc">Override</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">public</span> <span class="kw">int</span> compareTo<span class="b">(</span><span class="cc">Object</span> o<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">FloodPoint</span> other = <span class="b">(</span><span class="cc">FloodPoint</span><span class="b">)</span>o; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">if</span> <span class="b">(</span><span class="kw">this</span>.grey < other.grey <span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">return</span> -1; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> <span class="kw">else</span> <span class="kw">if</span> <span class="b">(</span><span class="kw">this</span>.grey > other.grey <span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">return</span> 1; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">return</span> 0; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td><span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
</tbody></table>
<br />
Sources:<br />
[1] <a href="http://en.wikipedia.org/wiki/Watershed_%28image_processing%29" target="_blank">http://en.wikipedia.org/wiki/Watershed_%28image_processing%29</a><br />
[2] <a href="http://imagej.1557.x6.nabble.com/Watershed-Algorithm-source-bug-td3685192.html" target="_blank">http://imagej.1557.x6.nabble.com/Watershed-Algorithm-source-bug-td3685192.html</a><br />
[3] <a href="http://cmm.ensmp.fr/~beucher/wtshed.html" target="_blank">http://cmm.ensmp.fr/~beucher/wtshed.html </a><br />
<br />
<iframe frameborder="0" height="200px" scrolling="no" src="http://www.eemeli.de" width="100%"></iframe>Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com3tag:blogger.com,1999:blog-1495123355536406202.post-77035892106177618312014-02-10T11:17:00.000+02:002014-04-25T16:05:10.187+03:00Transcranial magnetic stimulation for tinnitusI have tinnitus. I have had it for 20 years already, but it really got a lot worse almost exactly six years ago.<br />
<br />
<br />
Recently my local university hospital contacted me and offered me a possibility to take a part in their new study about using "repetitive transcranial magnetic stimulation" (rTMS) for alleviating my tinnitus symptoms.<br />
<br />
Sadly, I had to refuse from the offer. I refused because I have found a state of mind where my tinnitus does not bother me too much, or sometimes not at all. During the study I should have kept a diary about my tinnitus sounds and levels, and my fear was that the constant "listening" to my tinnitus, would have made me more aware of my tinnitus and thus completely ruin my progress in my habituation.<br />
<br />
I contacted the study assistant and explained my situation to him and he said my choice was probably best for me. Also my current tinnitus intensity level is somewhere around "4", maybe a little less, and the study participants must have the tinnitus intensity level at least 4.<br />
<br />
Still, as I was interested in the study, I asked from the assistant that if the treatment really works. His answer really made me happy, he said: "Sure, it works."<br />
<br />
The assistant told me, that if I someday feel that my tinnitus is getting too loud and I am not coping with it, I could always come by to take a treatment. Just the thought of having my tinnitus sound diminished even a little bit gives me hope and relief.<br />
<br />
You can see more details about this rTMS study from <a href="http://clinicaltrials.gov/ct2/show/NCT01929837">http://clinicaltrials.gov/ct2/show/NCT01929837.</a><br />
<br />
I have seen the news about rTMS not working on patients or working only as good as placebo treatment, for example <a href="http://www.reuters.com/article/2013/04/22/us-magnetic-therapy-idUSBRE93L14120130422">http://www.reuters.com/article/2013/04/22/us-magnetic-therapy-idUSBRE93L14120130422</a>.<br />
<br />
But looking at the results of this prior study, the tinnitus intensity and also the annoyance levels were reduced using rTMS, link to the pdf: <a href="http://www.tbmc.fi/images/PDF/satu%20jskelinen%20navigoiva%20magneettistimulaatio%20tyks%20kipu%20ja%20tinnitus%202013%20huhtikuu.pdf" target="_blank">link</a> (see page 20 for results, only in Finnish, sorry). <br />
<br />
<br>
<iframe frameborder="0" height="200px" scrolling="no" src="http://www.eemeli.de" width="100%"></iframe>Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com0tag:blogger.com,1999:blog-1495123355536406202.post-67731297693351538072014-02-05T12:42:00.000+02:002014-02-05T12:42:46.090+02:00Setting TTL to Amazon CloudFrontDo you want to clear the CloudFront cache? Don't want to wait 24 hours to see the new file? Don't want to rename your files?<br />
<br />
By default Amazon CloudFront checks only once in 24 hours if the source files in the "origin" have changed. It means that if you upload a new version of the file, for example "index.html", it may take up to 24 hours until the new file is visible for browsers and users. Meanwhile CloudFront keeps serving the old file.<br />
<br />
There are several ways to speed up the update:<br />
<ol>
<li>using invalidation object</li>
<li>renaming the files</li>
<li>setting the time-to-live (TTL) value for distribution origin and Cache-Control value for each individual file </li>
</ol>
<b>1. Using invalidation object</b><br />
After you have uploaded a new version from your file, you can make an invalidation request. The documentation says that it takes 10-15 minutes to clear the CloudFront cache for the given file, but in practice invalidation request handling may take up to 30 minutes (or even longer!). You can read more about invalidation requests from: <a href="http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Invalidation.html">http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Invalidation.html</a><br />
<br />
<b>2. Renaming the files</b><br />
New files are pushed to the CloudFront automatically. So if you don't mind that the file name changes for example from index.html to index_2.html, you can always upload a file which has completely new filename. Those files are visible in the CloudFront immediately.<br />
<br />
<b>3. Setting the TTL value and using Cache-Control </b><br />
The most flexible and I think also easiest method is to set up the TTL value for the distribution origin to 0 (zero) and then add Cache-Control header to all your files at the moment of upload.<br />
<b> </b><b> </b><br />
<h3>
<b>Setting TTL value using AWS Management Console</b></h3>
Follow these steps to set the TTL value:<br />
1. Login to the AWS Management Console<br />
2. Select CloudFront<br />
3. Tick the check box from the distribution you want to manage<br />
4. Select "Distribution settings"<br />
5. Select "Behaviours" tab<br />
6. Tick the check box from the origin you want to manage<br />
7. Click "edit"<br />
8. Set "Minimum TTL" to 0 (zero) and select "Object caching" value to be "Use Origin Cache Headers"<br />
9. Save changes by clicking the button "Yes, Edit" <br />
<br />
Follow these steps to set the headers for the uploaded file:<br />
1. From the AWS Management Console, choose "Services" -> "S3"<br />
2. Choose the bucket you are going to upload your file or files<br />
3. Click "Upload"->"Add files" and use the file browser to search your file to be uploaded<br />
4. Click "Set details"<br />
5. Click "Set permissions" -> tick the check box "Make everything public" (if you want so)<br />
6. Click "Set metadata"<br />
7. Click "Add more metadata"<br />
8. For the key, select from the drop-down menu "Cache-Control"<br />
9. For the value, type in: max-age=[SECONDS_1], s-maxage=[SECONDS_2], for example: max-age=60, s-maxage=60<br />
10. Click "Upload"<br />
<br />
Done! Browsers will now check every [SECONDS_1] if the file has changed in the CloudFront, and CloudFront will now check every [SECONDS_2] if the file has changed in the origin.<br />
<br />
<b>Note: </b>If the original file did not have the Cache-Control value set, you need to invalidate it first! <br />
<br />
<br />
Read more about Cache-Control and file expiration from <a href="http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Expiration.html">http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Expiration.html</a>Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com0tag:blogger.com,1999:blog-1495123355536406202.post-67641910454487788682014-01-08T21:18:00.003+02:002014-01-08T21:18:51.766+02:00Can not see Install button in Adobe Flash Player download page - solutionThis post's subject may be obvious and trivial to most of the people, but I for example searched the solution with the title from this post as a search phrase (and couldn't find help)... Really, I just could not see the install button what the instructions told me to click!<br />
<br />
But the solution was easy, I found it eventually by mistake: <b>in Windows 8.1, you can not install software, or in this case you can not even see the install button, unless you are using the Administrator's account!</b><br />
<br />
So, just change the user from guest/kids/family/etc to your Admin user, browse to Adobe Flash Player download page and you will see the big yellow "Install now" -button. Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com0tag:blogger.com,1999:blog-1495123355536406202.post-86837469059166290932014-01-08T20:56:00.002+02:002014-01-08T20:56:41.930+02:00Windows 8 does not load web sites correctly - solutionI recently started using a Windows 8 laptop, and installed the suggested Windows 8.1 version in to it. For a brief moment everything seemed to be fine, until I noticed that from time to time some web sites did not load at all or loaded only partially, like the CSS styles were missing or some Flash content was missing. The web site loading succeeded randomly: the same site could load nicely after first reload but not anymore after second reload.<br />
<br />
I spent hours trying to diagnose the problem and finally found the solution: <b>change or add the DNS servers from your network card settings to use Google DNS servers</b>. Crazy, I know, but it worked for me.<br />
<br />
What is really strange is that I already had the Google DNS servers in my wireless D-Link router's settings. <u>This was not enough on my Windows 8.1 laptop, I really had to add the DNS servers directly to the wireless network card settings!</u> Maybe someone could explain to me how this can change the situation, I mean, what is the effective difference between DNS settings on the router and on the network card, if the servers are same (other than just the value location)?<br />
<br />
Links:<br />
<a href="https://developers.google.com/speed/public-dns/docs/using">https://developers.google.com/speed/public-dns/docs/using</a><br />
<a href="http://www.eightforums.com/browsers-mail/33778-windows-8-1-not-loading-some-random-websites-correctly-2.html">http://www.eightforums.com/browsers-mail/33778-windows-8-1-not-loading-some-random-websites-correctly-2.html</a><br />
<br />
Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com0tag:blogger.com,1999:blog-1495123355536406202.post-22007055293667529162013-11-21T01:08:00.002+02:002013-11-21T01:10:24.548+02:00Detect if uploaded file is saved to the temporary folder using Django<span style="font-family: Arial,Helvetica,sans-serif;">When uploading a file to the Django server, using HTML form and POST method, it is not always clear what is the used upload handler and if the file is saved to the temporary folder or just kept in the memory.</span><br />
<span style="font-family: Arial,Helvetica,sans-serif;"><br /></span>
<span style="font-family: Arial,Helvetica,sans-serif;">Here is one way to detect if the file is stored to the temporary folder or not.</span><br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">def upload(request):<br /> uploaded_file = request.FILES['file']</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> if isinstance(uploaded_file, TemporaryUploadedFile):<br /> # file has exceeded the value FILE_UPLOAD_MAX_MEMORY_SIZE</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # and it has been saved to the temporary folder</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> print uploaded_tile.temporary_file_path()</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # closing the file will delete the file</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> uploaded_file.close() </span><br />
<span style="font-family: "Courier New",Courier,monospace;"> return "file too large"</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> else:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # file is instance of InMemoryUploadedFile</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # handle file</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> return "ok" </span><br />
<span style="font-family: "Courier New",Courier,monospace;"><br /></span>
<span style="font-family: Arial,Helvetica,sans-serif;">Other comparison function that can be used is:</span><br />
<br />
<span style="font-family: Georgia,"Times New Roman",serif;"><span style="font-family: "Courier New",Courier,monospace;"> if hasattr(uploaded_file, 'temporary_file_path'): </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><br /></span>
<span style="font-family: Arial,Helvetica,sans-serif;"><b>Links:</b> </span><br />
<span style="font-family: Arial,Helvetica,sans-serif;"><a href="https://docs.djangoproject.com/en/dev/topics/http/file-uploads/">https://docs.djangoproject.com/en/dev/topics/http/file-uploads/</a></span> <br />
<span style="font-family: Arial,Helvetica,sans-serif;"><a href="http://stackoverflow.com/questions/11835274/django-control-time-of-temporaryuploadedfile-life">http://stackoverflow.com/questions/11835274/django-control-time-of-temporaryuploadedfile-life</a></span>Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com0tag:blogger.com,1999:blog-1495123355536406202.post-7603148468717564512013-11-20T12:32:00.001+02:002013-11-20T12:44:35.797+02:00How to start using South database migration tool in your Django projectIf you are working with Django application using database, at some point you may need change your database schema. In my projects, when working with extreme style, the database changes are frequent.<br />
<br />
The 'syncdb' handles new tables, but it does not update changes to the existing tables. One solution is to start using migration tool 'South'. <br />
<br />
A lot of documentation for the South exists, but for some reason I was not able to get it up and running as easily as I thought I would. So I wrote the steps you have to take when starting to use South. I hope it helps. <br />
<br />
<b>How to start using South in your Django project</b><br />
<br />
1. start using south by setting it to <br />
- add 'south' to INSTALLED_APPS in your settings.py<br />
2. create needed databases, if you are starting from the scratch<br />
- <span style="font-family: "Courier New",Courier,monospace;">python manage.py syncdb</span><br />
3. create initial migration files<br />
- <span style="font-family: "Courier New",Courier,monospace;">python manage.py schemamigration APPNAME --initial</span><br />
4. make the first migration, use parameter --fake to avoid "table already exists error"<br />
- <span style="font-family: "Courier New",Courier,monospace;">python manage.py migrate APPNAME --fake</span><br />
5. create migration file for fixtures (if you have any)<br />
- <span style="font-family: "Courier New",Courier,monospace;">manage.py datamigration APPNAME load_fixtures</span><br />
6. edit the fixture file "000x_load_fixtures.py", search the file from "migrations" folder<br />
- edit the function forwards() to include json fixture of your own<br />
<span style="font-family: "Courier New",Courier,monospace;">def forwards(self, orm):<br /> from django.core.management import call_command<br /> call_command("loaddata", "my_initial_data.json")</span><br />
7. run the migration to import the fixtures<br />
- <span style="font-family: "Courier New",Courier,monospace;">python manage.py migrate APPNAME</span><br />
<br />
<br />
<br />
<br />
<b>Links:</b><br />
<a href="http://south.readthedocs.org/en/latest/index.html">http://south.readthedocs.org/en/latest/index.html</a><br />
<a href="http://south.readthedocs.org/en/latest/installation.html#installation">http://south.readthedocs.org/en/latest/installation.html#installation</a><br />
<a href="http://stackoverflow.com/questions/5687627/django-south-error-with-initial-migration">http://stackoverflow.com/questions/5687627/django-south-error-with-initial-migration</a><br />
<a href="http://south.readthedocs.org/en/latest/fixtures.html">http://south.readthedocs.org/en/latest/fixtures.html</a>Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com0tag:blogger.com,1999:blog-1495123355536406202.post-23856117988875714382013-10-03T08:46:00.000+03:002013-10-03T08:46:06.089+03:00Eclipse autocomplete not working - solutionSuddenly the autocompletion in my Eclipse PHP-project was not working anymore. I tried to restart Eclipse, clean and rebuild my projects but nothing worked. Until I found out the brute force solution: remove the index files autocomplete uses!<br />
<br />
1. Just delete folder in from your workspace: /.metadata/.plugins/org.eclipse.dltk.core.index.sql.h2<br />
2. Restart Eclipse <br />
<br />
<b>Note:</b> If the autocomplete has never worked in your setup, perhaps you have not enabled it? To check and enable autocomplete, go to Eclipse menu: Window > Preferences > PHP > Editor > Content Assist and select "Enable auto activation".Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com0tag:blogger.com,1999:blog-1495123355536406202.post-35061596178766869382013-08-01T14:50:00.000+03:002013-08-01T14:50:43.310+03:00Multiple static directories with Nginx and DjangoI had troubles setting up Nginx configuration to serve static files from two different Django applications. Finally, after searching hints for the solution from Nginx error logs, I managed to got the location configurations correctly.<br />
<br />
The following solution may not be optimal, but at least it works. If you know how to achieve similar functionality more elegantly, give me a comment, thanks! :)<br />
<br />
<table><tbody>
<tr><td bgcolor="#eeeeff"><pre>...
location /static/tools/ {
alias /var/www/sites/mysite/tools/static/tools/;
}
location /static/editor/ {
alias /var/www/sites/mysite/editor/static/editor/;
}
...
</pre>
</td></tr>
</tbody></table>
Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com0tag:blogger.com,1999:blog-1495123355536406202.post-85693451544538288002013-06-16T23:16:00.001+03:002014-04-25T15:58:14.605+03:00Image segmentation with K-means algorithm - Java implementationK-means algorithm is a well known clustering algorithm and it is described in many papers and online texts. But even after reading many of these said documents, I was confused and still had many questions in my mind.<br />
<br />
I was wondering questions like:<br />
<ul>
<li>What are the K cluster centers in digital image case?</li>
<li>What is the minimal distance function when comparing clusters?</li>
</ul>
I left these questions in my mind for few days, and finally on one morning I realized what the K-means algorithm means in a context of digital image segmentation. Segmentation in this case means "finding the continuous areas where the color and intensity is similar to adjacent pixels".<br />
<br />
I will try to explain the questions above in this post.<br />
<br />
<b>K-means algorithm for digital images in a nut shell</b><br />
<ol>
<li>create k clusters, k being the cluster count and the "center" being a color value</li>
<li>for each pixel, find the cluster which has minimal distance to the pixel</li>
<li>if the pixel was already in other cluster, remove the pixel from other cluster and add it to a new cluster</li>
<li>when pixel is added to a cluster, adjust the cluster center color value by adding the pixel colors to it, remove the pixel color values from the old cluster</li>
<li>loop back to 2. until there are no pixels that are changing clusters </li>
</ol>
The algorithm works like magic! By adding and removing the pixels from clusters, the clusters will transform automatically close to the optimal solution (but the result may not be the optional solution).<br />
<br />
<b>K-means cluster centers in digital images </b><br />
<b><br /></b>
In K-means algorithm you have to decide how many clusters you will have in your image. The simplest case is that the cluster count means the color count and the cluster centers are the color values. In other words, if you have an RGB image with millions of colors, after K-means clustering with value 20, you will have the image converted to a version which only has 20 colors.<br />
<br />
Take a look at the histograms below. Now, choosing the value 20 and running the K-means algorithm on the image, the colors are reduced to 20 colors. The histogram after running the algorithm is on below. <br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4iB7EFxTkAnvKZ-0m8jpSZ28Riz1lP8OMqf5qnZJGLIo-u9K9mCIJHLqqPQ-chJoW665dSTMtj4IhTfKur75-JrTCOjtqCRU-sWUYCl5kKn9VjK_9UtRDrJLkKshsgWChdQ2tnyn085cy/s1600/histogram_01.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4iB7EFxTkAnvKZ-0m8jpSZ28Riz1lP8OMqf5qnZJGLIo-u9K9mCIJHLqqPQ-chJoW665dSTMtj4IhTfKur75-JrTCOjtqCRU-sWUYCl5kKn9VjK_9UtRDrJLkKshsgWChdQ2tnyn085cy/s320/histogram_01.png" height="320" width="293" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Histogram from original image</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGWAQBGWS6n6ld7zITfrdwTeY8sOYLoec7HECj9SA4Zre9rT1LCGEY4pU_z_k5dw_SD4UADH0lLb7UkSiCgeYe7beUrcIZTQT98qqQT4mjPaCUk5SwX9H3l_iTpi22lGRJPJyGRpJ2VNJJ/s1600/histogram_02.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGWAQBGWS6n6ld7zITfrdwTeY8sOYLoec7HECj9SA4Zre9rT1LCGEY4pU_z_k5dw_SD4UADH0lLb7UkSiCgeYe7beUrcIZTQT98qqQT4mjPaCUk5SwX9H3l_iTpi22lGRJPJyGRpJ2VNJJ/s1600/histogram_02.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Histogram after K-means algorithm</td></tr>
</tbody></table>
<br />
In my algorithm implementation, I am choosing the cluster centers always
in the same way, so the result for the same original image is always
the same. But if you choose the cluster centers randomly, you will end
up having slightly different results.<br />
<b><br /></b>
<b>Distance function when comparing clusters</b><br />
<br />
If you chose to continue with simplest case where cluster centers are simply color values, the compare function is also simple. Just calculate how far, or what is the distance, between the pixel you are working with and the cluster center color is.<br />
<br />
When working with gray level images the distance calculation is easy, but for color images you need to split the RGB values to individual red, green and blue values. Then calculate the difference between each pixel color and cluster color and finally average the result.<br />
<b><br /></b>
<b>My implementation</b><br />
<br />
I have implemented two different approaches for adding pixels to the
clusters. I have named them "continuous" and "iterative" clustering.<br />
<br />
In
"continuous clustering" I am adding and removing pixels to and from
clusters for each pixel if necessary, and I am also counting the cluster
center again after each added or removed pixel. The algorithm finds
solution faster than the iterative clustering.<br />
<br />
In "iterative clustering" I am adding all the pixels to clusters first, and after that I am calculating the new cluster centers.<br />
<br />
There
are small differences between the results of these two methods. I
_guess_ the differences are coming from integer rounding.<br />
<b><br /></b>
<b>Sample images</b><br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVzv9p3EyRhHh68Bb86HwgZgyFVQzy7isf8Izkm14-qj0QROGeYQeW5osdV7upZ1_8BJf_LqPuIN2gPAHjarxpXdEu8X7mgrgpZSyMtuXrsTV3hneIxiqbkze3nscW9jE4hDhPyQGm-2Xd/s1600/kmeans.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVzv9p3EyRhHh68Bb86HwgZgyFVQzy7isf8Izkm14-qj0QROGeYQeW5osdV7upZ1_8BJf_LqPuIN2gPAHjarxpXdEu8X7mgrgpZSyMtuXrsTV3hneIxiqbkze3nscW9jE4hDhPyQGm-2Xd/s320/kmeans.png" height="240" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The original test image</td><td class="tr-caption" style="text-align: center;"><br /></td><td class="tr-caption" style="text-align: center;"><br /></td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9NI92GoMgm9xsYgBqZWdctF279IwZdnXks1iZF4eJg-nFtDhtYmIvNTKxIEgRlPcyWXlARl0Cnul6IF5lZxHv2m4fUd7zGKMnmJFYc77zf5I_LkRAewjRJRska3ApLI6UsBw_XzjEiWbT/s1600/kmeans.c.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9NI92GoMgm9xsYgBqZWdctF279IwZdnXks1iZF4eJg-nFtDhtYmIvNTKxIEgRlPcyWXlARl0Cnul6IF5lZxHv2m4fUd7zGKMnmJFYc77zf5I_LkRAewjRJRska3ApLI6UsBw_XzjEiWbT/s320/kmeans.c.png" height="240" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Result of continuous clustering (took 6 loops, 816 milliseconds)</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTyF0vDG2mDwkJzYuWHQ7teQpqIz3q5udYu4dr6eI4eqqXuZ8b-sGJRk1cqR_QOCcN1ATp-hS2-8DaKOopcoqbXBSwSEgSUmg735xAS0Fj8-zfbYoULk4Y9DVtYqX3sF5P8zgijc2lqtI_/s1600/kmeans.i.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTyF0vDG2mDwkJzYuWHQ7teQpqIz3q5udYu4dr6eI4eqqXuZ8b-sGJRk1cqR_QOCcN1ATp-hS2-8DaKOopcoqbXBSwSEgSUmg735xAS0Fj8-zfbYoULk4Y9DVtYqX3sF5P8zgijc2lqtI_/s320/kmeans.i.png" height="240" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Result of iterative clustering (took 62 loops, 9158 milliseconds)</td></tr>
</tbody></table>
<b><br /></b>
<b>Java implementation</b><br />
<br />
<style>tr { color: #888888; }h3 { font-family: Verdana,Arial,Serif; border-width: 3px; color: #000000; font-size: 8pt; }p { font-family: Verdana,Arial,Serif; color: #000000; font-size: 8pt; }tr { font-family: Courier,Georgia,Serif; font-size: 8pt; }span.comment { font-weight:bold; color: #008800; font-size: 8pt;}span.cc { font-weight:bold; color: #5555ee; font-size: 8pt; }span.b { font-weight:bold; color: #000000; font-size: 8pt; }span.o { color: #008800; font-size: 8pt; }span.kw { color: #0000aa; font-weight: bold; font-size: 8pt; }div#destination { border-style:solid; border-width:2px; border-color: #555555; background-color: #fefefe; }</style>
<br />
<table cellpadding="0" cellspacing="0"><tbody>
<tr bgcolor="#f0f0f0"><td><span class="kw">package</span> popscan; </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td><span class="kw">import</span> java.awt.image.<span class="cc">BufferedImage</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="kw">import</span> java.io.<span class="cc">File</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="kw">import</span> java.util.<span class="cc">Arrays</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="kw">import</span> javax.imageio.<span class="cc">ImageIO</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td><span class="kw">public</span><span class="kw"> class </span>KMeans <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">BufferedImage</span> original; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">BufferedImage</span> result; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">Cluster</span><span class="b">[</span><span class="b">]</span> clusters; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">public</span> <span class="kw">static</span> <span class="kw">final</span> <span class="kw">int</span> <span class="cc">MODE_CONTINUOUS</span> = 1; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">public</span> <span class="kw">static</span> <span class="kw">final</span> <span class="kw">int</span> <span class="cc">MODE_ITERATIVE</span> = 2; </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">public</span> <span class="kw">static</span> <span class="kw">void</span> main<span class="b">(</span><span class="cc">String</span><span class="b">[</span><span class="b">]</span> args<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>args.length!=4<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">System</span>.out.println<span class="b">(</span>"<span class="cc">Usage</span>: java popscan.KMeans" </td></tr>
<tr bgcolor="#ffffff"><td> + " <span class="b">[</span>source image filename<span class="b">]</span>" </td></tr>
<tr bgcolor="#f0f0f0"><td> + " <span class="b">[</span>destination image filename<span class="b">]</span>" </td></tr>
<tr bgcolor="#ffffff"><td> + " <span class="b">[</span>clustercount 0-255<span class="b">]</span>" </td></tr>
<tr bgcolor="#f0f0f0"><td> + " <span class="b">[</span>mode -i <span class="b">(</span><span class="cc">ITERATIVE</span><span class="b">)</span>|-c <span class="b">(</span><span class="cc">CONTINUOS</span><span class="b">)</span><span class="b">]</span>"<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">return</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // parse arguments</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">String</span> src = args<span class="b">[</span>0<span class="b">]</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">String</span> dst = args<span class="b">[</span>1<span class="b">]</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> k = <span class="cc">Integer</span>.parseInt<span class="b">(</span>args<span class="b">[</span>2<span class="b">]</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">String</span> m = args<span class="b">[</span>3<span class="b">]</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> mode = 1; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>m.equals<span class="b">(</span>"-i"<span class="b">)</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> mode = <span class="cc">MODE_ITERATIVE</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> <span class="kw">else</span> <span class="kw">if</span> <span class="b">(</span>m.equals<span class="b">(</span>"-c"<span class="b">)</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> mode = <span class="cc">MODE_CONTINUOUS</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // create new KMeans object</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> KMeans kmeans = <span class="kw">new</span> KMeans<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // call the function to actually start the clustering</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">BufferedImage</span> dstImage = kmeans.calculate<span class="b">(</span>loadImage<span class="b">(</span>src<span class="b">)</span>, </td></tr>
<tr bgcolor="#ffffff"><td> k,mode<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // save the resulting image</span> </td></tr>
<tr bgcolor="#ffffff"><td> saveImage<span class="b">(</span>dst, dstImage<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">public</span> KMeans<span class="b">(</span><span class="b">)</span> <span class="b">{</span> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">public</span> <span class="cc">BufferedImage</span> calculate<span class="b">(</span><span class="cc">BufferedImage</span> image, </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> k, <span class="kw">int</span> mode<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">long</span> start = <span class="cc">System</span>.currentTimeMillis<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> w = image.getWidth<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> h = image.getHeight<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // create clusters</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> clusters = createClusters<span class="b">(</span>image,k<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // create cluster lookup table</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span><span class="b">[</span><span class="b">]</span> lut = <span class="kw">new</span> <span class="kw">int</span><span class="b">[</span>w*h<span class="b">]</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">Arrays</span>.fill<span class="b">(</span>lut, -1<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // at first loop all pixels will move their clusters</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">boolean</span> pixelChangedCluster = true; </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // loop until all clusters are stable!</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> loops = 0; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">while</span> <span class="b">(</span>pixelChangedCluster<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> pixelChangedCluster = false; </td></tr>
<tr bgcolor="#f0f0f0"><td> loops++; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> y=0;y<h;y++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> x=0;x<w;x++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> pixel = image.getRGB<span class="b">(</span>x, y<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">Cluster</span> cluster = findMinimalCluster<span class="b">(</span>pixel<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>lut<span class="b">[</span>w*y+x<span class="b">]</span>!=cluster.getId<span class="b">(</span><span class="b">)</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // cluster changed</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>mode==<span class="cc">MODE_CONTINUOUS</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">if</span> <span class="b">(</span>lut<span class="b">[</span>w*y+x<span class="b">]</span>!=-1<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // remove from possible previous </span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // cluster</span> </td></tr>
<tr bgcolor="#ffffff"><td> clusters<span class="b">[</span>lut<span class="b">[</span>w*y+x<span class="b">]</span><span class="b">]</span>.removePixel<span class="b">(</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> pixel<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // add pixel to cluster</span> </td></tr>
<tr bgcolor="#ffffff"><td> cluster.addPixel<span class="b">(</span>pixel<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // continue looping </span> </td></tr>
<tr bgcolor="#f0f0f0"><td> pixelChangedCluster = true; </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // update lut</span> </td></tr>
<tr bgcolor="#ffffff"><td> lut<span class="b">[</span>w*y+x<span class="b">]</span> = cluster.getId<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>mode==<span class="cc">MODE_ITERATIVE</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // update clusters</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> i=0;i<clusters.length;i++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> clusters<span class="b">[</span>i<span class="b">]</span>.clear<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> y=0;y<h;y++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> x=0;x<w;x++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> clusterId = lut<span class="b">[</span>w*y+x<span class="b">]</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // add pixels to cluster</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> clusters<span class="b">[</span>clusterId<span class="b">]</span>.addPixel<span class="b">(</span> </td></tr>
<tr bgcolor="#ffffff"><td> image.getRGB<span class="b">(</span>x, y<span class="b">)</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // create result image</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">BufferedImage</span> result = <span class="kw">new</span> <span class="cc">BufferedImage</span><span class="b">(</span>w, h, </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">BufferedImage</span>.<span class="cc">TYPE_INT_RGB</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> y=0;y<h;y++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> x=0;x<w;x++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> clusterId = lut<span class="b">[</span>w*y+x<span class="b">]</span>; </td></tr>
<tr bgcolor="#ffffff"><td> result.setRGB<span class="b">(</span>x, y, clusters<span class="b">[</span>clusterId<span class="b">]</span>.getRGB<span class="b">(</span><span class="b">)</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">long</span> end = <span class="cc">System</span>.currentTimeMillis<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">System</span>.out.println<span class="b">(</span>"<span class="cc">Clustered</span> to "+k </td></tr>
<tr bgcolor="#f0f0f0"><td> + " clusters in "+loops </td></tr>
<tr bgcolor="#ffffff"><td> +" loops in "+<span class="b">(</span>end-start<span class="b">)</span>+" ms."<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">return</span> result; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">public</span> <span class="cc">Cluster</span><span class="b">[</span><span class="b">]</span> createClusters<span class="b">(</span><span class="cc">BufferedImage</span> image, <span class="kw">int</span> k<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // Here the clusters are taken with specific steps,</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // so the result looks always same with same image.</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // You can randomize the cluster centers, if you like.</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">Cluster</span><span class="b">[</span><span class="b">]</span> result = <span class="kw">new</span> <span class="cc">Cluster</span><span class="b">[</span>k<span class="b">]</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> x = 0; <span class="kw">int</span> y = 0; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> dx = image.getWidth<span class="b">(</span><span class="b">)</span>/k; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> dy = image.getHeight<span class="b">(</span><span class="b">)</span>/k; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> i=0;i<k;i++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> result<span class="b">[</span>i<span class="b">]</span> = <span class="kw">new</span> <span class="cc">Cluster</span><span class="b">(</span>i,image.getRGB<span class="b">(</span>x, y<span class="b">)</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> x+=dx; y+=dy; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">return</span> result; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">public</span> <span class="cc">Cluster</span> findMinimalCluster<span class="b">(</span><span class="kw">int</span> rgb<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">Cluster</span> cluster = null; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> min = <span class="cc">Integer</span>.<span class="cc">MAX_VALUE</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> i=0;i<clusters.length;i++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> distance = clusters<span class="b">[</span>i<span class="b">]</span>.distance<span class="b">(</span>rgb<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>distance<min<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> min = distance; </td></tr>
<tr bgcolor="#ffffff"><td> cluster = clusters<span class="b">[</span>i<span class="b">]</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">return</span> cluster; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">public</span> <span class="kw">static</span> <span class="kw">void</span> saveImage<span class="b">(</span><span class="cc">String</span> filename, </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">BufferedImage</span> image<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">File</span> file = <span class="kw">new</span> <span class="cc">File</span><span class="b">(</span>filename<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">try</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">ImageIO</span>.write<span class="b">(</span>image, "png", file<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> <span class="kw">catch</span> <span class="b">(</span><span class="cc">Exception</span> e<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">System</span>.out.println<span class="b">(</span>e.toString<span class="b">(</span><span class="b">)</span>+" <span class="cc">Image</span> '"+filename </td></tr>
<tr bgcolor="#f0f0f0"><td> +"' saving failed."<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">public</span> <span class="kw">static</span> <span class="cc">BufferedImage</span> loadImage<span class="b">(</span><span class="cc">String</span> filename<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">BufferedImage</span> result = null; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">try</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> result = <span class="cc">ImageIO</span>.read<span class="b">(</span><span class="kw">new</span> <span class="cc">File</span><span class="b">(</span>filename<span class="b">)</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> <span class="kw">catch</span> <span class="b">(</span><span class="cc">Exception</span> e<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">System</span>.out.println<span class="b">(</span>e.toString<span class="b">(</span><span class="b">)</span>+" <span class="cc">Image</span> '" </td></tr>
<tr bgcolor="#f0f0f0"><td> +filename+"' not found."<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">return</span> result; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td> class <span class="cc">Cluster</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> id; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> pixelCount; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> red; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> green; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> blue; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> reds; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> greens; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> blues; </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">public</span> <span class="cc">Cluster</span><span class="b">(</span><span class="kw">int</span> id, <span class="kw">int</span> rgb<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> r = rgb>>16&0x000000FF; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> g = rgb>> 8&0x000000FF; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> b = rgb>> 0&0x000000FF; </td></tr>
<tr bgcolor="#ffffff"><td> red = r; </td></tr>
<tr bgcolor="#f0f0f0"><td> green = g; </td></tr>
<tr bgcolor="#ffffff"><td> blue = b; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">this</span>.id = id; </td></tr>
<tr bgcolor="#ffffff"><td> addPixel<span class="b">(</span>rgb<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">public</span> <span class="kw">void</span> clear<span class="b">(</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> red = 0; </td></tr>
<tr bgcolor="#f0f0f0"><td> green = 0; </td></tr>
<tr bgcolor="#ffffff"><td> blue = 0; </td></tr>
<tr bgcolor="#f0f0f0"><td> reds = 0; </td></tr>
<tr bgcolor="#ffffff"><td> greens = 0; </td></tr>
<tr bgcolor="#f0f0f0"><td> blues = 0; </td></tr>
<tr bgcolor="#ffffff"><td> pixelCount = 0; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> getId<span class="b">(</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">return</span> id; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> getRGB<span class="b">(</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> r = reds / pixelCount; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> g = greens / pixelCount; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> b = blues / pixelCount; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">return</span> 0xff000000|r<<16|g<<8|b; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">void</span> addPixel<span class="b">(</span><span class="kw">int</span> color<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> r = color>>16&0x000000FF; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> g = color>> 8&0x000000FF; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> b = color>> 0&0x000000FF; </td></tr>
<tr bgcolor="#ffffff"><td> reds+=r; </td></tr>
<tr bgcolor="#f0f0f0"><td> greens+=g; </td></tr>
<tr bgcolor="#ffffff"><td> blues+=b; </td></tr>
<tr bgcolor="#f0f0f0"><td> pixelCount++; </td></tr>
<tr bgcolor="#ffffff"><td> red = reds/pixelCount; </td></tr>
<tr bgcolor="#f0f0f0"><td> green = greens/pixelCount; </td></tr>
<tr bgcolor="#ffffff"><td> blue = blues/pixelCount; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">void</span> removePixel<span class="b">(</span><span class="kw">int</span> color<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> r = color>>16&0x000000FF; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> g = color>> 8&0x000000FF; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> b = color>> 0&0x000000FF; </td></tr>
<tr bgcolor="#f0f0f0"><td> reds-=r; </td></tr>
<tr bgcolor="#ffffff"><td> greens-=g; </td></tr>
<tr bgcolor="#f0f0f0"><td> blues-=b; </td></tr>
<tr bgcolor="#ffffff"><td> pixelCount--; </td></tr>
<tr bgcolor="#f0f0f0"><td> red = reds/pixelCount; </td></tr>
<tr bgcolor="#ffffff"><td> green = greens/pixelCount; </td></tr>
<tr bgcolor="#f0f0f0"><td> blue = blues/pixelCount; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> distance<span class="b">(</span><span class="kw">int</span> color<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> r = color>>16&0x000000FF; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> g = color>> 8&0x000000FF; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> b = color>> 0&0x000000FF; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> rx = <span class="cc">Math</span>.abs<span class="b">(</span>red-r<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> gx = <span class="cc">Math</span>.abs<span class="b">(</span>green-g<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> bx = <span class="cc">Math</span>.abs<span class="b">(</span>blue-b<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> d = <span class="b">(</span>rx+gx+bx<span class="b">)</span> / 3; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">return</span> d; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
</tbody></table>
<br />
<br />
<table><tbody>
<tr><td bgcolor="#222222"><span style="font-size: small;"><span style="font-family: Arial,Helvetica,sans-serif;">Check out my blogpost about watershed segmentation: <span style="color: #333333;"><a href="http://popscan.blogspot.fi/2014/04/watershed-image-segmentation-algorithm.html" target="_blank">http://popscan.blogspot.fi/2014/04/watershed-image-segmentation-algorithm.html</a></span></span></span></td></tr>
</tbody></table>
<iframe frameborder="0" height="200px" scrolling="no" src="http://www.eemeli.de" width="100%"></iframe>
Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com20tag:blogger.com,1999:blog-1495123355536406202.post-85840687046386023352013-06-08T19:31:00.002+03:002014-04-25T16:04:49.220+03:00Color image segmentation by thresholding with JavaYou may need the image segmentation tool for various image analysis tasks. Different tasks may also need specialized segmentation algorithm, for example the segmentation process may discard all green pixels and keep yellow and red, or if you know the object you are trying to detect contains only blue. <br />
<br />
It may be difficult to adjust one general segmentation algorithm for special cases, so you may need to tweak the segmentation code itself, not just the parameters.<br />
<br />
I will present here one variation from the simplest segmentation algorithm, segmentation by thresholding, implemented in pure Java.<br />
<br />
More sophisticated methods exist, and you should use them if your problem requires so. <br />
<br />
In my opinion, this thresholding function gives you a nice starting point when starting to make experiments with segmentation. From the command line, you can only adjust the threshold level, int value 0 - 255, but from the source you can change the connectivity testing and balance the color thresholding if needed.<br />
<br />
<b>Example images:</b> <br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzraNIxS5tpMQuUXb210JUNCJbHXqxSbSBLNQgCQzp8Ud6lLOdOMUIW6G6s_czpz47JAtR8U8-ivbpiiPpuTkw2INtdBYyU1yhvt_nDfhgjHyViIpZfMIRH15Y92OG9_FHKLT_EfdCvO13/s1600/popscan_blogspot_com_colors_01.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzraNIxS5tpMQuUXb210JUNCJbHXqxSbSBLNQgCQzp8Ud6lLOdOMUIW6G6s_czpz47JAtR8U8-ivbpiiPpuTkw2INtdBYyU1yhvt_nDfhgjHyViIpZfMIRH15Y92OG9_FHKLT_EfdCvO13/s200/popscan_blogspot_com_colors_01.png" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The original photo<u><br /></u></td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjj1v7ffmqKLTrsvjarckQOvMJ2nwjlqelhqGAdaTavyofukZznMMNixZzfNt7K6RIXP3GeMw5GNq3qySli4GCYT213DVqjHkD40ippjSM7AXJecumFqByfROpdamns8iYVKHOSS_L5CSP0/s1600/popscan_blogspot_com_colors.20.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjj1v7ffmqKLTrsvjarckQOvMJ2nwjlqelhqGAdaTavyofukZznMMNixZzfNt7K6RIXP3GeMw5GNq3qySli4GCYT213DVqjHkD40ippjSM7AXJecumFqByfROpdamns8iYVKHOSS_L5CSP0/s200/popscan_blogspot_com_colors.20.png" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Segmented with threshold value 20</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJ02sGys_B83A1WQeCxGg-LuqphES1x7Jb4Qhr7ePxboki0240ajh3tRhgSY_PjMO48yOQkMbMuPU3p6sUFdzitHwOBX1QQgMC7wZwZDLz9LwFhf7DW2MWJ-Q6jMXZu-yGIMkoe1p1dYVt/s1600/popscan_blogspot_com_colors.40.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJ02sGys_B83A1WQeCxGg-LuqphES1x7Jb4Qhr7ePxboki0240ajh3tRhgSY_PjMO48yOQkMbMuPU3p6sUFdzitHwOBX1QQgMC7wZwZDLz9LwFhf7DW2MWJ-Q6jMXZu-yGIMkoe1p1dYVt/s200/popscan_blogspot_com_colors.40.png" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Segmented with threshold value 40</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUOkdZn_VCRpqM7wrmsjIOklVvkeZbUg3wB0b6uf1ij9kpISclbjn52gjERKBWTp1EBQqoEUf2e19oh9dWxK6HgxH_IZMZ99T4Um-p4GFYavEiD3SIso83ZllRCN4mQYaWHyYrC39ef5Iv/s1600/popscan_blogspot_com_colors.60.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUOkdZn_VCRpqM7wrmsjIOklVvkeZbUg3wB0b6uf1ij9kpISclbjn52gjERKBWTp1EBQqoEUf2e19oh9dWxK6HgxH_IZMZ99T4Um-p4GFYavEiD3SIso83ZllRCN4mQYaWHyYrC39ef5Iv/s200/popscan_blogspot_com_colors.60.png" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Segmented with threshold value 60</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9aRfaXLfMAdIoQPPf64vuNX-ISxorxLf-OMB_gFOIX8c4H-7iVaKN8n32h3dBs5K8-mhoDROBP3abHjog1ETMOZ_WoD5YSd_igkkJxZuJ0LHGkpCHt4RomL_hQrg0Haf0C-8ACSJtzblR/s1600/popscan_blogspot_com_colors.80.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9aRfaXLfMAdIoQPPf64vuNX-ISxorxLf-OMB_gFOIX8c4H-7iVaKN8n32h3dBs5K8-mhoDROBP3abHjog1ETMOZ_WoD5YSd_igkkJxZuJ0LHGkpCHt4RomL_hQrg0Haf0C-8ACSJtzblR/s200/popscan_blogspot_com_colors.80.png" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Segmented with threshold value 80</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnb9evFH4QoYoGBpiiXwV8_QfOQo2M0zH7ZIN2Tu1MJ575NK9YgWGcQhKl-0D1usqar8J9oawrON9iTXKrENprh32GslGTnQFVc_9stdbqq61E8bvEYwozst8GMzZXlj6Og3BWtvuO73Rf/s1600/popscan_blogspot_com_colors.100.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnb9evFH4QoYoGBpiiXwV8_QfOQo2M0zH7ZIN2Tu1MJ575NK9YgWGcQhKl-0D1usqar8J9oawrON9iTXKrENprh32GslGTnQFVc_9stdbqq61E8bvEYwozst8GMzZXlj6Og3BWtvuO73Rf/s200/popscan_blogspot_com_colors.100.png" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Segmented with threshold value 100</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPekZ6u9pa10ILc0J9lg1EoMRLXUJtCu6GtpF9PN6K01LgoWFYwqdrGBAW1JVKg8HY_7VjRdnsChEYVgiTObWg1WJFGGD1hE78bheAjjGNUPnqwPxzm_lkYLPJEcl7d8LIa7XoRynskfwo/s1600/popscan_blogspot_com_colors.120.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPekZ6u9pa10ILc0J9lg1EoMRLXUJtCu6GtpF9PN6K01LgoWFYwqdrGBAW1JVKg8HY_7VjRdnsChEYVgiTObWg1WJFGGD1hE78bheAjjGNUPnqwPxzm_lkYLPJEcl7d8LIa7XoRynskfwo/s200/popscan_blogspot_com_colors.120.png" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Segmented with threshold value 120</td></tr>
</tbody></table>
<br />
<br />
Feel free to copy the code and adapt it to your own source and frameworks.<br />
<br />
<b>Improvements:</b><br />
I will make an version from the algorithm where the segment color is averaged from the pixels in the segment. In this version, the color is the color which is the "seed" pixel color. <br />
<br />
<b>The algorithm in pseudo code:</b><br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;">for each pixel in image<br /> if pixel is not in segment<br /> create new segment<br /> add the pixel as new "seed" point to list of candidates<br /> while segment has candidate points<br /> remove first point from the list of candidates<br /> if the first candidate point is within threshold limit </span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"> add the first candidate point to the segment<br /> add neighbor pixel above to the candidate list<br /> add neighbor pixel below to the candidate list<br /> add neighbor pixel right to the candidate list<br /> add neighbor pixel left to the candidate list</span></span><br />
<br />
This kind of algorithm must use the candidate list and while loop instead of recursion, because in the worst case, the whole image (its pixels) belong to one segment. In that case, when using recursion, you will most likely see "<span style="font-family: "Courier New",Courier,monospace;">StackOverflowError</span>" with big images.<br />
<b><br /></b>
<b>The Java implementation:</b><br />
<br />
<style>tr { color: #888888; }h3 { font-family: Verdana,Arial,Serif; border-width: 3px; color: #000000; font-size: 8pt; }p { font-family: Verdana,Arial,Serif; color: #000000; font-size: 8pt; }tr { font-family: Courier,Georgia,Serif; font-size: 8pt; }span.comment { font-weight:bold; color: #008800; font-size: 8pt;}span.cc { font-weight:bold; color: #5555ee; font-size: 8pt; }span.b { font-weight:bold; color: #000000; font-size: 8pt; }span.o { color: #008800; font-size: 8pt; }span.kw { color: #0000aa; font-weight: bold; font-size: 8pt; }div#destination { border-style:solid; border-width:2px; border-color: #555555; background-color: #fefefe; }</style>
<br />
<table cellpadding="0" cellspacing="0"><tbody>
<tr bgcolor="#f0f0f0"><td><span class="kw">package</span> popscan; </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td><span class="kw">import</span> java.awt.image.<span class="cc">BufferedImage</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="kw">import</span> java.io.<span class="cc">File</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="kw">import</span> java.util.<span class="cc">Arrays</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="kw">import</span> java.util.<span class="cc">Vector</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td><span class="kw">import</span> javax.imageio.<span class="cc">ImageIO</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td><span class="kw">public</span><span class="kw"> class </span><span class="cc">Segmentize</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // value for visited pixel</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> <span class="cc">VISITED</span> = 0x00FF0000; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // value for not visited pixel</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> <span class="cc">NOT_VISITED</span> = 0x00000000; </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // source image filename</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">String</span> _srcFilename; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // destination image filename</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">String</span> _dstFilename; </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // the source image</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">BufferedImage</span> _srcImage; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // the destination image</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">BufferedImage</span> _dstImage; </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // threshold value 0 - 255</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> _threshold; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // image width</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> _width; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // image height</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> _height; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // "seed" color / segment color</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> _color; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // red value from seed</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> _red; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // green value from seed</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> _green; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // blue value from seed</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> _blue; </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // pixels from source image</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span><span class="b">[</span><span class="b">]</span> _pixels; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // table for keeping track or visits</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span><span class="b">[</span><span class="b">]</span> _visited; </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // keeping for candidate points</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">Vector</span><SPoint> _points; </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td> class SPoint <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> x; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> y; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">public</span> SPoint<span class="b">(</span><span class="kw">int</span> x, <span class="kw">int</span> y<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">this</span>.x = x; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">this</span>.y = y; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">public</span> <span class="kw">static</span> <span class="kw">void</span> main<span class="b">(</span><span class="cc">String</span><span class="b">[</span><span class="b">]</span> args<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>args.length!=3<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">System</span>.out.println<span class="b">(</span>"<span class="cc">Usage</span>: java <span class="cc">Segmentize</span>" </td></tr>
<tr bgcolor="#ffffff"><td> + " <span class="b">[</span>source image filename<span class="b">]</span>" </td></tr>
<tr bgcolor="#f0f0f0"><td> + " <span class="b">[</span>destination image filename<span class="b">]</span>" </td></tr>
<tr bgcolor="#ffffff"><td> + " <span class="b">[</span>threshold 0-255<span class="b">]</span>"<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">return</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // parse arguments</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">String</span> src = args<span class="b">[</span>0<span class="b">]</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">String</span> dst = args<span class="b">[</span>1<span class="b">]</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> threshold = <span class="cc">Integer</span>.parseInt<span class="b">(</span>args<span class="b">[</span>2<span class="b">]</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // create new Segmentize object</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">Segmentize</span> s = <span class="kw">new</span> <span class="cc">Segmentize</span><span class="b">(</span>loadImage<span class="b">(</span>src<span class="b">)</span>,threshold<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // call the function to actually start the segmentation</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">BufferedImage</span> dstImage = s.segmentize<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // save the resulting image</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> saveImage<span class="b">(</span>dst, dstImage<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">public</span> <span class="cc">Segmentize</span><span class="b">(</span><span class="cc">BufferedImage</span> _srcImage, <span class="kw">int</span> threshold<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> _threshold = threshold; </td></tr>
<tr bgcolor="#ffffff"><td> _width = _srcImage.getWidth<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> _height = _srcImage.getHeight<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // extract pixels from source image</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> _pixels = _srcImage.getRGB<span class="b">(</span>0, 0, _width, _height, </td></tr>
<tr bgcolor="#ffffff"><td> null, 0, _width<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // create empty destination image</span> </td></tr>
<tr bgcolor="#ffffff"><td> _dstImage = <span class="kw">new</span> <span class="cc">BufferedImage</span><span class="b">(</span>_width, </td></tr>
<tr bgcolor="#f0f0f0"><td> _height, </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">BufferedImage</span>.<span class="cc">TYPE_INT_RGB</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> _visited = <span class="kw">new</span> <span class="kw">int</span><span class="b">[</span>_pixels.length<span class="b">]</span>; </td></tr>
<tr bgcolor="#ffffff"><td> _points = <span class="kw">new</span> <span class="cc">Vector</span><SPoint><span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">private</span> <span class="cc">BufferedImage</span> segmentize<span class="b">(</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // initialize points</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> _points.clear<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // clear table with NOT_VISITED value</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">Arrays</span>.fill<span class="b">(</span>_visited, <span class="cc">NOT_VISITED</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // loop through all pixels</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> x=0;x<_width;x++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">for</span> <span class="b">(</span><span class="kw">int</span> y=0;y<_height;y++<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // if not visited, start new segment</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>_visited<span class="b">[</span>_width*y+x<span class="b">]</span>==<span class="cc">NOT_VISITED</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // extract segment color info from pixel</span> </td></tr>
<tr bgcolor="#ffffff"><td> _color = _pixels<span class="b">[</span>_width*y+x<span class="b">]</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> _red = _color>>16&0xff; </td></tr>
<tr bgcolor="#ffffff"><td> _green = _color>>8&0xff; </td></tr>
<tr bgcolor="#f0f0f0"><td> _blue = _color&0xff; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // add "seed"</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> _points.add<span class="b">(</span><span class="kw">new</span> SPoint<span class="b">(</span>x, y<span class="b">)</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // start finding neighboring pixels</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> flood<span class="b">(</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // save the result image</span> </td></tr>
<tr bgcolor="#ffffff"><td> _dstImage.setRGB<span class="b">(</span>0, 0, _width, _height, _pixels, 0, _width<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">return</span> _dstImage; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">public</span> <span class="kw">void</span> flood<span class="b">(</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // while there are candidates in points vector</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">while</span> <span class="b">(</span>_points.size<span class="b">(</span><span class="b">)</span>>0<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // remove the first candidate</span> </td></tr>
<tr bgcolor="#ffffff"><td> SPoint current = _points.remove<span class="b">(</span>0<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> x = current.x; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> y = current.y; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">if</span> <span class="b">(</span><span class="b">(</span>x>=0<span class="b">)</span>&&<span class="b">(</span>x<_width<span class="b">)</span>&&<span class="b">(</span>y>=0<span class="b">)</span>&&<span class="b">(</span>y<_height<span class="b">)</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // check if the candidate is NOT_VISITED yet</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">if</span> <span class="b">(</span>_visited<span class="b">[</span>_width*y+x<span class="b">]</span>==<span class="cc">NOT_VISITED</span><span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // extract color info from candidate pixel</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> _c = _pixels<span class="b">[</span>_width*y+x<span class="b">]</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> red = _c>>16&0xff; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> green = _c>>8&0xff; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> blue = _c>>0&0xff; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // calculate difference between </span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // seed's and candidate's</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // red, green and blue values</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> rx = <span class="cc">Math</span>.abs<span class="b">(</span>red - _red<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">int</span> gx = <span class="cc">Math</span>.abs<span class="b">(</span>green - _green<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">int</span> bx = <span class="cc">Math</span>.abs<span class="b">(</span>blue - _blue<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // if all colors are under threshold</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">if</span> <span class="b">(</span>rx<=_threshold </td></tr>
<tr bgcolor="#f0f0f0"><td> &&gx<=_threshold </td></tr>
<tr bgcolor="#ffffff"><td> &&bx<=_threshold<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // add the candidate to the segment <span class="b">(</span>image<span class="b">)</span></span> </td></tr>
<tr bgcolor="#ffffff"><td> _pixels<span class="b">[</span>_width*y+x<span class="b">]</span> = _color; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // mark the candidate as visited</span> </td></tr>
<tr bgcolor="#ffffff"><td> _visited<span class="b">[</span>_width*y+x<span class="b">]</span> = <span class="cc">VISITED</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="comment"> // add neighboring pixels as candidate</span> </td></tr>
<tr bgcolor="#ffffff"><td><span class="comment"> // <span class="b">(</span>8-connected here<span class="b">)</span></span> </td></tr>
<tr bgcolor="#f0f0f0"><td> _points.add<span class="b">(</span><span class="kw">new</span> SPoint<span class="b">(</span>x-1,y-1<span class="b">)</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> _points.add<span class="b">(</span><span class="kw">new</span> SPoint<span class="b">(</span>x ,y-1<span class="b">)</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> _points.add<span class="b">(</span><span class="kw">new</span> SPoint<span class="b">(</span>x+1,y-1<span class="b">)</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> _points.add<span class="b">(</span><span class="kw">new</span> SPoint<span class="b">(</span>x-1,y<span class="b">)</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> _points.add<span class="b">(</span><span class="kw">new</span> SPoint<span class="b">(</span>x+1,y<span class="b">)</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> _points.add<span class="b">(</span><span class="kw">new</span> SPoint<span class="b">(</span>x-1,y+1<span class="b">)</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> _points.add<span class="b">(</span><span class="kw">new</span> SPoint<span class="b">(</span>x ,y+1<span class="b">)</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> _points.add<span class="b">(</span><span class="kw">new</span> SPoint<span class="b">(</span>x+1,y+1<span class="b">)</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="kw">public</span> <span class="kw">static</span> <span class="kw">void</span> saveImage<span class="b">(</span><span class="cc">String</span> filename, </td></tr>
<tr bgcolor="#ffffff"><td> <span class="cc">BufferedImage</span> image<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">File</span> file = <span class="kw">new</span> <span class="cc">File</span><span class="b">(</span>filename<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">try</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">ImageIO</span>.write<span class="b">(</span>image, "png", file<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> <span class="kw">catch</span> <span class="b">(</span><span class="cc">Exception</span> e<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">System</span>.out.println<span class="b">(</span>e.toString<span class="b">(</span><span class="b">)</span>+" <span class="cc">Image</span> '"+filename </td></tr>
<tr bgcolor="#ffffff"><td> +"' saving failed."<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">public</span> <span class="kw">static</span> <span class="cc">BufferedImage</span> loadImage<span class="b">(</span><span class="cc">String</span> filename<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">BufferedImage</span> result = null; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">try</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> result = <span class="cc">ImageIO</span>.read<span class="b">(</span><span class="kw">new</span> <span class="cc">File</span><span class="b">(</span>filename<span class="b">)</span><span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td> <span class="b">}</span> <span class="kw">catch</span> <span class="b">(</span><span class="cc">Exception</span> e<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="cc">System</span>.out.println<span class="b">(</span>e.toString<span class="b">(</span><span class="b">)</span>+" <span class="cc">Image</span> '" </td></tr>
<tr bgcolor="#ffffff"><td> +filename+"' not found."<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> <span class="kw">return</span> result; </td></tr>
<tr bgcolor="#f0f0f0"><td> <span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td> </td></tr>
<tr bgcolor="#f0f0f0"><td><span class="b">}</span> </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
</tbody></table>
<br>
<iframe frameborder="0" height="200px" scrolling="no" src="http://www.eemeli.de" width="100%"></iframe>
Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com1tag:blogger.com,1999:blog-1495123355536406202.post-13257174067938461602013-05-24T18:07:00.002+03:002013-05-24T18:10:25.587+03:00Searching Live Events from YouTubeI was slightly surprised and also somewhat annoyed when I found out that there is no way to make a free text search for finding YouTube Live Events with YouTube Data API. The Live Events section of the API is still experimental, but I feel the search functionality is so essential that is almost strange that it is missing.<br />
<br />
Sure, you can filter the search results with some simple comparisons (see <a href="https://developers.google.com/youtube/2.0/developers_guide_protocol_partial" target="_blank">https://developers.google.com/youtube/2.0/developers_guide_protocol_partial</a>), but I was unable to find a wildcard for titles or description/summary searches, similar to SQL's functionality WHERE title LIKE '%bbc%'.<br />
<br />
So if you want to search live events, you have at least these<b> two </b>options:<br />
<br />
<b>1.</b> Load everything from one live event feed and make a string search over the xml result.<br />
<ul>
<li>Select the predefined feed, like "Current live events" (<a href="https://gdata.youtube.com/feeds/api/charts/live/events/live_now?v=2&max-results=50&inline=true&prettyprint=true&start-index=1" target="_blank">https://gdata.youtube.com/feeds/api/charts/live/events/live_now?v=2&max-results=50&inline=true&prettyprint=true&start-index=1</a>), load 50 results, increment start-index by 50, load again and so on until you have loaded everything. Then make a <i>strpos </i>or <i>regexp </i>find to find the Live Event entries that you are interested in.</li>
</ul>
<b>2.</b> Do not use YouTube Data API, but use the web page search instead.<br />
<ul>
<li>Load the YouTube page with your keywords and Live Event filters enabled (<a href="http://www.youtube.com/results?search_query=arirang&filters=live&lclk=live&page=1" target="_blank">http://www.youtube.com/results?search_query=arirang&filters=live&lclk=live&page=1</a>). Strip the video ids from the resulting HTML. Load detailed info for each found video id, for example (<a href="https://gdata.youtube.com/feeds/api/videos/WLqF0kEgMvw?v=2&prettyprint=true" target="_blank">https://gdata.youtube.com/feeds/api/videos/WLqF0kEgMvw?v=2&prettyprint=true</a>). The web page gives you only 20 entries, so you need to increment the page index and load the page again if you want to have more results. <b>This method relies on YouTube webpage's element attributes and therefore is not suitable for any final or commercial productions. </b>Also you have no control over the results: the result set may contain also already ended Live Events, not only currently broadcasted events...</li>
</ul>
<b>Example with PHP</b><br />
The next code snippet loads the web page url, finds the video ids, and loads the detailed information about the live event with YouTube Data API.
<br />
<style>tr { color: #888888; }h3 { font-family: Verdana,Arial,Serif; border-width: 3px; color: #000000; font-size: 8pt; }p { font-family: Verdana,Arial,Serif; color: #000000; font-size: 8pt; }tr { font-family: Courier,Georgia,Serif; font-size: 8pt; }span.comment { font-weight:bold; color: #008800; font-size: 8pt;}span.cc { font-weight:bold; color: #5555ee; font-size: 8pt; }span.b { font-weight:bold; color: #000000; font-size: 8pt; }span.o { color: #008800; font-size: 8pt; }span.kw { color: #0000aa; font-weight: bold; font-size: 8pt; }div#destination { border-style:solid; border-width:2px; border-color: #555555; background-color: #fefefe; }</style>
<br />
<table cellpadding="0" cellspacing="0"><tbody>
<tr bgcolor="#f0f0f0"><td>// get your keywords and page index from page request </td></tr>
<tr bgcolor="#ffffff"><td>// $searchwords = $_REQUEST<span class="b">[</span>"searchwords"<span class="b">]</span> </td></tr>
<tr bgcolor="#f0f0f0"><td>// $page = $_REQUEST<span class="b">[</span>"page"<span class="b">]</span> </td></tr>
<tr bgcolor="#ffffff"><td>$page = 1; </td></tr>
<tr bgcolor="#f0f0f0"><td>$searchwords = 'arirang'; </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td>// create url </td></tr>
<tr bgcolor="#ffffff"><td>$search_url = "http://www.youtube.com/results?search_query=" </td></tr>
<tr bgcolor="#f0f0f0"><td> ."$searchwords&filters=live&lclk=live&page=$page"; </td></tr>
<tr bgcolor="#ffffff"><td></td></tr>
<tr bgcolor="#f0f0f0"><td>// load web page contents </td></tr>
<tr bgcolor="#ffffff"><td>$html = file_get_contents<span class="b">(</span>$search_url<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td>// now search the content ids </td></tr>
<tr bgcolor="#f0f0f0"><td>$ids = array<span class="b">(</span><span class="b">)</span>; // to store the found ids </td></tr>
<tr bgcolor="#ffffff"><td>$idlength = 11; // length of youtube videoid </td></tr>
<tr bgcolor="#f0f0f0"><td>$attr = 'data-context-item-id="'; // video id in the html </td></tr>
<tr bgcolor="#ffffff"><td>$pos = strpos<span class="b">(</span>$html,$attr,0<span class="b">)</span>; // pos in html </td></tr>
<tr bgcolor="#f0f0f0"><td>while <span class="b">(</span>$pos!==FALSE<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> $ids<span class="b">[</span><span class="b">]</span> = substr<span class="b">(</span>$html, $pos+strlen<span class="b">(</span>$attr<span class="b">)</span>, $idlength<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> $pos=strpos<span class="b">(</span>$html,$attr,$pos+$idlength<span class="b">)</span>; </td></tr>
<tr bgcolor="#ffffff"><td><span class="b">}</span> </td></tr>
<tr bgcolor="#f0f0f0"><td></td></tr>
<tr bgcolor="#ffffff"><td>// now you can loop the ids and load live events for each id </td></tr>
<tr bgcolor="#f0f0f0"><td>foreach <span class="b">(</span>$ids as $id<span class="b">)</span> <span class="b">{</span> </td></tr>
<tr bgcolor="#ffffff"><td> $xmlurl = "http://gdata.youtube.com/feeds/api/videos/" </td></tr>
<tr bgcolor="#f0f0f0"><td> ."$id?v=2&prettyprint=true"; </td></tr>
<tr bgcolor="#ffffff"><td> $xmldata = file_get_contents<span class="b">(</span>$xmlurl<span class="b">)</span>; </td></tr>
<tr bgcolor="#f0f0f0"><td> // parse live event here etc... </td></tr>
<tr bgcolor="#ffffff"><td><span class="b">}</span> </td></tr>
</tbody></table>
Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com2tag:blogger.com,1999:blog-1495123355536406202.post-60685184083407081292013-04-26T18:29:00.002+03:002013-04-26T18:30:57.757+03:00My first Android app - Marble Lands has been released<div class="separator" style="clear: both; text-align: center;">
<a href="http://marblelands.blogspot.com/" target="_blank"><img alt="" border="0" height="171" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSZRVWk-mhvGnnGrRwBjs5e8J0w18pI3igaE4i8ETxz7r1eimhW0za2GTapSOEXXW5PHqj6EBIG7BNDq_590eGo7btMI_FAW4hJKepQD4YTeju7kfcmyoRtYeM_tVBiqtfk7XFlMl80jk/s320/teaser_image_small.png" title="Marble Lands" width="320" /></a></div>
<br />
I have been playing games since C64 era, but only recently I have joined to the group of people who are also actually making the games! Well, nowadays the iOs and Android platforms have made it "easy" for "everyone" to start programming and publishing games, so making an Android game is not that big of a deal, but I am still very happy and satisfied that I have been involved in this kind of a game programming project.<br />
<br />
You can check out the game from Google Play: <a href="https://play.google.com/store/apps/details?id=fi.vihmalo.marblelands" target="_blank">https://play.google.com/store/apps/details?id=fi.vihmalo.marblelands</a><br />
<br />
Screenshots<b> </b>and other info can be found from the game's blog: <a href="http://marblelands.blogspot.com/" target="_blank">http://marblelands.blogspot.com</a><br />
<br />
<b>Fun fact:</b> Actually my fisheye lens blog post (<a href="http://popscan.blogspot.fi/2012/04/fisheye-lens-equation-simple-fisheye.html" target="_blank">http://popscan.blogspot.fi/2012/04/fisheye-lens-equation-simple-fisheye.html</a>) was made based on game code, because we really needed that kind of an effect to the ball that is rolling in the game. So load the game and see the fish eye lens effect in action!<br />
<br />
<br />Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com0tag:blogger.com,1999:blog-1495123355536406202.post-8202123293463241222013-04-09T13:25:00.000+03:002013-04-09T15:47:28.061+03:00How enable Android Debug Bridge (ADB) in Acer Iconia B1-A71When you connect your Acer Iconia B1-A71 Android device to your laptop, in my case Windows laptop, the device chooses one connection method (Media device MTP) and installs drivers for that functionality.<br />
<br />
<b>Useful, but not necessary step: </b><br />
When still connected with USB, drag down the top status bar, and you can see the text "Connected as a media device". Click the text, and you can change the connection method from Media device to Camera (PTP) mode. Change the connection type and windows will install yet another bunch of drivers.<br />
<br />
<b>The most important step:</b><br />
Now go to the Settings > Developer Options and enable the developer options by sliding the top most button to right. <b>Now select USB Debugging to be active</b>. Windows will now download the drivers for ADB. Wait for the drivers to be installed and then test the connection.<br />
<br />
<b>Test the connection:</b><br />
Open command prompt and type: <span style="font-family: "Courier New",Courier,monospace;"> </span><br />
<span style="font-family: "Courier New",Courier,monospace;">adb devices</span><br />
<br />
You should see something like:<br />
<span style="font-family: "Courier New",Courier,monospace;">List of devices attached<br />C4F12260AFFF58F device </span><br />
<br />
Type command:<br />
<span style="font-family: "Courier New",Courier,monospace;">adb logcat</span><br />
And you will see the output from the device.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFqWZShDEgHRE_KTSyqYiuZdR5TDcVuCdmcEAf-MRVZRv1MUxBdOzv7eEhhocbz3dTnbBOvF4_Fg6vY67FVZJe3NpBPzZQgZWqtA_k6teT2bhIhvUNGUAmg8oVK-577xZCQqVBma1ASR_e/s1600/popscan_blogspot_com_acer_iconia_drivers.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="152" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFqWZShDEgHRE_KTSyqYiuZdR5TDcVuCdmcEAf-MRVZRv1MUxBdOzv7eEhhocbz3dTnbBOvF4_Fg6vY67FVZJe3NpBPzZQgZWqtA_k6teT2bhIhvUNGUAmg8oVK-577xZCQqVBma1ASR_e/s400/popscan_blogspot_com_acer_iconia_drivers.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Windows has finished installing drivers.</td></tr>
</tbody></table>
Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com0tag:blogger.com,1999:blog-1495123355536406202.post-87292509444670015762013-03-29T13:14:00.000+02:002013-04-03T16:26:10.968+03:00Angry Birds AmazonSo far we have seen Angry Birds soda cans with the Yellow Bird, Red Bird, Bad Piggie and Black Space Bird. The latest Angry Birds character to appear in a side of a soda can is the Boomerang Bird (also known as the Green Bird).<br />
<br />
The soda is named as "Amazon" and the flavor is citrus fruit.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlIRtVKT9EuBfsijk0UC4Dyu6XQi4jbImBfsKCbguOl3dAgqSG9mXcY_bura3UbNqA0McmOvffLOutF7Ta_WnIrxUl-lVVBliciTardGZ1DfBmeeFWkwQqeb9HQMLkWMeEE51V0XZHGkO7/s1600/popscan_blogspot_com_angry_birds_amazon_01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlIRtVKT9EuBfsijk0UC4Dyu6XQi4jbImBfsKCbguOl3dAgqSG9mXcY_bura3UbNqA0McmOvffLOutF7Ta_WnIrxUl-lVVBliciTardGZ1DfBmeeFWkwQqeb9HQMLkWMeEE51V0XZHGkO7/s320/popscan_blogspot_com_angry_birds_amazon_01.jpg" width="240" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTOSbIy312S9oSZU_P7XC12Hw63U-3naGfb5Z5A8uqVylLn5gRIppejR4qGf2s-NdQ96ujbA6xwK4uq4t2XvJHDwycnMuaaNv0YLoO_iaXTFb8H5NLOqJhzCh3gnYtO10AKxUwv6OnJRqt/s1600/popscan_blogspot_com_angry_birds_amazon_02.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTOSbIy312S9oSZU_P7XC12Hw63U-3naGfb5Z5A8uqVylLn5gRIppejR4qGf2s-NdQ96ujbA6xwK4uq4t2XvJHDwycnMuaaNv0YLoO_iaXTFb8H5NLOqJhzCh3gnYtO10AKxUwv6OnJRqt/s320/popscan_blogspot_com_angry_birds_amazon_02.jpg" width="240" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUU4SdAUczfyBwWKKLhgWxpaiEt7mb5FHkUfvNdtx69e2y_zoDhiSxZx4UxcxS-YS2fXy6ku9NDkVvgnh6RwA5JqpfNE6AlTsMC2lKtjVTAzfTQzp-z7Nn_2h4bjn6WzSdDHoCJ-TpHYyL/s1600/popscan_blogspot_com_angry_birds_amazon_03.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUU4SdAUczfyBwWKKLhgWxpaiEt7mb5FHkUfvNdtx69e2y_zoDhiSxZx4UxcxS-YS2fXy6ku9NDkVvgnh6RwA5JqpfNE6AlTsMC2lKtjVTAzfTQzp-z7Nn_2h4bjn6WzSdDHoCJ-TpHYyL/s320/popscan_blogspot_com_angry_birds_amazon_03.jpg" width="320" /></a></div>
<br />
<br />
<br />
<br />
<b>Links:</b><br />
The official manufacturer homepage for the Amazon soda: <a href="http://www.olvi.fi/web/en/293">http://www.olvi.fi/web/en/293</a><br />
The first Angry Birds sodas: <a href="http://popscan.blogspot.fi/2012/03/angry-birds-soda-cans.html">http://popscan.blogspot.fi/2012/03/angry-birds-soda-cans.html</a><br />
More Angry Birds sodas: <a href="http://popscan.blogspot.fi/2012/09/new-angry-birds-soda-cans-lagoon-and.html">http://popscan.blogspot.fi/2012/09/new-angry-birds-soda-cans-lagoon-and.html</a><br />
<br>
<iframe frameborder="0" height="200px" scrolling="no" src="http://www.eemeli.de" width="100%"></iframe>
Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com0tag:blogger.com,1999:blog-1495123355536406202.post-41794814424508799742013-02-25T16:03:00.001+02:002013-02-25T16:03:59.671+02:00Angry Birds chocolate Easter eggsAngry Birds Easter eggs from Fazer are now available in Finnish stores!<br />
<br />
Each chocolate egg contains an Angry Birds toy, which can be used as a pencil topper or as a decorative on your desk. There are eight different toys available. <i>Sorry, not yet images from the toys... :)</i><br /> <div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgh8JdslqC6VXGPhvGMaN5N6p6rFpggfFXzlkRRUV0okV-nkO7PC80h76KluCmbz_iaZqdQ2EbV-U0skfDfDdmBGlsjsSu-SmTca9FNNurdZeLv_DAwf1fJ37vVJEiMAWrEhjZaHPD-hJgU/s1600/popscan_blogspot_com_angry_birds_easter_eggs_02.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgh8JdslqC6VXGPhvGMaN5N6p6rFpggfFXzlkRRUV0okV-nkO7PC80h76KluCmbz_iaZqdQ2EbV-U0skfDfDdmBGlsjsSu-SmTca9FNNurdZeLv_DAwf1fJ37vVJEiMAWrEhjZaHPD-hJgU/s320/popscan_blogspot_com_angry_birds_easter_eggs_02.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQOkKhqaq-JT_JbttKBEIbCyUNemgsGBZlhWmewJ50Ntej-C0AIknsbO12lqZIeVNIcqTKgyKxJjmCsXQ4QCvgjkhSGzZjG3n-vKi9SPEv7VmpJ8zF1-R3jiueg8mVcDKycQ5tu0KE2__j/s1600/popscan_blogspot_com_angry_birds_easter_eggs_01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQOkKhqaq-JT_JbttKBEIbCyUNemgsGBZlhWmewJ50Ntej-C0AIknsbO12lqZIeVNIcqTKgyKxJjmCsXQ4QCvgjkhSGzZjG3n-vKi9SPEv7VmpJ8zF1-R3jiueg8mVcDKycQ5tu0KE2__j/s320/popscan_blogspot_com_angry_birds_easter_eggs_01.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjesxbpm2PVN1ckzHoguLrnWdEpRcDRBdqbauC7qEZSTgusMNPWqLD6-v2sUIN32RXVDezj2i7cW9dtk1r3-nf3ofqnoPOhh2nP3L8vDhdtp1jebevm6mdnuTCm_G4eQiHy2_KHNzaX07US/s1600/popscan_blogspot_com_angry_birds_easter_eggs_03.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjesxbpm2PVN1ckzHoguLrnWdEpRcDRBdqbauC7qEZSTgusMNPWqLD6-v2sUIN32RXVDezj2i7cW9dtk1r3-nf3ofqnoPOhh2nP3L8vDhdtp1jebevm6mdnuTCm_G4eQiHy2_KHNzaX07US/s320/popscan_blogspot_com_angry_birds_easter_eggs_03.jpg" width="240" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiO2HyDiaL89NNU1sk8IqUE9DMifxyOPxJdIefxLmC4cq7RBT2UXH7cbnTDMxR3B6xF65gvvBWHKfytVbRPJxVztDEf86UoX7eArrMRLQavwaD4DRTSDCfQ2G43HbE3c4rES2SYy7icRcTN/s1600/popscan_blogspot_com_angry_birds_easter_eggs_04.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiO2HyDiaL89NNU1sk8IqUE9DMifxyOPxJdIefxLmC4cq7RBT2UXH7cbnTDMxR3B6xF65gvvBWHKfytVbRPJxVztDEf86UoX7eArrMRLQavwaD4DRTSDCfQ2G43HbE3c4rES2SYy7icRcTN/s320/popscan_blogspot_com_angry_birds_easter_eggs_04.jpg" width="240" /></a></div>
<br />
<b>Links </b><br />
Info in Finnish - <a href="http://www.fazer.fi/Tuotteet/Uutuudet/Vihaiset-linnut-munivat-yllatyksia-Fazerin-perinteiseen-paasiaiseen/">http://www.fazer.fi/Tuotteet/Uutuudet/Vihaiset-linnut-munivat-yllatyksia-Fazerin-perinteiseen-paasiaiseen/</a>Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com0tag:blogger.com,1999:blog-1495123355536406202.post-31265693526374647272013-01-15T23:06:00.001+02:002013-01-15T23:06:19.891+02:00Angry Birds soda in big bottlesThis are the latest Angry Birds sodas available: Diamond and Sunrise!<br />
<br />
The orange color soda with Orange Bird (Sunrise) has a mandarin flavor and the red soda with Pink Bird (Diamond) has a raspberry flavor in it.<br />
<br />
The bottle size is 1,5 litres, which is 50,7210341 US fluid ounces, according to Google.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgX1MFP4hjjrOy6OI6LlN6AV4VAhrBVmUtzgtKwka0hUJR1_fDxkR8ytWQSQuvndN-qRi_KrlRGjUz4RLERNPi6AONozWdOjKnquWyv4JoEKxtyvBLCUfEhUk2C0ZIvQGa4NOBY8OJbuQYD/s1600/popscan_blogspot_com_angry_birds_big_bottles_01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgX1MFP4hjjrOy6OI6LlN6AV4VAhrBVmUtzgtKwka0hUJR1_fDxkR8ytWQSQuvndN-qRi_KrlRGjUz4RLERNPi6AONozWdOjKnquWyv4JoEKxtyvBLCUfEhUk2C0ZIvQGa4NOBY8OJbuQYD/s320/popscan_blogspot_com_angry_birds_big_bottles_01.jpg" width="253" /></a></div>
<br />
Links:<br />
Olvi Oy, Sunrise - <a href="http://www.olvi.fi/web/en/283">http://www.olvi.fi/web/en/283</a><br />
Olvi Oy, Diamond - <a href="http://www.olvi.fi/web/en/282">http://www.olvi.fi/web/en/282</a>Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com0tag:blogger.com,1999:blog-1495123355536406202.post-58919122677385000032012-12-15T14:40:00.000+02:002013-01-15T15:55:15.206+02:00Angry Birds coffeeYes, we have also Angry Birds coffee available now...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3YSJ-l3sHMdDO1BB66VyUbTYxBkym023vBuWf-xzIm9aAgmwdeP_neFnVlPKmDtVaFDVdYiBI8UIeNdlHJKIKU9_Ex4Vdc-TOP6ywWjU1Ny0ewtHPIuv9spuTgsA1_XHhOxg8xcGPAwUK/s1600/popscan_blogspot_com_angry_birds_coffee_02.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3YSJ-l3sHMdDO1BB66VyUbTYxBkym023vBuWf-xzIm9aAgmwdeP_neFnVlPKmDtVaFDVdYiBI8UIeNdlHJKIKU9_Ex4Vdc-TOP6ywWjU1Ny0ewtHPIuv9spuTgsA1_XHhOxg8xcGPAwUK/s320/popscan_blogspot_com_angry_birds_coffee_02.jpg" width="239" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgggdhw6qiDfMx9fuPPJMu7K02KHF5yDF48Fko-PGZpOhukCZXe8bwxVjW_KKC0gLTYKmITnZ1bTqg9Jid27dspMBtm-dUI_aUnbglbUR2LnfmqcI0jsr6eP_82kVXfPUGKbMUvUQMYZyIy/s1600/popscan_blogspot_com_angry_birds_coffee_03.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgggdhw6qiDfMx9fuPPJMu7K02KHF5yDF48Fko-PGZpOhukCZXe8bwxVjW_KKC0gLTYKmITnZ1bTqg9Jid27dspMBtm-dUI_aUnbglbUR2LnfmqcI0jsr6eP_82kVXfPUGKbMUvUQMYZyIy/s320/popscan_blogspot_com_angry_birds_coffee_03.jpg" width="239" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdV12qcgDv0LHQnNgmbgmsPT1q-ZIBjg9-AyfxeVAY6u-MbbZYzer2PMqlmSywc4qgePM8052HZ1_8uUNd3JMoDepvcbwCnjLnc6QT6Nx1DRTewoDQG-9xRr54lOb6p2O_e-g0xOcwuYY2/s1600/popscan_blogspot_com_angry_birds_coffee_01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdV12qcgDv0LHQnNgmbgmsPT1q-ZIBjg9-AyfxeVAY6u-MbbZYzer2PMqlmSywc4qgePM8052HZ1_8uUNd3JMoDepvcbwCnjLnc6QT6Nx1DRTewoDQG-9xRr54lOb6p2O_e-g0xOcwuYY2/s320/popscan_blogspot_com_angry_birds_coffee_01.jpg" width="239" /></a></div>
<br />
<br />
<br />
<center>
<iframe allowfullscreen="allowfullscreen" frameborder="0" height="252" src="http://www.youtube.com/embed/G567z6kLyvM" width="448"></iframe>
</center>
<br />
Links:<br />
<a href="http://www.pauligcafe.fi/angrybirds/">http://www.pauligcafe.fi/angrybirds/</a><br />
<br />
<div style="text-align: left;">
<iframe frameborder="0" height="200px" scrolling="no" src="http://www.eemeli.de" width="100%"></iframe>
</div>
Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com1tag:blogger.com,1999:blog-1495123355536406202.post-8672139778898643652012-10-17T10:33:00.001+03:002012-10-17T10:33:46.054+03:00Angry Birds lollipopsThese lollipops were released at the same time with the bubble gums. The flavors are strawberry, pear and cola. In the center of the candy there is sour "powder" which surprises you when you reach it. All colors and flavors are 100 % natural. <br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIxYhxV-HgwOm8KYYyMp7nPEq7dWTalXsBHzb1PeL_0ZNtCmRs9ySGf3QpIcAOPFltEKguhMbGdi0dyj3iFOF698tmN4FaW2QgQqra6whMPO0tXKC3xTQLKLAQb2qf_SkXjRmeSZAUXbUM/s1600/popscan_blogspot_com_angry_birds_lollipop_01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIxYhxV-HgwOm8KYYyMp7nPEq7dWTalXsBHzb1PeL_0ZNtCmRs9ySGf3QpIcAOPFltEKguhMbGdi0dyj3iFOF698tmN4FaW2QgQqra6whMPO0tXKC3xTQLKLAQb2qf_SkXjRmeSZAUXbUM/s320/popscan_blogspot_com_angry_birds_lollipop_01.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYl0HY4RmBggPUVnP75oPuELAHRWe37cbYtKAdrFyR-6PKeZ58US_qo3xoy804-2Kb8sudyB7V4up4Cc0W_lSBp8eWaaS6NkONSbakA9d7UqKiB3RqHmYtuMqsZlyrgA1QHrpPtA9PsoD8/s1600/popscan_blogspot_com_angry_birds_lollipop_02.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYl0HY4RmBggPUVnP75oPuELAHRWe37cbYtKAdrFyR-6PKeZ58US_qo3xoy804-2Kb8sudyB7V4up4Cc0W_lSBp8eWaaS6NkONSbakA9d7UqKiB3RqHmYtuMqsZlyrgA1QHrpPtA9PsoD8/s320/popscan_blogspot_com_angry_birds_lollipop_02.jpg" width="320" /></a></div>
<br />
<br />
<br />
<br />
<br />
Ad from Fazer:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<object width="320" height="266" class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://2.gvt0.com/vi/BGsb_Atbrz4/0.jpg"><param name="movie" value="http://www.youtube.com/v/BGsb_Atbrz4&fs=1&source=uds" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="320" height="266" src="http://www.youtube.com/v/BGsb_Atbrz4&fs=1&source=uds" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
<br />
Links:<br />
<a href="http://www.fazer.com/Brands/Angry-Birds/Products/Lollipops/">http://www.fazer.com/Brands/Angry-Birds/Products/Lollipops/</a><br />
Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com0tag:blogger.com,1999:blog-1495123355536406202.post-15352139747850427392012-10-04T10:49:00.002+03:002012-10-04T10:49:44.819+03:00Angry Birds chewing gumA Finnish candy manufacturer Fazer has launched more sweets for the Angry Birds brand.<br />
<br />
These are the Angry Birds chewing gum packages: the Red Bird bag contains eucalyptus and strawberry flavored chewing gums and the Bad Piggie bag contains spearmint and pear flavored chewing gums.<br />
<br />
The Angry Birds chewing gum contains xylitol, which is a natural sweetener that is used as a sugar substitute. The xylitol has health benefits as it reduces caries and ear infections. The xylitol is a very popular (or almost a must!) sweetener in chewing gums and refreshing mints in Finland, as Finns as are very keen on keeping their teeth in good condition.<br />
<br />
<b>Links:</b><br />
Fazer - <a href="http://www.fazer.com/fi/brands/angrybirds/">http://www.fazer.com/fi/brands/angrybirds/</a><br />
Xylitol - <a href="http://en.wikipedia.org/wiki/Xylitol">http://en.wikipedia.org/wiki/Xylitol</a><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVYPSCRCTT8AV_fz86rreLaLsv6Kxm632-B7xaJ9_2cJT6psm8AXACsI5PRnF7T75UiznRQt-2Ca87RwpYDnRCKAhFTrTisOzsdsaQ0ekalaehtQNnlbB09qcsg91BDJ16i5KRP9vQMI4X/s1600/popscan_blogspot_com_angry_birds_bubblegum_01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVYPSCRCTT8AV_fz86rreLaLsv6Kxm632-B7xaJ9_2cJT6psm8AXACsI5PRnF7T75UiznRQt-2Ca87RwpYDnRCKAhFTrTisOzsdsaQ0ekalaehtQNnlbB09qcsg91BDJ16i5KRP9vQMI4X/s320/popscan_blogspot_com_angry_birds_bubblegum_01.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8XFDnuKG9fZ3SRskK_Yaptl-YbLrkKyOL99CyRD0qC8fZfsclh9rxofOfjkaA-1C_tui1CZY6hNwIkSNAMmoIfK3IKagriuzIhB7XnuMGIuqi9-D1Po7UpzKZjUmpJzPDlmZIpcnTpQhP/s1600/popscan_blogspot_com_angry_birds_bubblegum_02.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8XFDnuKG9fZ3SRskK_Yaptl-YbLrkKyOL99CyRD0qC8fZfsclh9rxofOfjkaA-1C_tui1CZY6hNwIkSNAMmoIfK3IKagriuzIhB7XnuMGIuqi9-D1Po7UpzKZjUmpJzPDlmZIpcnTpQhP/s320/popscan_blogspot_com_angry_birds_bubblegum_02.jpg" width="240" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhU9bNFpXQd_MzHKnj7WHDsYOGyAMiuc3zUDdp4WsU6lJdDKt9YARUfpQEJPJyvSMh4tEMLpsDTji0N874RMVHUjd7SoEfkXXu1-kGZUCrIUcZF6c8lssxLEyL36jMVNJcUHPSIAylKa_d3/s1600/popscan_blogspot_com_angry_birds_bubblegum_03.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhU9bNFpXQd_MzHKnj7WHDsYOGyAMiuc3zUDdp4WsU6lJdDKt9YARUfpQEJPJyvSMh4tEMLpsDTji0N874RMVHUjd7SoEfkXXu1-kGZUCrIUcZF6c8lssxLEyL36jMVNJcUHPSIAylKa_d3/s320/popscan_blogspot_com_angry_birds_bubblegum_03.jpg" width="240" /></a></div>
<br />Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com0tag:blogger.com,1999:blog-1495123355536406202.post-39786797190988676392012-09-10T15:53:00.001+03:002012-09-21T23:15:13.002+03:00Difficulties accessing any service from GoogleWhen trying to access anything by Google (YouTube, Google search, Blogger) I am having difficulties loading the pages, or the pages will not load at all.<br />
<br />
<i>This post is made at another location which uses different router and different ISP. </i><br />
<br />
<b>Edit 2012-09-12: </b>this problem still exists... <i><br /></i><br />
<b><br /></b>
<b>Edit 2012-09-13:</b> Could this be locale related, see <a href="https://groups.google.com/a/chromium.org/forum/?fromgroups=#!topic/chromium-bugs/a_jEG6skYo8">https://groups.google.com/a/chromium.org/forum/?fromgroups=#!topic/chromium-bugs/a_jEG6skYo8</a><br />
<br />
<b>Edit 2012-09-14:</b> D-Link 2470B does not work for me even with latest firmware. I have hardware version E1 and firmware 5.17. <br />
<br />
<br />
<b>Edit 2012-09-21:</b> The problems have disappeared as suddenly they appeared. I have not made any further efforts to fix the problem, but now everything works nicely.<br />
<br />
<b>Firefox: </b><br />
<br />
On Firefox 15.0.1 the pages will load, but the redirection (possibly with JavaScript) is not sending me forward. Like when signing in, the page remains the same after pressing the "Sign in" button. However, if I go to the dashboard from a shortcut, the sign in button actually had logged me in and the browser happily loads the dashboard.<br />
<br />
If I try to post something to the blog, the blog message gets mangled. The characters are copied and replaced randomly inside of the message. Like the URLs can be "http://3.blo.3.blospotblogspot.comcom/popscan_angrygrygryrds_soda". I could not find pattern for this behavior.<br />
<br />
Examples:<br />
1) image URL gets corrupted: http://4.bp.blogspot.com/-M7iw-UjQfDI/UEy4L9IHgefDI/UEy4L9IHgeI/AAAAAAAAAPM/vLbiX9ZdfZ4/s1600/popscan_blogspot_com_angry_birds_soda_2_03.png<br />
2) CSS style get corrupted: style="margin-gin-right: 1em;" <br />
<br />
If the randomness occurs inside of the HTML or CSS, the post (web page) gets corrupted completely. And if the HTML gets broken, the posting will fail. And that happens for the most of the time... If I can successfully watch the page preview, the HTML is not corrupted (but the visible text may be) and I can publish the text.<br />
<br />
With all the problems, errors and retries, writing a short text with 4 images took me 5 hours. And I had to keep the HTML extremely short; little longer text would get messed up.<br />
<br />
Before I could post anything, I was seeing error "You have logged out from another location. Do you want to log in again?" I am pretty sure these two things are related... However, I got rid of this error by clearing the browser history and cache, first time this year! After using the Blogger for a while, the "logged out" problem reappears...<br />
<br />
<b>Chrome: </b><br />
<br />
Chrome will report:<br />
"Virhe 126 (net::ERR_SSL_BAD_RECORD_MAC_ALERT): Tuntematon virhe."<br />
<br />
Which is in English: <br />
"Error 126:(net::ERR_SSL_BAD_RECORD_MAC_ALERT): Unknown error."<br />
<br />
Absolutely nothing works.
<b> </b><br />
<br />
<b>IE:</b><br />
<br />
The result is exactly the same as in Chrome.<br />
<br />
<b>What have I done?</b><br />
<br />
1) Cleared history and cache for all browsers<br />
2) Rebooted
my laptop<br />
3) Made a complete antivirus scan<br />
4) Replaced the antivirus software and made a new complete scan<br />
5) Made a root-kit scan<br />
6) Rebooted my laptop again<br />
7) Tried different MTU values for my ADSL router<br />
8) Rebooted my ADSL router
several times<br />
9) Spent hours looking for the solution<br />
10) Performed factory reset and fresh setup for router<br />
11) Tried different MTU values from 1200 up to 1500<br />
<br />
<b>Luckily I am not alone with my problem</b><br />
<br />
The same issue is visible for other Finnish users at the moment (http://murobbs.plaza.fi/internet-tietoturva-ja-muu-tietoliikenne/926370-tp-link-mr3420-ja-google-ei-toimi-keskenaan-err_ssl_bad_record_mac_alert.html).<br />
<br />
Also the same errors are shown in Google support forums, sadly there are no proper solutions for fixing this. <br />
<br />
Edit 2012-09-12: It seems that routers/modems from many manufacturers have this problem, at least: TP-Link, D-Link, Buffalo, ZTE and Telewell.<br />
<br />
<b>SOLUTION:</b><br />
<br />
<b>Workaround 1:</b><br />
<br />
Change your modem/router OR upgrade its firmware.<br />
<br />
I have D-Link 2740B, which stopped working Friday 7th September. I found other modem from my closet and hooked it to ADSL-line; everything works.<br />
<br />
The reason why it works, is yet unknown to me. I am beginning to think it is actually related to MTU value. But the strangest thing is, that the problem appeared suddenly on one day, and not only for me.<br />
<br />
<b>Workaround 2:</b><br />
<br />
You can try to change the MTU value from your router/modem to 1400.<br />
<br />
I have read that for some people this change has fixed the issue. The MTU value can be changed from the devices configuration pages, usually accessible by the web browser. See your device manual for details.<br />
<br />
Edit 2012-09-12: For me, Google services work only like 2 minutes after MTU change.<br />
<br />
<strike><b>Fix that works for me:</b></strike><br />
<strike><br /></strike>
<strike>From the router settings, I changed the default DNS address from ISP to Google's DNS which is "<b>8.8.8.8</b>" and <b>rebooted</b> the router. After the router was booted, I was able to access blogger with Firefox and also Chrome.</strike><br />
<br />
The Blogger will function properly only for a while after changing DNS address.<br />
<br />
Does these fixes work for you?Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com4tag:blogger.com,1999:blog-1495123355536406202.post-34386719942715660662012-09-07T12:12:00.002+03:002013-03-29T13:16:38.643+02:00New Angry Birds soda cans - Lagoon and Comet<br />
<br />
These have just arrived! New Angry Birds soda cans with Bad Pig and Black Bird.<br />
<br />
Lagoon (Bad Pig) has apple and pear flavor and Comet (Black Bird) has orange and cola flavor.
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIE6C-XQkx-z5mZiVgsiAPnB_HCBFQHSEQqn6bEO3lCkvCrN2N6tmLUx8dP-2NCiHEilu2I4QubyWgEQsNhq-f1k6MHxE6Bg-gd7B5m2rfl4IiuVi5yqM43lo2A_XqfjDfzx8a8YiKhE68/s1600/popscan_blogspot_com_angry_birds_soda_2_01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIE6C-XQkx-z5mZiVgsiAPnB_HCBFQHSEQqn6bEO3lCkvCrN2N6tmLUx8dP-2NCiHEilu2I4QubyWgEQsNhq-f1k6MHxE6Bg-gd7B5m2rfl4IiuVi5yqM43lo2A_XqfjDfzx8a8YiKhE68/s320/popscan_blogspot_com_angry_birds_soda_2_01.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhozLh7tfjK4EpOU2SfD-m3qcC6rFnfErzxZLLYW063YoYGKpa4ZKnE__UkZTNBEoYgaLyGl3fREUeqcBaCkx2HrJ6Sq7Xjw3PPyzMN5cPspKe5I3SWPlAp7RsSH6N9z4lbpL0cbQCuc0aA/s1600/popscan_blogspot_com_angry_birds_soda_2_02.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhozLh7tfjK4EpOU2SfD-m3qcC6rFnfErzxZLLYW063YoYGKpa4ZKnE__UkZTNBEoYgaLyGl3fREUeqcBaCkx2HrJ6Sq7Xjw3PPyzMN5cPspKe5I3SWPlAp7RsSH6N9z4lbpL0cbQCuc0aA/s320/popscan_blogspot_com_angry_birds_soda_2_02.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7RzC1mOZe6-QSU1m5RyabFCEYiPTEYYLx6wEW7D49C02BYGoe9Qdx-Jx31d1RnLUJYS8-FJv2s4weOOwWjAHLT5n1LW8O0QKTD29-kSUR3g7idqmSFvfySNnU7NgiOfXbnJFcR2VuCQWD/s1600/popscan_blogspot_com_angry_birds_soda_2_03.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7RzC1mOZe6-QSU1m5RyabFCEYiPTEYYLx6wEW7D49C02BYGoe9Qdx-Jx31d1RnLUJYS8-FJv2s4weOOwWjAHLT5n1LW8O0QKTD29-kSUR3g7idqmSFvfySNnU7NgiOfXbnJFcR2VuCQWD/s320/popscan_blogspot_com_angry_birds_soda_2_03.png" width="240" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZ1FRdETr5h2euy6OjBCgGGEw_SwHYXU0OToNg6olYSFzxGL9LgSuZodqhlmcwNx1lHyGzLT0P0bDiYG6EJXYBbMeQy6OCRWgg3YI9iB_Bhn632MvbZrb4Qp3b13T2ornsz3SXBho_BlNJ/s1600/popscan_blogspot_com_angry_birds_soda_2_04.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZ1FRdETr5h2euy6OjBCgGGEw_SwHYXU0OToNg6olYSFzxGL9LgSuZodqhlmcwNx1lHyGzLT0P0bDiYG6EJXYBbMeQy6OCRWgg3YI9iB_Bhn632MvbZrb4Qp3b13T2ornsz3SXBho_BlNJ/s320/popscan_blogspot_com_angry_birds_soda_2_04.png" width="240" /></a></div>
<br />
The manufacturer is Finnish company Olvi; check out the official pages at <a href="http://www.olvi.fi/web/en/267" target="_blank">http://www.olvi.fi/web/en/267</a>. <br />
<br />
The price for the can is 1,29 e, at our local stores, in Finland.
<br />
<br />
<iframe frameborder="0" height="200px" scrolling="no" src="http://www.eemeli.de" width="100%"></iframe>
Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com0tag:blogger.com,1999:blog-1495123355536406202.post-61696613074873049302012-09-05T17:52:00.001+03:002012-09-05T17:54:00.731+03:00How to enable and find WinSCP ini fileI just updated my WinSCP from version 4.1.3 to version 4.3.9 and I noticed that the application did not read .ini file at the start up, or at least the ini file was not where I thought it would be.<br />
<br />
Well, besides upgrading my WinSCP client, also my OS did change from XP to Win7, so I guess it is natural that the file locations do change also.
But even after full hard drive search, I could not find any *.ini file related to WinSCP!<br />
<br />
Luckily I was not the only person who tried to find the ini file, read related forum post from here (<a href="http://winscp.net/forum/viewtopic.php?t=11264">http://winscp.net/forum/viewtopic.php?t=11264</a>).<br />
<br />
So the correct steps to enable your old ini file with saved sessions for WinSCP (<b>in Windows 7</b>) is following:<br />
<ol>
<li>Launch your WinSCP</li>
<li>Select from the menu at left "<b>Preferences</b>" -> then from right hand side "<b>Preferences</b>" -> then "<b>Storage</b>" from lower left -> then select "<b>INI file (WinSCP.ini)</b>" -> "<b>OK</b>" -> "<b>Close</b>"</li>
<li>The "WinSCP.ini" file was created to your "virtual folder", which can be found from "c:/Users/USERNAME/AppData/Local/VirtualStore/Program Files (x86)/WinSCP"</li>
<li>Manually copy and paste (with text editor) the wanted sessions from old to new ini file </li>
</ol>
<b>Note 1:</b> The AppData folder is not visible by default, so change your folder settings to display hidden and system files. <br />
<br />
<b>Note 2</b>: To make sure the new WinSCP works correctly, you need to copy&paste manually the sessions from the old Winscpxxx.ini to the new Winscp.ini<br />
<br />
<br />
<br />
<iframe frameborder="0" height="200px" scrolling="no" src="http://www.eemeli.de" width="100%"></iframe>Jussihttp://www.blogger.com/profile/05808789748549866047noreply@blogger.com0