2
0
mirror of https://github.com/boostorg/gil.git synced 2026-01-24 18:02:17 +00:00
Files
gil/develop/doc/html/tutorial.html
Stefan Seefeld 2181d948e4 Regenerate docs.
2018-03-22 16:36:50 -04:00

796 lines
115 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Tutorial - Boost.GIL 1.0 documentation</title>
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/style.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '1.0',
COLLAPSE_MODINDEX: false,
FILE_SUFFIX: '.html'
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="top" title="Boost.GIL 1.0 documentation" href="index.html" />
<link rel="next" title="Design Guide" href="design_guide.html" />
<link rel="prev" title="Boost Generic Image Library" href="index.html" />
</head>
<body>
<div class="header">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<h3><a href="index.html"><img
alt="C++ Boost" src="_static/boost.png" border="0"></a></h3>
</td>
<td >
<h1 align="center"><a href="index.html"></a></h1>
</td>
<td>
<div id="searchbox" style="display: none">
<form class="search" action="search.html" method="get">
<input type="text" name="q" size="18" />
<input type="submit" value="Search" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</td>
</tr>
</table>
</div>
<hr/>
<div class="content">
<div class="navbar" style="text-align:right;">
<a class="prev" title="Boost Generic Image Library" href="index.html"><img src="_static/prev.png" alt="prev"/></a>
<a class="next" title="Design Guide" href="design_guide.html"><img src="_static/next.png" alt="next"/></a>
</div>
<div class="section" id="tutorial">
<h1>Tutorial</h1>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">authors:</th><td class="field-body">Lubomir Bourdev
Hailin Jin</td>
</tr>
<tr class="field-even field"><th class="field-name">version:</th><td class="field-body">2.1</td>
</tr>
<tr class="field-odd field"><th class="field-name">date:</th><td class="field-body">September 15, 200</td>
</tr>
</tbody>
</table>
<p>The Generic Image Library (GIL) is a C++ library that abstracts image
representations from algorithms and allows writing code that can work on
a variety of images with performance similar to hand-writing for a specific
image type.
This document will give you a jump-start in using GIL. It does not discuss the
underlying design of the library and does not cover all aspects of it.</p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#installation" id="id1">Installation</a></li>
<li><a class="reference internal" href="#example-computing-the-image-gradient" id="id2">Example - Computing the Image Gradient</a><ul>
<li><a class="reference internal" href="#interface-and-glue-code" id="id3">Interface and Glue Code</a></li>
<li><a class="reference internal" href="#first-implementation" id="id4">First Implementation</a></li>
<li><a class="reference internal" href="#using-locators" id="id5">Using Locators</a></li>
<li><a class="reference internal" href="#creating-a-generic-version-of-gil-algorithms" id="id6">Creating a Generic Version of GIL Algorithms</a></li>
<li><a class="reference internal" href="#image-view-transformations" id="id7">Image View Transformations</a></li>
<li><a class="reference internal" href="#d-pixel-iterators" id="id8">1D pixel iterators</a></li>
<li><a class="reference internal" href="#stl-equivalent-algorithms" id="id9">STL Equivalent Algorithms</a></li>
<li><a class="reference internal" href="#color-conversion" id="id10">Color Conversion</a></li>
<li><a class="reference internal" href="#image" id="id11">Image</a></li>
<li><a class="reference internal" href="#virtual-image-views" id="id12">Virtual Image Views</a></li>
<li><a class="reference internal" href="#run-time-specified-images-and-image-views" id="id13">Run-Time Specified Images and Image Views</a></li>
<li><a class="reference internal" href="#conclusion" id="id14">Conclusion</a></li>
</ul>
</li>
<li><a class="reference internal" href="#appendix" id="id15">Appendix</a><ul>
<li><a class="reference internal" href="#naming-convention-for-gil-concrete-types" id="id16">Naming convention for GIL concrete types</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="installation">
<h2><a class="toc-backref" href="#id1">Installation</a></h2>
<p>The latest version of GIL can be downloaded from GILs web page, at <a class="reference external" href="http://stlab.adobe.com/gil">http://stlab.adobe.com/gil</a>.
GIL is approved for integration into Boost and in the future will be installed simply by installing Boost from <a class="reference external" href="http://www.boost.org">http://www.boost.org</a>.
GIL consists of header files only and does not require any libraries to link against. It does not require Boost to be built.
Including <code class="docutils literal"><span class="pre">boost/gil/gil_all.hpp</span></code> will be sufficient for most projects.</p>
</div>
<div class="section" id="example-computing-the-image-gradient">
<h2><a class="toc-backref" href="#id2">Example - Computing the Image Gradient</a></h2>
<p>This tutorial will walk through an example of using GIL to compute the image
gradients. We will start with some very simple and non-generic code and make it
more generic as we go along.
Let us start with a horizontal gradient and use the simplest possible approximation
to a gradient - central difference.
The gradient at pixel x can be approximated with the half-difference of its two
neighboring pixels:
D[x] = (I[x-1] - I[x+1]) / 2</p>
<p>For simplicity, we will also ignore the boundary cases - the pixels along the edges
of the image for which one of the neighbors is not defined.
The focus of this document is how to use GIL, not how to create a good gradient
generation algorithm.</p>
<div class="section" id="interface-and-glue-code">
<h3><a class="toc-backref" href="#id3">Interface and Glue Code</a></h3>
<p>Let us first start with 8-bit unsigned grayscale image as the input and 8-bit
signed grayscale image as the output.
Here is how the interface to our algorithm looks like:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf">&lt;boost/gil/gil_all.hpp&gt;</span><span class="cp"></span>
<span class="k">using</span> <span class="k">namespace</span> <span class="n">boost</span><span class="o">::</span><span class="n">gil</span><span class="p">;</span>
<span class="kt">void</span> <span class="nf">x_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">gray8c_view_t</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">gray8s_view_t</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">assert</span><span class="p">(</span><span class="n">src</span><span class="p">.</span><span class="n">dimensions</span><span class="p">()</span> <span class="o">==</span> <span class="n">dst</span><span class="p">.</span><span class="n">dimensions</span><span class="p">());</span>
<span class="p">...</span> <span class="c1">// compute the gradient</span>
<span class="p">}</span>
</pre></div>
</div>
<p><code class="docutils literal"><span class="pre">gray8c_view_t</span></code> is the type of the source image view - an 8-bit grayscale view, whose pixels are read-only (denoted by the “c”). The output
is a grayscale view with a 8-bit signed (denoted by the “s”) integer channel type. See Appendix 1 for the complete convension GIL uses to name concrete types.</p>
<p>GIL makes a distinction between an image and an image view. A GIL <strong>image view</strong>, is a shallow, lightweight view of a rectangular grid of pixels. It provides access to the pixels
but does not own the pixels. Copy-constructing a view does not deep-copy the pixels. Image views do not propagate their constness to the pixels and should
always be taken by a const reference. Whether a view is mutable or read-only (immutable) is a property of the view type.</p>
<p>A GIL <cite>image</cite>, on the other hand, is a view with associated ownership. It is a container of pixels; its constructor/destructor allocates/deallocates the pixels, its copy-constructor
performs deep-copy of the pixels and its operator== performs deep-compare of the pixels. Images also propagate their constness to their pixels - a constant reference to an image will not
allow for modifying its pixels.</p>
<p>Most GIL algorithms operate on image views; images are rarely needed. GILs design is very similar to that of the STL. The STL equivalent of GILs image is a container, like <code class="docutils literal"><span class="pre">std::vector</span></code>, whereas
GILs image view corresponds to STLs range, which is often represented with a pair of iterators. STL algorithms operate on ranges, just like GIL algorithms operate on image views.</p>
<p>GILs image views can be constructed from raw data - the dimensions, the number of bytes per row and the pixels, which for chunky views are represented with one pointer. Here is how to provide
the glue between your code and GIL:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">ComputeXGradientGray8</span><span class="p">(</span><span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">char</span><span class="o">*</span> <span class="n">src_pixels</span><span class="p">,</span> <span class="kt">ptrdiff_t</span> <span class="n">src_row_bytes</span><span class="p">,</span> <span class="kt">int</span> <span class="n">w</span><span class="p">,</span> <span class="kt">int</span> <span class="n">h</span><span class="p">,</span>
<span class="kt">signed</span> <span class="kt">char</span><span class="o">*</span> <span class="n">dst_pixels</span><span class="p">,</span> <span class="kt">ptrdiff_t</span> <span class="n">dst_row_bytes</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">gray8c_view_t</span> <span class="n">src</span> <span class="o">=</span> <span class="n">interleaved_view</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">h</span><span class="p">,</span> <span class="p">(</span><span class="k">const</span> <span class="n">gray8_pixel_t</span><span class="o">*</span><span class="p">)</span><span class="n">src_pixels</span><span class="p">,</span><span class="n">src_row_bytes</span><span class="p">);</span>
<span class="n">gray8s_view_t</span> <span class="n">dst</span> <span class="o">=</span> <span class="n">interleaved_view</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">h</span><span class="p">,</span> <span class="p">(</span> <span class="n">gray8s_pixel_t</span><span class="o">*</span><span class="p">)</span><span class="n">dst_pixels</span><span class="p">,</span><span class="n">dst_row_bytes</span><span class="p">);</span>
<span class="n">x_gradient</span><span class="p">(</span><span class="n">src</span><span class="p">,</span><span class="n">dst</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>This glue code is very fast and views are lightweight - in the above example the views have a size of 16 bytes. They consist of a pointer to the top left pixel and three integers - the width, height,
and number of bytes per row.</p>
</div>
<div class="section" id="first-implementation">
<h3><a class="toc-backref" href="#id4">First Implementation</a></h3>
<p>Focusing on simplicity at the expense of speed, we can compute the horizontal gradient like this:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">x_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">gray8c_view_t</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">gray8s_view_t</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">y</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">y</span><span class="o">&lt;</span><span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">();</span> <span class="o">++</span><span class="n">y</span><span class="p">)</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">x</span><span class="o">&lt;</span><span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">()</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="o">++</span><span class="n">x</span><span class="p">)</span>
<span class="n">dst</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">)</span> <span class="o">=</span> <span class="p">(</span><span class="n">src</span><span class="p">(</span><span class="n">x</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="n">y</span><span class="p">)</span> <span class="o">-</span> <span class="n">src</span><span class="p">(</span><span class="n">x</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span><span class="n">y</span><span class="p">))</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>We use image views <code class="docutils literal"><span class="pre">operator(x,y)</span></code> to get a reference to the pixel at a given location and we set it to the half-difference of its left and right neighbors.
<code class="docutils literal"><span class="pre">operator()</span></code> returns a reference to a grayscale pixel. A grayscale pixel is convertible to its channel type (<code class="docutils literal"><span class="pre">unsigned</span> <span class="pre">char</span></code> for <code class="docutils literal"><span class="pre">src</span></code>) and it can be copy-constructed from a channel.
(This is only true for grayscale pixels).
While the above code is easy to read, it is not very fast, because the binary <code class="docutils literal"><span class="pre">operator()</span></code> computes the location of the pixel in a 2D grid, which involves addition and multiplication. Here is
a faster version of the above:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">x_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">gray8c_view_t</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">gray8s_view_t</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">y</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">y</span><span class="o">&lt;</span><span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">();</span> <span class="o">++</span><span class="n">y</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">gray8c_view_t</span><span class="o">::</span><span class="n">x_iterator</span> <span class="n">src_it</span> <span class="o">=</span> <span class="n">src</span><span class="p">.</span><span class="n">row_begin</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
<span class="n">gray8s_view_t</span><span class="o">::</span><span class="n">x_iterator</span> <span class="n">dst_it</span> <span class="o">=</span> <span class="n">dst</span><span class="p">.</span><span class="n">row_begin</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">x</span><span class="o">&lt;</span><span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">()</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="o">++</span><span class="n">x</span><span class="p">)</span>
<span class="n">dst_it</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">src_it</span><span class="p">[</span><span class="n">x</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">src_it</span><span class="p">[</span><span class="n">x</span><span class="o">+</span><span class="mi">1</span><span class="p">])</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>We use pixel iterators initialized at the beginning of each row. GILs iterators are Random Access Traversal iterators. If you are not familiar with random access iterators, think of them as if they
were pointers. In fact, in the above example the two iterator types are raw C pointers and their <code class="docutils literal"><span class="pre">operator[]</span></code> is a fast pointer indexing operator.</p>
<p>The code to compute gradient in the vertical direction is very similar:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">y_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">gray8c_view_t</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">gray8s_view_t</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">x</span><span class="o">&lt;</span><span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">();</span> <span class="o">++</span><span class="n">x</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">gray8c_view_t</span><span class="o">::</span><span class="n">y_iterator</span> <span class="n">src_it</span> <span class="o">=</span> <span class="n">src</span><span class="p">.</span><span class="n">col_begin</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
<span class="n">gray8s_view_t</span><span class="o">::</span><span class="n">y_iterator</span> <span class="n">dst_it</span> <span class="o">=</span> <span class="n">dst</span><span class="p">.</span><span class="n">col_begin</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">y</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">y</span><span class="o">&lt;</span><span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">()</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="o">++</span><span class="n">y</span><span class="p">)</span>
<span class="n">dst_it</span><span class="p">[</span><span class="n">y</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">src_it</span><span class="p">[</span><span class="n">y</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">src_it</span><span class="p">[</span><span class="n">y</span><span class="o">+</span><span class="mi">1</span><span class="p">])</span><span class="o">/</span><span class="mi">2</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Instead of looping over the rows, we loop over each column and create a p y_iterator, an iterator moving vertically. In this case a simple pointer cannot be used because the distance
between two adjacent pixels equals the number of bytes in each row of the image. GIL uses here a special step iterator class whose size is 8 bytes - it contains a raw C pointer and a step.
Its <code class="docutils literal"><span class="pre">operator[]</span></code> multiplies the index by its step.</p>
<p>The above version of <code class="docutils literal"><span class="pre">y_gradient</span></code>, however, is much slower (easily an order of magnitude slower) than <code class="docutils literal"><span class="pre">x_gradient</span></code> because of the memory access pattern; traversing an image vertically
results in lots of cache misses. A much more efficient and cache-friendly version will iterate over the columns in the inner loop:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">y_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">gray8c_view_t</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">gray8s_view_t</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">y</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">y</span><span class="o">&lt;</span><span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">()</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="o">++</span><span class="n">y</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">gray8c_view_t</span><span class="o">::</span><span class="n">x_iterator</span> <span class="n">src1_it</span> <span class="o">=</span> <span class="n">src</span><span class="p">.</span><span class="n">row_begin</span><span class="p">(</span><span class="n">y</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span>
<span class="n">gray8c_view_t</span><span class="o">::</span><span class="n">x_iterator</span> <span class="n">src2_it</span> <span class="o">=</span> <span class="n">src</span><span class="p">.</span><span class="n">row_begin</span><span class="p">(</span><span class="n">y</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span>
<span class="n">gray8s_view_t</span><span class="o">::</span><span class="n">x_iterator</span> <span class="n">dst_it</span> <span class="o">=</span> <span class="n">dst</span><span class="p">.</span><span class="n">row_begin</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">x</span><span class="o">&lt;</span><span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">();</span> <span class="o">++</span><span class="n">x</span><span class="p">)</span> <span class="p">{</span>
<span class="o">*</span><span class="n">dst_it</span> <span class="o">=</span> <span class="p">((</span><span class="o">*</span><span class="n">src1_it</span><span class="p">)</span> <span class="o">-</span> <span class="p">(</span><span class="o">*</span><span class="n">src2_it</span><span class="p">))</span><span class="o">/</span><span class="mi">2</span><span class="p">;</span>
<span class="o">++</span><span class="n">dst_it</span><span class="p">;</span>
<span class="o">++</span><span class="n">src1_it</span><span class="p">;</span>
<span class="o">++</span><span class="n">src2_it</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>This sample code also shows an alternative way of using pixel iterators - instead of <code class="docutils literal"><span class="pre">operator[]</span></code> one could use increments and dereferences.</p>
</div>
<div class="section" id="using-locators">
<h3><a class="toc-backref" href="#id5">Using Locators</a></h3>
<p>Unfortunately this cache-friendly version requires the extra hassle of maintaining two separate iterators in the source view. For every pixel,
we want to access its neighbors above and below it. Such relative access can be done with GIL locators:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">y_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">gray8c_view_t</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">gray8s_view_t</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">gray8c_view_t</span><span class="o">::</span><span class="n">xy_locator</span> <span class="n">src_loc</span> <span class="o">=</span> <span class="n">src</span><span class="p">.</span><span class="n">xy_at</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">y</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">y</span><span class="o">&lt;</span><span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">()</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="o">++</span><span class="n">y</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">gray8s_view_t</span><span class="o">::</span><span class="n">x_iterator</span> <span class="n">dst_it</span> <span class="o">=</span> <span class="n">dst</span><span class="p">.</span><span class="n">row_begin</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">x</span><span class="o">&lt;</span><span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">();</span> <span class="o">++</span><span class="n">x</span><span class="p">)</span>
<span class="p">{</span>
<span class="p">(</span><span class="o">*</span><span class="n">dst_it</span><span class="p">)</span> <span class="o">=</span> <span class="p">(</span><span class="n">src_loc</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="o">-</span> <span class="n">src_loc</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">))</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span>
<span class="o">++</span><span class="n">dst_it</span><span class="p">;</span>
<span class="o">++</span><span class="n">src_loc</span><span class="p">.</span><span class="n">x</span><span class="p">();</span> <span class="c1">// each dimension can be advanced separately</span>
<span class="p">}</span>
<span class="n">src_loc</span><span class="o">+=</span><span class="n">point2</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="kt">ptrdiff_t</span><span class="o">&gt;</span><span class="p">(</span><span class="o">-</span><span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">(),</span><span class="mi">1</span><span class="p">);</span> <span class="c1">// carriage return</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>The first line creates a locator pointing to the first pixel of the second row of the source view. A GIL pixel locator is very similar to an iterator,
except that it can move both horizontally and vertically. <code class="docutils literal"><span class="pre">src_loc.x()</span></code> and <code class="docutils literal"><span class="pre">src_loc.y()</span></code> return references to a horizontal and a vertical iterator
respectively, which can be used to move the locator along the desired dimension, as shown above. Additionally, the locator can be advanced in both dimensions
simultaneously using its <code class="docutils literal"><span class="pre">operator+=</span></code> and <code class="docutils literal"><span class="pre">operator-=</span></code>. Similar to image views, locators provide binary <code class="docutils literal"><span class="pre">operator()</span></code> which returns a reference to a pixel
with a relative offset to the current locator position. For example, <code class="docutils literal"><span class="pre">src_loc(0,1)</span></code> returns a reference to the neighbor below the current pixel.
Locators are very lightweight objects - in the above example the locator has a size of 8 bytes - it consists of a raw pointer to the current pixel and an int
indicating the number of bytes from one row to the next (which is the step when moving vertically). The call to <code class="docutils literal"><span class="pre">++src_loc.x()</span></code> corresponds to a single C pointer increment.
However, the example above performs more computations than necessary. The code <code class="docutils literal"><span class="pre">src_loc(0,1)</span></code> has to compute the offset of the pixel in two dimensions, which is slow.
Notice though that the offset of the two neighbors is the same, regardless of the pixel location. To improve the performance, GIL can cache and reuse this offset:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">y_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">gray8c_view_t</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">gray8s_view_t</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">gray8c_view_t</span><span class="o">::</span><span class="n">xy_locator</span> <span class="n">src_loc</span> <span class="o">=</span> <span class="n">src</span><span class="p">.</span><span class="n">xy_at</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">);</span>
<span class="n">gray8c_view_t</span><span class="o">::</span><span class="n">xy_locator</span><span class="o">::</span><span class="n">cached_location_t</span> <span class="n">above</span> <span class="o">=</span> <span class="n">src_loc</span><span class="p">.</span><span class="n">cache_location</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span>
<span class="n">gray8c_view_t</span><span class="o">::</span><span class="n">xy_locator</span><span class="o">::</span><span class="n">cached_location_t</span> <span class="n">below</span> <span class="o">=</span> <span class="n">src_loc</span><span class="p">.</span><span class="n">cache_location</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">y</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">y</span><span class="o">&lt;</span><span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">()</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="o">++</span><span class="n">y</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">gray8s_view_t</span><span class="o">::</span><span class="n">x_iterator</span> <span class="n">dst_it</span> <span class="o">=</span> <span class="n">dst</span><span class="p">.</span><span class="n">row_begin</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">x</span><span class="o">&lt;</span><span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">();</span> <span class="o">++</span><span class="n">x</span><span class="p">)</span>
<span class="p">{</span>
<span class="p">(</span><span class="o">*</span><span class="n">dst_it</span><span class="p">)</span> <span class="o">=</span> <span class="p">(</span><span class="n">src_loc</span><span class="p">[</span><span class="n">above</span><span class="p">]</span> <span class="o">-</span> <span class="n">src_loc</span><span class="p">[</span><span class="n">below</span><span class="p">])</span><span class="o">/</span><span class="mi">2</span><span class="p">;</span>
<span class="o">++</span><span class="n">dst_it</span><span class="p">;</span>
<span class="o">++</span><span class="n">src_loc</span><span class="p">.</span><span class="n">x</span><span class="p">();</span>
<span class="p">}</span>
<span class="n">src_loc</span><span class="o">+=</span><span class="n">point2</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="kt">ptrdiff_t</span><span class="o">&gt;</span><span class="p">(</span><span class="o">-</span><span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">(),</span><span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>In this example <code class="docutils literal"><span class="pre">src_loc[above]</span></code> corresponds to a fast pointer indexing operation and the code is efficient.</p>
</div>
<div class="section" id="creating-a-generic-version-of-gil-algorithms">
<h3><a class="toc-backref" href="#id6">Creating a Generic Version of GIL Algorithms</a></h3>
<p>Let us make our <code class="docutils literal"><span class="pre">x_gradient</span></code> more generic. It should work with any image views, as long as they have the same number of channels.
The gradient operation is to be computed for each channel independently. Here is how the new interface looks like:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstView</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">x_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">SrcView</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">DstView</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">gil_function_requires</span><span class="o">&lt;</span><span class="n">ImageViewConcept</span><span class="o">&lt;</span><span class="n">SrcView</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">();</span>
<span class="n">gil_function_requires</span><span class="o">&lt;</span><span class="n">MutableImageViewConcept</span><span class="o">&lt;</span><span class="n">DstView</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">();</span>
<span class="n">gil_function_requires</span><span class="o">&lt;</span><span class="n">ColorSpacesCompatibleConcept</span><span class="o">&lt;</span>
<span class="k">typename</span> <span class="n">color_space_type</span><span class="o">&lt;</span><span class="n">SrcView</span><span class="o">&gt;::</span><span class="n">type</span><span class="p">,</span>
<span class="k">typename</span> <span class="n">color_space_type</span><span class="o">&lt;</span><span class="n">DstView</span><span class="o">&gt;::</span><span class="n">type</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">();</span>
<span class="p">...</span> <span class="c1">// compute the gradient</span>
<span class="p">}</span>
</pre></div>
</div>
<p>The new algorithm now takes the types of the input and output image views as template parameters.
That allows using both built-in GIL image views, as well as any user-defined image view classes.
The first three lines are optional; they use <code class="docutils literal"><span class="pre">boost::concept_check</span></code> to ensure that the two arguments
are valid GIL image views, that the second one is mutable and that their color spaces are compatible (i.e. have the same set of channels).</p>
<p>GIL does not require using its own built-in constructs. You are free to use your own channels, color spaces, iterators, locators, views and images.
However, to work with the rest of GIL they have to satisfy a set of requirements; in other words, they have to e model the corresponding GIL _concept_.
GILs concepts are defined in the user guide.</p>
<p>One of the biggest drawbacks of using
templates and generic programming in C++ is that compile errors can be very difficult to comprehend.
This is a side-effect of the lack of early type checking - a generic argument may not satisfy the requirements of a function,
but the incompatibility may be triggered deep into a nested call, in code unfamiliar and hardly related to the problem.
GIL uses <code class="docutils literal"><span class="pre">boost::concept_check</span></code> to mitigate this problem. The above three lines of code check whether the
template parameters are valid models of their corresponding concepts.
If a model is incorrect, the compile error will be inside <code class="docutils literal"><span class="pre">gil_function_requires</span></code>, which is much closer to the problem
and easier to track. Furthermore, such checks get compiled out and have zero performance overhead. The disadvantage of using
concept checks is the sometimes severe impact they have on compile time. This is why GIL performs concept checks only in
debug mode, and only if <code class="docutils literal"><span class="pre">BOOST_GIL_USE_CONCEPT_CHECK</span></code> is defined (off by default).</p>
<p>The body of the generic function is very similar to that of the concrete one. The biggest difference is that we need to loop over the
channels of the pixel and compute the gradient for each channel:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstView</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">x_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">SrcView</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">DstView</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">y</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">y</span><span class="o">&lt;</span><span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">();</span> <span class="o">++</span><span class="n">y</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">typename</span> <span class="n">SrcView</span><span class="o">::</span><span class="n">x_iterator</span> <span class="n">src_it</span> <span class="o">=</span> <span class="n">src</span><span class="p">.</span><span class="n">row_begin</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
<span class="k">typename</span> <span class="n">DstView</span><span class="o">::</span><span class="n">x_iterator</span> <span class="n">dst_it</span> <span class="o">=</span> <span class="n">dst</span><span class="p">.</span><span class="n">row_begin</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">x</span><span class="o">&lt;</span><span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">()</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="o">++</span><span class="n">x</span><span class="p">)</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">c</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">c</span><span class="o">&lt;</span><span class="n">num_channels</span><span class="o">&lt;</span><span class="n">SrcView</span><span class="o">&gt;::</span><span class="n">value</span><span class="p">;</span> <span class="o">++</span><span class="n">c</span><span class="p">)</span>
<span class="n">dst_it</span><span class="p">[</span><span class="n">x</span><span class="p">][</span><span class="n">c</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">src_it</span><span class="p">[</span><span class="n">x</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">c</span><span class="p">]</span><span class="o">-</span> <span class="n">src_it</span><span class="p">[</span><span class="n">x</span><span class="o">+</span><span class="mi">1</span><span class="p">][</span><span class="n">c</span><span class="p">])</span><span class="o">/</span><span class="mi">2</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Having an explicit loop for each channel could be a performance problem. GIL allows us to abstract out such per-channel operations:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Out</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">halfdiff_cast_channels</span>
<span class="p">{</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="n">Out</span> <span class="k">operator</span><span class="p">()(</span><span class="k">const</span> <span class="n">T</span><span class="o">&amp;</span> <span class="n">in1</span><span class="p">,</span> <span class="k">const</span> <span class="n">T</span><span class="o">&amp;</span> <span class="n">in2</span><span class="p">)</span> <span class="k">const</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">Out</span><span class="p">((</span><span class="n">in1</span><span class="o">-</span><span class="n">in2</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstView</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">x_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">SrcView</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">DstView</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">typedef</span> <span class="k">typename</span> <span class="n">channel_type</span><span class="o">&lt;</span><span class="n">DstView</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">dst_channel_t</span><span class="p">;</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">y</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">y</span><span class="o">&lt;</span><span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">();</span> <span class="o">++</span><span class="n">y</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">typename</span> <span class="n">SrcView</span><span class="o">::</span><span class="n">x_iterator</span> <span class="n">src_it</span> <span class="o">=</span> <span class="n">src</span><span class="p">.</span><span class="n">row_begin</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
<span class="k">typename</span> <span class="n">DstView</span><span class="o">::</span><span class="n">x_iterator</span> <span class="n">dst_it</span> <span class="o">=</span> <span class="n">dst</span><span class="p">.</span><span class="n">row_begin</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">x</span><span class="o">&lt;</span><span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">()</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="o">++</span><span class="n">x</span><span class="p">)</span>
<span class="n">static_transform</span><span class="p">(</span><span class="n">src_it</span><span class="p">[</span><span class="n">x</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">src_it</span><span class="p">[</span><span class="n">x</span><span class="o">+</span><span class="mi">1</span><span class="p">],</span> <span class="n">dst_it</span><span class="p">[</span><span class="n">x</span><span class="p">],</span>
<span class="n">halfdiff_cast_channels</span><span class="o">&lt;</span><span class="n">dst_channel_t</span><span class="o">&gt;</span><span class="p">());</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p><code class="docutils literal"><span class="pre">static_transform</span></code> is an example of a channel-level GIL algorithm. Other such algorithms are <code class="docutils literal"><span class="pre">static_generate</span></code>, <code class="docutils literal"><span class="pre">static_fill</span></code> and <code class="docutils literal"><span class="pre">static_for_each</span></code>. They are the channel-level equivalents
of STLs <code class="docutils literal"><span class="pre">generate</span></code>, <code class="docutils literal"><span class="pre">transform</span></code>, <code class="docutils literal"><span class="pre">fill</span></code> and <code class="docutils literal"><span class="pre">for_each</span></code> respectively. GIL channel algorithms use static recursion to unroll the loops; they never loop over the channels explicitly.
Note that sometimes modern compilers (at least Visual Studio 8) already unroll channel-level loops, such as the one above. However, another advantage of using
GILs channel-level algorithms is that they pair the channels semantically, not based on their order in memory. For example, the above example will properly match an RGB source
with a BGR destination.</p>
<p>Here is how we can use our generic version with images of different types:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="c1">// Calling with 16-bit grayscale data</span>
<span class="kt">void</span> <span class="nf">XGradientGray16_Gray32</span><span class="p">(</span><span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">short</span><span class="o">*</span> <span class="n">src_pixels</span><span class="p">,</span> <span class="kt">ptrdiff_t</span> <span class="n">src_row_bytes</span><span class="p">,</span> <span class="kt">int</span> <span class="n">w</span><span class="p">,</span> <span class="kt">int</span> <span class="n">h</span><span class="p">,</span>
<span class="kt">signed</span> <span class="kt">int</span><span class="o">*</span> <span class="n">dst_pixels</span><span class="p">,</span> <span class="kt">ptrdiff_t</span> <span class="n">dst_row_bytes</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">gray16c_view_t</span> <span class="n">src</span><span class="o">=</span><span class="n">interleaved_view</span><span class="p">(</span><span class="n">w</span><span class="p">,</span><span class="n">h</span><span class="p">,(</span><span class="k">const</span> <span class="n">gray16_pixel_t</span><span class="o">*</span><span class="p">)</span><span class="n">src_pixels</span><span class="p">,</span><span class="n">src_row_bytes</span><span class="p">);</span>
<span class="n">gray32s_view_t</span> <span class="n">dst</span><span class="o">=</span><span class="n">interleaved_view</span><span class="p">(</span><span class="n">w</span><span class="p">,</span><span class="n">h</span><span class="p">,(</span> <span class="n">gray32s_pixel_t</span><span class="o">*</span><span class="p">)</span><span class="n">dst_pixels</span><span class="p">,</span><span class="n">dst_row_bytes</span><span class="p">);</span>
<span class="n">x_gradient</span><span class="p">(</span><span class="n">src</span><span class="p">,</span><span class="n">dst</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// Calling with 8-bit RGB data into 16-bit BGR</span>
<span class="kt">void</span> <span class="nf">XGradientRGB8_BGR16</span><span class="p">(</span><span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">char</span><span class="o">*</span> <span class="n">src_pixels</span><span class="p">,</span> <span class="kt">ptrdiff_t</span> <span class="n">src_row_bytes</span><span class="p">,</span> <span class="kt">int</span> <span class="n">w</span><span class="p">,</span> <span class="kt">int</span> <span class="n">h</span><span class="p">,</span>
<span class="kt">signed</span> <span class="kt">short</span><span class="o">*</span> <span class="n">dst_pixels</span><span class="p">,</span> <span class="kt">ptrdiff_t</span> <span class="n">dst_row_bytes</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">rgb8c_view_t</span> <span class="n">src</span> <span class="o">=</span> <span class="n">interleaved_view</span><span class="p">(</span><span class="n">w</span><span class="p">,</span><span class="n">h</span><span class="p">,(</span><span class="k">const</span> <span class="n">rgb8_pixel_t</span><span class="o">*</span><span class="p">)</span><span class="n">src_pixels</span><span class="p">,</span><span class="n">src_row_bytes</span><span class="p">);</span>
<span class="n">rgb16s_view_t</span> <span class="n">dst</span> <span class="o">=</span> <span class="n">interleaved_view</span><span class="p">(</span><span class="n">w</span><span class="p">,</span><span class="n">h</span><span class="p">,(</span> <span class="n">rgb16s_pixel_t</span><span class="o">*</span><span class="p">)</span><span class="n">dst_pixels</span><span class="p">,</span><span class="n">dst_row_bytes</span><span class="p">);</span>
<span class="n">x_gradient</span><span class="p">(</span><span class="n">src</span><span class="p">,</span><span class="n">dst</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// Either or both the source and the destination could be planar - the gradient code does not change</span>
<span class="kt">void</span> <span class="nf">XGradientPlanarRGB8_RGB32</span><span class="p">(</span>
<span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">short</span><span class="o">*</span> <span class="n">src_r</span><span class="p">,</span> <span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">short</span><span class="o">*</span> <span class="n">src_g</span><span class="p">,</span> <span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">short</span><span class="o">*</span> <span class="n">src_b</span><span class="p">,</span>
<span class="kt">ptrdiff_t</span> <span class="n">src_row_bytes</span><span class="p">,</span> <span class="kt">int</span> <span class="n">w</span><span class="p">,</span> <span class="kt">int</span> <span class="n">h</span><span class="p">,</span>
<span class="kt">signed</span> <span class="kt">int</span><span class="o">*</span> <span class="n">dst_pixels</span><span class="p">,</span> <span class="kt">ptrdiff_t</span> <span class="n">dst_row_bytes</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">rgb16c_planar_view_t</span> <span class="n">src</span><span class="o">=</span><span class="n">planar_rgb_view</span> <span class="p">(</span><span class="n">w</span><span class="p">,</span><span class="n">h</span><span class="p">,</span> <span class="n">src_r</span><span class="p">,</span><span class="n">src_g</span><span class="p">,</span><span class="n">src_b</span><span class="p">,</span> <span class="n">src_row_bytes</span><span class="p">);</span>
<span class="n">rgb32s_view_t</span> <span class="n">dst</span><span class="o">=</span><span class="n">interleaved_view</span><span class="p">(</span><span class="n">w</span><span class="p">,</span><span class="n">h</span><span class="p">,(</span><span class="n">rgb32s_pixel_t</span><span class="o">*</span><span class="p">)</span><span class="n">dst_pixels</span><span class="p">,</span><span class="n">dst_row_bytes</span><span class="p">);</span>
<span class="n">x_gradient</span><span class="p">(</span><span class="n">src</span><span class="p">,</span><span class="n">dst</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>As these examples illustrate, both the source and the destination can be interleaved or planar, of any channel depth (assuming the destination channel is
assignable to the source), and of any compatible color spaces.</p>
<p>GIL 2.1 can also natively represent images whose channels are not byte-aligned, such as 6-bit RGB222 image or a 1-bit Gray1 image.
GIL algorithms apply to these images natively. See the design guide or sample files for more on using such images.</p>
</div>
<div class="section" id="image-view-transformations">
<h3><a class="toc-backref" href="#id7">Image View Transformations</a></h3>
<p>One way to compute the y-gradient is to rotate the image by 90 degrees, compute the x-gradient and rotate the result back. Here is how to do this in GIL:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstView</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">y_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">SrcView</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">DstView</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">x_gradient</span><span class="p">(</span><span class="n">rotated90ccw_view</span><span class="p">(</span><span class="n">src</span><span class="p">),</span> <span class="n">rotated90ccw_view</span><span class="p">(</span><span class="n">dst</span><span class="p">));</span>
<span class="p">}</span>
</pre></div>
</div>
<p><code class="docutils literal"><span class="pre">rotated90ccw_view</span></code> takes an image view and returns an image view representing 90-degrees counter-clockwise rotation of its input. It is an example of a GIL view transformation function. GIL provides
a variety of transformation functions that can perform any axis-aligned rotation, transpose the view, flip it vertically or horizontally, extract a rectangular subimage,
perform color conversion, subsample view, etc. The view transformation functions are fast and shallow - they dont copy the pixels, they just change the “coordinate system” of
accessing the pixels. <code class="docutils literal"><span class="pre">rotated90cw_view</span></code>, for example, returns a view whose horizontal iterators are the vertical iterators of the original view. The above code to compute <code class="docutils literal"><span class="pre">y_gradient</span></code>
is slow because of the memory access pattern; using <code class="docutils literal"><span class="pre">rotated90cw_view</span></code> does not make it any slower.</p>
<p>Another example: suppose we want to compute the gradient of the N-th channel of a color image. Here is how to do that:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstView</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">nth_channel_x_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">SrcView</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="k">const</span> <span class="n">DstView</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">x_gradient</span><span class="p">(</span><span class="n">nth_channel_view</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">n</span><span class="p">),</span> <span class="n">dst</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p><code class="docutils literal"><span class="pre">nth_channel_view</span></code> is a view transformation function that takes any view and returns a single-channel (grayscale) view of its N-th channel.
For interleaved RGB view, for example, the returned view is a step view - a view whose horizontal iterator skips over two channels when incremented.
If applied on a planar RGB view, the returned type is a simple grayscale view whose horizontal iterator is a C pointer.
Image view transformation functions can be piped together. For example, to compute the y gradient of the second channel of the even pixels in the view, use:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">y_gradient</span><span class="p">(</span><span class="n">subsampled_view</span><span class="p">(</span><span class="n">nth_channel_view</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">dst</span><span class="p">);</span>
</pre></div>
</div>
<p>GIL can sometimes simplify piped views. For example, two nested subsampled views (views that skip over pixels in X and in Y) can be represented as a single subsampled view whose step
is the product of the steps of the two views.</p>
</div>
<div class="section" id="d-pixel-iterators">
<h3><a class="toc-backref" href="#id8">1D pixel iterators</a></h3>
<p>Lets go back to <code class="docutils literal"><span class="pre">x_gradient</span></code> one more time.
Many image view algorithms apply the same operation for each pixel and GIL provides an abstraction to handle them. However, our algorithm has an unusual access pattern, as it skips the
first and the last column. It would be nice and instructional to see how we can rewrite it in canonical form. The way to do that in GIL is to write a version that works for every pixel, but
apply it only on the subimage that excludes the first and last column:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">x_gradient_unguarded</span><span class="p">(</span><span class="k">const</span> <span class="n">gray8c_view_t</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">gray8s_view_t</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">y</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">y</span><span class="o">&lt;</span><span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">();</span> <span class="o">++</span><span class="n">y</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">gray8c_view_t</span><span class="o">::</span><span class="n">x_iterator</span> <span class="n">src_it</span> <span class="o">=</span> <span class="n">src</span><span class="p">.</span><span class="n">row_begin</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
<span class="n">gray8s_view_t</span><span class="o">::</span><span class="n">x_iterator</span> <span class="n">dst_it</span> <span class="o">=</span> <span class="n">dst</span><span class="p">.</span><span class="n">row_begin</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">x</span><span class="o">&lt;</span><span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">();</span> <span class="o">++</span><span class="n">x</span><span class="p">)</span>
<span class="n">dst_it</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">src_it</span><span class="p">[</span><span class="n">x</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">src_it</span><span class="p">[</span><span class="n">x</span><span class="o">+</span><span class="mi">1</span><span class="p">])</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="nf">x_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">gray8c_view_t</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">gray8s_view_t</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">assert</span><span class="p">(</span><span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">()</span><span class="o">&gt;=</span><span class="mi">2</span><span class="p">);</span>
<span class="n">x_gradient_unguarded</span><span class="p">(</span><span class="n">subimage_view</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">()</span><span class="o">-</span><span class="mi">2</span><span class="p">,</span> <span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">()),</span>
<span class="n">subimage_view</span><span class="p">(</span><span class="n">dst</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">()</span><span class="o">-</span><span class="mi">2</span><span class="p">,</span> <span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">()));</span>
<span class="p">}</span>
</pre></div>
</div>
<p><code class="docutils literal"><span class="pre">subimage_view</span></code> is another example of a GIL view transformation function. It takes a source view and a rectangular region (in this case, defined as x_min,y_min,width,height) and
returns a view operating on that region of the source view. The above implementation has no measurable performance degradation from the version that operates on the original views.</p>
<p>Now that <code class="docutils literal"><span class="pre">x_gradient_unguarded</span></code> operates on every pixel, we can rewrite it more compactly:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">x_gradient_unguarded</span><span class="p">(</span><span class="k">const</span> <span class="n">gray8c_view_t</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">gray8s_view_t</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">gray8c_view_t</span><span class="o">::</span><span class="n">iterator</span> <span class="n">src_it</span> <span class="o">=</span> <span class="n">src</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span>
<span class="k">for</span> <span class="p">(</span><span class="n">gray8s_view_t</span><span class="o">::</span><span class="n">iterator</span> <span class="n">dst_it</span> <span class="o">=</span> <span class="n">dst</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span> <span class="n">dst_it</span><span class="o">!=</span><span class="n">dst</span><span class="p">.</span><span class="n">end</span><span class="p">();</span> <span class="o">++</span><span class="n">dst_it</span><span class="p">,</span> <span class="o">++</span><span class="n">src_it</span><span class="p">)</span>
<span class="o">*</span><span class="n">dst_it</span> <span class="o">=</span> <span class="p">(</span><span class="n">src_it</span><span class="p">.</span><span class="n">x</span><span class="p">()[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">src_it</span><span class="p">.</span><span class="n">x</span><span class="p">()[</span><span class="mi">1</span><span class="p">])</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>GIL image views provide <code class="docutils literal"><span class="pre">begin()</span></code> and <code class="docutils literal"><span class="pre">end()</span></code> methods that return one dimensional pixel iterators which iterate over each pixel in the view,
left to right and top to bottom. They do a proper “carriage return” - they skip any unused bytes at the end of a row. As such, they are slightly suboptimal, because they need to keep
track of their current position with respect to the end of the row. Their increment operator performs one extra check (are we at the end of the row?), a check that is avoided if two
nested loops are used instead. These iterators have a method <code class="docutils literal"><span class="pre">x()</span></code> which returns the more lightweight horizontal iterator that we used previously. Horizontal iterators have no
notion of the end of rows. In this case, the horizontal iterators are raw C pointers. In our example, we must use the horizontal iterators to access the two neighbors properly, since they
could reside outside the image view.</p>
</div>
<div class="section" id="stl-equivalent-algorithms">
<h3><a class="toc-backref" href="#id9">STL Equivalent Algorithms</a></h3>
<p>GIL provides STL equivalents of many algorithms. For example, <code class="docutils literal"><span class="pre">std::transform</span></code> is an STL algorithm that sets each element in a destination range the result of a generic function taking the
corresponding element of the source range. In our example, we want to assign to each destination pixel the value of the half-difference of the horizontal neighbors of the corresponding source pixel.
If we abstract that operation in a function object, we can use GILs <code class="docutils literal"><span class="pre">transform_pixel_positions</span></code> to do that:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">half_x_difference</span>
<span class="p">{</span>
<span class="kt">int</span> <span class="k">operator</span><span class="p">()(</span><span class="k">const</span> <span class="n">gray8c_loc_t</span><span class="o">&amp;</span> <span class="n">src_loc</span><span class="p">)</span> <span class="k">const</span>
<span class="p">{</span>
<span class="k">return</span> <span class="p">(</span><span class="n">src_loc</span><span class="p">.</span><span class="n">x</span><span class="p">()[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">src_loc</span><span class="p">.</span><span class="n">x</span><span class="p">()[</span><span class="mi">1</span><span class="p">])</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">};</span>
<span class="kt">void</span> <span class="nf">x_gradient_unguarded</span><span class="p">(</span><span class="k">const</span> <span class="n">gray8c_view_t</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">gray8s_view_t</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">transform_pixel_positions</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">dst</span><span class="p">,</span> <span class="n">half_x_difference</span><span class="p">());</span>
<span class="p">}</span>
</pre></div>
</div>
<p>GIL provides the algorithms <code class="docutils literal"><span class="pre">for_each_pixel</span></code> and <code class="docutils literal"><span class="pre">transform_pixels</span></code> which are image view equivalents of STLs <code class="docutils literal"><span class="pre">std::for_each</span></code> and <code class="docutils literal"><span class="pre">std::transform</span></code>. It also provides
<code class="docutils literal"><span class="pre">for_each_pixel_position</span></code> and <code class="docutils literal"><span class="pre">transform_pixel_positions</span></code>, which instead of references to pixels, pass to the generic function pixel locators. This allows for more powerful functions
that can use the pixel neighbors through the passed locators.
GIL algorithms iterate through the pixels using the more efficient two nested loops (as opposed to the single loop using 1-D iterators)</p>
</div>
<div class="section" id="color-conversion">
<h3><a class="toc-backref" href="#id10">Color Conversion</a></h3>
<p>Instead of computing the gradient of each color plane of an image, we often want to compute the gradient of the luminosity. In other words, we want to convert the
color image to grayscale and compute the gradient of the result. Here how to compute the luminosity gradient of a 32-bit float RGB image:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">x_gradient_rgb_luminosity</span><span class="p">(</span><span class="k">const</span> <span class="n">rgb32fc_view_t</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">gray8s_view_t</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">x_gradient</span><span class="p">(</span><span class="n">color_converted_view</span><span class="o">&lt;</span><span class="n">gray8_pixel_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">src</span><span class="p">),</span> <span class="n">dst</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p><code class="docutils literal"><span class="pre">color_converted_view</span></code> is a GIL view transformation function that takes any image view and returns a view in a target color space and channel depth (specified
as template parameters). In our example, it constructs an 8-bit integer grayscale view over 32-bit float RGB pixels. Like all other view transformation functions, <code class="docutils literal"><span class="pre">color_converted_view</span></code> is very
fast and shallow. It doesnt copy the data or perform any color conversion. Instead it returns a view that performs color conversion every time its pixels are accessed.</p>
<p>In the generic version of this algorithm we might like to convert the color space to grayscale, but keep the channel depth the same. We do that by constructing the
type of a GIL grayscale pixel with the same channel as the source, and color convert to that pixel type:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstView</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">x_luminosity_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">SrcView</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">DstView</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">typedef</span> <span class="n">pixel</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">channel_type</span><span class="o">&lt;</span><span class="n">SrcView</span><span class="o">&gt;::</span><span class="n">type</span><span class="p">,</span> <span class="n">gray_layout_t</span><span class="o">&gt;</span> <span class="n">gray_pixel_t</span><span class="p">;</span>
<span class="n">x_gradient</span><span class="p">(</span><span class="n">color_converted_view</span><span class="o">&lt;</span><span class="n">gray_pixel_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">src</span><span class="p">),</span> <span class="n">dst</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>When the destination color space and channel type happens to be the same as the source one, color conversion is unnecessary. GIL detects this case and avoids calling the color conversion
code at all - i.e. <code class="docutils literal"><span class="pre">color_converted_view</span></code> returns back the source view unchanged.</p>
</div>
<div class="section" id="image">
<h3><a class="toc-backref" href="#id11">Image</a></h3>
<p>The above example has a performance problem - <code class="docutils literal"><span class="pre">x_gradient</span></code> dereferences most source pixels twice, which will cause the above code to perform color conversion twice.
Sometimes it may be more efficient to copy the color converted image into a temporary buffer and use it to compute the gradient - that way color conversion is invoked once per pixel.
Using our non-generic version we can do it like this:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">x_luminosity_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">rgb32fc_view_t</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">gray8s_view_t</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">gray8_image_t</span> <span class="n">ccv_image</span><span class="p">(</span><span class="n">src</span><span class="p">.</span><span class="n">dimensions</span><span class="p">());</span>
<span class="n">copy_pixels</span><span class="p">(</span><span class="n">color_converted_view</span><span class="o">&lt;</span><span class="n">gray8_pixel_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">src</span><span class="p">),</span> <span class="n">view</span><span class="p">(</span><span class="n">ccv_image</span><span class="p">));</span>
<span class="n">x_gradient</span><span class="p">(</span><span class="n">const_view</span><span class="p">(</span><span class="n">ccv_image</span><span class="p">),</span> <span class="n">dst</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>First we construct an 8-bit grayscale image with the same dimensions as our source. Then we copy a color-converted view of the source into the temporary image.
Finally we use a read-only view of the temporary image in our <code class="docutils literal"><span class="pre">x_gradient</span> <span class="pre">algorithm</span></code>. As the example shows, GIL provides global functions <code class="docutils literal"><span class="pre">view</span></code> and <code class="docutils literal"><span class="pre">const_view</span></code>
that take an image and return a mutable or an immutable view of its pixels.</p>
<p>Creating a generic version of the above is a bit trickier:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstView</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">x_luminosity_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">SrcView</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">DstView</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">typedef</span> <span class="k">typename</span> <span class="n">channel_type</span><span class="o">&lt;</span><span class="n">DstView</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">d_channel_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="k">typename</span> <span class="n">channel_convert_to_unsigned</span><span class="o">&lt;</span><span class="n">d_channel_t</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">channel_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">pixel</span><span class="o">&lt;</span><span class="n">channel_t</span><span class="p">,</span> <span class="n">gray_layout_t</span><span class="o">&gt;</span> <span class="n">gray_pixel_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">image</span><span class="o">&lt;</span><span class="n">gray_pixel_t</span><span class="p">,</span> <span class="nb">false</span><span class="o">&gt;</span> <span class="n">gray_image_t</span><span class="p">;</span>
<span class="n">gray_image_t</span> <span class="nf">ccv_image</span><span class="p">(</span><span class="n">src</span><span class="p">.</span><span class="n">dimensions</span><span class="p">());</span>
<span class="n">copy_pixels</span><span class="p">(</span><span class="n">color_converted_view</span><span class="o">&lt;</span><span class="n">gray_pixel_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">src</span><span class="p">),</span> <span class="n">view</span><span class="p">(</span><span class="n">ccv_image</span><span class="p">));</span>
<span class="n">x_gradient</span><span class="p">(</span><span class="n">const_view</span><span class="p">(</span><span class="n">ccv_image</span><span class="p">),</span> <span class="n">dst</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>First we use the <code class="docutils literal"><span class="pre">channel_type</span></code> metafunction to get the channel type of the destination view. A metafunction is a function operating on types. In GIL metafunctions
are structs which take their parameters as template parameters and return their result in a nested typedef called <code class="docutils literal"><span class="pre">type</span></code>. In this case, <code class="docutils literal"><span class="pre">channel_type</span></code> is
a unary metafunction which in this example is called with the type of an image view and returns the type of the channel associated with that image view.</p>
<p>GIL constructs that have an associated pixel type, such as pixels, pixel iterators, locators, views and images, all model <code class="docutils literal"><span class="pre">PixelBasedConcept</span></code>, which means
that they provide a set of metafunctions to query the pixel properties, such as <code class="docutils literal"><span class="pre">channel_type</span></code>, <code class="docutils literal"><span class="pre">color_space_type</span></code>, <code class="docutils literal"><span class="pre">channel_mapping_type</span></code>, and <code class="docutils literal"><span class="pre">num_channels</span></code>.</p>
<p>After we get the channel type of the destination view, we use another metafunction to remove its sign (if it is a signed integral type) and then use it
to generate the type of a grayscale pixel. From the pixel type we create the image type. GILs image class is templated over the pixel type and a boolean
indicating whether the image should be planar or interleaved.
Single-channel (grayscale) images in GIL must always be interleaved. There are multiple ways of constructing types in GIL. Instead of instantiating the classes
directly we could have used type factory metafunctions. The following code is equivalent:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstView</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">x_luminosity_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">SrcView</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">DstView</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">typedef</span> <span class="k">typename</span> <span class="n">channel_type</span><span class="o">&lt;</span><span class="n">DstView</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">d_channel_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="k">typename</span> <span class="n">channel_convert_to_unsigned</span><span class="o">&lt;</span><span class="n">d_channel_t</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">channel_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="k">typename</span> <span class="n">image_type</span><span class="o">&lt;</span><span class="n">channel_t</span><span class="p">,</span> <span class="n">gray_layout_t</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">gray_image_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="k">typename</span> <span class="n">gray_image_t</span><span class="o">::</span><span class="n">value_type</span> <span class="n">gray_pixel_t</span><span class="p">;</span>
<span class="n">gray_image_t</span> <span class="nf">ccv_image</span><span class="p">(</span><span class="n">src</span><span class="p">.</span><span class="n">dimensions</span><span class="p">());</span>
<span class="n">copy_and_convert_pixels</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">view</span><span class="p">(</span><span class="n">ccv_image</span><span class="p">));</span>
<span class="n">x_gradient</span><span class="p">(</span><span class="n">const_view</span><span class="p">(</span><span class="n">ccv_image</span><span class="p">),</span> <span class="n">dst</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>GIL provides a set of metafunctions that generate GIL types - <code class="docutils literal"><span class="pre">image_type</span></code> is one such meta-function that constructs the type of an image from
a given channel type, color layout, and planar/interleaved option (the default is interleaved). There are also similar meta-functions to
construct the types of pixel references, iterators, locators and image views. GIL also has metafunctions <code class="docutils literal"><span class="pre">derived_pixel_reference_type</span></code>, <code class="docutils literal"><span class="pre">derived_iterator_type</span></code>,
<code class="docutils literal"><span class="pre">derived_view_type</span></code> and <code class="docutils literal"><span class="pre">derived_image_type</span></code> that construct the type of a GIL construct from a given source one by changing one or more properties of
the type and keeping the rest.</p>
<p>From the image type we can use the nested typedef <code class="docutils literal"><span class="pre">value_type</span></code> to obtain the type of a pixel. GIL images, image views and locators have nested typedefs
<code class="docutils literal"><span class="pre">value_type</span></code> and <code class="docutils literal"><span class="pre">reference</span></code> to obtain the type of the pixel and a reference to the pixel. If you have a pixel iterator, you can get these types from its
<code class="docutils literal"><span class="pre">iterator_traits</span></code>. Note also the algorithm <code class="docutils literal"><span class="pre">copy_and_convert_pixels</span></code>, which is an abbreviated version of <code class="docutils literal"><span class="pre">copy_pixels</span></code> with a color converted source view.</p>
</div>
<div class="section" id="virtual-image-views">
<h3><a class="toc-backref" href="#id12">Virtual Image Views</a></h3>
<p>So far we have been dealing with images that have pixels stored in memory. GIL allows you to create an image view of an arbitrary image, including
a synthetic function. To demonstrate this, let us create a view of the Mandelbrot set.
First, we need to create a function object that computes the value of the Mandelbrot set at a given location (x,y) in the image:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="c1">// models PixelDereferenceAdaptorConcept</span>
<span class="k">struct</span> <span class="n">mandelbrot_fn</span>
<span class="p">{</span>
<span class="k">typedef</span> <span class="n">point2</span><span class="o">&lt;</span><span class="kt">ptrdiff_t</span><span class="o">&gt;</span> <span class="n">point_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">mandelbrot_fn</span> <span class="n">const_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">gray8_pixel_t</span> <span class="n">value_type</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">value_type</span> <span class="n">reference</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">value_type</span> <span class="n">const_reference</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">point_t</span> <span class="n">argument_type</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">reference</span> <span class="n">result_type</span><span class="p">;</span>
<span class="n">BOOST_STATIC_CONSTANT</span><span class="p">(</span><span class="kt">bool</span><span class="p">,</span> <span class="n">is_mutable</span><span class="o">=</span><span class="nb">false</span><span class="p">);</span>
<span class="n">mandelbrot_fn</span><span class="p">()</span> <span class="p">{}</span>
<span class="n">mandelbrot_fn</span><span class="p">(</span><span class="k">const</span> <span class="n">point_t</span><span class="o">&amp;</span> <span class="n">sz</span><span class="p">)</span> <span class="o">:</span> <span class="n">_img_size</span><span class="p">(</span><span class="n">sz</span><span class="p">)</span> <span class="p">{}</span>
<span class="n">result_type</span> <span class="k">operator</span><span class="p">()(</span><span class="k">const</span> <span class="n">point_t</span><span class="o">&amp;</span> <span class="n">p</span><span class="p">)</span> <span class="k">const</span>
<span class="p">{</span>
<span class="c1">// normalize the coords to (-2..1, -1.5..1.5)</span>
<span class="kt">double</span> <span class="n">t</span><span class="o">=</span><span class="n">get_num_iter</span><span class="p">(</span><span class="n">point2</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">x</span><span class="o">/</span><span class="p">(</span><span class="kt">double</span><span class="p">)</span><span class="n">_img_size</span><span class="p">.</span><span class="n">x</span><span class="o">*</span><span class="mi">3</span><span class="o">-</span><span class="mi">2</span><span class="p">,</span> <span class="n">p</span><span class="p">.</span><span class="n">y</span><span class="o">/</span><span class="p">(</span><span class="kt">double</span><span class="p">)</span><span class="n">_img_size</span><span class="p">.</span><span class="n">y</span><span class="o">*</span><span class="mi">3</span><span class="o">-</span><span class="mf">1.5f</span><span class="p">));</span>
<span class="k">return</span> <span class="nf">value_type</span><span class="p">((</span><span class="n">bits8</span><span class="p">)(</span><span class="n">pow</span><span class="p">(</span><span class="n">t</span><span class="p">,</span><span class="mf">0.2</span><span class="p">)</span><span class="o">*</span><span class="mi">255</span><span class="p">));</span> <span class="c1">// raise to power suitable for viewing</span>
<span class="p">}</span>
<span class="k">private</span><span class="o">:</span>
<span class="n">point_t</span> <span class="n">_img_size</span><span class="p">;</span>
<span class="kt">double</span> <span class="nf">get_num_iter</span><span class="p">(</span><span class="k">const</span> <span class="n">point2</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;&amp;</span> <span class="n">p</span><span class="p">)</span> <span class="k">const</span>
<span class="p">{</span>
<span class="n">point2</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;</span> <span class="n">Z</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="mi">100</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="c1">// 100 iterations</span>
<span class="p">{</span>
<span class="n">Z</span> <span class="o">=</span> <span class="n">point2</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;</span><span class="p">(</span><span class="n">Z</span><span class="p">.</span><span class="n">x</span><span class="o">*</span><span class="n">Z</span><span class="p">.</span><span class="n">x</span> <span class="o">-</span> <span class="n">Z</span><span class="p">.</span><span class="n">y</span><span class="o">*</span><span class="n">Z</span><span class="p">.</span><span class="n">y</span> <span class="o">+</span> <span class="n">p</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="mi">2</span><span class="o">*</span><span class="n">Z</span><span class="p">.</span><span class="n">x</span><span class="o">*</span><span class="n">Z</span><span class="p">.</span><span class="n">y</span> <span class="o">+</span> <span class="n">p</span><span class="p">.</span><span class="n">y</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">Z</span><span class="p">.</span><span class="n">x</span><span class="o">*</span><span class="n">Z</span><span class="p">.</span><span class="n">x</span> <span class="o">+</span> <span class="n">Z</span><span class="p">.</span><span class="n">y</span><span class="o">*</span><span class="n">Z</span><span class="p">.</span><span class="n">y</span> <span class="o">&gt;</span> <span class="mi">4</span><span class="p">)</span>
<span class="k">return</span> <span class="n">i</span><span class="o">/</span><span class="p">(</span><span class="kt">double</span><span class="p">)</span><span class="mi">100</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">};</span>
</pre></div>
</div>
<p>We can now use GILs <code class="docutils literal"><span class="pre">virtual_2d_locator</span></code> with this function object to construct a Mandelbrot view of size 200x200 pixels:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="k">typedef</span> <span class="n">mandelbrot_fn</span><span class="o">::</span><span class="n">point_t</span> <span class="n">point_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">virtual_2d_locator</span><span class="o">&lt;</span><span class="n">mandelbrot_fn</span><span class="p">,</span><span class="nb">false</span><span class="o">&gt;</span> <span class="n">locator_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">image_view</span><span class="o">&lt;</span><span class="n">locator_t</span><span class="o">&gt;</span> <span class="n">my_virt_view_t</span><span class="p">;</span>
<span class="n">point_t</span> <span class="nf">dims</span><span class="p">(</span><span class="mi">200</span><span class="p">,</span><span class="mi">200</span><span class="p">);</span>
<span class="c1">// Construct a Mandelbrot view with a locator, taking top-left corner (0,0) and step (1,1)</span>
<span class="n">my_virt_view_t</span> <span class="nf">mandel</span><span class="p">(</span><span class="n">dims</span><span class="p">,</span> <span class="n">locator_t</span><span class="p">(</span><span class="n">point_t</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">),</span> <span class="n">point_t</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">),</span> <span class="n">mandelbrot_fn</span><span class="p">(</span><span class="n">dims</span><span class="p">)));</span>
</pre></div>
</div>
<p>We can treat the synthetic view just like a real one. For example, lets invoke our <code class="docutils literal"><span class="pre">x_gradient</span></code> algorithm to compute
the gradient of the 90-degree rotated view of the Mandelbrot set and save the original and the result:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">gray8s_image_t</span> <span class="nf">img</span><span class="p">(</span><span class="n">dims</span><span class="p">);</span>
<span class="n">x_gradient</span><span class="p">(</span><span class="n">rotated90cw_view</span><span class="p">(</span><span class="n">mandel</span><span class="p">),</span> <span class="n">view</span><span class="p">(</span><span class="n">img</span><span class="p">));</span>
<span class="c1">// Save the Mandelbrot set and its 90-degree rotated gradient (jpeg cannot save signed char; must convert to unsigned char)</span>
<span class="n">jpeg_write_view</span><span class="p">(</span><span class="s">&quot;mandel.jpg&quot;</span><span class="p">,</span><span class="n">mandel</span><span class="p">);</span>
<span class="n">jpeg_write_view</span><span class="p">(</span><span class="s">&quot;mandel_grad.jpg&quot;</span><span class="p">,</span><span class="n">color_converted_view</span><span class="o">&lt;</span><span class="n">gray8_pixel_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">const_view</span><span class="p">(</span><span class="n">img</span><span class="p">)));</span>
</pre></div>
</div>
<p>Here is what the two files look like:</p>
<img alt="_images/mandel.jpg" src="_images/mandel.jpg" />
</div>
<div class="section" id="run-time-specified-images-and-image-views">
<h3><a class="toc-backref" href="#id13">Run-Time Specified Images and Image Views</a></h3>
<p>So far we have created a generic function that computes the image gradient of a templated image view.
Sometimes, however, the properties of an image view, such as its color space and channel depth, may not be available at compile time.
GILs <code class="docutils literal"><span class="pre">dynamic_image</span></code> extension allows for working with GIL constructs that are specified at run time, also called _variants_. GIL provides
models of a run-time instantiated image, <code class="docutils literal"><span class="pre">any_image</span></code>, and a run-time instantiated image view, <code class="docutils literal"><span class="pre">any_image_view</span></code>. The mechanisms are in place to create
other variants, such as <code class="docutils literal"><span class="pre">any_pixel</span></code>, <code class="docutils literal"><span class="pre">any_pixel_iterator</span></code>, etc.
Most of GILs algorithms and all of the view transformation functions also work with run-time instantiated image views and binary algorithms, such
as <code class="docutils literal"><span class="pre">copy_pixels</span></code> can have either or both arguments be variants.</p>
<p>Lets make our <code class="docutils literal"><span class="pre">x_luminosity_gradient</span></code> algorithm take a variant image view. For simplicity, lets assume that only the source view can be a variant.
(As an example of using multiple variants, see GILs image view algorithm overloads taking multiple variants.)</p>
<p>First, we need to make a function object that contains the templated destination view and has an application operator taking a templated source view:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf">&lt;boost/gil/extension/dynamic_image/dynamic_image_all.hpp&gt;</span><span class="cp"></span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">DstView</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">x_gradient_obj</span>
<span class="p">{</span>
<span class="k">typedef</span> <span class="kt">void</span> <span class="n">result_type</span><span class="p">;</span> <span class="c1">// required typedef</span>
<span class="k">const</span> <span class="n">DstView</span><span class="o">&amp;</span> <span class="n">_dst</span><span class="p">;</span>
<span class="n">x_gradient_obj</span><span class="p">(</span><span class="k">const</span> <span class="n">DstView</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span> <span class="o">:</span> <span class="n">_dst</span><span class="p">(</span><span class="n">dst</span><span class="p">)</span> <span class="p">{}</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="k">operator</span><span class="p">()(</span><span class="k">const</span> <span class="n">SrcView</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> <span class="n">x_luminosity_gradient</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">_dst</span><span class="p">);</span> <span class="p">}</span>
<span class="p">};</span>
</pre></div>
</div>
<p>The second step is to provide an overload of <code class="docutils literal"><span class="pre">x_luminosity_gradient</span></code> that takes image view variant and calls GILs <code class="docutils literal"><span class="pre">apply_operation</span></code>
passing it the function object:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcViews</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstView</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">x_luminosity_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">any_image_view</span><span class="o">&lt;</span><span class="n">SrcViews</span><span class="o">&gt;&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">DstView</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">apply_operation</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">x_gradient_obj</span><span class="o">&lt;</span><span class="n">DstView</span><span class="o">&gt;</span><span class="p">(</span><span class="n">dst</span><span class="p">));</span>
<span class="p">}</span>
</pre></div>
</div>
<p><code class="docutils literal"><span class="pre">any_image_view&lt;SrcViews&gt;</span></code> is the image view variant. It is templated over <code class="docutils literal"><span class="pre">SrcViews</span></code>, an enumeration of all possible view types the variant can take.
<code class="docutils literal"><span class="pre">src</span></code> contains inside an index of the currently instantiated type, as well as a block of memory containing the instance.
<code class="docutils literal"><span class="pre">apply_operation</span></code> goes through a switch statement over the index, each case of which casts the memory to the correct view type and invokes the
function object with it. Invoking an algorithm on a variant has the overhead of one switch statement. Algorithms that perform an operation for
each pixel in an image view have practically no performance degradation when used with a variant.</p>
<p>Here is how we can construct a variant and invoke the algorithm:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf">&lt;boost/mpl/vector.hpp&gt;</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">&lt;boost/gil/extension/io/jpeg_dynamic_io.hpp&gt;</span><span class="cp"></span>
<span class="k">typedef</span> <span class="n">mpl</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">gray8_image_t</span><span class="p">,</span> <span class="n">gray16_image_t</span><span class="p">,</span> <span class="n">rgb8_image_t</span><span class="p">,</span> <span class="n">rgb16_image_t</span><span class="o">&gt;</span> <span class="n">my_img_types</span><span class="p">;</span>
<span class="n">any_image</span><span class="o">&lt;</span><span class="n">my_img_types</span><span class="o">&gt;</span> <span class="n">runtime_image</span><span class="p">;</span>
<span class="n">jpeg_read_image</span><span class="p">(</span><span class="s">&quot;input.jpg&quot;</span><span class="p">,</span> <span class="n">runtime_image</span><span class="p">);</span>
<span class="n">gray8s_image_t</span> <span class="nf">gradient</span><span class="p">(</span><span class="n">runtime_image</span><span class="p">.</span><span class="n">dimensions</span><span class="p">());</span>
<span class="n">x_luminosity_gradient</span><span class="p">(</span><span class="n">const_view</span><span class="p">(</span><span class="n">runtime_image</span><span class="p">),</span> <span class="n">view</span><span class="p">(</span><span class="n">gradient</span><span class="p">));</span>
<span class="n">jpeg_write_view</span><span class="p">(</span><span class="s">&quot;x_gradient.jpg&quot;</span><span class="p">,</span> <span class="n">color_converted_view</span><span class="o">&lt;</span><span class="n">gray8_pixel_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">const_view</span><span class="p">(</span><span class="n">gradient</span><span class="p">)));</span>
</pre></div>
</div>
<p>In this example, we create an image variant that could be 8-bit or 16-bit RGB or grayscale image. We then use GILs I/O extension to load the image from file
in its native color space and channel depth. If none of the allowed image types matches the image on disk, an exception will be thrown.
We then construct a 8 bit signed (i.e. <code class="docutils literal"><span class="pre">char</span></code>) image to store the gradient and invoke <code class="docutils literal"><span class="pre">x_gradient</span></code> on it. Finally we save the result into another file.
We save the view converted to 8-bit unsigned, because JPEG I/O does not support signed char.</p>
<p>Note how free functions and methods such as <code class="docutils literal"><span class="pre">jpeg_read_image</span></code>, <code class="docutils literal"><span class="pre">dimensions</span></code>, <code class="docutils literal"><span class="pre">view</span></code> and <code class="docutils literal"><span class="pre">const_view</span></code> work on both templated and variant types.
For templated images <code class="docutils literal"><span class="pre">view(img)</span></code> returns a templated view, whereas for image variants it returns a view variant.
For example, the return type of <code class="docutils literal"><span class="pre">view(runtime_image)</span></code> is <code class="docutils literal"><span class="pre">any_image_view&lt;Views&gt;</span></code> where <code class="docutils literal"><span class="pre">Views</span></code> enumerates four views corresponding to the four image types.
<code class="docutils literal"><span class="pre">const_view(runtime_image)</span></code> returns a <code class="docutils literal"><span class="pre">any_image_view</span></code> of the four read-only view types, etc.</p>
<p>A warning about using variants: instantiating an algorithm with a variant effectively instantiates it with every possible type the variant can take.
For binary algorithms, the algorithm is instantiated with every possible combination of the two input types! This can take a toll on both the compile time
and the executable size.</p>
</div>
<div class="section" id="conclusion">
<h3><a class="toc-backref" href="#id14">Conclusion</a></h3>
<p>This tutorial provides a glimpse at the challenges associated with writing generic and efficient image processing algorithms in GIL.
We have taken a simple algorithm and shown how to make it work with image representations that vary in bit depth, color space, ordering of the
channels, and planar/interleaved structure. We have demonstrated that the algorithm can work with fully abstracted virtual images, and even images
whose type is specified at run time. The associated video presentation also demonstrates that even for complex scenarios the generated assembly
is comparable to that of a C version of the algorithm, hand-written for the specific image types.</p>
<p>Yet, even for such a simple algorithm, we are far from making a fully generic and optimized code. In particular, the presented algorithms work on homogeneous
images, i.e. images whose pixels have channels that are all of the same type. There are examples of images, such as a packed 565 RGB format, which contain
channels of different types. While GIL provides concepts and algorithms operating on heterogeneous pixels, we leave the task of extending x_gradient as an
exercise for the reader.
Second, after computing the value of the gradient we are simply casting it to the destination channel type. This may not always be the desired operation. For
example, if the source channel is a float with range [0..1] and the destination is unsigned char, casting the half-difference to unsigned char will result in
either 0 or 1. Instead, what we might want to do is scale the result into the range of the destination channel. GILs channel-level algorithms might be useful
in such cases. For example, p channel_convert converts between channels by linearly scaling the source channel value into the range of the destination channel.</p>
<p>There is a lot to be done in improving the performance as well. Channel-level operations, such as the half-difference, could be abstracted out into atomic
channel-level algorithms and performance overloads could be provided for concrete channel types. Processor-specific operations could be used, for example,
to perform the operation over an entire row of pixels simultaneously, or the data could be prefetched. All of these optimizations can be realized as performance
specializations of the generic algorithm. Finally, compilers, while getting better over time, are still failing to fully optimize generic code in some cases, such
as failing to inline some functions or put some variables into registers. If performance is an issue, it might be worth trying your code with different compilers.</p>
</div>
</div>
<div class="section" id="appendix">
<h2><a class="toc-backref" href="#id15">Appendix</a></h2>
<div class="section" id="naming-convention-for-gil-concrete-types">
<h3><a class="toc-backref" href="#id16">Naming convention for GIL concrete types</a></h3>
<p>Concrete (non-generic) GIL types follow this naming convention:</p>
<p>_ColorSpace_ + _BitDepth_ + [<code class="docutils literal"><span class="pre">f</span></code> | <code class="docutils literal"><span class="pre">s</span></code>]+ [<code class="docutils literal"><span class="pre">c</span></code>] + [<code class="docutils literal"><span class="pre">_planar</span></code>] + [<code class="docutils literal"><span class="pre">_step</span></code>] + _ClassType_ + <code class="docutils literal"><span class="pre">_t</span></code></p>
<p>Where _ColorSpace_ also indicates the ordering of components. Examples are <code class="docutils literal"><span class="pre">rgb</span></code>, <code class="docutils literal"><span class="pre">bgr</span></code>, <code class="docutils literal"><span class="pre">cmyk</span></code>, <code class="docutils literal"><span class="pre">rgba</span></code>.
_BitDepth_ indicates the bit depth of the color channel. Examples are <code class="docutils literal"><span class="pre">8</span></code>,``16``,``32``. By default the type of channel is unsigned integral; using <code class="docutils literal"><span class="pre">s</span></code> indicates
signed integral and <code class="docutils literal"><span class="pre">f</span></code> - a floating point type, which is always signed. <code class="docutils literal"><span class="pre">c</span></code> indicates object operating over immutable pixels. <code class="docutils literal"><span class="pre">_planar</span></code> indicates planar organization
(as opposed to interleaved). <code class="docutils literal"><span class="pre">_step</span></code> indicates special image views,
locators and iterators which traverse the data in non-trivial way (for example, backwards or every other pixel).
_ClassType_ is <code class="docutils literal"><span class="pre">_image</span></code> (image), <code class="docutils literal"><span class="pre">_view</span></code> (image view), <code class="docutils literal"><span class="pre">_loc</span></code> (pixel 2D locator) <code class="docutils literal"><span class="pre">_ptr</span></code> (pixel iterator), <code class="docutils literal"><span class="pre">_ref</span></code> (pixel reference),
<code class="docutils literal"><span class="pre">_pixel</span></code> (pixel value).</p>
<p>examples:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">bgr8_image_t</span> <span class="n">a</span><span class="p">;</span> <span class="c1">// 8-bit interleaved BGR image</span>
<span class="n">cmyk16_pixel_t</span> <span class="n">b</span><span class="p">;</span> <span class="c1">// 16-bit CMYK pixel value;</span>
<span class="n">cmyk16c_planar_ref_t</span> <span class="nf">c</span><span class="p">(</span><span class="n">b</span><span class="p">);</span> <span class="c1">// const reference to a 16-bit planar CMYK pixel.</span>
<span class="n">rgb32f_planar_step_ptr_t</span> <span class="n">d</span><span class="p">;</span> <span class="c1">// step pointer to a 32-bit planar RGB pixel.</span>
</pre></div>
</div>
</div>
</div>
</div>
<div class="navbar" style="text-align:right;">
<a class="prev" title="Boost Generic Image Library" href="index.html"><img src="_static/prev.png" alt="prev"/></a>
<a class="next" title="Design Guide" href="design_guide.html"><img src="_static/next.png" alt="next"/></a>
</div>
</div>
</body>
</html>