<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Recent changes to SampleImageProcess</title><link>https://sourceforge.net/p/arcomem/wiki/SampleImageProcess/</link><description>Recent changes to SampleImageProcess</description><atom:link href="https://sourceforge.net/p/arcomem/wiki/SampleImageProcess/feed" rel="self"/><language>en</language><lastBuildDate>Wed, 19 Feb 2014 00:36:32 -0000</lastBuildDate><atom:link href="https://sourceforge.net/p/arcomem/wiki/SampleImageProcess/feed" rel="self" type="application/rss+xml"/><item><title>SampleImageProcess modified by John Arcoman</title><link>https://sourceforge.net/p/arcomem/wiki/SampleImageProcess/</link><description>&lt;div class="markdown_content"&gt;&lt;h1 id="the-sample-image-process-module"&gt;The Sample Image Process Module&lt;/h1&gt;
&lt;p&gt;The &lt;a class="" href="../apidocs/eu/arcomem/framework/offline/processes/SampleImageProcess"&gt;&lt;code&gt;SampleImageProcess&lt;/code&gt;&lt;/a&gt; module&lt;br /&gt;
shows a simple example of how to process images in an offline module. The class&lt;br /&gt;
also shows the use of a map-heavy offline module - one that has no reducer but&lt;br /&gt;
produces output for every valid row of the HBase table.&lt;/p&gt;
&lt;p&gt;The class has one internal class - the &lt;a class="" href="../apidocs/eu/arcomem/framework/offline/processes/SampleImageProcess.SampleImageProcessingMapper"&gt;&lt;code&gt;SampleImageProcessMapper&lt;/code&gt;&lt;/a&gt;&lt;br /&gt;
- that, for every image in the database, runs a face detector. The&lt;br /&gt;
&lt;a href="../apidocs/eu/arcomem/framework/offline/processes/SampleImageProcess.html#getMapperClass()"&gt;&lt;tt&gt;getMapperClass()&lt;/tt&gt;&lt;/a&gt;&lt;br /&gt;
returns the &lt;code&gt;class&lt;/code&gt; definition for this inner class - Hadoop will instantiate it.&lt;br /&gt;
The &lt;code&gt;Reducer&lt;/code&gt; returned by the&lt;br /&gt;
&lt;a href="../apidocs/eu/arcomem/framework/offline/processes/SampleImageProcess.html#getReducerClass()"&gt;&lt;tt&gt;getReducerClass()&lt;/tt&gt;&lt;/a&gt;&lt;br /&gt;
method is the &lt;a class="" href="../apidocs/eu/arcomem/framework/offline/util/NullReducer"&gt;&lt;code&gt;NullReducer&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Most offline processes will need the same sort of data for processing. The required&lt;br /&gt;
data is provided by the&lt;br /&gt;
&lt;a href="../apidocs/eu/arcomem/framework/offline/processes/SampleImageProcess.html#getRequiredColumnFamilies()"&gt;&lt;tt&gt;getRequiredColumnFamilies()&lt;/tt&gt;&lt;/a&gt;&lt;br /&gt;
method. We need the metadata field from the HBase (which contains the headers, mime&lt;br /&gt;
types and whatnot) and the actual content that was crawled (the image itself),&lt;br /&gt;
so we return a list with those fields named like so:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;    &lt;span class="n"&gt;final&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;AMResource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;METADATA_CF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AMResource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CONTENT_CF&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The class shows the best practice for creating counters. An internal enumeration&lt;br /&gt;
(called &lt;a class="" href="../apidocs/eu/arcomem/framework/offline/processes/SampleImageProcess.Counters"&gt;&lt;code&gt;Counters&lt;/code&gt;&lt;/a&gt;)&lt;br /&gt;
defines the counters that the process provides to the Hadoop context.&lt;br /&gt;
These are then set using the Hadoop &lt;code&gt;Context#getCounter()&lt;/code&gt; method. For example,&lt;br /&gt;
when a row of the database is encountered which is not an image we call:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getCounter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Counters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NOT_AN_IMAGE&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;a href="../apidocs/eu/arcomem/framework/offline/processes/SampleImageProcess.SampleImageProcessingMapper.html#map(org.apache.hadoop.io.Text,%20eu.arcomem.framework.offline.ResultResourceWrapper,%20org.apache.hadoop.mapreduce.Mapper.Context))"&gt;&lt;code&gt;map&lt;/code&gt; method&lt;/a&gt;&lt;br /&gt;
of the &lt;a class="" href="../apidocs/eu/arcomem/framework/offline/processes/SampleImageProcess.SampleImageProcessingMapper"&gt;&lt;code&gt;SampleImageProcessMapper&lt;/code&gt;&lt;/a&gt;&lt;br /&gt;
class begins by retrieving the row from the database:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span class="n"&gt;AMResourceVersion&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getResource&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;getLatestRowVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AMResourceVersion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We use the mime type of the row to determine whether we\'re trying to process&lt;br /&gt;
an image or not:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span class="c1"&gt;// Check if the incoming document appears to be an image&lt;/span&gt;
&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;mime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getDetectedMime&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;mime&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;mime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getMime&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;mime&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;mime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;image/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Increase the &amp;quot;not an image&amp;quot; counter&lt;/span&gt;
    &lt;span class="k"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getCounter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;Counters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="no"&gt;NOT_AN_IMAGE&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that we first try the detected mime type. This is detected during crawling&lt;br /&gt;
and stored into the database. If no mime type was detected, then we use the&lt;br /&gt;
mime type that was returned by the server when crawled. If the mime type&lt;br /&gt;
doesn\'t begin with &lt;code&gt;image/&lt;/code&gt; then we don\'t try to process the resource. Of course,&lt;br /&gt;
it\'s still possible it\'s not an image, but we carry on at this point anyway.&lt;/p&gt;
&lt;p&gt;We can then use the &lt;code&gt;resource.getContentAsInputStream()&lt;/code&gt; to get an input stream&lt;br /&gt;
to the bytes of the resource and read in an image (we use OpenIMAJ to read in&lt;br /&gt;
the images are we\'re processing using the OpenIMAJ face detector, but you can&lt;br /&gt;
use any image loader that accepts an &lt;code&gt;InputStream&lt;/code&gt; here).&lt;/p&gt;
&lt;p&gt;The processing that takes place from here on in depends entirely on your required&lt;br /&gt;
analysis. We simply do a face detection and increase some face counters. If&lt;br /&gt;
you wanted to write to the triple store then you can use the &lt;a class="" href="/p/arcomem/wiki/DataModel/"&gt;data model&lt;/a&gt;&lt;br /&gt;
to do that. Check the &lt;a class="" href="/p/arcomem/wiki/OfflineOutputs/"&gt;Writing Module Outputs&lt;/a&gt; section&lt;br /&gt;
for details on how to write the module analysis somewhere useful.&lt;/p&gt;&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">John Arcoman</dc:creator><pubDate>Wed, 19 Feb 2014 00:36:32 -0000</pubDate><guid>https://sourceforge.netbac60e255b83dc178cd12c580a28f31f795e8c53</guid></item></channel></rss>