// ĠCopyright Ġ 2 0 2 0 ĠGoogle ĠLLC Ċ // Ċ // ĠLicensed Ġunder Ġthe ĠApache ĠLicense , ĠVersion Ġ 2 . 0 Ġ( the Ġ" License "); Ċ // Ġyou Ġmay Ġnot Ġuse Ġthis Ġfile Ġexcept Ġin Ġcompliance Ġwith Ġthe ĠLicense . Ċ // ĠYou Ġmay Ġobtain Ġa Ġcopy Ġof Ġthe ĠLicense Ġat Ċ // Ċ // ĠĠĠĠĠ Ġhttp :// www . apache . org / licenses / LICENSE - 2 . 0 Ċ // Ċ // ĠUnless Ġrequired Ġby Ġapplicable Ġlaw Ġor Ġagreed Ġto Ġin Ġwriting , Ġsoftware Ċ // Ġdistributed Ġunder Ġthe ĠLicense Ġis Ġdistributed Ġon Ġan Ġ" AS ĠIS " ĠBASIS , Ċ // ĠWITHOUT ĠWARRANTIES ĠOR ĠCONDITIONS ĠOF ĠANY ĠKIND , Ġeither Ġexpress Ġor Ġimplied . Ċ // ĠSee Ġthe ĠLicense Ġfor Ġthe Ġspecific Ġlanguage Ġgoverning Ġpermissions Ġand Ċ // Ġlimitations Ġunder Ġthe ĠLicense . Ċ Ċ package Ġorg . tensorflow . lite . examples . digit classifier Ċ Ċ import Ġandroid . content . Context Ċ import Ġandroid . graphics . Bitmap Ċ import Ġandroid . util . Log Ċ import Ġcom . google . android . gms . tasks . Task Ċ import Ġcom . google . android . gms . tasks . Tasks . call Ċ import Ġjava . nio . ByteBuffer Ċ import Ġjava . nio . Byte Order Ċ import Ġjava . util . concurrent . Callable Ċ import Ġjava . util . concurrent . ExecutorService Ċ import Ġjava . util . concurrent . Executors Ċ import Ġorg . tensorflow . lite . Interpreter Ċ import Ġjava . io . File Ċ Ċ class ĠDig it Classifier ( private Ġval Ġcontext : ĠContext ) Ġ{ ĊĠ Ġprivate Ġvar Ġinterpreter : ĠInterpreter ? Ġ= Ġnull ĊĠ Ġvar Ġis Initialized Ġ= Ġfalse ĊĠĠĠ Ġprivate Ġset ĊĊĠ Ġ/** ĠExecutor Ġto Ġrun Ġinference Ġtask Ġin Ġthe Ġbackground Ġ*/ ĊĠ Ġprivate Ġval ĠexecutorService : ĠExecutor Service Ġ= ĠExec utors . new Cached ThreadPool () ĊĊĠ Ġprivate Ġvar Ġinput Image Width : ĠInt Ġ= Ġ 0 Ġ// Ġwill Ġbe Ġinferred Ġfrom ĠTF ĠLite Ġmodel ĊĠ Ġprivate Ġvar Ġinput Image Height : ĠInt Ġ= Ġ 0 Ġ// Ġwill Ġbe Ġinferred Ġfrom ĠTF ĠLite Ġmodel ĊĠ Ġprivate Ġvar Ġmodel Input Size : ĠInt Ġ= Ġ 0 Ġ// Ġwill Ġbe Ġinferred Ġfrom ĠTF ĠLite Ġmodel ĊĊĠ Ġfun Ġinitialize ( model : ĠAny ): ĠTask < Void > Ġ{ ĊĠĠĠ Ġreturn Ġcall ( ĊĠĠĠĠĠ ĠexecutorService , ĊĠĠĠĠĠ ĠCallable < Void > Ġ{ ĊĠĠĠĠĠĠĠ Ġinitialize Interpreter ( model ) ĊĠĠĠĠĠĠĠ Ġnull ĊĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ) ĊĠ Ġ} ĊĊĠ Ġprivate Ġfun Ġinitialize Interpreter ( model : ĠAny ) Ġ{ ĊĠĠĠ Ġ// ĠInitialize ĠTF ĠLite ĠInterpreter Ġwith ĠN NA PI Ġenabled ĊĠĠĠ Ġval Ġoptions Ġ= ĠInterpreter . Options () ĊĠĠĠ Ġoptions . set Use N NA PI ( true ) ĊĠĠĠ Ġvar Ġinterpreter : ĠInterpreter ĊĠĠĠ Ġif Ġ( model Ġis ĠByteBuffer ) Ġ{ ĊĠĠĠĠĠ Ġinterpreter Ġ= ĠInterpreter ( model , Ġoptions ) ĊĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠ Ġinterpreter Ġ= ĠInterpreter ( model Ġas ĠFile , Ġoptions ) ĊĠĠĠ Ġ} ĊĠĠĠ Ġ// ĠRead Ġinput Ġshape Ġfrom Ġmodel Ġfile ĊĠĠĠ Ġval Ġinput Shape Ġ= Ġinterpreter . getInput Tensor ( 0 ). shape () ĊĠĠĠ Ġinput Image Width Ġ= Ġinput Shape [ 1 ] ĊĠĠĠ Ġinput Image Height Ġ= Ġinput Shape [ 2 ] ĊĠĠĠ Ġmodel Input Size Ġ= ĠFLOAT _ TYPE _ SIZE Ġ* Ġinput Image Width Ġ* Ġinput Image Height Ġ* ĠPIX EL _ SIZE ĊĊĠĠĠ Ġ// ĠFinish Ġinterpreter Ġinitialization ĊĠĠĠ Ġthis . interpreter Ġ= Ġinterpreter ĊĠĠĠ Ġis Initialized Ġ= Ġtrue ĊĠĠĠ ĠLog . d ( TAG , Ġ" Initialized ĠT FL ite Ġinterpreter .") ĊĠ Ġ} ĊĊĠ Ġprivate Ġfun Ġclassify ( bitmap : ĠBitmap ): ĠString Ġ{ ĊĠĠĠ Ġif Ġ(! isInitialized ) Ġ{ ĊĠĠĠĠĠ Ġthrow ĠIllegalStateException (" TF ĠLite ĠInterpreter Ġis Ġnot Ġinitialized Ġyet .") ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġvar ĠstartTime : ĠLong ĊĠĠĠ Ġvar Ġelapsed Time : ĠLong ĊĊĠĠĠ Ġ// ĠPre processing : Ġresize Ġthe Ġinput ĊĠĠĠ ĠstartTime Ġ= ĠSystem . nano Time () ĊĠĠĠ Ġval Ġresized Image Ġ= ĠBitmap . create Scaled Bitmap ( bitmap , Ġinput Image Width , Ġinput Image Height , Ġtrue ) ĊĠĠĠ Ġval Ġbyte Buffer Ġ= Ġconvert Bitmap To ByteBuffer ( res ized Image ) ĊĠĠĠ Ġelapsed Time Ġ= Ġ( System . nano Time () Ġ- ĠstartTime ) Ġ/ Ġ 1 0 0 0 0 0 0 ĊĠĠĠ ĠLog . d ( TAG , Ġ" Pre processing Ġtime Ġ= Ġ" Ġ+ Ġelapsed Time Ġ+ Ġ" ms ") ĊĊĠĠĠ ĠstartTime Ġ= ĠSystem . nano Time () ĊĠĠĠ Ġval Ġresult Ġ= ĠArray ( 1 ) Ġ{ ĠFloat Array ( OUTPUT _ CLASSES _ COUNT ) Ġ} ĊĠĠĠ Ġinterpreter ?. run ( byte Buffer , Ġresult ) ĊĠĠĠ Ġelapsed Time Ġ= Ġ( System . nano Time () Ġ- ĠstartTime ) Ġ/ Ġ 1 0 0 0 0 0 0 ĊĠĠĠ ĠLog . d ( TAG , Ġ" Inference Ġtime Ġ= Ġ" Ġ+ Ġelapsed Time Ġ+ Ġ" ms ") ĊĊĠĠĠ Ġreturn Ġget Output String ( result [ 0 ]) ĊĠ Ġ} ĊĊĠ Ġfun Ġclassify Async ( bitmap : ĠBitmap ): ĠTask < String > Ġ{ ĊĠĠĠ Ġreturn Ġcall ( executor Service , ĠCallable < String > Ġ{ Ġclassify ( bitmap ) Ġ}) ĊĠ Ġ} ĊĊĠ Ġfun Ġclose () Ġ{ ĊĠĠĠ Ġcall ( ĊĠĠĠĠĠ ĠexecutorService , ĊĠĠĠĠĠ ĠCallable < String > Ġ{ ĊĠĠĠĠĠĠĠ Ġinterpreter ?. close () ĊĠĠĠĠĠĠĠ ĠLog . d ( TAG , Ġ" Closed ĠT FL ite Ġinterpreter .") ĊĠĠĠĠĠĠĠ Ġnull ĊĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ) ĊĠ Ġ} ĊĊĠ Ġprivate Ġfun Ġconvert Bitmap To ByteBuffer ( bitmap : ĠBitmap ): ĠByteBuffer Ġ{ ĊĠĠĠ Ġval Ġbyte Buffer Ġ= ĠByteBuffer . allocate Direct ( model Input Size ) ĊĠĠĠ Ġbyte Buffer . order ( Byte Order . native Order ()) ĊĊĠĠĠ Ġval Ġpixels Ġ= ĠInt Array ( input Image Width Ġ* Ġinput Image Height ) ĊĠĠĠ Ġbitmap . get Pixels ( pixels , Ġ 0 , Ġbitmap . width , Ġ 0 , Ġ 0 , Ġbitmap . width , Ġbitmap . height ) ĊĊĠĠĠ Ġfor Ġ( pixel Value Ġin Ġpixels ) Ġ{ ĊĠĠĠĠĠ Ġval Ġr Ġ= Ġ( pixel Value Ġshr Ġ 1 6 Ġand Ġ 0 xFF ) ĊĠĠĠĠĠ Ġval Ġg Ġ= Ġ( pixel Value Ġshr Ġ 8 Ġand Ġ 0 xFF ) ĊĠĠĠĠĠ Ġval Ġb Ġ= Ġ( pixel Value Ġand Ġ 0 xFF ) ĊĊĠĠĠĠĠ Ġ// ĠConvert ĠRGB Ġto Ġgray scale Ġand Ġnormalize Ġpixel Ġvalue Ġto Ġ[ 0 .. 1 ] ĊĠĠĠĠĠ Ġval Ġnormalized Pixel Value Ġ= Ġ( r Ġ+ Ġg Ġ+ Ġb ) Ġ/ Ġ 3 . 0 f Ġ/ Ġ 2 5 5 . 0 f ĊĠĠĠĠĠ Ġbyte Buffer . put Float ( normalized Pixel Value ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġreturn Ġbyte Buffer ĊĠ Ġ} ĊĊĠ Ġprivate Ġfun Ġget Output String ( output : ĠFloat Array ): ĠString Ġ{ ĊĠĠĠ Ġval Ġmax Index Ġ= Ġoutput . indices . max By Ġ{ Ġoutput [ it ] Ġ} Ġ?: Ġ- 1 ĊĠĠĠ Ġreturn Ġ" Prediction ĠResult : Ġ% d \ n Confidence : Ġ% 2 f ". format ( max Index , Ġoutput [ max Index ]) ĊĠ Ġ} ĊĊĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠ Ġprivate Ġconst Ġval ĠTAG Ġ= Ġ" Digit Classifier " ĊĊĠĠĠ Ġprivate Ġconst Ġval ĠFLOAT _ TYPE _ SIZE Ġ= Ġ 4 ĊĠĠĠ Ġprivate Ġconst Ġval ĠPIX EL _ SIZE Ġ= Ġ 1 ĊĊĠĠĠ Ġprivate Ġconst Ġval ĠOUTPUT _ CLASSES _ COUNT Ġ= Ġ 1 0 ĊĠĠĠ Ġprivate Ġconst Ġval ĠMODEL _ NAME _ KEY Ġ= Ġ" model _ name " ĊĠ Ġ} Ċ } Ċ