123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959 |
- <!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: Image Gradient - Boost.GIL 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: '',
- 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 documentation" href="../index.html" />
- <link rel="next" title="Naming Conventions" href="../naming.html" />
- <link rel="prev" title="Tutorial: Histogram" href="histogram.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/gil.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="Tutorial: Histogram" href="histogram.html"><img src="../_static/prev.png" alt="prev"/></a>
- <a class="next" title="Naming Conventions" href="../naming.html"><img src="../_static/next.png" alt="next"/></a>
-
- </div>
-
- <div class="section" id="tutorial-image-gradient">
- <h1>Tutorial: Image Gradient</h1>
- <div class="contents local topic" id="contents">
- <ul class="simple">
- <li><a class="reference internal" href="#interface-and-glue-code" id="id1">Interface and Glue Code</a></li>
- <li><a class="reference internal" href="#first-implementation" id="id2">First Implementation</a></li>
- <li><a class="reference internal" href="#using-locators" id="id3">Using Locators</a></li>
- <li><a class="reference internal" href="#creating-a-generic-version-of-gil-algorithms" id="id4">Creating a Generic Version of GIL Algorithms</a></li>
- <li><a class="reference internal" href="#image-view-transformations" id="id5">Image View Transformations</a></li>
- <li><a class="reference internal" href="#d-pixel-iterators" id="id6">1D pixel iterators</a></li>
- <li><a class="reference internal" href="#stl-equivalent-algorithms" id="id7">STL Equivalent Algorithms</a></li>
- <li><a class="reference internal" href="#color-conversion" id="id8">Color Conversion</a></li>
- <li><a class="reference internal" href="#image" id="id9">Image</a></li>
- <li><a class="reference internal" href="#virtual-image-views" id="id10">Virtual Image Views</a></li>
- <li><a class="reference internal" href="#run-time-specified-images-and-image-views" id="id11">Run-Time Specified Images and Image Views</a></li>
- <li><a class="reference internal" href="#conclusion" id="id12">Conclusion</a></li>
- </ul>
- </div>
- <p>This comprehensive (and long) tutorial will walk you through an example of
- using GIL to compute the image gradients.</p>
- <p>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.</p>
- <p>The gradient at pixel x can be approximated with the half-difference of its
- two neighboring pixels:</p>
- <div class="highlight-c++"><div class="highlight"><pre><span class="n">D</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">I</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">I</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>
- </pre></div>
- </div>
- <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">
- <h2><a class="toc-backref" href="#id1">Interface and Glue Code</a></h2>
- <p>Let us first start with 8-bit unsigned grayscale image as the input and 8-bit
- signed grayscale image as the output.</p>
- <p>Here is how the interface to our algorithm looks like:</p>
- <div class="highlight-cpp"><div class="highlight"><pre><span class="cp">#include</span> <span class="cpf"><boost/gil.hpp></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="n">gray8c_view_t</span> <span class="k">const</span><span class="o">&</span> <span class="n">src</span><span class="p">,</span> <span class="n">gray8s_view_t</span> <span class="k">const</span><span class="o">&</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”).</p>
- <p>The output is a grayscale view with a 8-bit signed (denoted by the “s”)
- integer channel type. See Appendix 1 for the complete convention 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
- <code class="docutils literal"><span class="pre">operator==</span></code> 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. GIL’s design is very similar to that of the STL. The STL
- equivalent of GIL’s image is a container, like <code class="docutils literal"><span class="pre">std::vector</span></code>,
- whereas GIL’s image view corresponds to STL 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>GIL’s 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-cpp"><div class="highlight"><pre><span class="kt">void</span> <span class="nf">ComputeXGradientGray8</span><span class="p">(</span>
- <span class="kt">unsigned</span> <span class="kt">char</span> <span class="k">const</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="n">gray8_pixel_t</span> <span class="k">const</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">
- <h2><a class="toc-backref" href="#id2">First Implementation</a></h2>
- <p>Focusing on simplicity at the expense of speed, we can compute the horizontal
- gradient like this:</p>
- <div class="highlight-cpp"><div class="highlight"><pre><span class="kt">void</span> <span class="nf">x_gradient</span><span class="p">(</span><span class="n">gray8c_view_t</span> <span class="k">const</span><span class="o">&</span> <span class="n">src</span><span class="p">,</span> <span class="n">gray8s_view_t</span> <span class="k">const</span><span class="o">&</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"><</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"><</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 view’s <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).</p>
- <p>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-cpp"><div class="highlight"><pre><span class="kt">void</span> <span class="nf">x_gradient</span><span class="p">(</span><span class="n">gray8c_view_t</span> <span class="k">const</span><span class="o">&</span> <span class="n">src</span><span class="p">,</span> <span class="n">gray8s_view_t</span> <span class="k">const</span><span class="o">&</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"><</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"><</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. GIL’s
- 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>
- <p>Instead of looping over the rows, we loop over each column and create a
- <code class="docutils literal"><span class="pre">y_iterator</span></code>, 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-cpp"><div class="highlight"><pre><span class="kt">void</span> <span class="nf">y_gradient</span><span class="p">(</span><span class="n">gray8c_view_t</span> <span class="k">const</span><span class="o">&</span> <span class="n">src</span><span class="p">,</span> <span class="n">gray8s_view_t</span> <span class="k">const</span><span class="o">&</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"><</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"><</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">
- <h2><a class="toc-backref" href="#id3">Using Locators</a></h2>
- <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-cpp"><div class="highlight"><pre><span class="kt">void</span> <span class="nf">y_gradient</span><span class="p">(</span><span class="n">gray8c_view_t</span> <span class="k">const</span><span class="o">&</span> <span class="n">src</span><span class="p">,</span> <span class="n">gray8s_view_t</span> <span class="k">const</span><span class="o">&</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"><</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"><</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">point</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="kt">ptrdiff_t</span><span class="o">></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 class="kt">void</span> <span class="nf">y_gradient</span><span class="p">(</span><span class="n">gray8c_view_t</span> <span class="k">const</span><span class="o">&</span> <span class="n">src</span><span class="p">,</span> <span class="n">gray8s_view_t</span> <span class="k">const</span><span class="o">&</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"><</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"><</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">point</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="kt">ptrdiff_t</span><span class="o">></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">
- <h2><a class="toc-backref" href="#id4">Creating a Generic Version of GIL Algorithms</a></h2>
- <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.</p>
- <p>Here is how the new interface looks like:</p>
- <div class="highlight-cpp"><div class="highlight"><pre><span class="k">template</span> <span class="o"><</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">></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">&</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">DstView</span><span class="o">&</span> <span class="n">dst</span><span class="p">)</span>
- <span class="p">{</span>
- <span class="n">gil_function_requires</span><span class="o"><</span><span class="n">ImageViewConcept</span><span class="o"><</span><span class="n">SrcView</span><span class="o">></span> <span class="o">></span><span class="p">();</span>
- <span class="n">gil_function_requires</span><span class="o"><</span><span class="n">MutableImageViewConcept</span><span class="o"><</span><span class="n">DstView</span><span class="o">></span> <span class="o">></span><span class="p">();</span>
- <span class="n">gil_function_requires</span>
- <span class="o"><</span>
- <span class="n">ColorSpacesCompatibleConcept</span>
- <span class="o"><</span>
- <span class="k">typename</span> <span class="n">color_space_type</span><span class="o"><</span><span class="n">SrcView</span><span class="o">>::</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"><</span><span class="n">DstView</span><span class="o">>::</span><span class="n">type</span>
- <span class="o">></span>
- <span class="o">></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_. GIL’s 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-cpp"><div class="highlight"><pre><span class="k">template</span> <span class="o"><</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">></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">&</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">DstView</span><span class="o">&</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"><</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"><</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"><</span> <span class="n">num_channels</span><span class="o"><</span><span class="n">SrcView</span><span class="o">>::</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-cpp"><div class="highlight"><pre><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">Out</span><span class="o">></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"><</span><span class="k">typename</span> <span class="n">T</span><span class="o">></span> <span class="n">Out</span> <span class="k">operator</span><span class="p">()(</span><span class="n">T</span> <span class="k">const</span><span class="o">&</span> <span class="n">in1</span><span class="p">,</span> <span class="n">T</span> <span class="k">const</span><span class="o">&</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"><</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">></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">&</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">DstView</span><span class="o">&</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"><</span><span class="n">DstView</span><span class="o">>::</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"><</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"><</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="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"><</span><span class="n">dst_channel_t</span><span class="o">></span><span class="p">());</span>
- <span class="p">}</span>
- <span class="p">}</span>
- <span class="p">}</span>
- </pre></div>
- </div>
- <p>The <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 STL
- <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.</p>
- <p>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 GIL’s 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-cpp"><div class="highlight"><pre><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="kt">unsigned</span> <span class="kt">short</span> <span class="k">const</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="p">(</span><span class="n">gray16_pixel_t</span> <span class="k">const</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="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="kt">unsigned</span> <span class="kt">char</span> <span class="k">const</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="p">(</span><span class="n">rgb8_pixel_t</span> <span class="k">const</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="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="kt">unsigned</span> <span class="kt">short</span> <span class="k">const</span><span class="o">*</span> <span class="n">src_r</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">short</span> <span class="k">const</span><span class="o">*</span> <span class="n">src_g</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">short</span> <span class="k">const</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">
- <h2><a class="toc-backref" href="#id5">Image View Transformations</a></h2>
- <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-cpp"><div class="highlight"><pre><span class="k">template</span> <span class="o"><</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">></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">&</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">DstView</span><span class="o">&</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 don’t 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-cpp"><div class="highlight"><pre><span class="k">template</span> <span class="o"><</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">></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">&</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">&</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-cpp"><div class="highlight"><pre><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">
- <h2><a class="toc-backref" href="#id6">1D pixel iterators</a></h2>
- <p>Let’s 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-cpp"><div class="highlight"><pre><span class="kt">void</span> <span class="nf">x_gradient_unguarded</span><span class="p">(</span><span class="n">gray8c_view_t</span> <span class="k">const</span><span class="o">&</span> <span class="n">src</span><span class="p">,</span> <span class="n">gray8s_view_t</span> <span class="k">const</span><span class="o">&</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"><</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"><</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="n">gray8c_view_t</span> <span class="k">const</span><span class="o">&</span> <span class="n">src</span><span class="p">,</span> <span class="n">gray8s_view_t</span> <span class="k">const</span><span class="o">&</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">>=</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-cpp"><div class="highlight"><pre><span class="kt">void</span> <span class="nf">x_gradient_unguarded</span><span class="p">(</span><span class="n">gray8c_view_t</span> <span class="k">const</span><span class="o">&</span> <span class="n">src</span><span class="p">,</span> <span class="n">gray8s_view_t</span> <span class="k">const</span><span class="o">&</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">
- <h2><a class="toc-backref" href="#id7">STL Equivalent Algorithms</a></h2>
- <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 GIL’s
- <code class="docutils literal"><span class="pre">transform_pixel_positions</span></code> to do that:</p>
- <div class="highlight-cpp"><div class="highlight"><pre><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">&</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="n">gray8c_view_t</span> <span class="k">const</span><span class="o">&</span> <span class="n">src</span><span class="p">,</span> <span class="n">gray8s_view_t</span> <span class="k">const</span><span class="o">&</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 STL
- <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">
- <h2><a class="toc-backref" href="#id8">Color Conversion</a></h2>
- <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-cpp"><div class="highlight"><pre><span class="kt">void</span> <span class="nf">x_gradient_rgb_luminosity</span><span class="p">(</span><span class="n">rgb32fc_view_t</span> <span class="k">const</span><span class="o">&</span> <span class="n">src</span><span class="p">,</span> <span class="n">gray8s_view_t</span> <span class="k">const</span><span class="o">&</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"><</span><span class="n">gray8_pixel_t</span><span class="o">></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 doesn’t 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-cpp"><div class="highlight"><pre><span class="k">template</span> <span class="o"><</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">></span>
- <span class="kt">void</span> <span class="n">x_luminosity_gradient</span><span class="p">(</span><span class="n">SrcView</span> <span class="k">const</span><span class="o">&</span> <span class="n">src</span><span class="p">,</span> <span class="n">DstView</span> <span class="k">const</span><span class="o">&</span> <span class="n">dst</span><span class="p">)</span>
- <span class="p">{</span>
- <span class="k">using</span> <span class="n">gray_pixel_t</span> <span class="o">=</span> <span class="n">pixel</span><span class="o"><</span><span class="k">typename</span> <span class="n">channel_type</span><span class="o"><</span><span class="n">SrcView</span><span class="o">>::</span><span class="n">type</span><span class="p">,</span> <span class="n">gray_layout_t</span><span class="o">></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"><</span><span class="n">gray_pixel_t</span><span class="o">></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">
- <h2><a class="toc-backref" href="#id9">Image</a></h2>
- <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-cpp"><div class="highlight"><pre><span class="kt">void</span> <span class="nf">x_luminosity_gradient</span><span class="p">(</span><span class="n">rgb32fc_view_t</span> <span class="k">const</span><span class="o">&</span> <span class="n">src</span><span class="p">,</span> <span class="n">gray8s_view_t</span> <span class="k">const</span><span class="o">&</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"><</span><span class="n">gray8_pixel_t</span><span class="o">></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-cpp"><div class="highlight"><pre><span class="k">template</span> <span class="o"><</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">></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">&</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">DstView</span><span class="o">&</span> <span class="n">dst</span><span class="p">)</span>
- <span class="p">{</span>
- <span class="k">using</span> <span class="n">d_channel_t</span> <span class="o">=</span> <span class="k">typename</span> <span class="n">channel_type</span><span class="o"><</span><span class="n">DstView</span><span class="o">>::</span><span class="n">type</span><span class="p">;</span>
- <span class="k">using</span> <span class="n">channel_t</span> <span class="o">=</span> <span class="k">typename</span> <span class="n">channel_convert_to_unsigned</span><span class="o"><</span><span class="n">d_channel_t</span><span class="o">>::</span><span class="n">type</span><span class="p">;</span>
- <span class="k">using</span> <span class="n">gray_pixel_t</span> <span class="o">=</span> <span class="n">pixel</span><span class="o"><</span><span class="n">channel_t</span><span class="p">,</span> <span class="n">gray_layout_t</span><span class="o">></span><span class="p">;</span>
- <span class="k">using</span> <span class="n">gray_image_t</span> <span class="o">=</span> <span class="n">image</span><span class="o"><</span><span class="n">gray_pixel_t</span><span class="p">,</span> <span class="nb">false</span><span class="o">></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"><</span><span class="n">gray_pixel_t</span><span class="o">></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 class templates (declared with
- <code class="docutils literal"><span class="pre">struct</span></code> type specifier) 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. GIL’s image class is specialized 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-cpp"><div class="highlight"><pre><span class="k">template</span> <span class="o"><</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">></span>
- <span class="kt">void</span> <span class="n">x_luminosity_gradient</span><span class="p">(</span><span class="n">SrcView</span> <span class="k">const</span><span class="o">&</span> <span class="n">src</span><span class="p">,</span> <span class="n">DstView</span> <span class="k">const</span><span class="o">&</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"><</span><span class="n">DstView</span><span class="o">>::</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"><</span><span class="n">d_channel_t</span><span class="o">>::</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"><</span><span class="n">channel_t</span><span class="p">,</span> <span class="n">gray_layout_t</span><span class="o">>::</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">
- <h2><a class="toc-backref" href="#id10">Virtual Image Views</a></h2>
- <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-cpp"><div class="highlight"><pre><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">point</span><span class="o"><</span><span class="kt">ptrdiff_t</span><span class="o">></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="k">static</span> <span class="kt">bool</span> <span class="k">constexpr</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">&</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">&</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">point</span><span class="o"><</span><span class="kt">double</span><span class="o">></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">point</span><span class="o"><</span><span class="kt">double</span><span class="o">>&</span> <span class="n">p</span><span class="p">)</span> <span class="k">const</span>
- <span class="p">{</span>
- <span class="n">point</span><span class="o"><</span><span class="kt">double</span><span class="o">></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"><</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">point</span><span class="o"><</span><span class="kt">double</span><span class="o">></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">></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 GIL’s <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-cpp"><div class="highlight"><pre><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"><</span><span class="n">mandelbrot_fn</span><span class="p">,</span><span class="nb">false</span><span class="o">></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"><</span><span class="n">locator_t</span><span class="o">></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,
- let’s 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-cpp"><div class="highlight"><pre><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">"mandel.jpg"</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">"mandel_grad.jpg"</span><span class="p">,</span><span class="n">color_converted_view</span><span class="o"><</span><span class="n">gray8_pixel_t</span><span class="o">></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">
- <h2><a class="toc-backref" href="#id11">Run-Time Specified Images and Image Views</a></h2>
- <p>So far we have created a generic function that computes the image
- gradient of an image view template specialization. Sometimes,
- however, the properties of an image view, such as its color space and
- channel depth, may not be available at compile time. GIL’s
- <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 GIL’s 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, let’s assume that only the source view can be a
- variant. (As an example of using multiple variants, see GIL’s 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-cpp"><div class="highlight"><pre><span class="cp">#include</span> <span class="cpf"><boost/gil/extension/dynamic_image/dynamic_image_all.hpp></span><span class="cp"></span>
- <span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">DstView</span><span class="o">></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">&</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">&</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"><</span><span class="k">typename</span> <span class="n">SrcView</span><span class="o">></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">&</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 GIL’s <code class="docutils literal"><span class="pre">apply_operation</span></code> passing it the
- function object:</p>
- <div class="highlight-cpp"><div class="highlight"><pre><span class="k">template</span> <span class="o"><</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">></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"><</span><span class="n">SrcViews</span><span class="o">>&</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">DstView</span><span class="o">&</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"><</span><span class="n">DstView</span><span class="o">></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<SrcViews></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-cpp"><div class="highlight"><pre><span class="cp">#include</span> <span class="cpf"><boost/mpl/vector.hpp></span><span class="cp"></span>
- <span class="cp">#include</span> <span class="cpf"><boost/gil/extension/io/jpeg_dynamic_io.hpp></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"><</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">></span> <span class="n">my_img_types</span><span class="p">;</span>
- <span class="n">any_image</span><span class="o"><</span><span class="n">my_img_types</span><span class="o">></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">"input.jpg"</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">"x_gradient.jpg"</span><span class="p">,</span> <span class="n">color_converted_view</span><span class="o"><</span><span class="n">gray8_pixel_t</span><span class="o">></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 GIL’s 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<Views></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">
- <h2><a class="toc-backref" href="#id12">Conclusion</a></h2>
- <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. GIL’s
- 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 pre-fetched. 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="navbar" style="text-align:right;">
-
-
- <a class="prev" title="Tutorial: Histogram" href="histogram.html"><img src="../_static/prev.png" alt="prev"/></a>
- <a class="next" title="Naming Conventions" href="../naming.html"><img src="../_static/next.png" alt="next"/></a>
-
- </div>
- </div>
- <div class="footer" role="contentinfo">
- Last updated on 2019-12-10 00:12:10.
- Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.5.6.
- </div>
- </body>
- </html>
|