<h3 id="image-editing-operations-using-arrayfire">Image editing operations using ArrayFire</h3>
<p>In this post, we will be looking at the following simple image editing operations using the ArrayFire library.</p>
<ul>
<li>contrast modification<br /></li>
<li>brightness modification<br /></li>
<li>translation<br /></li>
<li>digital zoom<br /></li>
<li>alpha blending<br /></li>
<li>unsharp mask</li>
</ul>
<p>Code required to do each operation and the corresponding input/output sample are given below in their corresponding sections.<br />All the operations are built using some existing image manipulation functions and the awesome element-wise operations enabled in ArrayFire.<br />If you are not aware of what the JIT feature in ArrayFire lets you do, please refer to one of our previous post here.</p>
<h4 id="contrast-modification">Contrast modification</h4>
<pre class="sourceCode c"><code class="sourceCode c"><span class="co">/**</span>
<span class="co"> * contrast value should be in the range [-1,1]</span>
<span class="co"> **/</span>
<span class="dt">void</span> changeContrast(array &amp;in, <span class="dt">const</span> <span class="dt">float</span> contrast)
{
    <span class="dt">float</span> scale     = tan((contrast<span class="dv">+1</span>)*Pi/<span class="dv">4</span>);
    in = ((in/<span class="fl">255.</span>0f - <span class="fl">0.</span>5f) * scale + <span class="fl">0.</span>5f) * <span class="fl">255.</span>0f;
}</code></pre>
<h2 id="brightness-modification">Brightness modification</h2>
<pre class="sourceCode c"><code class="sourceCode c"><span class="co">/**</span>
<span class="co"> * brightness value should be in the range [0,1]</span>
<span class="co"> **/</span>
<span class="dt">void</span> changeBrightness(array &amp;in, <span class="dt">const</span> <span class="dt">float</span> brightness, <span class="dt">const</span> <span class="dt">float</span> channelMax=<span class="fl">255.</span>0f)
{
    <span class="dt">float</span> factor = brightness*channelMax;
    <span class="kw">return</span> (in + factor);
}</code></pre>
<p>You may add an additional step to the above function that clamps each pixel value to [0,255] range. Clamping can be easily achieved by the following line of code.</p>
<pre class="sourceCode c"><code class="sourceCode c">image = (image&lt;<span class="fl">0.</span>0f)*<span class="fl">0.</span>0f + (image&gt;<span class="fl">255.</span>0f)*<span class="fl">255.</span>0f + (image&gt;=<span class="fl">0.</span>0f &amp;&amp; image&lt;=<span class="fl">255.</span>0f)*image;</code></pre>
<p>or a more generalized thresholding operation would like as below.</p>
<pre class="sourceCode c"><code class="sourceCode c">array clamp(<span class="dt">const</span> array &amp;in, <span class="dt">float</span> min=<span class="fl">0.</span>0f, <span class="dt">float</span> max=<span class="fl">255.</span>0f)
{
    <span class="kw">return</span> ((in&lt;min)*<span class="fl">0.</span>0f + (in&gt;max)*<span class="fl">255.</span>0f + (in&gt;=min &amp;&amp; in &lt;=max)*in);
}</code></pre>
<h2 id="image-translation">Image translation</h2>
<p>This operation can be achieved directly by a function in our library <code>translate</code>.</p>
<h2 id="digital-zoom">Digital Zoom</h2>
<pre class="sourceCode c"><code class="sourceCode c">array digZoom(<span class="dt">const</span> array &amp;in, <span class="dt">int</span> x, <span class="dt">int</span> y, <span class="dt">int</span> width, <span class="dt">int</span> height)
{
    array cropped = in(seq(height)+x,seq(width)+y,span);
    <span class="kw">return</span> resize((<span class="dt">unsigned</span>)in.dims(<span class="dv">0</span>),(<span class="dt">unsigned</span>)in.dims(<span class="dv">1</span>),cropped);
}</code></pre>
<h2 id="alpha-blending">Alpha Blending</h2>
<pre class="sourceCode c"><code class="sourceCode c">array alphaBlend(<span class="dt">const</span> array &amp;foreground, <span class="dt">const</span> array &amp;background, <span class="dt">const</span> array &amp;mask)
{
    array tiledMask;
    <span class="kw">if</span> (mask.dims(<span class="dv">2</span>)!=foreground.dims(<span class="dv">2</span>))
        tiledMask = tile(mask,<span class="dv">1</span>,<span class="dv">1</span>,foreground.dims(<span class="dv">2</span>));
    <span class="kw">return</span> foreground*tiledMask+(<span class="fl">1.</span>0f-tiledMask)*background;
}</code></pre>
<p>For the purpose of this example, a very simple mask was created using this single line of code <code>array mask = clamp(intensity,10.0f,255.0f)&gt;0.0f;</code>. A more detailed and accurate mask would deliver more appropiate blending.</p>
<h2 id="unsharpmask">Unsharpmask</h2>
<pre class="sourceCode c"><code class="sourceCode c"><span class="co">/**</span>
<span class="co"> * radius effects the level of details that will effected during sharpening process</span>
<span class="co"> * amount value should be in the range [0,1] or [1,]</span>
<span class="co"> * note: value of 1.0 for amount results unsharp masking</span>
<span class="co"> *       values &gt; 1.0 results in highboost filter effect</span>
<span class="co"> **/</span>
array usm(<span class="dt">const</span> array &amp;in, <span class="dt">float</span> radius, <span class="dt">float</span> amount)
{
    <span class="dt">int</span> gKernelLen  = <span class="dv">2</span>*radius + <span class="dv">1</span>;
    array blurKernel= gaussiankernel(gKernelLen,gKernelLen);
    array blur  = convolve(in,blurKernel);
    <span class="kw">return</span> (in + amount*(in - blur));
}</code></pre>