<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

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

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

#include &quot;LineUtils.h&quot;

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

using namespace std;

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

    LineUtils::LineUtils() {
    }

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

    LineUtils::~LineUtils() {
    }

    /**
     * Get the equation parameters for the line that passes through (x,y) and is perpendicular
     * to the line specified by parameters (p0, theta0) in normal form.
     *
     * @param p0 : distance to line from origin.
     * @param theta0 : the slope of p0.
     * @param x : x coordinate of the point where the perpendicular line passes through
     * @param y : y coordinate of the point where the perpendicular line passes through
     * @param &amp;p : the perpendicular line's distance from origin.
     * @param &amp;theta : the slope of p.
     **/
    void LineUtils::GetPerpendicularLineParameters(float p0, float theta0, float x, float y, float &amp;p, float &amp;theta) {
        float x0 = p0 * cos(theta0);
        float y0 = p0 * sin(theta0);

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

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

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

        if (d1 &lt; d2)
            theta = a1;
        else
            theta = a2;
    }

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

    /**
     * Get a line segement's coordinates. The segement is centered at x0, y0.
     *
     * @param points[] : the x,y coordinate of the input points (ordered).
     * @param threashold : the threashold of disconnected points before a line is considered no
     *              longer connected.
     * @param lpoints[] : the x,y coordinates of the points in the detected longest connected line.
     * @param &amp;maxLen : the maximum length of the output array, addtional line points
     *                  will be discarded if exceed this limit.
     **/
    void LineUtils::GetLongestConnectedLinePoints(IppiPoint points[], int len, int threshold, IppiPoint lpoints[], int &amp;maxLen) {
        int maxIndexEnd = 0, curRunLength = 0, maxRunLength = 0;

        lpoints[curRunLength] = points[0];

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

                //}
            } else {
                if (curRunLength &gt;= maxLen) {
                    maxRunLength = maxLen;
                    break;
                }

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

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

        maxLen = maxRunLength;
    }

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

        int numCrossings = 0;

        minIndex = 0;
        maxIndex = 0;

        float avg = 0;

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

        avg = avg / (float) len;        

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

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

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

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

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

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

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

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

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

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

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

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

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

        zerosCount += 2;

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

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

        zerosCount += 2;

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

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

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

        if (zerosCount == 0)
            return 0;
        else
            return r / (float) zerosCount;
    }
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrywong.com/2009/07/03/image-blur-detection-via-hough-transform-iv/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Image Blur Detection via Hough Transform &#8212; III</title>
		<link>http://www.kerrywong.com/2009/06/27/image-blur-detection-via-hough-transform-iii/</link>
		<comments>http://www.kerrywong.com/2009/06/27/image-blur-detection-via-hough-transform-iii/#comments</comments>
		<pubDate>Sun, 28 Jun 2009 01:31:01 +0000</pubDate>
		<dc:creator>kwong</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Blur Detection]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Edge Detection]]></category>
		<category><![CDATA[Hough Transform]]></category>
		<category><![CDATA[Intel IPP]]></category>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        lpoints[curRunLength] = points[0];

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

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

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

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

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