Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / gil / doc / html / tutorial / gradient.html
1
2
3 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5 <html xmlns="http://www.w3.org/1999/xhtml">
6   <head>
7     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
8     
9     <title>Tutorial: Image Gradient - Boost.GIL  documentation</title>
10     <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
11     <link rel="stylesheet" href="../_static/style.css" type="text/css" />
12     <script type="text/javascript">
13       var DOCUMENTATION_OPTIONS = {
14           URL_ROOT:    '../',
15           VERSION:     '',
16           COLLAPSE_MODINDEX: false,
17           FILE_SUFFIX: '.html'
18       };
19     </script>
20     <script type="text/javascript" src="../_static/jquery.js"></script>
21     <script type="text/javascript" src="../_static/underscore.js"></script>
22     <script type="text/javascript" src="../_static/doctools.js"></script>
23     <link rel="index" title="Index" href="../genindex.html" />
24     <link rel="search" title="Search" href="../search.html" />
25     <link rel="top" title="Boost.GIL  documentation" href="../index.html" />
26     <link rel="next" title="Naming Conventions" href="../naming.html" />
27     <link rel="prev" title="Tutorial: Histogram" href="histogram.html" /> 
28   </head>
29   <body>
30     <div class="header">
31     <table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
32     "header">
33       <tr>
34         <td valign="top" width="300">
35           <h3><a href="../index.html"><img
36           alt="C++ Boost" src="../_static/gil.png" border="0"></a></h3>
37         </td>
38
39         <td >
40           <h1 align="center"><a href="../index.html"></a></h1>
41         </td>
42         <td>
43       <div id="searchbox" style="display: none">
44         <form class="search" action="../search.html" method="get">
45           <input type="text" name="q" size="18" />
46           <input type="submit" value="Search" />
47           <input type="hidden" name="check_keywords" value="yes" />
48           <input type="hidden" name="area" value="default" />
49         </form>
50       </div>
51       <script type="text/javascript">$('#searchbox').show(0);</script>
52         </td>
53       </tr>
54     </table>
55     </div>
56     <hr/>
57     <div class="content">
58     <div class="navbar" style="text-align:right;">
59       
60       
61       <a class="prev" title="Tutorial: Histogram" href="histogram.html"><img src="../_static/prev.png" alt="prev"/></a>
62       <a class="next" title="Naming Conventions" href="../naming.html"><img src="../_static/next.png" alt="next"/></a>
63       
64     </div>
65       
66   <div class="section" id="tutorial-image-gradient">
67 <h1>Tutorial: Image Gradient</h1>
68 <div class="contents local topic" id="contents">
69 <ul class="simple">
70 <li><a class="reference internal" href="#interface-and-glue-code" id="id1">Interface and Glue Code</a></li>
71 <li><a class="reference internal" href="#first-implementation" id="id2">First Implementation</a></li>
72 <li><a class="reference internal" href="#using-locators" id="id3">Using Locators</a></li>
73 <li><a class="reference internal" href="#creating-a-generic-version-of-gil-algorithms" id="id4">Creating a Generic Version of GIL Algorithms</a></li>
74 <li><a class="reference internal" href="#image-view-transformations" id="id5">Image View Transformations</a></li>
75 <li><a class="reference internal" href="#d-pixel-iterators" id="id6">1D pixel iterators</a></li>
76 <li><a class="reference internal" href="#stl-equivalent-algorithms" id="id7">STL Equivalent Algorithms</a></li>
77 <li><a class="reference internal" href="#color-conversion" id="id8">Color Conversion</a></li>
78 <li><a class="reference internal" href="#image" id="id9">Image</a></li>
79 <li><a class="reference internal" href="#virtual-image-views" id="id10">Virtual Image Views</a></li>
80 <li><a class="reference internal" href="#run-time-specified-images-and-image-views" id="id11">Run-Time Specified Images and Image Views</a></li>
81 <li><a class="reference internal" href="#conclusion" id="id12">Conclusion</a></li>
82 </ul>
83 </div>
84 <p>This comprehensive (and long) tutorial will walk you through an example of
85 using GIL to compute the image gradients.</p>
86 <p>We will start with some very simple and non-generic code and make it more
87 generic as we go along.  Let us start with a horizontal gradient and use the
88 simplest possible approximation to a gradient - central difference.</p>
89 <p>The gradient at pixel x can be approximated with the half-difference of its
90 two neighboring pixels:</p>
91 <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>
92 </pre></div>
93 </div>
94 <p>For simplicity, we will also ignore the boundary cases - the pixels along the
95 edges of the image for which one of the neighbors is not defined. The focus of
96 this document is how to use GIL, not how to create a good gradient generation
97 algorithm.</p>
98 <div class="section" id="interface-and-glue-code">
99 <h2><a class="toc-backref" href="#id1">Interface and Glue Code</a></h2>
100 <p>Let us first start with 8-bit unsigned grayscale image as the input and 8-bit
101 signed grayscale image as the output.</p>
102 <p>Here is how the interface to our algorithm looks like:</p>
103 <div class="highlight-cpp"><div class="highlight"><pre><span class="cp">#include</span> <span class="cpf">&lt;boost/gil.hpp&gt;</span><span class="cp"></span>
104 <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>
105
106 <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">&amp;</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">&amp;</span> <span class="n">dst</span><span class="p">)</span>
107 <span class="p">{</span>
108   <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>
109   <span class="p">...</span>    <span class="c1">// compute the gradient</span>
110 <span class="p">}</span>
111 </pre></div>
112 </div>
113 <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
114 view, whose pixels are read-only (denoted by the &#8220;c&#8221;).</p>
115 <p>The output is a grayscale view with a 8-bit signed (denoted by the &#8220;s&#8221;)
116 integer channel type. See Appendix 1 for the complete convention GIL uses to
117 name concrete types.</p>
118 <p>GIL makes a distinction between an image and an image view.
119 A GIL <strong>image view</strong>, is a shallow, lightweight view of a rectangular grid of
120 pixels. It provides access to the pixels but does not own the pixels.
121 Copy-constructing a view does not deep-copy the pixels. Image views do not
122 propagate their constness to the pixels and should always be taken by a const
123 reference. Whether a view is mutable or read-only (immutable) is a property of
124 the view type.</p>
125 <p>A GIL <cite>image</cite>, on the other hand, is a view with associated ownership.
126 It is a container of pixels; its constructor/destructor allocates/deallocates
127 the pixels, its copy-constructor performs deep-copy of the pixels and its
128 <code class="docutils literal"><span class="pre">operator==</span></code> performs deep-compare of the pixels. Images also propagate
129 their constness to their pixels - a constant reference to an image will not
130 allow for modifying its pixels.</p>
131 <p>Most GIL algorithms operate on image views; images are rarely
132 needed. GIL&#8217;s design is very similar to that of the STL. The STL
133 equivalent of GIL&#8217;s image is a container, like <code class="docutils literal"><span class="pre">std::vector</span></code>,
134 whereas GIL&#8217;s image view corresponds to STL range, which is often
135 represented with a pair of iterators. STL algorithms operate on
136 ranges, just like GIL algorithms operate on image views.</p>
137 <p>GIL&#8217;s image views can be constructed from raw data - the dimensions,
138 the number of bytes per row and the pixels, which for chunky views are
139 represented with one pointer. Here is how to provide the glue between
140 your code and GIL:</p>
141 <div class="highlight-cpp"><div class="highlight"><pre><span class="kt">void</span> <span class="nf">ComputeXGradientGray8</span><span class="p">(</span>
142     <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>
143     <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>
144     <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>
145 <span class="p">{</span>
146   <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>
147   <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>
148   <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>
149 <span class="p">}</span>
150 </pre></div>
151 </div>
152 <p>This glue code is very fast and views are lightweight - in the above example
153 the views have a size of 16 bytes. They consist of a pointer to the top left
154 pixel and three integers - the width, height, and number of bytes per row.</p>
155 </div>
156 <div class="section" id="first-implementation">
157 <h2><a class="toc-backref" href="#id2">First Implementation</a></h2>
158 <p>Focusing on simplicity at the expense of speed, we can compute the horizontal
159 gradient like this:</p>
160 <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">&amp;</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">&amp;</span> <span class="n">dst</span><span class="p">)</span>
161 <span class="p">{</span>
162   <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">y</span> <span class="o">&lt;</span> <span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">();</span> <span class="o">++</span><span class="n">y</span><span class="p">)</span>
163       <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="o">++</span><span class="n">x</span><span class="p">)</span>
164           <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>
165 <span class="p">}</span>
166 </pre></div>
167 </div>
168 <p>We use image view&#8217;s <code class="docutils literal"><span class="pre">operator(x,y)</span></code> to get a reference to the pixel at a
169 given location and we set it to the half-difference of its left and right
170 neighbors.  <code class="docutils literal"><span class="pre">operator()</span></code> returns a reference to a grayscale pixel.
171 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
172 <code class="docutils literal"><span class="pre">src</span></code>) and it can be copy-constructed from a channel.
173 (This is only true for grayscale pixels).</p>
174 <p>While the above code is easy to read, it is not very fast, because the binary
175 <code class="docutils literal"><span class="pre">operator()</span></code> computes the location of the pixel in a 2D grid, which involves
176 addition and multiplication. Here is a faster version of the above:</p>
177 <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">&amp;</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">&amp;</span> <span class="n">dst</span><span class="p">)</span>
178 <span class="p">{</span>
179   <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">y</span> <span class="o">&lt;</span> <span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">();</span> <span class="o">++</span><span class="n">y</span><span class="p">)</span>
180   <span class="p">{</span>
181       <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>
182       <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>
183
184       <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="o">++</span><span class="n">x</span><span class="p">)</span>
185           <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>
186   <span class="p">}</span>
187 <span class="p">}</span>
188 </pre></div>
189 </div>
190 <p>We use pixel iterators initialized at the beginning of each row. GIL&#8217;s
191 iterators are Random Access Traversal iterators. If you are not
192 familiar with random access iterators, think of them as if they were
193 pointers. In fact, in the above example the two iterator types are raw
194 C pointers and their <code class="docutils literal"><span class="pre">operator[]</span></code> is a fast pointer indexing
195 operator.</p>
196 <p>The code to compute gradient in the vertical direction is very
197 similar:</p>
198 <p>Instead of looping over the rows, we loop over each column and create a
199 <code class="docutils literal"><span class="pre">y_iterator</span></code>, an iterator moving vertically. In this case a simple pointer
200 cannot be used because the distance between two adjacent pixels equals the
201 number of bytes in each row of the image. GIL uses here a special step
202 iterator class whose size is 8 bytes - it contains a raw C pointer and a step.
203 Its <code class="docutils literal"><span class="pre">operator[]</span></code> multiplies the index by its step.</p>
204 <p>The above version of <code class="docutils literal"><span class="pre">y_gradient</span></code>, however, is much slower (easily an order
205 of magnitude slower) than <code class="docutils literal"><span class="pre">x_gradient</span></code> because of the memory access pattern;
206 traversing an image vertically results in lots of cache misses. A much more
207 efficient and cache-friendly version will iterate over the columns in the inner
208 loop:</p>
209 <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">&amp;</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">&amp;</span> <span class="n">dst</span><span class="p">)</span>
210 <span class="p">{</span>
211   <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">y</span> <span class="o">&lt;</span> <span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="o">++</span><span class="n">y</span><span class="p">)</span>
212   <span class="p">{</span>
213       <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>
214       <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>
215       <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>
216
217       <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">();</span> <span class="o">++</span><span class="n">x</span><span class="p">)</span>
218       <span class="p">{</span>
219           <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>
220           <span class="o">++</span><span class="n">dst_it</span><span class="p">;</span>
221           <span class="o">++</span><span class="n">src1_it</span><span class="p">;</span>
222           <span class="o">++</span><span class="n">src2_it</span><span class="p">;</span>
223       <span class="p">}</span>
224   <span class="p">}</span>
225 <span class="p">}</span>
226 </pre></div>
227 </div>
228 <p>This sample code also shows an alternative way of using pixel iterators -
229 instead of <code class="docutils literal"><span class="pre">operator[]</span></code> one could use increments and dereferences.</p>
230 </div>
231 <div class="section" id="using-locators">
232 <h2><a class="toc-backref" href="#id3">Using Locators</a></h2>
233 <p>Unfortunately this cache-friendly version requires the extra hassle of
234 maintaining two separate iterators in the source view. For every pixel, we
235 want to access its neighbors above and below it. Such relative access can be
236 done with GIL locators:</p>
237 <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">&amp;</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">&amp;</span> <span class="n">dst</span><span class="p">)</span>
238 <span class="p">{</span>
239   <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>
240   <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">y</span> <span class="o">&lt;</span> <span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="o">++</span><span class="n">y</span><span class="p">)</span>
241   <span class="p">{</span>
242       <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>
243
244       <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">();</span> <span class="o">++</span><span class="n">x</span><span class="p">)</span>
245   <span class="p">{</span>
246           <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>
247           <span class="o">++</span><span class="n">dst_it</span><span class="p">;</span>
248           <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>
249       <span class="p">}</span>
250       <span class="n">src_loc</span><span class="o">+=</span><span class="n">point</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="kt">ptrdiff_t</span><span class="o">&gt;</span><span class="p">(</span><span class="o">-</span><span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">(),</span> <span class="mi">1</span><span class="p">);</span> <span class="c1">// carriage return</span>
251   <span class="p">}</span>
252 <span class="p">}</span>
253 </pre></div>
254 </div>
255 <p>The first line creates a locator pointing to the first pixel of the
256 second row of the source view. A GIL pixel locator is very similar to
257 an iterator, except that it can move both horizontally and
258 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
259 horizontal and a vertical iterator respectively, which can be used to
260 move the locator along the desired dimension, as shown
261 above. Additionally, the locator can be advanced in both dimensions
262 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
263 image views, locators provide binary <code class="docutils literal"><span class="pre">operator()</span></code> which returns a
264 reference to a pixel with a relative offset to the current locator
265 position. For example, <code class="docutils literal"><span class="pre">src_loc(0,1)</span></code> returns a reference to the
266 neighbor below the current pixel.  Locators are very lightweight
267 objects - in the above example the locator has a size of 8 bytes - it
268 consists of a raw pointer to the current pixel and an int indicating
269 the number of bytes from one row to the next (which is the step when
270 moving vertically). The call to <code class="docutils literal"><span class="pre">++src_loc.x()</span></code> corresponds to a
271 single C pointer increment.  However, the example above performs more
272 computations than necessary. The code <code class="docutils literal"><span class="pre">src_loc(0,1)</span></code> has to compute
273 the offset of the pixel in two dimensions, which is slow.  Notice
274 though that the offset of the two neighbors is the same, regardless of
275 the pixel location. To improve the performance, GIL can cache and
276 reuse this offset:</p>
277 <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">&amp;</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">&amp;</span> <span class="n">dst</span><span class="p">)</span>
278 <span class="p">{</span>
279   <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>
280   <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>
281   <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>
282
283   <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">y</span> <span class="o">&lt;</span> <span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="o">++</span><span class="n">y</span><span class="p">)</span>
284   <span class="p">{</span>
285       <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>
286
287       <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">();</span> <span class="o">++</span><span class="n">x</span><span class="p">)</span>
288   <span class="p">{</span>
289           <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>
290           <span class="o">++</span><span class="n">dst_it</span><span class="p">;</span>
291           <span class="o">++</span><span class="n">src_loc</span><span class="p">.</span><span class="n">x</span><span class="p">();</span>
292       <span class="p">}</span>
293       <span class="n">src_loc</span><span class="o">+=</span><span class="n">point</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="kt">ptrdiff_t</span><span class="o">&gt;</span><span class="p">(</span><span class="o">-</span><span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">(),</span> <span class="mi">1</span><span class="p">);</span>
294   <span class="p">}</span>
295 <span class="p">}</span>
296 </pre></div>
297 </div>
298 <p>In this example <code class="docutils literal"><span class="pre">src_loc[above]</span></code> corresponds to a fast pointer indexing
299 operation and the code is efficient.</p>
300 </div>
301 <div class="section" id="creating-a-generic-version-of-gil-algorithms">
302 <h2><a class="toc-backref" href="#id4">Creating a Generic Version of GIL Algorithms</a></h2>
303 <p>Let us make our <code class="docutils literal"><span class="pre">x_gradient</span></code> more generic. It should work with any image
304 views, as long as they have the same number of channels. The gradient
305 operation is to be computed for each channel independently.</p>
306 <p>Here is how the new interface looks like:</p>
307 <div class="highlight-cpp"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstView</span><span class="o">&gt;</span>
308 <span class="kt">void</span> <span class="n">x_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">SrcView</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">DstView</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
309 <span class="p">{</span>
310   <span class="n">gil_function_requires</span><span class="o">&lt;</span><span class="n">ImageViewConcept</span><span class="o">&lt;</span><span class="n">SrcView</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">();</span>
311   <span class="n">gil_function_requires</span><span class="o">&lt;</span><span class="n">MutableImageViewConcept</span><span class="o">&lt;</span><span class="n">DstView</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">();</span>
312   <span class="n">gil_function_requires</span>
313   <span class="o">&lt;</span>
314     <span class="n">ColorSpacesCompatibleConcept</span>
315     <span class="o">&lt;</span>
316       <span class="k">typename</span> <span class="n">color_space_type</span><span class="o">&lt;</span><span class="n">SrcView</span><span class="o">&gt;::</span><span class="n">type</span><span class="p">,</span>
317       <span class="k">typename</span> <span class="n">color_space_type</span><span class="o">&lt;</span><span class="n">DstView</span><span class="o">&gt;::</span><span class="n">type</span>
318     <span class="o">&gt;</span>
319   <span class="o">&gt;</span><span class="p">();</span>
320
321   <span class="p">...</span> <span class="c1">// compute the gradient</span>
322 <span class="p">}</span>
323 </pre></div>
324 </div>
325 <p>The new algorithm now takes the types of the input and output image
326 views as template parameters.  That allows using both built-in GIL
327 image views, as well as any user-defined image view classes.  The
328 first three lines are optional; they use <code class="docutils literal"><span class="pre">boost::concept_check</span></code> to
329 ensure that the two arguments are valid GIL image views, that the
330 second one is mutable and that their color spaces are compatible
331 (i.e. have the same set of channels).</p>
332 <p>GIL does not require using its own built-in constructs. You are free
333 to use your own channels, color spaces, iterators, locators, views and
334 images.  However, to work with the rest of GIL they have to satisfy a
335 set of requirements; in other words, they have to e model the
336 corresponding GIL _concept_.  GIL&#8217;s concepts are defined in the user
337 guide.</p>
338 <p>One of the biggest drawbacks of using templates and generic
339 programming in C++ is that compile errors can be very difficult to
340 comprehend.  This is a side-effect of the lack of early type
341 checking - a generic argument may not satisfy the requirements of a
342 function, but the incompatibility may be triggered deep into a nested
343 call, in code unfamiliar and hardly related to the problem.  GIL uses
344 <code class="docutils literal"><span class="pre">boost::concept_check</span></code> to mitigate this problem. The above three
345 lines of code check whether the template parameters are valid models
346 of their corresponding concepts.  If a model is incorrect, the compile
347 error will be inside <code class="docutils literal"><span class="pre">gil_function_requires</span></code>, which is much closer
348 to the problem and easier to track. Furthermore, such checks get
349 compiled out and have zero performance overhead. The disadvantage of
350 using concept checks is the sometimes severe impact they have on
351 compile time. This is why GIL performs concept checks only in debug
352 mode, and only if <code class="docutils literal"><span class="pre">BOOST_GIL_USE_CONCEPT_CHECK</span></code> is defined (off by
353 default).</p>
354 <p>The body of the generic function is very similar to that of the
355 concrete one. The biggest difference is that we need to loop over the
356 channels of the pixel and compute the gradient for each channel:</p>
357 <div class="highlight-cpp"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstView</span><span class="o">&gt;</span>
358 <span class="kt">void</span> <span class="n">x_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">SrcView</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">DstView</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
359 <span class="p">{</span>
360   <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">y</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">y</span> <span class="o">&lt;</span> <span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">();</span> <span class="o">++</span><span class="n">y</span><span class="p">)</span>
361   <span class="p">{</span>
362       <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>
363       <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>
364
365       <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="o">++</span><span class="n">x</span><span class="p">)</span>
366           <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">c</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">c</span> <span class="o">&lt;</span> <span class="n">num_channels</span><span class="o">&lt;</span><span class="n">SrcView</span><span class="o">&gt;::</span><span class="n">value</span><span class="p">;</span> <span class="o">++</span><span class="n">c</span><span class="p">)</span>
367               <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>
368   <span class="p">}</span>
369 <span class="p">}</span>
370 </pre></div>
371 </div>
372 <p>Having an explicit loop for each channel could be a performance problem.
373 GIL allows us to abstract out such per-channel operations:</p>
374 <div class="highlight-cpp"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Out</span><span class="o">&gt;</span>
375 <span class="k">struct</span> <span class="n">halfdiff_cast_channels</span>
376 <span class="p">{</span>
377   <span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="n">Out</span> <span class="k">operator</span><span class="p">()(</span><span class="n">T</span> <span class="k">const</span><span class="o">&amp;</span> <span class="n">in1</span><span class="p">,</span> <span class="n">T</span> <span class="k">const</span><span class="o">&amp;</span> <span class="n">in2</span><span class="p">)</span> <span class="k">const</span>
378   <span class="p">{</span>
379       <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>
380   <span class="p">}</span>
381 <span class="p">};</span>
382
383 <span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstView</span><span class="o">&gt;</span>
384 <span class="kt">void</span> <span class="n">x_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">SrcView</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">DstView</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
385 <span class="p">{</span>
386   <span class="k">typedef</span> <span class="k">typename</span> <span class="n">channel_type</span><span class="o">&lt;</span><span class="n">DstView</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">dst_channel_t</span><span class="p">;</span>
387
388   <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">y</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">y</span> <span class="o">&lt;</span> <span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">();</span> <span class="o">++</span><span class="n">y</span><span class="p">)</span>
389   <span class="p">{</span>
390       <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>
391       <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>
392
393       <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="o">++</span><span class="n">x</span><span class="p">)</span>
394       <span class="p">{</span>
395           <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>
396               <span class="n">halfdiff_cast_channels</span><span class="o">&lt;</span><span class="n">dst_channel_t</span><span class="o">&gt;</span><span class="p">());</span>
397       <span class="p">}</span>
398   <span class="p">}</span>
399 <span class="p">}</span>
400 </pre></div>
401 </div>
402 <p>The <code class="docutils literal"><span class="pre">static_transform</span></code> is an example of a channel-level GIL algorithm.
403 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
404 <code class="docutils literal"><span class="pre">static_for_each</span></code>. They are the channel-level equivalents of STL
405 <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.
406 GIL channel algorithms use static recursion to unroll the loops; they never
407 loop over the channels explicitly.</p>
408 <p>Note that sometimes modern compilers (at least Visual Studio 8) already unroll
409 channel-level loops, such as the one above. However, another advantage of
410 using GIL&#8217;s channel-level algorithms is that they pair the channels
411 semantically, not based on their order in memory. For example, the above
412 example will properly match an RGB source with a BGR destination.</p>
413 <p>Here is how we can use our generic version with images of different types:</p>
414 <div class="highlight-cpp"><div class="highlight"><pre><span class="c1">// Calling with 16-bit grayscale data</span>
415 <span class="kt">void</span> <span class="nf">XGradientGray16_Gray32</span><span class="p">(</span>
416     <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>
417     <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>
418     <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>
419 <span class="p">{</span>
420   <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>
421   <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>
422   <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>
423 <span class="p">}</span>
424
425 <span class="c1">// Calling with 8-bit RGB data into 16-bit BGR</span>
426 <span class="kt">void</span> <span class="nf">XGradientRGB8_BGR16</span><span class="p">(</span>
427     <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>
428     <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>
429     <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>
430 <span class="p">{</span>
431   <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>
432   <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>
433   <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>
434 <span class="p">}</span>
435
436 <span class="c1">// Either or both the source and the destination could be planar - the gradient code does not change</span>
437 <span class="kt">void</span> <span class="nf">XGradientPlanarRGB8_RGB32</span><span class="p">(</span>
438     <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>
439     <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>
440     <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>
441 <span class="p">{</span>
442   <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>
443   <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>
444   <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>
445 <span class="p">}</span>
446 </pre></div>
447 </div>
448 <p>As these examples illustrate, both the source and the destination can be
449 interleaved or planar, of any channel depth (assuming the destination channel
450 is assignable to the source), and of any compatible color spaces.</p>
451 <p>GIL 2.1 can also natively represent images whose channels are not
452 byte-aligned, such as 6-bit RGB222 image or a 1-bit Gray1 image.
453 GIL algorithms apply to these images natively. See the design guide or sample
454 files for more on using such images.</p>
455 </div>
456 <div class="section" id="image-view-transformations">
457 <h2><a class="toc-backref" href="#id5">Image View Transformations</a></h2>
458 <p>One way to compute the y-gradient is to rotate the image by 90 degrees,
459 compute the x-gradient and rotate the result back.
460 Here is how to do this in GIL:</p>
461 <div class="highlight-cpp"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstView</span><span class="o">&gt;</span>
462 <span class="kt">void</span> <span class="n">y_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">SrcView</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">DstView</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
463 <span class="p">{</span>
464   <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>
465 <span class="p">}</span>
466 </pre></div>
467 </div>
468 <p><code class="docutils literal"><span class="pre">rotated90ccw_view</span></code> takes an image view and returns an image view
469 representing 90-degrees counter-clockwise rotation of its input. It is
470 an example of a GIL view transformation function. GIL provides a
471 variety of transformation functions that can perform any axis-aligned
472 rotation, transpose the view, flip it vertically or horizontally,
473 extract a rectangular subimage, perform color conversion, subsample
474 view, etc. The view transformation functions are fast and shallow -
475 they don&#8217;t copy the pixels, they just change the &#8220;coordinate system&#8221;
476 of accessing the pixels. <code class="docutils literal"><span class="pre">rotated90cw_view</span></code>, for example, returns a
477 view whose horizontal iterators are the vertical iterators of the
478 original view. The above code to compute <code class="docutils literal"><span class="pre">y_gradient</span></code> is slow
479 because of the memory access pattern; using <code class="docutils literal"><span class="pre">rotated90cw_view</span></code> does
480 not make it any slower.</p>
481 <p>Another example: suppose we want to compute the gradient of the N-th
482 channel of a color image. Here is how to do that:</p>
483 <div class="highlight-cpp"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstView</span><span class="o">&gt;</span>
484 <span class="kt">void</span> <span class="n">nth_channel_x_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">SrcView</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="k">const</span> <span class="n">DstView</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
485 <span class="p">{</span>
486   <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>
487 <span class="p">}</span>
488 </pre></div>
489 </div>
490 <p><code class="docutils literal"><span class="pre">nth_channel_view</span></code> is a view transformation function that takes any
491 view and returns a single-channel (grayscale) view of its N-th
492 channel.  For interleaved RGB view, for example, the returned view is
493 a step view - a view whose horizontal iterator skips over two channels
494 when incremented.  If applied on a planar RGB view, the returned type
495 is a simple grayscale view whose horizontal iterator is a C pointer.
496 Image view transformation functions can be piped together. For
497 example, to compute the y gradient of the second channel of the even
498 pixels in the view, use:</p>
499 <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>
500 </pre></div>
501 </div>
502 <p>GIL can sometimes simplify piped views. For example, two nested
503 subsampled views (views that skip over pixels in X and in Y) can be
504 represented as a single subsampled view whose step is the product of
505 the steps of the two views.</p>
506 </div>
507 <div class="section" id="d-pixel-iterators">
508 <h2><a class="toc-backref" href="#id6">1D pixel iterators</a></h2>
509 <p>Let&#8217;s go back to <code class="docutils literal"><span class="pre">x_gradient</span></code> one more time.  Many image view
510 algorithms apply the same operation for each pixel and GIL provides an
511 abstraction to handle them. However, our algorithm has an unusual
512 access pattern, as it skips the first and the last column. It would be
513 nice and instructional to see how we can rewrite it in canonical
514 form. The way to do that in GIL is to write a version that works for
515 every pixel, but apply it only on the subimage that excludes the first
516 and last column:</p>
517 <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">&amp;</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">&amp;</span> <span class="n">dst</span><span class="p">)</span>
518 <span class="p">{</span>
519   <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">y</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">y</span> <span class="o">&lt;</span> <span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">();</span> <span class="o">++</span><span class="n">y</span><span class="p">)</span>
520   <span class="p">{</span>
521       <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>
522       <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>
523
524       <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">();</span> <span class="o">++</span><span class="n">x</span><span class="p">)</span>
525           <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>
526   <span class="p">}</span>
527 <span class="p">}</span>
528
529 <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">&amp;</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">&amp;</span> <span class="n">dst</span><span class="p">)</span>
530 <span class="p">{</span>
531   <span class="n">assert</span><span class="p">(</span><span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">()</span><span class="o">&gt;=</span><span class="mi">2</span><span class="p">);</span>
532   <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>
533                        <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>
534 <span class="p">}</span>
535 </pre></div>
536 </div>
537 <p><code class="docutils literal"><span class="pre">subimage_view</span></code> is another example of a GIL view transformation
538 function. It takes a source view and a rectangular region (in this
539 case, defined as x_min,y_min,width,height) and returns a view
540 operating on that region of the source view. The above implementation
541 has no measurable performance degradation from the version that
542 operates on the original views.</p>
543 <p>Now that <code class="docutils literal"><span class="pre">x_gradient_unguarded</span></code> operates on every pixel, we can
544 rewrite it more compactly:</p>
545 <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">&amp;</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">&amp;</span> <span class="n">dst</span><span class="p">)</span>
546 <span class="p">{</span>
547   <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>
548   <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>
549       <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>
550 <span class="p">}</span>
551 </pre></div>
552 </div>
553 <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
554 one dimensional pixel iterators which iterate over each pixel in the
555 view, left to right and top to bottom. They do a proper &#8220;carriage
556 return&#8221; - they skip any unused bytes at the end of a row. As such,
557 they are slightly suboptimal, because they need to keep track of their
558 current position with respect to the end of the row. Their increment
559 operator performs one extra check (are we at the end of the row?), a
560 check that is avoided if two nested loops are used instead. These
561 iterators have a method <code class="docutils literal"><span class="pre">x()</span></code> which returns the more lightweight
562 horizontal iterator that we used previously. Horizontal iterators have
563 no notion of the end of rows. In this case, the horizontal iterators
564 are raw C pointers. In our example, we must use the horizontal
565 iterators to access the two neighbors properly, since they could
566 reside outside the image view.</p>
567 </div>
568 <div class="section" id="stl-equivalent-algorithms">
569 <h2><a class="toc-backref" href="#id7">STL Equivalent Algorithms</a></h2>
570 <p>GIL provides STL equivalents of many algorithms. For example,
571 <code class="docutils literal"><span class="pre">std::transform</span></code> is an STL algorithm that sets each element in a
572 destination range the result of a generic function taking the
573 corresponding element of the source range. In our example, we want to
574 assign to each destination pixel the value of the half-difference of
575 the horizontal neighbors of the corresponding source pixel.  If we
576 abstract that operation in a function object, we can use GIL&#8217;s
577 <code class="docutils literal"><span class="pre">transform_pixel_positions</span></code> to do that:</p>
578 <div class="highlight-cpp"><div class="highlight"><pre><span class="k">struct</span> <span class="n">half_x_difference</span>
579 <span class="p">{</span>
580   <span class="kt">int</span> <span class="k">operator</span><span class="p">()(</span><span class="k">const</span> <span class="n">gray8c_loc_t</span><span class="o">&amp;</span> <span class="n">src_loc</span><span class="p">)</span> <span class="k">const</span>
581   <span class="p">{</span>
582       <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>
583   <span class="p">}</span>
584 <span class="p">};</span>
585
586 <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">&amp;</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">&amp;</span> <span class="n">dst</span><span class="p">)</span>
587 <span class="p">{</span>
588   <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>
589 <span class="p">}</span>
590 </pre></div>
591 </div>
592 <p>GIL provides the algorithms <code class="docutils literal"><span class="pre">for_each_pixel</span></code> and
593 <code class="docutils literal"><span class="pre">transform_pixels</span></code> which are image view equivalents of STL
594 <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
595 <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
596 instead of references to pixels, pass to the generic function pixel
597 locators. This allows for more powerful functions that can use the
598 pixel neighbors through the passed locators.  GIL algorithms iterate
599 through the pixels using the more efficient two nested loops (as
600 opposed to the single loop using 1-D iterators)</p>
601 </div>
602 <div class="section" id="color-conversion">
603 <h2><a class="toc-backref" href="#id8">Color Conversion</a></h2>
604 <p>Instead of computing the gradient of each color plane of an image, we
605 often want to compute the gradient of the luminosity. In other words,
606 we want to convert the color image to grayscale and compute the
607 gradient of the result. Here how to compute the luminosity gradient of
608 a 32-bit float RGB image:</p>
609 <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">&amp;</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">&amp;</span> <span class="n">dst</span><span class="p">)</span>
610 <span class="p">{</span>
611   <span class="n">x_gradient</span><span class="p">(</span><span class="n">color_converted_view</span><span class="o">&lt;</span><span class="n">gray8_pixel_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">src</span><span class="p">),</span> <span class="n">dst</span><span class="p">);</span>
612 <span class="p">}</span>
613 </pre></div>
614 </div>
615 <p><code class="docutils literal"><span class="pre">color_converted_view</span></code> is a GIL view transformation function that
616 takes any image view and returns a view in a target color space and
617 channel depth (specified as template parameters). In our example, it
618 constructs an 8-bit integer grayscale view over 32-bit float RGB
619 pixels. Like all other view transformation functions,
620 <code class="docutils literal"><span class="pre">color_converted_view</span></code> is very fast and shallow. It doesn&#8217;t copy the
621 data or perform any color conversion. Instead it returns a view that
622 performs color conversion every time its pixels are accessed.</p>
623 <p>In the generic version of this algorithm we might like to convert the
624 color space to grayscale, but keep the channel depth the same. We do
625 that by constructing the type of a GIL grayscale pixel with the same
626 channel as the source, and color convert to that pixel type:</p>
627 <div class="highlight-cpp"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstView</span><span class="o">&gt;</span>
628 <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">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="n">DstView</span> <span class="k">const</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
629 <span class="p">{</span>
630   <span class="k">using</span> <span class="n">gray_pixel_t</span> <span class="o">=</span> <span class="n">pixel</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">channel_type</span><span class="o">&lt;</span><span class="n">SrcView</span><span class="o">&gt;::</span><span class="n">type</span><span class="p">,</span> <span class="n">gray_layout_t</span><span class="o">&gt;</span><span class="p">;</span>
631   <span class="n">x_gradient</span><span class="p">(</span><span class="n">color_converted_view</span><span class="o">&lt;</span><span class="n">gray_pixel_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">src</span><span class="p">),</span> <span class="n">dst</span><span class="p">);</span>
632 <span class="p">}</span>
633 </pre></div>
634 </div>
635 <p>When the destination color space and channel type happens to be the
636 same as the source one, color conversion is unnecessary. GIL detects
637 this case and avoids calling the color conversion code at all -
638 i.e. <code class="docutils literal"><span class="pre">color_converted_view</span></code> returns back the source view unchanged.</p>
639 </div>
640 <div class="section" id="image">
641 <h2><a class="toc-backref" href="#id9">Image</a></h2>
642 <p>The above example has a performance problem - <code class="docutils literal"><span class="pre">x_gradient</span></code>
643 dereferences most source pixels twice, which will cause the above code
644 to perform color conversion twice.  Sometimes it may be more efficient
645 to copy the color converted image into a temporary buffer and use it
646 to compute the gradient - that way color conversion is invoked once
647 per pixel. Using our non-generic version we can do it like this:</p>
648 <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">&amp;</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">&amp;</span> <span class="n">dst</span><span class="p">)</span>
649 <span class="p">{</span>
650   <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>
651   <span class="n">copy_pixels</span><span class="p">(</span><span class="n">color_converted_view</span><span class="o">&lt;</span><span class="n">gray8_pixel_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">src</span><span class="p">),</span> <span class="n">view</span><span class="p">(</span><span class="n">ccv_image</span><span class="p">));</span>
652
653   <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>
654 <span class="p">}</span>
655 </pre></div>
656 </div>
657 <p>First we construct an 8-bit grayscale image with the same dimensions
658 as our source. Then we copy a color-converted view of the source into
659 the temporary image.  Finally we use a read-only view of the temporary
660 image in our <code class="docutils literal"><span class="pre">x_gradient</span> <span class="pre">algorithm</span></code>. As the example shows, GIL
661 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
662 image and return a mutable or an immutable view of its pixels.</p>
663 <p>Creating a generic version of the above is a bit trickier:</p>
664 <div class="highlight-cpp"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstView</span><span class="o">&gt;</span>
665 <span class="kt">void</span> <span class="n">x_luminosity_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">SrcView</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">DstView</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
666 <span class="p">{</span>
667   <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">&lt;</span><span class="n">DstView</span><span class="o">&gt;::</span><span class="n">type</span><span class="p">;</span>
668   <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">&lt;</span><span class="n">d_channel_t</span><span class="o">&gt;::</span><span class="n">type</span><span class="p">;</span>
669   <span class="k">using</span> <span class="n">gray_pixel_t</span> <span class="o">=</span> <span class="n">pixel</span><span class="o">&lt;</span><span class="n">channel_t</span><span class="p">,</span> <span class="n">gray_layout_t</span><span class="o">&gt;</span><span class="p">;</span>
670   <span class="k">using</span> <span class="n">gray_image_t</span> <span class="o">=</span> <span class="n">image</span><span class="o">&lt;</span><span class="n">gray_pixel_t</span><span class="p">,</span> <span class="nb">false</span><span class="o">&gt;</span><span class="p">;</span>
671
672   <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>
673   <span class="n">copy_pixels</span><span class="p">(</span><span class="n">color_converted_view</span><span class="o">&lt;</span><span class="n">gray_pixel_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">src</span><span class="p">),</span> <span class="n">view</span><span class="p">(</span><span class="n">ccv_image</span><span class="p">));</span>
674   <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>
675 <span class="p">}</span>
676 </pre></div>
677 </div>
678 <p>First we use the <code class="docutils literal"><span class="pre">channel_type</span></code> metafunction to get the channel type
679 of the destination view. A metafunction is a function operating on
680 types. In GIL metafunctions are class templates (declared with
681 <code class="docutils literal"><span class="pre">struct</span></code> type specifier) which take their parameters as template
682 parameters and return their result in a nested typedef called
683 <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
684 in this example is called with the type of an image view and returns
685 the type of the channel associated with that image view.</p>
686 <p>GIL constructs that have an associated pixel type, such as pixels,
687 pixel iterators, locators, views and images, all model
688 <code class="docutils literal"><span class="pre">PixelBasedConcept</span></code>, which means that they provide a set of
689 metafunctions to query the pixel properties, such as <code class="docutils literal"><span class="pre">channel_type</span></code>,
690 <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>
691 <p>After we get the channel type of the destination view, we use another
692 metafunction to remove its sign (if it is a signed integral type) and
693 then use it to generate the type of a grayscale pixel. From the pixel
694 type we create the image type. GIL&#8217;s image class is specialized over
695 the pixel type and a boolean indicating whether the image should be
696 planar or interleaved.  Single-channel (grayscale) images in GIL must
697 always be interleaved. There are multiple ways of constructing types
698 in GIL. Instead of instantiating the classes directly we could have
699 used type factory metafunctions. The following code is equivalent:</p>
700 <div class="highlight-cpp"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstView</span><span class="o">&gt;</span>
701 <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">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="n">DstView</span> <span class="k">const</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
702 <span class="p">{</span>
703   <span class="k">typedef</span> <span class="k">typename</span> <span class="n">channel_type</span><span class="o">&lt;</span><span class="n">DstView</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">d_channel_t</span><span class="p">;</span>
704   <span class="k">typedef</span> <span class="k">typename</span> <span class="n">channel_convert_to_unsigned</span><span class="o">&lt;</span><span class="n">d_channel_t</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">channel_t</span><span class="p">;</span>
705   <span class="k">typedef</span> <span class="k">typename</span> <span class="n">image_type</span><span class="o">&lt;</span><span class="n">channel_t</span><span class="p">,</span> <span class="n">gray_layout_t</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">gray_image_t</span><span class="p">;</span>
706   <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>
707
708   <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>
709   <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>
710   <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>
711 <span class="p">}</span>
712 </pre></div>
713 </div>
714 <p>GIL provides a set of metafunctions that generate GIL types -
715 <code class="docutils literal"><span class="pre">image_type</span></code> is one such meta-function that constructs the type of
716 an image from a given channel type, color layout, and
717 planar/interleaved option (the default is interleaved). There are also
718 similar meta-functions to construct the types of pixel references,
719 iterators, locators and image views. GIL also has metafunctions
720 <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>,
721 <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
722 type of a GIL construct from a given source one by changing one or
723 more properties of the type and keeping the rest.</p>
724 <p>From the image type we can use the nested typedef <code class="docutils literal"><span class="pre">value_type</span></code> to
725 obtain the type of a pixel. GIL images, image views and locators have
726 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
727 the pixel and a reference to the pixel. If you have a pixel iterator,
728 you can get these types from its <code class="docutils literal"><span class="pre">iterator_traits</span></code>. Note also the
729 algorithm <code class="docutils literal"><span class="pre">copy_and_convert_pixels</span></code>, which is an abbreviated version
730 of <code class="docutils literal"><span class="pre">copy_pixels</span></code> with a color converted source view.</p>
731 </div>
732 <div class="section" id="virtual-image-views">
733 <h2><a class="toc-backref" href="#id10">Virtual Image Views</a></h2>
734 <p>So far we have been dealing with images that have pixels stored in
735 memory. GIL allows you to create an image view of an arbitrary image,
736 including a synthetic function. To demonstrate this, let us create a
737 view of the Mandelbrot set.  First, we need to create a function
738 object that computes the value of the Mandelbrot set at a given
739 location (x,y) in the image:</p>
740 <div class="highlight-cpp"><div class="highlight"><pre><span class="c1">// models PixelDereferenceAdaptorConcept</span>
741 <span class="k">struct</span> <span class="n">mandelbrot_fn</span>
742 <span class="p">{</span>
743   <span class="k">typedef</span> <span class="n">point</span><span class="o">&lt;</span><span class="kt">ptrdiff_t</span><span class="o">&gt;</span>   <span class="n">point_t</span><span class="p">;</span>
744
745   <span class="k">typedef</span> <span class="n">mandelbrot_fn</span>       <span class="n">const_t</span><span class="p">;</span>
746   <span class="k">typedef</span> <span class="n">gray8_pixel_t</span>       <span class="n">value_type</span><span class="p">;</span>
747   <span class="k">typedef</span> <span class="n">value_type</span>          <span class="n">reference</span><span class="p">;</span>
748   <span class="k">typedef</span> <span class="n">value_type</span>          <span class="n">const_reference</span><span class="p">;</span>
749   <span class="k">typedef</span> <span class="n">point_t</span>             <span class="n">argument_type</span><span class="p">;</span>
750   <span class="k">typedef</span> <span class="n">reference</span>           <span class="n">result_type</span><span class="p">;</span>
751   <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>
752
753   <span class="n">mandelbrot_fn</span><span class="p">()</span> <span class="p">{}</span>
754   <span class="n">mandelbrot_fn</span><span class="p">(</span><span class="k">const</span> <span class="n">point_t</span><span class="o">&amp;</span> <span class="n">sz</span><span class="p">)</span> <span class="o">:</span> <span class="n">_img_size</span><span class="p">(</span><span class="n">sz</span><span class="p">)</span> <span class="p">{}</span>
755
756   <span class="n">result_type</span> <span class="k">operator</span><span class="p">()(</span><span class="k">const</span> <span class="n">point_t</span><span class="o">&amp;</span> <span class="n">p</span><span class="p">)</span> <span class="k">const</span>
757   <span class="p">{</span>
758       <span class="c1">// normalize the coords to (-2..1, -1.5..1.5)</span>
759       <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">&lt;</span><span class="kt">double</span><span class="o">&gt;</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">x</span><span class="o">/</span><span class="p">(</span><span class="kt">double</span><span class="p">)</span><span class="n">_img_size</span><span class="p">.</span><span class="n">x</span><span class="o">*</span><span class="mi">3</span><span class="o">-</span><span class="mi">2</span><span class="p">,</span> <span class="n">p</span><span class="p">.</span><span class="n">y</span><span class="o">/</span><span class="p">(</span><span class="kt">double</span><span class="p">)</span><span class="n">_img_size</span><span class="p">.</span><span class="n">y</span><span class="o">*</span><span class="mi">3</span><span class="o">-</span><span class="mf">1.5f</span><span class="p">));</span>
760       <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>
761   <span class="p">}</span>
762 <span class="k">private</span><span class="o">:</span>
763   <span class="n">point_t</span> <span class="n">_img_size</span><span class="p">;</span>
764
765   <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">&lt;</span><span class="kt">double</span><span class="o">&gt;&amp;</span> <span class="n">p</span><span class="p">)</span> <span class="k">const</span>
766   <span class="p">{</span>
767       <span class="n">point</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;</span> <span class="n">Z</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
768       <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="mi">100</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span>  <span class="c1">// 100 iterations</span>
769   <span class="p">{</span>
770           <span class="n">Z</span> <span class="o">=</span> <span class="n">point</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;</span><span class="p">(</span><span class="n">Z</span><span class="p">.</span><span class="n">x</span><span class="o">*</span><span class="n">Z</span><span class="p">.</span><span class="n">x</span> <span class="o">-</span> <span class="n">Z</span><span class="p">.</span><span class="n">y</span><span class="o">*</span><span class="n">Z</span><span class="p">.</span><span class="n">y</span> <span class="o">+</span> <span class="n">p</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="mi">2</span><span class="o">*</span><span class="n">Z</span><span class="p">.</span><span class="n">x</span><span class="o">*</span><span class="n">Z</span><span class="p">.</span><span class="n">y</span> <span class="o">+</span> <span class="n">p</span><span class="p">.</span><span class="n">y</span><span class="p">);</span>
771           <span class="k">if</span> <span class="p">(</span><span class="n">Z</span><span class="p">.</span><span class="n">x</span><span class="o">*</span><span class="n">Z</span><span class="p">.</span><span class="n">x</span> <span class="o">+</span> <span class="n">Z</span><span class="p">.</span><span class="n">y</span><span class="o">*</span><span class="n">Z</span><span class="p">.</span><span class="n">y</span> <span class="o">&gt;</span> <span class="mi">4</span><span class="p">)</span>
772               <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>
773       <span class="p">}</span>
774       <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
775   <span class="p">}</span>
776 <span class="p">};</span>
777 </pre></div>
778 </div>
779 <p>We can now use GIL&#8217;s <code class="docutils literal"><span class="pre">virtual_2d_locator</span></code> with this function object
780 to construct a Mandelbrot view of size 200x200 pixels:</p>
781 <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>
782 <span class="k">typedef</span> <span class="n">virtual_2d_locator</span><span class="o">&lt;</span><span class="n">mandelbrot_fn</span><span class="p">,</span><span class="nb">false</span><span class="o">&gt;</span> <span class="n">locator_t</span><span class="p">;</span>
783 <span class="k">typedef</span> <span class="n">image_view</span><span class="o">&lt;</span><span class="n">locator_t</span><span class="o">&gt;</span> <span class="n">my_virt_view_t</span><span class="p">;</span>
784
785 <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>
786
787 <span class="c1">// Construct a Mandelbrot view with a locator, taking top-left corner (0,0) and step (1,1)</span>
788 <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>
789 </pre></div>
790 </div>
791 <p>We can treat the synthetic view just like a real one. For example,
792 let&#8217;s invoke our <code class="docutils literal"><span class="pre">x_gradient</span></code> algorithm to compute the gradient of
793 the 90-degree rotated view of the Mandelbrot set and save the original
794 and the result:</p>
795 <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>
796 <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>
797
798 <span class="c1">// Save the Mandelbrot set and its 90-degree rotated gradient (jpeg cannot save signed char; must convert to unsigned char)</span>
799 <span class="n">jpeg_write_view</span><span class="p">(</span><span class="s">&quot;mandel.jpg&quot;</span><span class="p">,</span><span class="n">mandel</span><span class="p">);</span>
800 <span class="n">jpeg_write_view</span><span class="p">(</span><span class="s">&quot;mandel_grad.jpg&quot;</span><span class="p">,</span><span class="n">color_converted_view</span><span class="o">&lt;</span><span class="n">gray8_pixel_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">const_view</span><span class="p">(</span><span class="n">img</span><span class="p">)));</span>
801 </pre></div>
802 </div>
803 <p>Here is what the two files look like:</p>
804 <img alt="../_images/mandel.jpg" src="../_images/mandel.jpg" />
805 </div>
806 <div class="section" id="run-time-specified-images-and-image-views">
807 <h2><a class="toc-backref" href="#id11">Run-Time Specified Images and Image Views</a></h2>
808 <p>So far we have created a generic function that computes the image
809 gradient of an image view template specialization.  Sometimes,
810 however, the properties of an image view, such as its color space and
811 channel depth, may not be available at compile time.  GIL&#8217;s
812 <code class="docutils literal"><span class="pre">dynamic_image</span></code> extension allows for working with GIL constructs
813 that are specified at run time, also called _variants_. GIL provides
814 models of a run-time instantiated image, <code class="docutils literal"><span class="pre">any_image</span></code>, and a run-time
815 instantiated image view, <code class="docutils literal"><span class="pre">any_image_view</span></code>. The mechanisms are in
816 place to create other variants, such as <code class="docutils literal"><span class="pre">any_pixel</span></code>,
817 <code class="docutils literal"><span class="pre">any_pixel_iterator</span></code>, etc.  Most of GIL&#8217;s algorithms and all of the
818 view transformation functions also work with run-time instantiated
819 image views and binary algorithms, such as <code class="docutils literal"><span class="pre">copy_pixels</span></code> can have
820 either or both arguments be variants.</p>
821 <p>Lets make our <code class="docutils literal"><span class="pre">x_luminosity_gradient</span></code> algorithm take a variant image
822 view. For simplicity, let&#8217;s assume that only the source view can be a
823 variant.  (As an example of using multiple variants, see GIL&#8217;s image
824 view algorithm overloads taking multiple variants.)</p>
825 <p>First, we need to make a function object that contains the templated
826 destination view and has an application operator taking a templated
827 source view:</p>
828 <div class="highlight-cpp"><div class="highlight"><pre><span class="cp">#include</span> <span class="cpf">&lt;boost/gil/extension/dynamic_image/dynamic_image_all.hpp&gt;</span><span class="cp"></span>
829
830 <span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">DstView</span><span class="o">&gt;</span>
831 <span class="k">struct</span> <span class="n">x_gradient_obj</span>
832 <span class="p">{</span>
833   <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>
834
835   <span class="k">const</span> <span class="n">DstView</span><span class="o">&amp;</span> <span class="n">_dst</span><span class="p">;</span>
836   <span class="n">x_gradient_obj</span><span class="p">(</span><span class="k">const</span> <span class="n">DstView</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span> <span class="o">:</span> <span class="n">_dst</span><span class="p">(</span><span class="n">dst</span><span class="p">)</span> <span class="p">{}</span>
837
838   <span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="o">&gt;</span>
839   <span class="kt">void</span> <span class="k">operator</span><span class="p">()(</span><span class="k">const</span> <span class="n">SrcView</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> <span class="n">x_luminosity_gradient</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">_dst</span><span class="p">);</span> <span class="p">}</span>
840 <span class="p">};</span>
841 </pre></div>
842 </div>
843 <p>The second step is to provide an overload of <code class="docutils literal"><span class="pre">x_luminosity_gradient</span></code> that
844 takes image view variant and calls GIL&#8217;s <code class="docutils literal"><span class="pre">apply_operation</span></code> passing it the
845 function object:</p>
846 <div class="highlight-cpp"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcViews</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstView</span><span class="o">&gt;</span>
847 <span class="kt">void</span> <span class="n">x_luminosity_gradient</span><span class="p">(</span><span class="k">const</span> <span class="n">any_image_view</span><span class="o">&lt;</span><span class="n">SrcViews</span><span class="o">&gt;&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">DstView</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
848 <span class="p">{</span>
849   <span class="n">apply_operation</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">x_gradient_obj</span><span class="o">&lt;</span><span class="n">DstView</span><span class="o">&gt;</span><span class="p">(</span><span class="n">dst</span><span class="p">));</span>
850 <span class="p">}</span>
851 </pre></div>
852 </div>
853 <p><code class="docutils literal"><span class="pre">any_image_view&lt;SrcViews&gt;</span></code> is the image view variant. It is
854 templated over <code class="docutils literal"><span class="pre">SrcViews</span></code>, an enumeration of all possible view types
855 the variant can take.  <code class="docutils literal"><span class="pre">src</span></code> contains inside an index of the
856 currently instantiated type, as well as a block of memory containing
857 the instance.  <code class="docutils literal"><span class="pre">apply_operation</span></code> goes through a switch statement
858 over the index, each case of which casts the memory to the correct
859 view type and invokes the function object with it. Invoking an
860 algorithm on a variant has the overhead of one switch
861 statement. Algorithms that perform an operation for each pixel in an
862 image view have practically no performance degradation when used with
863 a variant.</p>
864 <p>Here is how we can construct a variant and invoke the algorithm:</p>
865 <div class="highlight-cpp"><div class="highlight"><pre><span class="cp">#include</span> <span class="cpf">&lt;boost/mpl/vector.hpp&gt;</span><span class="cp"></span>
866 <span class="cp">#include</span> <span class="cpf">&lt;boost/gil/extension/io/jpeg_dynamic_io.hpp&gt;</span><span class="cp"></span>
867
868 <span class="k">typedef</span> <span class="n">mpl</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">gray8_image_t</span><span class="p">,</span> <span class="n">gray16_image_t</span><span class="p">,</span> <span class="n">rgb8_image_t</span><span class="p">,</span> <span class="n">rgb16_image_t</span><span class="o">&gt;</span> <span class="n">my_img_types</span><span class="p">;</span>
869 <span class="n">any_image</span><span class="o">&lt;</span><span class="n">my_img_types</span><span class="o">&gt;</span> <span class="n">runtime_image</span><span class="p">;</span>
870 <span class="n">jpeg_read_image</span><span class="p">(</span><span class="s">&quot;input.jpg&quot;</span><span class="p">,</span> <span class="n">runtime_image</span><span class="p">);</span>
871
872 <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>
873 <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>
874 <span class="n">jpeg_write_view</span><span class="p">(</span><span class="s">&quot;x_gradient.jpg&quot;</span><span class="p">,</span> <span class="n">color_converted_view</span><span class="o">&lt;</span><span class="n">gray8_pixel_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">const_view</span><span class="p">(</span><span class="n">gradient</span><span class="p">)));</span>
875 </pre></div>
876 </div>
877 <p>In this example, we create an image variant that could be 8-bit or
878 16-bit RGB or grayscale image. We then use GIL&#8217;s I/O extension to load
879 the image from file in its native color space and channel depth. If
880 none of the allowed image types matches the image on disk, an
881 exception will be thrown.  We then construct a 8 bit signed
882 (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>
883 on it. Finally we save the result into another file.  We save the view
884 converted to 8-bit unsigned, because JPEG I/O does not support signed
885 char.</p>
886 <p>Note how free functions and methods such as <code class="docutils literal"><span class="pre">jpeg_read_image</span></code>,
887 <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
888 variant types.  For templated images <code class="docutils literal"><span class="pre">view(img)</span></code> returns a templated
889 view, whereas for image variants it returns a view variant.  For
890 example, the return type of <code class="docutils literal"><span class="pre">view(runtime_image)</span></code> is
891 <code class="docutils literal"><span class="pre">any_image_view&lt;Views&gt;</span></code> where <code class="docutils literal"><span class="pre">Views</span></code> enumerates four views
892 corresponding to the four image types.  <code class="docutils literal"><span class="pre">const_view(runtime_image)</span></code>
893 returns a <code class="docutils literal"><span class="pre">any_image_view</span></code> of the four read-only view types, etc.</p>
894 <p>A warning about using variants: instantiating an algorithm with a
895 variant effectively instantiates it with every possible type the
896 variant can take.  For binary algorithms, the algorithm is
897 instantiated with every possible combination of the two input types!
898 This can take a toll on both the compile time and the executable size.</p>
899 </div>
900 <div class="section" id="conclusion">
901 <h2><a class="toc-backref" href="#id12">Conclusion</a></h2>
902 <p>This tutorial provides a glimpse at the challenges associated with
903 writing generic and efficient image processing algorithms in GIL.  We
904 have taken a simple algorithm and shown how to make it work with image
905 representations that vary in bit depth, color space, ordering of the
906 channels, and planar/interleaved structure. We have demonstrated that
907 the algorithm can work with fully abstracted virtual images, and even
908 images whose type is specified at run time. The associated video
909 presentation also demonstrates that even for complex scenarios the
910 generated assembly is comparable to that of a C version of the
911 algorithm, hand-written for the specific image types.</p>
912 <p>Yet, even for such a simple algorithm, we are far from making a fully
913 generic and optimized code. In particular, the presented algorithms
914 work on homogeneous images, i.e. images whose pixels have channels
915 that are all of the same type. There are examples of images, such as a
916 packed 565 RGB format, which contain channels of different
917 types. While GIL provides concepts and algorithms operating on
918 heterogeneous pixels, we leave the task of extending x_gradient as an
919 exercise for the reader.  Second, after computing the value of the
920 gradient we are simply casting it to the destination channel
921 type. This may not always be the desired operation. For example, if
922 the source channel is a float with range [0..1] and the destination is
923 unsigned char, casting the half-difference to unsigned char will
924 result in either 0 or 1. Instead, what we might want to do is scale
925 the result into the range of the destination channel. GIL&#8217;s
926 channel-level algorithms might be useful in such cases. For example,
927 p channel_convert converts between channels by linearly scaling the
928 source channel value into the range of the destination channel.</p>
929 <p>There is a lot to be done in improving the performance as
930 well. Channel-level operations, such as the half-difference, could be
931 abstracted out into atomic channel-level algorithms and performance
932 overloads could be provided for concrete channel
933 types. Processor-specific operations could be used, for example, to
934 perform the operation over an entire row of pixels simultaneously, or
935 the data could be pre-fetched. All of these optimizations can be
936 realized as performance specializations of the generic
937 algorithm. Finally, compilers, while getting better over time, are
938 still failing to fully optimize generic code in some cases, such as
939 failing to inline some functions or put some variables into
940 registers. If performance is an issue, it might be worth trying your
941 code with different compilers.</p>
942 </div>
943 </div>
944
945
946     <div class="navbar" style="text-align:right;">
947       
948       
949       <a class="prev" title="Tutorial: Histogram" href="histogram.html"><img src="../_static/prev.png" alt="prev"/></a>
950       <a class="next" title="Naming Conventions" href="../naming.html"><img src="../_static/next.png" alt="next"/></a>
951       
952     </div>
953     </div>
954     <div class="footer" role="contentinfo">
955       Last updated on 2019-12-10 00:12:10.
956       Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.5.6.
957     </div>
958   </body>
959 </html>