Klasifikasi Citra Menggunakan Convolutional Neural Network (CNN) dengan Model TensorFlow Lite pada Android

Klasifikasi Citra Menggunakan Convolutional Neural Network (CNN) dengan Model TensorFlow Lite pada Android - Hallo sahabat pawang bisnis, Pada sharing INFO TEKNIK berjudul Klasifikasi Citra Menggunakan Convolutional Neural Network (CNN) dengan Model TensorFlow Lite pada Android, saya telah menulis sebuah artikel. mudah-mudahan isi postingan dapat bermanfaat dan mudah anda pahami. okelah, ini dia isi contennya.

Artikel : Klasifikasi Citra Menggunakan Convolutional Neural Network (CNN) dengan Model TensorFlow Lite pada Android
Judul : Klasifikasi Citra Menggunakan Convolutional Neural Network (CNN) dengan Model TensorFlow Lite pada Android


Klasifikasi Citra Menggunakan Convolutional Neural Network (CNN) dengan Model TensorFlow Lite pada Android

Artikel Tugas Kuliah,
        Assalamu'alaikum Wr. Wb. pada kesempatan ini saya ingin melanjutkan tutorial sebelumnya yaitu Deep Learning dengan Convolutional Neural Network (CNN) pada Google Colaboratory. Pada tutorial ini akan menerapkan model hasil pelatihan CNN dari postingan sebelumnya pada perangkat Android. Agar CNN tersebut dapat digunakan pada perangkat Android maka diperlukan model hasil pelatihannya dalam bentuk TensorFlow Lite. TensorFlow Lite berfungsi untuk menjalankan model hasil pelatihan CNN pada perangkat dengan kebutuhan sumber daya yang rendah dan membutuhkan kecepatan proses yang tinggi. File Model TensorFlow Lite (.tflite) tersebut nantinya akan diimpor ke dalam folder project pada Android Studio.
        Sebelum menuju langkah pembuatannya, pastikan Anda telah memenuhi persyaratan sebagai berikut :
  1. Paham dalam menggunakan perangkat lunak Android Studio IDE.
  2. Mengerti bahasa pemrograman Java/Kotlin.
  3. Mengerti bahasa pemrograman Xml.
  4. Sudah melatih dan menyimpan model hasil pelatihan arsitektur CNN pada Google Colab.
  5. Sudah memasang aplikasi Android Studio IDE.
  6. Pastikan terkoneksi dengan Wi-Fi atau menggunakan paket internet unlimited, karena Android Studio akan men-download resources yang dibutuhkan dengan ukuran yang cukup besar selama pembuatan aplikasi Android.
Jika sudah terpenuhi semuanya maka langsung saja ke tahap pembuatannya.

  1. Buka software Android Studio yang sudah di-install sebelumnya.
  2. Membuat project baru dengan cara klik Menu FileNewNew Project....
  3. Pada jendela "Create New Project" pilih "Empty Activity" dan klik "Next".
  4. Kemudian atur seperti pada gambar, untuk "Name" dan "Package Name" isi sesuai keinginan dan "Save location" sesuaikan dengan keinginan Anda.
  5. Tunggu proses sinkronisasi dan download resources sampai selesai.
  6. Jika sudah selesai prosesnya maka tampilannya akan seperti berikut.
  7. Selanjutnya buka "AndroidManifest.xml" dan tambahkan beberapa perizinan dan fitur yang nantinya akan digunakan seperti pada gambar.
  8. Tambahkan Source code program berikut tepat di atas tag "<application":
    1. <dist:module dist:instant="true"/>
    2. <uses-permission android:name="android.permission.CAMERA" />
    3. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    4. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    5. <uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
    6. <uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
    7. <uses-feature android:name="android.hardware.camera" />
    8. <uses-feature android:name="android.hardware.camera.autofocus" />
    9. <!--<uses-feature android:name="android.hardware.camera.flash" />-->
    10. <uses-permission android:name="android.permission.FLASHLIGHT"/>
  9. Jika terdapat source code yang error (berwarna merah) pada text editor maka cukup menekan tombol Alt+Enter pada keyboard untuk menambahkan attribute yang dibutuhkan.
  10. Setelah itu source code tersebut sudah tidak error lagi.
  11. Kemudian terdapat source code yang diberi highlight berwarna kuning yang menandakan adanya peringatan dalam source code tersebut. Peringatan tersebut terjadi karena program yang dibuat tidak dapat diindeks oleh pencarian Google.
  12. Untuk menghilangkan peringatannya maka perlu ditambah atribut seperti ini.
  13. Maka peringatan tersebut sudah tidak muncul kembali.
  14. Sesudah itu kita akan membuat sebuah Class Kotlin baru seperti berikut.
  15. Kemudian isi nama class-nya "Bantuan" dan ganti jenis file menjadi "Class".
  16. Selanjutnya klik "OK" pada jendela "New Kotlin File/Class".
  17. Lengkapi source code berikut pada Class Kotlin "Bantuan.kt". Class ini bertujuan untuk membuat aktivitas baru dengan title bar "Halaman Bantuan". Class ini nantinya digunakan untuk memberi petunjuk cara kerja dan cara menggunakan apikasi ini.
    1. class Bantuan : AppCompatActivity() {

    2.     override fun onCreate(savedInstanceState: Bundle?) {
    3.         super.onCreate(savedInstanceState)
    4.         setContentView(R.layout.activity_bantuan)

    5.         if (supportActionBar != null) {
    6.             (supportActionBar as ActionBar).title = "Halaman Bantuan"
    7.         }
    8.     }
    9. }
    Jika muncul jendela seperti gambar di bawah maka pilih saja semua library yang dibutuhkan kemudian klik "OK". Hal tersebut biasanya terjadi ketika Anda menyalin potongan source code program dari luar yang tidak disertakan library-nya.
  18. Selanjutnya tambahkan class "Bantuan.kt" ke dalam "AndroidManifest.xml" dengan cara seperti pada gambar di bawah ini.
  19. Setelah ditambahkan ke manifest, maka dapat dicek pada "AndroidManifest.xml" apakah aktivitas class "Bantuan" sudah ditambahkan secara otomatis.
  20. Selanjutnya kembali lagi ke aktivitas "Bantuan.kt". Terdapat referensi layout yang tidak ditemukan sehingga menjadi error (source code berwarna merah). Hal itu terjadi karena kita belum membuat tampilan layout dari class Bantuan. Layout tersebut dibuat dengan nama "activity_bantuan.xml". Untuk cara membuatnya seperti berikut.
  21. Setelah terbuka jendela "New Resource File" lakukan seperti berikut.
  22. Kemudian akan dibuat secara otomatis layout-nya pada direktori app → res → layout → activity_bantuan.xml di dalam project Android tersebut.
  23. Untuk mengedit antarmuka "activity_bantuan.xml" nanti akan dilakukan di langkah terakhir dikarenakan nilai string yang dimasukkan cukup banyak.
  24. Setelah itu kita membuat file class baru dengan nama "Deskripsi" serta tampilan layout pada aplikasi Android-nya dengan nama "activity_deskripsi". class Deskripsi ini berfungsi untuk menampilkan informasi varietas beras. Pembuatan antarmuka layout aktivitas tersebut juga sama akan di buat di bagian akhir.
  25. Lengkapi source code pada class tersebut seperti berikut :
    1. class Deskripsi : AppCompatActivity() {

    2.     override fun onCreate(savedInstanceState: Bundle?) {
    3.         super.onCreate(savedInstanceState)
    4.         setContentView(R.layout.activity_deskripsi)

    5.         if (supportActionBar != null) {
    6.             (supportActionBar as ActionBar).title = "Deskripsi Varietas Beras"
    7.         }
    8.     }
    9. }
  26. Sehingga program pada text editor-nya menjadi seperti ini.
  27. Setelah itu buat class "Klasifikasi.kt" dan lengkapi source code-nya seperti ini.
    1. <div style="-goog-ms-box-shadow: 0 0 10px #000000; -moz-box-shadow: 0 0 10px #000000; -webkit-box-shadow: 0 0 10px #000000; border: 6px double #3399FF; color: #b4040; height: 200px; overflow: auto; padding: 0px; width: 450px;">
    2. <ol>
    3. <li style="text-align: justify;"><span style="color: orange; font-family: calibri;">class Deskripsi : AppCompatActivity() {</span></li>
    4. <li style="text-align: justify;"><span style="color: orange; font-family: &quot;calibri&quot;;">
    5. </span></li>
    6. <li style="text-align: justify;"><span style="color: orange; font-family: &quot;calibri&quot;;">&nbsp; &nbsp; override fun onCreate(savedInstanceState: Bundle?) {</span></li>
    7. <li style="text-align: justify;"><span style="color: orange; font-family: &quot;calibri&quot;;">&nbsp; &nbsp; &nbsp; &nbsp; super.onCreate(savedInstanceState)</span></li>
    8. <li style="text-align: justify;"><span style="color: orange; font-family: &quot;calibri&quot;;">&nbsp; &nbsp; &nbsp; &nbsp; setContentView(R.layout.activity_deskripsi)</span></li>
    9. <li style="text-align: justify;"><span style="color: orange; font-family: &quot;calibri&quot;;">
    10. </span></li>
    11. <li style="text-align: justify;"><span style="color: orange; font-family: &quot;calibri&quot;;">&nbsp; &nbsp; &nbsp; &nbsp; if (supportActionBar != null) {</span></li>
    12. <li style="text-align: justify;"><span style="color: orange; font-family: &quot;calibri&quot;;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (supportActionBar as ActionBar).title = "Deskripsi Varietas Beras"</span></li>
    13. <li style="text-align: justify;"><span style="color: orange; font-family: &quot;calibri&quot;;">&nbsp; &nbsp; &nbsp; &nbsp; }</span></li>
    14. <li style="text-align: justify;"><span style="color: orange; font-family: &quot;calibri&quot;;">&nbsp; &nbsp; }</span></li>
    15. <li style="text-align: justify;"><span style="color: orange; font-family: &quot;calibri&quot;;">}</span></li>
    16. </ol>
    17. </div>
  28. Pada source code tersebut terdapat nama variabel "Interpreter" yang tidak dikenal sehingga menjadi berwarna merah seperti pada gambar berikut.
  29. Hal tersebut disebabkan oleh tidak adanya library yang cocok untuk ditambahkan. Sehingga diperlukannya penambahan modul dependency pada "build.gradle (Module: app)". Library yang dibutuhkan adalah TensorFlow Lite versi 1.13.1. Cara menambahkannya seperti berikut.
  30. Source code dependency untuk TensorFlow Lite :
    1. //menambah library tensorflowlite
    2.     implementation 'org.tensorflow:tensorflow-lite:1.13.1'
  31. Setelah itu kita dapat mengimpor library TensorFlow Lite pada class Klasifikasi dengan cara menekan Alt+Enter seperti pada langkah sebelumnya.
  32. Maka hasilnya akan seperti ini.
  33. Buat lagi class baru dengan nama "Deteksi". Class ini berfungsi untuk menyimpan nilai data hasil deteksi dari class "Pendeteksi" dan mengubah nilai probabilitasnya ke dalam bentuk persentase (%). Pada class "Deteksi" tidak perlu ditambahkan ke manifest karena class ini tidak akan ditampilkan pada layout aplikasi Android.
  34. Source code kelas Deteksi :
    1. data class Deteksi(
    2.     val name: String,
    3.     val probability: Float
    4. ) {
    5.     override fun toString() =
    6.         "$name : ${probability*100}%"
    7. }
  35. Selanjutnya buat class "Pendeteksi.kt" yang digunakan untuk mendeteksi obyek beras menggunakan fitur kamera pada smartphone Android. Setelah dibuat class-nya lalu tambahkan ke manifest yang sama seperti pada langkah2 sebelumnya.
  36. Source code class Pendeteksi.kt :
    1. class Pendeteksi : AppCompatActivity() {

    2.     private lateinit var classifier: Klasifikasi
    3.     //mendeklarasikan komponen TextView resultbar yang akan dimanipulasi
    4.     private lateinit var resultbar: TextView
    5.     private lateinit var processtime: TextView
    6.     //deklarasi variabel lastprocessingtimems bertipe data long
    7.     private var lastProcessingTimeMs: Long = 0

    8.     @SuppressLint("MissingPermission")
    9.     override fun onCreate(savedInstanceState: Bundle?) {
    10.         super.onCreate(savedInstanceState)
    11.         setContentView(R.layout.activity_pendeteksi)

    12.         //mengganti nama title bar tiap activity
    13.         if (supportActionBar != null) {
    14.             (supportActionBar as ActionBar).title = "Pendeteksi Varietas Beras"
    15.         }

    16.         //obyek TextView resultbar disesuaikan (cast) dengan komponen TextView ber-ID result_bar di layout activity_pendeteksi.xml melalui metode findViewById().
    17.         resultbar = findViewById(R.id.result_bar)
    18.         processtime = findViewById(R.id.process_time_bar)

    19.         classifier = Klasifikasi(assets)

    20.         if (!canUseCamera()) {
    21.             requestCameraPermissions()
    22.         } else {
    23.             setupCamera()
    24.         }
    25.     }

    26.     private fun requestCameraPermissions() {
    27.         ActivityCompat.requestPermissions(
    28.             this,
    29.             arrayOf(Manifest.permission.CAMERA),
    30.             REQUEST_CAMERA_CODE
    31.         )
    32.     }

    33.     @SuppressLint("MissingPermission", "SetTextI18n")
    34.     private fun setupCamera() {
    35.         camera.addPictureTakenListener {
    36.             AsyncTask.execute {
    37.                 val startTime = SystemClock.uptimeMillis()//menghitung waktu awal
    38.                 val recognitions = classifier.recognize(it.data)
    39.                 val txt = recognitions.joinToString(separator = "\n")
    40.                 lastProcessingTimeMs = SystemClock.uptimeMillis() - startTime//menghitung lamanya proses
    41.                 val waktu = lastProcessingTimeMs.toString()//konversi ke string
    42.                 runOnUiThread {
    43.                     /*menampilkan hasil pada UI*/
    44.                     //Toast.makeText(this, txt, Toast.LENGTH_LONG).show()
    45.                     /*menampilkan hasil pada layout TextView*/
    46.                     resultbar.text = txt
    47.                     processtime.text = "$waktu ms "
    48.                 }
    49.             }
    50.         }

    51.         capturePhoto.setOnClickListener {
    52.             camera.capture()
    53.         }

    54.     }

    55.     override fun onRequestPermissionsResult(
    56.         requestCode: Int,
    57.         permissions: Array<out String>,
    58.         grantResults: IntArray
    59.     ) {
    60.         super.onRequestPermissionsResult(requestCode, permissions, grantResults)

    61.         if (REQUEST_CAMERA_CODE == requestCode) {
    62.             if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
    63.                 setupCamera()
    64.             } else {
    65.                 Toast.makeText(this, "App needs camera in order to work.", Toast.LENGTH_LONG).show()
    66.                 requestCameraPermissions()
    67.             }
    68.         }
    69.     }

    70.     @SuppressLint("MissingPermission")
    71.     override fun onResume() {
    72.         super.onResume()
    73.         if (canUseCamera()) {
    74.             camera.start()
    75.         }
    76.     }

    77.     override fun onPause() {
    78.         if (canUseCamera()) {
    79.             camera.stop()
    80.         }
    81.         super.onPause()
    82.     }

    83.     override fun onDestroy() {
    84.         if (canUseCamera()) {
    85.             camera.destroy()
    86.         }
    87.         super.onDestroy()
    88.     }

    89.     private fun canUseCamera() =
    90.         ActivityCompat.checkSelfPermission(
    91.             this,
    92.             Manifest.permission.CAMERA
    93.         ) == PackageManager.PERMISSION_GRANTED

    94.     companion object {
    95.         private const val REQUEST_CAMERA_CODE = 1
    96.     }
    97. }
  37. Kemudian buat juga layout "activity_pendeteksi.xml" dengan jenis layout "ConstraintLayout" yang digunakan untuk class "Pendeteksi".
  38. Source code layout "activity_pendeteksi.xml" :
    1. <?xml version="1.0" encoding="utf-8"?>
    2. <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    3.     xmlns:app="http://schemas.android.com/apk/res-auto"
    4.     xmlns:tools="http://schemas.android.com/tools"
    5.     android:layout_width="match_parent"
    6.     android:layout_height="match_parent"
    7.     android:background="@drawable/gradient_pendeteksi"
    8.     tools:context=".Pendeteksi">

    9.     <com.priyankvasa.android.cameraviewex.CameraView
    10.         android:id="@+id/camera"
    11.         android:layout_width="480dp"
    12.         android:layout_height="640dp"
    13.         android:layout_marginBottom="0dp"
    14.         android:adjustViewBounds="true"
    15.         android:keepScreenOn="true"
    16.         app:aspectRatio="4:3"
    17.         app:autoFocus="continuous_picture"
    18.         app:awb="auto"
    19.         app:cameraMode="single_capture"
    20.         app:facing="back"
    21.         app:flash="auto"
    22.         app:layout_constraintBottom_toBottomOf="parent"
    23.         app:layout_constraintEnd_toEndOf="parent"
    24.         app:layout_constraintStart_toStartOf="parent"
    25.         app:layout_constraintTop_toTopOf="parent"
    26.         app:opticalStabilization="true"
    27.         app:outputFormat="jpeg"
    28.         app:pinchToZoom="true"
    29.         app:shutter="short_time"
    30.         app:touchToFocus="true"
    31.         app:zsl="true" />

    32.     <TextView
    33.         android:id="@+id/process_time_bar"
    34.         android:layout_width="match_parent"
    35.         android:layout_height="wrap_content"
    36.         android:background="#CCFF6633"
    37.         android:padding="2dp"
    38.         android:fontFamily="times"
    39.         android:gravity="right"
    40.         android:text="@string/process_time"
    41.         android:textAlignment="gravity"
    42.         android:textColor="#FFFF00"
    43.         android:textSize="18sp"
    44.         app:layout_constraintBottom_toBottomOf="parent"
    45.         app:layout_constraintTop_toTopOf="parent"
    46.         app:layout_constraintVertical_bias="0.0"
    47.         tools:layout_editor_absoluteX="0dp" />

    48.     <TextView
    49.         android:id="@+id/process_name_bar"
    50.         android:layout_width="match_parent"
    51.         android:layout_height="wrap_content"
    52.         android:padding="2dp"
    53.         android:fontFamily="times"
    54.         android:gravity="left"
    55.         android:text="  Waktu Proses Deteksi : "
    56.         android:textAlignment="gravity"
    57.         android:textColor="#FFFF00"
    58.         android:textSize="18sp"
    59.         app:layout_constraintBottom_toBottomOf="parent"
    60.         app:layout_constraintTop_toTopOf="parent"
    61.         app:layout_constraintVertical_bias="0.0"
    62.         tools:layout_editor_absoluteX="0dp" />

    63.     <TextView
    64.         android:id="@+id/info_bar"
    65.         android:layout_width="match_parent"
    66.         android:layout_height="wrap_content"
    67.         android:background="#80000000"
    68.         android:fontFamily="times"
    69.         android:gravity="center"
    70.         android:padding="2dp"
    71.         android:text="@string/info"
    72.         android:textAlignment="gravity"
    73.         android:textColor="#FFFFFF"
    74.         android:textSize="16sp"
    75.         app:layout_constraintBottom_toBottomOf="parent"
    76.         app:layout_constraintTop_toTopOf="parent"
    77.         app:layout_constraintVertical_bias="0.05"
    78.         tools:layout_editor_absoluteX="0dp" />

    79.     <TextView
    80.         android:id="@+id/capturePhoto"
    81.         android:layout_width="wrap_content"
    82.         android:layout_height="wrap_content"
    83.         android:layout_marginBottom="84dp"
    84.         android:background="#8000CC33"
    85.         android:padding="7dp"
    86.         android:shadowColor="@android:color/darker_gray"
    87.         android:text="Deteksi"
    88.         android:textColor="@android:color/black"
    89.         android:textSize="30sp"
    90.         app:layout_constraintBottom_toBottomOf="parent"
    91.         app:layout_constraintLeft_toLeftOf="parent"
    92.         app:layout_constraintRight_toRightOf="parent" />

    93.     <TextView
    94.         android:id="@+id/prediction_bar"
    95.         android:layout_width="match_parent"
    96.         android:layout_height="wrap_content"
    97.         android:layout_marginBottom="63dp"
    98.         android:background="#9000CC33"
    99.         android:fontFamily="times"
    100.         android:text="HASIL PREDIKSI :"
    101.         android:textAlignment="center"
    102.         android:textColor="#000099"
    103.         android:textSize="16sp"
    104.         app:layout_constraintBottom_toBottomOf="parent" />

    105.     <TextView
    106.         android:id="@+id/result_bar"
    107.         android:layout_width="match_parent"
    108.         android:layout_height="wrap_content"
    109.         android:layout_marginBottom="0dp"
    110.         android:background="#9000CC33"
    111.         android:fontFamily="times"
    112.         android:text="@string/hasil_1_nhasil_2_nhasil_3"
    113.         android:textAlignment="center"
    114.         android:textColor="#000099"
    115.         android:textSize="16sp"
    116.         app:layout_constraintBottom_toBottomOf="parent" />

    117. </androidx.constraintlayout.widget.ConstraintLayout>
  39. Kemudian buat drawable resource file "gradient_pendeteksi.xml" yang digunakan untuk menambah warna latar belakang layout. Anda dapat melewati langkah ini jika tidak ingin menambahkan warna background (default warna putih). Jika ingin melewatinya anda tidak perlu membuat "gradient_pendeteksi.xml" dan hanya perlu menghapus baris program "android:background="@drawable/gradient_pendeteksi"". Jika ingin menambahkan warna background gradasi silahkan mengikutin langkah berikut.
  40. Setelah itu maka akan dibuat secara otomatis file resource-nya pada direktori app → res → drawable. Kemudian ubah source code-nya menjadi seperti ini. Untuk pengaturan warna dan efek gradasinya Anda bisa mengubahnya sendiri sesuai selera.
  41. Source code "gradient_pendeteksi.xml" :
    1. <?xml version="1.0" encoding="utf-8"?>
    2. <shape xmlns:android="http://schemas.android.com/apk/res/android">
    3.     <gradient
    4.         android:type="linear"
    5.         android:startColor="@android:color/holo_blue_bright"
    6.         android:centerColor="#FFFF66"
    7.         android:endColor="@android:color/holo_green_light"
    8.         android:angle="315"/>
    9. </shape>
  42. Selanjutnya buat nilai dari resources string untuk "process_time".
  43. Masukkan nilai string-nya seperti berikut dan klik "OK". Nilai string ini nantinya akan terus diupdate nilai waktunya seiring dilakukannya pendeteksian.
  44. Selanjutnya nilai string yang sudah dibuat pada direktori app → res → values → strings.xml diubah sesuai karakter yang disarankan oleh Android Studio.
  45. Selanjutnya buat nilai string untuk text "info". string ini digunakan untuk menampilkan informasi berupa karakter pada layout aplikasi Android.
  46. Selanjutnya buat string teks lagi untuk menampilkan Text View nilai probabilitas hasil deteksi.
  47. Kemudian menuju nilai string resources-nya dengan cara tekan tombol Ctrl+Klik kiri pada keyboard untuk mengubah nilai string-nya secara manual.
  48. Setelah itu ubah string-nya sesuai pada gambar
  49. Source code untuk string hasil prediksi deteksi :
    1. <string name="hasil_1_nhasil_2_nhasil_3"><b>Hasil 1</b>\nHasil 2\nHasil 3</string>
  50. Kembali lagi ke "activity_pendeteksi.xml" di sini terdapat baris kode yang jenis layout untuk kamera menggunakan library cameraview-ex milik google yang dimodifikasi oleh priyankvasa. Namun sumbernya masih tidak dikenal. Library tersebut sangat cocok digunakan untuk keperluan image processing menggunakan fitur kamera pada Android.
  51. Agar dapat menggunakannya, maka perlu ditambahkan implementation di dalam dependencies pada "build.gradle (Module: app)" seperti pada langkah 27 sebelumnya.
  52. Source code dependency untuk cameraview-ex :
    1. //menambah tampilan kamera
    2.     implementation "com.priyankvasa.android:cameraview-ex:3.5.1-alpha"
  53. Setelah ditambahkan dan disinkronisasi, maka library sudah dikenal.
  54. Sesudah itu kembali lagi menuju class "Pendeteksi.kt" untuk mengimpor library tersebut.
  55. Buat kelas baru lagi dengan nama "KlasifikasiDariGaleri.kt".
  56. Lengkapi source code-nya seperti berikut :
    1. class KlasifikasiDariGaleri(assetManager: AssetManager, modelPath: String, labelPath: String, inputSize: Int) {
    2.     private var interpreter: Interpreter
    3.     private var labellist: List<String>
    4.     private val inputsize: Int = inputSize
    5.     private val pixelsize: Int = 3
    6.     private val imagemean = 0
    7.     private val imagestd = 255.0f
    8.     private val maxresults = 3
    9.     private val threshold = 0.4f

    10.     data class Recognition(
    11.         var id: String = "",
    12.         var title: String = "",
    13.         var confidence: Float = 0F,
    14.         val percent: Float = confidence*100
    15.     )  {
    16.         override fun toString(): String {
    17.             return "Title = $title, Hasil Prediksi = $percent)"
    18.         }
    19.     }

    20.     init {
    21.         interpreter = Interpreter(loadModelFile(assetManager, modelPath))
    22.         labellist = loadLabelList(assetManager, labelPath)
    23.     }

    24.     private fun loadModelFile(assetManager: AssetManager, modelPath: String): MappedByteBuffer {
    25.         val fileDescriptor = assetManager.openFd(modelPath)
    26.         val inputStream = FileInputStream(fileDescriptor.fileDescriptor)
    27.         val fileChannel = inputStream.channel
    28.         val startOffset = fileDescriptor.startOffset
    29.         val declaredLength = fileDescriptor.declaredLength
    30.         return fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength)
    31.     }

    32.     private fun loadLabelList(assetManager: AssetManager, labelPath: String): List<String> {
    33.         return assetManager.open(labelPath).bufferedReader().useLines { it.toList() }

    34.     }

    35.     fun recognizeImage(bitmap: Bitmap): List<Recognition> {
    36.         val scaledBitmap = Bitmap.createScaledBitmap(bitmap, inputsize, inputsize, false)
    37.         val byteBuffer = convertBitmapToByteBuffer(scaledBitmap)
    38.         val result = Array(1) { FloatArray(labellist.size) }
    39.         interpreter.run(byteBuffer, result)
    40.         return getSortedResult(result)
    41.     }



    42.     private fun convertBitmapToByteBuffer(bitmap: Bitmap): ByteBuffer {
    43.         val byteBuffer = ByteBuffer.allocateDirect(4 * inputsize * inputsize * pixelsize)
    44.         byteBuffer.order(ByteOrder.nativeOrder())
    45.         val intValues = IntArray(inputsize * inputsize)

    46.         bitmap.getPixels(intValues, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)
    47.         var pixel = 0
    48.         for (i in 0 until inputsize) {
    49.             for (j in 0 until inputsize) {
    50.                 val `val` = intValues[pixel++]

    51.                 byteBuffer.putFloat((((`val`.shr(16)  and 0xFF) - imagemean) / imagestd))
    52.                 byteBuffer.putFloat((((`val`.shr(8) and 0xFF) - imagemean) / imagestd))
    53.                 byteBuffer.putFloat((((`val` and 0xFF) - imagemean) / imagestd))
    54.             }
    55.         }
    56.         return byteBuffer
    57.     }


    58.     private fun getSortedResult(labelProbArray: Array<FloatArray>): List<Recognition> {
    59.         Log.d("KlasifikasiDariGaleri", "List Size:(%d, %d, %d)".format(labelProbArray.size,labelProbArray[0].size,labellist.size))

    60.         val pq = PriorityQueue(
    61.             maxresults,
    62.             Comparator<Recognition> {
    63.                     (_, _, confidence1), (_, _, confidence2)
    64.                 -> confidence1.compareTo(confidence2) * -1
    65.             })

    66.         for (i in labellist.indices) {
    67.             val confidence = labelProbArray[0][i]
    68.             if (confidence >= threshold) {
    69.                 pq.add(Recognition("" + i,
    70.                     if (labellist.size > i) labellist[i] else "Unknown", confidence)
    71.                 )
    72.             }
    73.         }
    74.         Log.d("KlasifikasiDariGaleri", "pqsize:(%d)".format(pq.size))

    75.         val recognitions = ArrayList<Recognition>()
    76.         val recognitionsSize = pq.size.coerceAtMost(maxresults)
    77.         for (i in 0 until recognitionsSize) {
    78.             recognitions.add(pq.poll())
    79.         }
    80.         return recognitions
    81.     }
    82. }
  57. Buat lagi class "DeteksiDariGaleri.kt" dan tambahkan class tersebut ke manifest.
  58. Source code class "DeteksiDariGaleri.kt" :
    1. class DeteksiDariGaleri : AppCompatActivity() {
    2.     private lateinit var mClassifier: KlasifikasiDariGaleri
    3.     private lateinit var mBitmap: Bitmap

    4.     private val mGalleryRequestCode = 2

    5.     private val mInputSize = 224
    6.     private val mModelPath = "Klasifikasi_3_Varietas_Beras_MobileNet.tflite"
    7.     private val mLabelPath = "Klasifikasi_3_Varietas_Beras_MobileNet.txt"
    8.     private val mSamplePath = "basmathi.jpg"

    9.     private var lastProcessingTimeMs: Long = 0

    10.     @SuppressLint("SetTextI18n")
    11.     @RequiresApi(Build.VERSION_CODES.O)
    12.     override fun onCreate(savedInstanceState: Bundle?) {
    13.         super.onCreate(savedInstanceState)

    14.         if (supportActionBar != null) {
    15.             (supportActionBar as ActionBar).title = "Pendeteksi Varietas Beras"
    16.         }

    17.         requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
    18.         setContentView(R.layout.activity_import_gallery)
    19.         mClassifier = KlasifikasiDariGaleri(assets, mModelPath, mLabelPath, mInputSize)

    20.         resources.assets.open(mSamplePath).use {
    21.             mBitmap = BitmapFactory.decodeStream(it)
    22.             mBitmap = Bitmap.createScaledBitmap(mBitmap, mInputSize, mInputSize, true)
    23.             mPhotoImageView.setImageBitmap(mBitmap)
    24.         }

    25.         mGalleryButton.setOnClickListener {
    26.             val callGalleryIntent = Intent(Intent.ACTION_PICK)
    27.             callGalleryIntent.type = "image/*"
    28.             startActivityForResult(callGalleryIntent, mGalleryRequestCode)
    29.         }
    30.         mDetectButton.setOnClickListener {
    31.             val startTime = SystemClock.uptimeMillis()//menghitung waktu awal
    32.             val results = mClassifier.recognizeImage(mBitmap).firstOrNull()
    33.             mResultTextView.text= results?.title+"\n Probabilitas: "+results?.percent+"%"
    34.             lastProcessingTimeMs = SystemClock.uptimeMillis() - startTime//menghitung lamanya proses
    35.             val waktu = lastProcessingTimeMs.toString()//konversi ke string
    36.             delaytime.text = "$waktu ms "

    37.         }
    38.     }

    39.     @SuppressLint("MissingSuperCall", "SetTextI18n")
    40.     override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    41.         if(requestCode == mGalleryRequestCode) {
    42.             if (data != null) {
    43.                 val uri = data.data

    44.                 try {
    45.                     mBitmap = MediaStore.Images.Media.getBitmap(this.contentResolver, uri)
    46.                 } catch (e: IOException) {
    47.                     e.printStackTrace()
    48.                 }

    49.                 println("Selesai!")
    50.                 mBitmap = scaleImage(mBitmap)
    51.                 mPhotoImageView.setImageBitmap(mBitmap)

    52.             }
    53.         } else {
    54.             Toast.makeText(this, "Unrecognized request code", Toast.LENGTH_LONG).show()

    55.         }
    56.     }


    57.     fun scaleImage(bitmap: Bitmap?): Bitmap {
    58.         val orignalWidth = bitmap!!.width
    59.         val originalHeight = bitmap.height
    60.         val scaleWidth = mInputSize.toFloat() / orignalWidth
    61.         val scaleHeight = mInputSize.toFloat() / originalHeight
    62.         val matrix = Matrix()
    63.         matrix.postScale(scaleWidth, scaleHeight)
    64.         return Bitmap.createBitmap(bitmap, 0, 0, orignalWidth, originalHeight, matrix, true)
    65.     }
    66. }
  59. Kemudian buat layout-nya dengan nama "activity_import_gallery".
  60. Atur jenis layout-nya menjadi "ConstraintLayout" seperti pada gambar.
  61. Tambahkan source code berikut pada text editor di bawah "android:layout_height="match_parent"" kemudian tekan Alt+Enter untuk menambahkan library tools yang dibutuhkan.
    1. android:background="@drawable/gradient_pendeteksi"
    2.     tools:context=".DeteksiDariGaleri"
  62. Selanjutnya tambahkan source code berikut di bawah "tools:context=".DeteksiDariGaleri">".
    1. <TextView
    2.         android:id="@+id/delaytime"
    3.         android:layout_width="match_parent"
    4.         android:layout_height="wrap_content"
    5.         android:background="#CCFF6633"
    6.         android:padding="2dp"
    7.         android:fontFamily="times"
    8.         android:gravity="right"
    9.         android:text="@string/delay_time"
    10.         android:textAlignment="gravity"
    11.         android:textColor="#FFFF00"
    12.         android:textSize="18sp"
    13.         app:layout_constraintBottom_toBottomOf="parent"
    14.         app:layout_constraintTop_toTopOf="parent"
    15.         app:layout_constraintVertical_bias="0.0"
    16.         tools:layout_editor_absoluteX="0dp" />

    17.     <TextView
    18.         android:id="@+id/process_name_bar"
    19.         android:layout_width="match_parent"
    20.         android:layout_height="wrap_content"
    21.         android:padding="2dp"
    22.         android:fontFamily="times"
    23.         android:gravity="left"
    24.         android:text="  Waktu Proses Deteksi : "
    25.         android:textAlignment="gravity"
    26.         android:textColor="#FFFF00"
    27.         android:textSize="18sp"
    28.         app:layout_constraintBottom_toBottomOf="parent"
    29.         app:layout_constraintTop_toTopOf="parent"
    30.         app:layout_constraintVertical_bias="0.0"
    31.         tools:layout_editor_absoluteX="0dp" />

    32.     <TextView
    33.         android:id="@+id/hints_bar"
    34.         android:layout_width="match_parent"
    35.         android:layout_height="wrap_content"
    36.         android:background="#80000000"
    37.         android:fontFamily="times"
    38.         android:gravity="center"
    39.         android:padding="2dp"
    40.         android:text="@string/hints"
    41.         android:textAlignment="gravity"
    42.         android:textColor="#FFFFFF"
    43.         android:textSize="16sp"
    44.         app:layout_constraintBottom_toBottomOf="parent"
    45.         app:layout_constraintTop_toTopOf="parent"
    46.         app:layout_constraintVertical_bias="0.05"
    47.         tools:layout_editor_absoluteX="0dp" />

    48.     <Button
    49.         android:id="@+id/mGalleryButton"
    50.         android:layout_width="wrap_content"
    51.         android:layout_height="wrap_content"
    52.         android:layout_marginTop="0dp"
    53.         android:text="@string/buttonSelectPhoto"
    54.         android:textColor="@android:color/holo_green_dark"
    55.         android:textSize="18sp"
    56.         app:layout_constraintEnd_toEndOf="parent"
    57.         app:layout_constraintHorizontal_bias="0.5"
    58.         app:layout_constraintStart_toStartOf="parent"
    59.         app:layout_constraintTop_toBottomOf="@+id/hints_bar" />

    60.     <ImageView
    61.         android:id="@+id/mPhotoImageView"
    62.         android:layout_width="360dp"
    63.         android:layout_height="360dp"
    64.         android:contentDescription="@string/descriptionImage"
    65.         app:layout_constraintBottom_toTopOf="@+id/mDetectButton"
    66.         app:layout_constraintEnd_toEndOf="parent"
    67.         app:layout_constraintHorizontal_bias="0.5"
    68.         app:layout_constraintStart_toStartOf="parent"
    69.         app:layout_constraintTop_toBottomOf="@+id/mGalleryButton"
    70.         app:layout_constraintVertical_chainStyle="packed"
    71.         app:srcCompat="@android:color/darker_gray" />


    72.     <Button
    73.         android:id="@+id/mDetectButton"
    74.         android:layout_width="wrap_content"
    75.         android:layout_height="wrap_content"
    76.         android:layout_marginBottom="8dp"
    77.         android:background="#8000CC33"
    78.         android:padding="7dp"
    79.         android:shadowColor="@android:color/darker_gray"
    80.         android:text="Deteksi"
    81.         android:textColor="@android:color/black"
    82.         android:textSize="24sp"
    83.         app:layout_constraintBottom_toBottomOf="parent"
    84.         app:layout_constraintBottom_toTopOf="@+id/mResultTextView"
    85.         app:layout_constraintEnd_toEndOf="parent"
    86.         app:layout_constraintStart_toStartOf="parent" />

    87.     <TextView
    88.         android:id="@+id/mResultTextView"
    89.         android:layout_width="match_parent"
    90.         android:layout_height="wrap_content"
    91.         android:layout_marginBottom="0dp"
    92.         android:background="#9000CC33"
    93.         android:fontFamily="times"
    94.         android:text="@string/display_result"
    95.         android:textAlignment="center"
    96.         android:textColor="#000099"
    97.         android:textSize="16sp"
    98.         android:textStyle="bold"
    99.         app:layout_constraintBottom_toBottomOf="parent"
    100.         app:layout_constraintEnd_toEndOf="parent"
    101.         app:layout_constraintStart_toStartOf="parent" />
  63. Tambahkan lagi library skema layout untuk baris program "app".
  64. Selanjutnya buat nilai string untuk "delay_time" dan isi value-nya "… ms   ".
  65. Buat string untuk "hints" dan isikan value-nya dengan "Pilih Gambar Lalu Klik DETEKSI".
  66. Buat string untuk "buttonSelectPhoto", kemudian isi value-nya "Pilih Gambar".
  67. Buat string untuk "descriptionimage", isikan value-nya "Lihat untuk Menampilkan Gambar".
  68. Buat string untuk "display_result" dan isikan secara manual "<b>Hasil Prediksi</b>\n".
  69. Kembali ke "DeteksiDariGaleri.kt" untuk meingimpor library import gallery.
  70. Setelah itu buat class baru "SplashScreen" yang digunakan untuk menampilkan layout awal memulai ketika aplikasi Android baru dijalankan.
  71. Source code "SplashScreen.kt" :
    1. class SplashScreen : AppCompatActivity() {

    2.     override fun onCreate(savedInstanceState: Bundle?) {
    3.         super.onCreate(savedInstanceState)

    4.         //menghilangkan ActionBar
    5.         this.requestWindowFeature(Window.FEATURE_NO_TITLE)
    6.         setContentView(R.layout.activity_splash_screen)

    7.         //tvSplash = findViewById(R.id.tvSplash) as TextView

    8.         //setelah loading maka akan langsung berpindah ke MainActivity
    9.         val handler = Handler()
    10.         handler.postDelayed(Runnable {
    11.             startActivity(Intent(applicationContext, MainActivity::class.java))
    12.             finish()
    13.         }, 3000L) //3000 L = 3 detik

    14.     }
    15. }
  72. Kemudian tambahkan layout-nya "activity_splash_screen".
  73. Atur jenis layout-nya seperti pada gambar di bawah ini.
  74. Lengkapi source code-nya seperti berikut :
    1. <?xml version="1.0" encoding="utf-8"?>
    2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    3.     xmlns:app="http://schemas.android.com/apk/res-auto"
    4.     xmlns:tools="http://schemas.android.com/tools"
    5.     android:layout_width="match_parent"
    6.     android:layout_height="match_parent"
    7.     android:id="@+id/activity_splash_screen"
    8.     android:background="@drawable/gradient_splash_screen"
    9.     android:gravity="center"
    10.     tools:context=".SplashScreen">

    11.     <TextView
    12.         android:id="@+id/tvSplash"
    13.         android:layout_width="match_parent"
    14.         android:layout_height="wrap_content"
    15.         android:layout_alignParentStart="true"
    16.         android:layout_alignParentLeft="true"
    17.         android:layout_alignParentTop="true"
    18.         android:layout_marginTop="280dp"
    19.         android:fontFamily="sans-serif-smallcaps"
    20.         android:text="Klasifikasi Varietas Beras"
    21.         android:textAlignment="center"
    22.         android:textColor="@android:color/holo_green_dark"
    23.         android:textSize="24sp"
    24.         android:textStyle="bold" />

    25.     <ImageView
    26.         android:id="@+id/logo_kvb"
    27.         android:layout_width="match_parent"
    28.         android:layout_height="100dp"
    29.         android:layout_alignParentStart="true"
    30.         android:layout_alignParentLeft="true"
    31.         android:layout_alignParentTop="true"
    32.         android:layout_marginTop="176dp"
    33.         android:scaleType="centerInside"
    34.         android:src="@drawable/logo_kvb" />

    35.     <ImageView
    36.         android:id="@+id/logo_tflite"
    37.         android:layout_width="match_parent"
    38.         android:layout_height="20dp"
    39.         android:layout_alignParentStart="true"
    40.         android:layout_alignParentLeft="true"
    41.         android:layout_alignParentTop="true"
    42.         android:layout_marginTop="320dp"
    43.         android:scaleType="centerInside"
    44.         android:src="@drawable/tflite" />

    45.     <ProgressBar
    46.         android:id="@+id/progresBar"
    47.         style="@style/Widget.AppCompat.ProgressBar"
    48.         android:layout_width="wrap_content"
    49.         android:layout_height="wrap_content"
    50.         android:layout_alignParentBottom="true"
    51.         android:layout_centerHorizontal="true"
    52.         android:layout_marginBottom="60dp" />

    53. </RelativeLayout>
  75. Tambahkan warna latar belakangnya jika Anda mau, jika tidak lewati saja.
  76. Kemudian ubah source code-nya seperti ini :
    1. <?xml version="1.0" encoding="utf-8"?>
    2. <shape xmlns:android="http://schemas.android.com/apk/res/android">
    3.     <gradient
    4.         android:type="linear"
    5.         android:startColor="@android:color/holo_blue_bright"
    6.         android:endColor="@android:color/holo_green_light"
    7.         android:angle="-90"/>
    8. </shape>
  77. Tambahkan juga logonya jika Anda mau, jika tidak hapus baris program ini.
  78. Untuk menambahkan logo maka copy gambar dari Windows Explorer.
  79. Kemudian paste-kan di direktori app → res → drawable → (di sini).
  80. Selanjutnya pilih yang hanya drawable saja dan klik "OK".
  81. Setelah itu samakan nama logonya dengan yang di layout.
  82. Jika sukses maka tampilannya akan seperti pada gambar di bawah.
  83. Jika Anda ingin menambahkan logo lain di bawahnya misal "TensorFlow Lite" maka langkahnya sama saja seperti pada langkah 63-68 di atas.
  84. Sesudah itu buat class "Tentang.kt" dan tambahkan juga ke manifest. Class pada aktivitas ini berfungsi untuk menampilkan halaman informasi aplikasi Android.
  85. Buat layout-nya dengan nama "activity_tentang".
  86. Atur jenis layout-nya menjadi "ScrollView" agar dapat digulir ke atas/bawah.
  87. Kemudian lengkapi source code-nya seperti di bawah ini :
    1. <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    2.     xmlns:app="http://schemas.android.com/apk/res-auto"
    3.     xmlns:tools="http://schemas.android.com/tools"
    4.     android:layout_width="match_parent"
    5.     android:layout_height="match_parent"
    6.     android:background="@drawable/gradient_tentang"
    7.     android:textAlignment="center"
    8.     tools:context=".Tentang">

    9.     <LinearLayout
    10.         android:layout_width="match_parent"
    11.         android:layout_height="wrap_content"
    12.         android:orientation="vertical">
    13.         <TextView
    14.             android:layout_width="match_parent"
    15.             android:layout_height="wrap_content"
    16.             android:textSize="24sp"
    17.             android:fontFamily="times"
    18.             android:text="Klasifikasi Varietas Beras"
    19.             android:background="#20000000"
    20.             android:textAlignment="center"
    21.             android:layout_marginLeft="0dp"
    22.             android:layout_marginRight="0dp"
    23.             android:layout_marginTop="16dp"
    24.             android:layout_marginBottom="8dp"
    25.             android:textColor="@android:color/holo_blue_dark"/>
    26.         <TextView
    27.             android:layout_width="match_parent"
    28.             android:layout_height="wrap_content"
    29.             android:text="Versi 2.0"
    30.             android:fontFamily="times"
    31.             android:background="#80FFFFFF"
    32.             android:textSize="16sp"
    33.             android:textAlignment="center"
    34.             android:layout_marginLeft="16dp"
    35.             android:layout_marginRight="16dp"
    36.             android:layout_marginBottom="16dp"
    37.             android:textColor="@android:color/holo_green_dark"/>
    38.         <TextView
    39.             android:textSize="14dp"
    40.             android:layout_width="match_parent"
    41.             android:layout_height="wrap_content"
    42.             android:text="@string/update"
    43.             android:layout_marginLeft="16dp"
    44.             android:layout_marginRight="16dp"
    45.             android:layout_marginBottom="16dp"
    46.             android:lineSpacingMultiplier="1"
    47.             android:textColor="#000099"/>
    48.         <TableLayout
    49.             android:layout_width="match_parent"
    50.             android:layout_height="wrap_content"
    51.             android:layout_marginLeft="16dp"
    52.             android:layout_marginRight="16dp"
    53.             android:layout_marginBottom="16dp">
    54.             <TableRow
    55.                 android:layout_width="match_parent"
    56.                 android:layout_height="wrap_content"
    57.                 android:layout_marginBottom="8dp">
    58.                 <TextView
    59.                     android:layout_width="wrap_content"
    60.                     android:layout_height="wrap_content"
    61.                     android:textSize="14sp"
    62.                     android:layout_marginRight="16dp"
    63.                     android:textColor="#000099"
    64.                     android:text="1. "/>
    65.                 <TextView
    66.                     android:layout_width="match_parent"
    67.                     android:layout_height="wrap_content"
    68.                     android:textSize="14sp"
    69.                     android:layout_weight="1"
    70.                     android:text="@string/content_update_1"
    71.                     android:textColor="#000099"/>
    72.             </TableRow>
    73.             <TableRow
    74.                 android:layout_width="match_parent"
    75.                 android:layout_height="wrap_content"
    76.                 android:layout_marginBottom="8dp">
    77.                 <TextView
    78.                     android:layout_width="wrap_content"
    79.                     android:layout_height="wrap_content"
    80.                     android:textSize="14sp"
    81.                     android:layout_marginRight="16dp"
    82.                     android:textColor="#000099"
    83.                     android:text="2. "/>
    84.                 <TextView
    85.                     android:layout_width="match_parent"
    86.                     android:layout_height="wrap_content"
    87.                     android:textSize="14sp"
    88.                     android:layout_weight="1"
    89.                     android:text="@string/content_update_2"
    90.                     android:textColor="#000099"/>
    91.             </TableRow>
    92.         </TableLayout>
    93.         <TextView
    94.             android:layout_width="match_parent"
    95.             android:layout_height="wrap_content"
    96.             android:text="@string/content_about"
    97.             android:layout_marginLeft="16dp"
    98.             android:layout_marginRight="16dp"
    99.             android:layout_marginBottom="16dp"
    100.             android:lineSpacingMultiplier="1"
    101.             android:textColor="@android:color/black"
    102.             android:autoLink="all"
    103.             android:linksClickable="true"/>
    104.         <TextView
    105.             android:layout_width="match_parent"
    106.             android:layout_height="wrap_content"
    107.             android:textAlignment="center"
    108.             android:text="Author : Vidi Fitriansyah Hidarlan"
    109.             android:layout_marginTop="50dp"
    110.             app:layout_constraintBottom_toBottomOf="parent"
    111.             app:layout_constraintLeft_toLeftOf="parent"
    112.             app:layout_constraintRight_toRightOf="parent"
    113.             android:textColor="@android:color/black"/>
    114.     </LinearLayout>
    115. </ScrollView>
  88. Buat warna latar belakangnya seperti berikut jika diinginkan.
  89. Ubah source code "gradient_tentang.xml"nya menjadi seperti berikut :
    1. <?xml version="1.0" encoding="utf-8"?>
    2. <shape xmlns:android="http://schemas.android.com/apk/res/android">
    3.     <gradient
    4.         android:type="linear"
    5.         android:startColor="@android:color/holo_blue_bright"
    6.         android:centerColor="#FFFF66"
    7.         android:endColor="@android:color/holo_green_light"
    8.         android:angle="225"/>
    9. </shape>
  90. Selanjutnya buat string untuk "update" kemudian edit value-nya pada strings.xml.
  91. Lakukan hal yang sama untuk membuat nilai resources string dari "content_update_1","content_update_2","content_about" dan isikan nilai string-nya masing-masing dengan source code di bawah seperti pada gambar berikut.
  92. Nilai string yang diperlukan :
    1. <string name="content_about">Aplikasi ini dibuat hanya untuk klasifikasi tiga varietas beras (Basmathi, IR-64, dan Ketan) menggunakan sebuah metode CNN (<i>Convolutional Neural Network</i>) dengan model arsitektur MobileNetV1. Arsitektur tersebut dilatih pada <i>Google Colaboratory</i>. Setelah dilatih disimpan modelnya dan dikonversi menggunakan <i>TensorFlow Lite</i>. Setelah dikonversi diunduh <i>file</i> modelnya dan di-<i>import</i> untuk diimplementasikan pada <i>smartphone Android</i> agar dapat melakukan klasifikasi varietas beras secara langsung menggunakan sebuah perangkat Android.\n\n
    2.         Pada aplikasi ini juga diatur secara otomatis penggunaan <i>flash</i> kameranya agar perubahan cahaya yang ada tidak berbeda signifikan ketika berada di luar ruangan yang banyak cahaya maupun di dalam ruangan yang minim cahaya karena cahaya <i>flash</i> kamera <i>smartphone</i> dapat menyala dan mati secara otomatis berdasarkan intensitas cahaya yang ada. Hal itu dapat mempermudah pengguna untuk mendeteksi varietas berasnya.\n\n
    3.         <i>Sourcecode</i> program pada <i>Google Colaboratory</i> dan <i>Android Studio</i> : https://github.com/Soedirman-Machine-Learning/rice-varieties-classification\natau\nhttps://github.com/Vidi005/Klasifikasi-3-Varietas-Beras</string>
    4. <string name="update"><b>Pembaruan Fitur :</b></string>
    5. <string name="content_update_1">Versi 1.0\n- Klasifikasi 3 varietas beras dengan kamera\n- Memperbaiki <i>bug force closed</i>\n- Mengubah aspek rasio kamera menjadi 4:3\n- Menambah fitur waktu respon deteksi</string>
    6. <string name="content_update_2">Versi 2.0\n- Menambah fitur deteksi dengan impor galeri</string>
  93. Sehingga tampilan preview pada layout tentang akan seperti ini.
  94. Selanjutnya kita mengedit tampilan layout untuk "activity_bantuan.xml". Buat gambar untuk background-nya jika Anda mau dan letakan di dalam folder drawable.
  95. Lengkapi source code-nya seperti di bawah ini :
    1. <?xml version="1.0" encoding="utf-8"?>
    2. <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    3.     xmlns:tools="http://schemas.android.com/tools"
    4.     android:layout_width="match_parent"
    5.     android:layout_height="match_parent"
    6.     android:background="@drawable/background"
    7.     tools:context=".Bantuan">

    8.     <LinearLayout
    9.         android:layout_width="match_parent"
    10.         android:layout_height="wrap_content"
    11.         android:orientation="vertical">
    12.         <TextView
    13.             android:layout_width="match_parent"
    14.             android:layout_height="wrap_content"
    15.             android:textSize="20sp"
    16.             android:textStyle="bold"
    17.             android:fontFamily="times"
    18.             android:text="1. Cara Kerja Aplikasi"
    19.             android:layout_marginLeft="16dp"
    20.             android:layout_marginRight="16dp"
    21.             android:layout_marginTop="16dp"
    22.             android:layout_marginBottom="8dp"
    23.             android:textColor="@android:color/holo_green_dark"/>
    24.         <TextView
    25.             android:layout_width="match_parent"
    26.             android:layout_height="wrap_content"
    27.             android:text="@string/content_work"
    28.             android:background="#80FF6600"
    29.             android:layout_marginLeft="16dp"
    30.             android:layout_marginRight="16dp"
    31.             android:layout_marginBottom="16dp"
    32.             android:lineSpacingMultiplier="1"
    33.             android:textColor="#FFFFFF"/>
    34.         <TextView
    35.             android:layout_width="match_parent"
    36.             android:layout_height="wrap_content"
    37.             android:textSize="20sp"
    38.             android:textStyle="bold"
    39.             android:fontFamily="times"
    40.             android:text="2. Cara Menggunakan"
    41.             android:layout_marginLeft="16dp"
    42.             android:layout_marginRight="16dp"
    43.             android:layout_marginTop="16dp"
    44.             android:layout_marginBottom="8dp"
    45.             android:textColor="@android:color/holo_green_dark"/>
    46.         <TableLayout
    47.             android:layout_width="match_parent"
    48.             android:layout_height="wrap_content"
    49.             android:layout_marginLeft="16dp"
    50.             android:layout_marginRight="16dp"
    51.             android:layout_marginBottom="16dp">
    52.             <TableRow
    53.                 android:layout_width="match_parent"
    54.                 android:layout_height="wrap_content"
    55.                 android:layout_marginBottom="8dp">
    56.                 <TextView
    57.                     android:layout_width="wrap_content"
    58.                     android:layout_height="wrap_content"
    59.                     android:textSize="14sp"
    60.                     android:layout_marginRight="16dp"
    61.                     android:textColor="#FFFFFF"
    62.                     android:text="1. "/>
    63.                 <TextView
    64.                     android:layout_width="match_parent"
    65.                     android:layout_height="wrap_content"
    66.                     android:textSize="14sp"
    67.                     android:layout_weight="1"
    68.                     android:text="@string/content_step_1"
    69.                     android:textColor="#FFFFFF"/>
    70.             </TableRow>
    71.             <TableRow
    72.                 android:layout_width="match_parent"
    73.                 android:layout_height="wrap_content"
    74.                 android:layout_marginBottom="8dp">
    75.                 <TextView
    76.                     android:layout_width="wrap_content"
    77.                     android:layout_height="wrap_content"
    78.                     android:textSize="14sp"
    79.                     android:layout_marginRight="16dp"
    80.                     android:textColor="#FFFFFF"
    81.                     android:text="2. "/>
    82.                 <TextView
    83.                     android:layout_width="match_parent"
    84.                     android:layout_height="wrap_content"
    85.                     android:textSize="14sp"
    86.                     android:layout_weight="1"
    87.                     android:text="@string/content_step_2"
    88.                     android:textColor="#FFFFFF"/>
    89.             </TableRow>
    90.             <TableRow
    91.                 android:layout_width="match_parent"
    92.                 android:layout_height="wrap_content"
    93.                 android:layout_marginBottom="8dp">
    94.                 <TextView
    95.                     android:layout_width="wrap_content"
    96.                     android:layout_height="wrap_content"
    97.                     android:textSize="14sp"
    98.                     android:layout_marginRight="16dp"
    99.                     android:textColor="#FFFFFF"
    100.                     android:text="3. "/>
    101.                 <TextView
    102.                     android:layout_width="match_parent"
    103.                     android:layout_height="wrap_content"
    104.                     android:textSize="14sp"
    105.                     android:layout_weight="1"
    106.                     android:text="@string/content_step_3"
    107.                     android:textColor="#FFFFFF"/>
    108.             </TableRow>
    109.             <TableRow
    110.                 android:layout_width="match_parent"
    111.                 android:layout_height="wrap_content"
    112.                 android:layout_marginBottom="8dp">
    113.                 <TextView
    114.                     android:layout_width="wrap_content"
    115.                     android:layout_height="wrap_content"
    116.                     android:textSize="14sp"
    117.                     android:layout_marginRight="16dp"
    118.                     android:textColor="#FFFFFF"
    119.                     android:text="4. "/>
    120.                 <TextView
    121.                     android:layout_width="match_parent"
    122.                     android:layout_height="wrap_content"
    123.                     android:textSize="14sp"
    124.                     android:layout_weight="1"
    125.                     android:text="@string/content_step_4"
    126.                     android:textColor="#FFFFFF"/>
    127.             </TableRow>
    128.             <TableRow
    129.                 android:layout_width="match_parent"
    130.                 android:layout_height="wrap_content"
    131.                 android:layout_marginBottom="8dp">
    132.                 <TextView
    133.                     android:layout_width="wrap_content"
    134.                     android:layout_height="wrap_content"
    135.                     android:textSize="14sp"
    136.                     android:layout_marginRight="16dp"
    137.                     android:textColor="#FFFFFF"
    138.                     android:text="5. "/>
    139.                 <TextView
    140.                     android:layout_width="match_parent"
    141.                     android:layout_height="wrap_content"
    142.                     android:textSize="14sp"
    143.                     android:layout_weight="1"
    144.                     android:text="@string/content_step_5"
    145.                     android:textColor="#FFFFFF"/>
    146.             </TableRow>
    147.             <TableRow
    148.                 android:layout_width="match_parent"
    149.                 android:layout_height="wrap_content"
    150.                 android:layout_marginBottom="8dp">
    151.                 <TextView
    152.                     android:layout_width="wrap_content"
    153.                     android:layout_height="wrap_content"
    154.                     android:textSize="14sp"
    155.                     android:layout_marginRight="16dp"
    156.                     android:textColor="#FFFFFF"
    157.                     android:text="6. "/>
    158.                 <TextView
    159.                     android:layout_width="match_parent"
    160.                     android:layout_height="wrap_content"
    161.                     android:textSize="14sp"
    162.                     android:layout_weight="1"
    163.                     android:text="@string/content_step_6"
    164.                     android:textColor="#FFFFFF"/>
    165.             </TableRow>
    166.             <TableRow
    167.                 android:layout_width="match_parent"
    168.                 android:layout_height="wrap_content"
    169.                 android:layout_marginBottom="8dp">
    170.                 <TextView
    171.                     android:layout_width="wrap_content"
    172.                     android:layout_height="wrap_content"
    173.                     android:textSize="14sp"
    174.                     android:layout_marginRight="16dp"
    175.                     android:textColor="#FFFFFF"
    176.                     android:text="7. "/>
    177.                 <TextView
    178.                     android:layout_width="match_parent"
    179.                     android:layout_height="wrap_content"
    180.                     android:textSize="14sp"
    181.                     android:layout_weight="1"
    182.                     android:text="@string/content_step_7"
    183.                     android:textColor="#FFFFFF"/>
    184.             </TableRow>
    185.         </TableLayout>
    186.     </LinearLayout>
    187. </ScrollView>
  96. Buat string untuk "content_work", masukkan value-nya kosong saja karena nanti akan dimasukkan secara manual ke dalam "strings.xml".
  97. Lakukan hal yang sama pada string "content_step_1" sampai dengan "content_step_7" seperti pada langkah 81. Kemudian isi masing-masing nilai value-nya seperti ini.
  98. Nilai string untuk "content_step_1" sampai "content step_7" :
    1. <string name="content_work">Aplikasi ini bekerja dengan cara mengambil citra/gambar obyek dari varietas beras menggunakan kamera <i>smartphone</i> atau mengimpor gambar dari galeri foto yang sudah tersimpan. Setelah itu diekstrak fitur dari piksel obyek tersebut dan diubah ke dalam bentuk <i>array</i> dengan ukuran piksel 224 x 224 dengan format gambar berwarna (RGB). Kemudian dilatih dan diproses menggunakan model yang sudah dilatih sebelumnya sehingga dapat diprediksi hasil keluaran dari varietas beras yang dideteksi.</string>
    2. <string name="content_step_1">Buka Aplikasi Klasifikasi Varietas Beras kemudian pilih menu "DETEKSI BERAS DENGAN KAMERA" untuk klasifikasi secara langsung</string>
    3. <string name="content_step_2">Setelah terbuka menu tersebut arahkan kamera ke obyek varietas beras yang ingin dideteksi (jarak kamera dengan obyek sekitar 10 cm), kemudian klik/tap tombol "Deteksi"</string>
    4. <string name="content_step_3">Hasil prediksi akan muncul beberapa saat setelah menekan tombol "Deteksi" di bagian bawah layar dalam persentase (% diurutkan dari yang tertinggi). Persentase tertinggi merupakan hasil prediksi yang paling mendekati/mirip</string>
    5. <string name="content_step_4">Buka menu "DETEKSI BERAS DARI GALERI" jika ingin mengklasifikasi secara manual dengan mengimpor gambar yang sudah tersimpan di galeri foto</string>
    6. <string name="content_step_5">Klik tombol "PILIH GAMBAR" dan cari gambar obyek beras yang ingin dideteksi</string>
    7. <string name="content_step_6">Selanjutnya tekan tombol DETEKSI dan hasil prediksinya akan muncul beberapa saat setelah menekannya di bagian bawah layar</string>
    8. <string name="content_step_7">Jika Anda ingin mengetahui penjelasan singkat tiap varietas beras pilih menu "DESKRIPSI VARIETAS BERAS, Menu "BANTUAN" untuk mengetahui cara penggunaan aplikasi ini, dan Menu "TENTANG APLIKASI" sebagai informasi pembuatan aplikasi ini.</string>
  99. Maka tampilan layout-nya akan seperti berikut.
  100. Kemudian kembali lagi ke "activity_deskripsi.xml" untuk mengedit layout-nya. Lengkapi source code programnya seperti di bawah ini.
    1. <?xml version="1.0" encoding="utf-8"?>
    2. <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    3.     xmlns:app="http://schemas.android.com/apk/res-auto"
    4.     xmlns:tools="http://schemas.android.com/tools"
    5.     android:layout_width="match_parent"
    6.     android:layout_height="match_parent"
    7.     android:background="@drawable/background"
    8.     tools:context=".Deskripsi">

    9.     <LinearLayout
    10.         android:layout_width="match_parent"
    11.         android:layout_height="wrap_content"
    12.         android:orientation="vertical">
    13.         <TextView
    14.             android:layout_width="match_parent"
    15.             android:layout_height="wrap_content"
    16.             android:textSize="26sp"
    17.             android:fontFamily="times"
    18.             android:text="Deskripsi Tiga Varietas Beras (Basmathi, IR-64, dan Ketan)"
    19.             android:layout_marginLeft="16dp"
    20.             android:layout_marginRight="16dp"
    21.             android:layout_marginTop="16dp"
    22.             android:layout_marginBottom="8dp"
    23.             android:textColor="@android:color/holo_blue_dark"/>
    24.         <TextView
    25.             android:layout_width="match_parent"
    26.             android:layout_height="wrap_content"
    27.             android:textStyle="bold"
    28.             android:text="1. Varietas Beras Basmathi"
    29.             android:textSize="20sp"
    30.             android:layout_marginLeft="16dp"
    31.             android:layout_marginRight="16dp"
    32.             android:layout_marginBottom="16dp"
    33.             android:textColor="@android:color/holo_green_dark"/>
    34.         <FrameLayout
    35.             android:layout_width="match_parent"
    36.             android:layout_height="wrap_content">

    37.             <ImageView
    38.                 android:layout_width="match_parent"
    39.                 android:layout_height="wrap_content"
    40.                 android:adjustViewBounds="true"
    41.                 android:scaleType="fitCenter"
    42.                 android:src="@drawable/basmathi" />
    43.         </FrameLayout>
    44.         <TextView
    45.             android:layout_width="match_parent"
    46.             android:layout_height="wrap_content"
    47.             android:text="@string/content_basmathi"
    48.             android:background="#60FFFFFF"
    49.             android:layout_marginLeft="16dp"
    50.             android:layout_marginRight="16dp"
    51.             android:layout_marginBottom="16dp"
    52.             android:lineSpacingMultiplier="1"
    53.             android:textColor="#FFFFFF"
    54.             android:autoLink="all"
    55.             android:linksClickable="true"/>

    56.         <TextView
    57.             android:layout_width="match_parent"
    58.             android:layout_height="wrap_content"
    59.             android:textStyle="bold"
    60.             android:text="2. Varietas Beras IR-64"
    61.             android:textSize="20sp"
    62.             android:layout_marginLeft="16dp"
    63.             android:layout_marginRight="16dp"
    64.             android:layout_marginBottom="16dp"
    65.             android:textColor="@android:color/holo_green_dark"/>
    66.         <FrameLayout
    67.             android:layout_width="match_parent"
    68.             android:layout_height="wrap_content">

    69.             <ImageView
    70.                 android:layout_width="match_parent"
    71.                 android:layout_height="wrap_content"
    72.                 android:adjustViewBounds="true"
    73.                 android:scaleType="fitCenter"
    74.                 android:src="@drawable/ir64" />
    75.         </FrameLayout>
    76.         <TextView
    77.             android:layout_width="match_parent"
    78.             android:layout_height="wrap_content"
    79.             android:text="@string/content_ir64"
    80.             android:background="#60FFFFFF"
    81.             android:layout_marginLeft="16dp"
    82.             android:layout_marginRight="16dp"
    83.             android:layout_marginBottom="16dp"
    84.             android:lineSpacingMultiplier="1"
    85.             android:textColor="#FFFFFF"/>

    86.         <TextView
    87.             android:layout_width="match_parent"
    88.             android:layout_height="wrap_content"
    89.             android:textStyle="bold"
    90.             android:text="3. Varietas Beras Ketan"
    91.             android:textSize="20sp"
    92.             android:layout_marginLeft="16dp"
    93.             android:layout_marginRight="16dp"
    94.             android:layout_marginBottom="16dp"
    95.             android:textColor="@android:color/holo_green_dark"/>
    96.         <FrameLayout
    97.             android:layout_width="match_parent"
    98.             android:layout_height="wrap_content">

    99.             <ImageView
    100.                 android:layout_width="match_parent"
    101.                 android:layout_height="wrap_content"
    102.                 android:adjustViewBounds="true"
    103.                 android:scaleType="fitCenter"
    104.                 android:src="@drawable/ketan" />
    105.         </FrameLayout>
    106.         <TextView
    107.             android:layout_width="match_parent"
    108.             android:layout_height="wrap_content"
    109.             android:text="@string/content_ketan"
    110.             android:background="#60FFFFFF"
    111.             android:layout_marginLeft="16dp"
    112.             android:layout_marginRight="16dp"
    113.             android:layout_marginBottom="16dp"
    114.             android:lineSpacingMultiplier="1"
    115.             android:textColor="#FFFFFF"
    116.             android:autoLink="all"
    117.             android:linksClickable="true"/>
    118.     </LinearLayout>
    119. </ScrollView>
  101. Kemudian masukkan gambar masing-masing jenis berasnya ke dalam folder drawable.
  102. Selain itu juga buat nilai string-nya masing-masing jenis beras.
  103. Isikan masing-masing nilai string-nya pada "string.xml".
  104. Nilai masing-masing string yang diperlukan :
    1. <string name="content_basmathi">Beras basmathi bersal dari negara india/pakistan, beras basmathi berasal dari bahasa sanskerta ‘basmathi’ artinya berarti harum atau wangi dalam bahasa india ia juga mempunyai maksud ”soft rice” yaitu lembut.\n
    2.             Beras ini akan melar memanjang butiran, sedikit pera, mudah terurai butiran berasnya dan aromanya sangat harum, beras ini memang aromanya sangat harum. Keistimewaan lainnya, butiran atau buliran beras ini panjang dan kecil melebihi ukuran beras yang biasanya agak pendek dan bulat.\n
    3.             Sumber : https://www.asshidiqaqiqah.com/kandungan-kandungan-beras-basmati/</string>
    4. <string name="content_ir64">Beras IR 64 merupakan salah satu jenis varietas padi sawah yang memiliki bentuk tegak, tinggi sekitar 115-126 cm. Gabahnya berbentuk ramping dan panjang dan berwarna kuning bersih. Padi jenis ini cocok ditanam di daerah lahan sawah irigasi dataran rendah sampai sedang.\n
    5.             Beras IR 64 adalah jenis beras yang pulen jika dimasak menjadi nasi karena memiliki kadar amilosa sebanyak 23%. Bobot beras per seribu butir beras IR64 adalah 24,1 gram.\n
    6.             Sumber : Suprihatno, B, Daradjat, dkk. 2010. Deskripsi Varietas Padi. Balai Besar Penelitian Tanaman Padi.\n</string>
    7. <string name="content_ketan">Beras ketan putih (Oryza sativa glutinosa) merupakan salah satu varietas padi yang termasuk dalam famili Graminae.\n
    8.             Butir beras sebagian besar terdiri dari zat pati sekitar 80-85% yang terdapat dalam endosperma yang tersusun oleh granula-granula pati yang berukuran 3-10 milimikron. Beras ketan juga mengandung vitamin (terutama pada bagian aleuron), mineral dan air. Dari komposisi kimiawinya diketahui bahwa karbohidrat penyusun utama beras ketan adalah pati. Pati merupakan karbohidrat polimer glukosa yang mempunyai dua struktur yakni amilosa dan amilopektin.\n
    9.             Sumber : http://www.alatcetakrengginang.com/2012/02/beras-ketan-sifat-fisika-kimianya.html</string>
  105. Sehingga tampilan layout-nya akan seperti berikut.
  106. Sesudah itu kita masuk ke tahap pembuatan intent untuk membuat tombol menu yang dapat berpindah menuju ke aktivitas lainnya. Untuk membuat intent pada Android perlu ditambahkan "View.OnClickListener" pada class "MainActivity.kt" yang berfungsi mendeteksi adanya penekanan tombol pada suatu aktivitas yang sudah dibuat.
  107. Kemudian tambahkan pada fungsi "onCreate" untuk memperkenalkan setiap tombol yang dibuat sesuai dengan nama id-nya masing-masing yang dipanggil pada layout "activity_main.xml". Selain itu juga dibuat fungsi untuk menambahkan kejadian "onClick" pada masing-masing tombol yang sudah dibuat. Selain itu tambahkan juga pada fungsi "onClick" untuk memindahkan suatu intent ketika adanya kondisi penekanan tombol.
  108. Source code "MainActivity.kt" :
    1. class MainActivity : AppCompatActivity(), View.OnClickListener {

    2.     override fun onCreate(savedInstanceState: Bundle?) {
    3.         super.onCreate(savedInstanceState)
    4.         setContentView(R.layout.activity_main)
    5.         //memperkenalkan button yang sudah ditambahkan di layout activity_main.xml
    6.         val btnPendeteksi: Button = findViewById(R.id.btn_move_detection)
    7.         //menambahkan event onClick pada button btnMoveDetection
    8.         btnPendeteksi.setOnClickListener(this)

    9.         val btnImporGaleri: Button = findViewById(R.id.btn_move_import)
    10.         btnImporGaleri.setOnClickListener(this)

    11.         val btnDeskripsi: Button = findViewById(R.id.btn_move_description)
    12.         btnDeskripsi.setOnClickListener(this)

    13.         val btnBantuan: Button = findViewById(R.id.btn_move_help)
    14.         btnBantuan.setOnClickListener(this)

    15.         val btnTentang: Button = findViewById(R.id.btn_move_about)
    16.         btnTentang.setOnClickListener(this)
    17.     }
    18.     override fun onClick(v: View) {
    19.         when (v.id) {
    20.             R.id.btn_move_detection -> {
    21.                 //menambahkan suatu Intent pada method onClick()
    22.                 val moveIntent = Intent(this@MainActivity, Pendeteksi::class.java)
    23.                 startActivity(moveIntent)
    24.             }
    25.             R.id.btn_move_import -> {
    26.                 val moveIntent = Intent(this@MainActivity, DeteksiDariGaleri::class.java)
    27.                 startActivity(moveIntent)
    28.             }
    29.             R.id.btn_move_description -> {
    30.                 val moveIntent = Intent(this@MainActivity, Deskripsi::class.java)
    31.                 startActivity(moveIntent)
    32.             }
    33.             R.id.btn_move_help -> {
    34.                 val moveIntent = Intent(this@MainActivity, Bantuan::class.java)
    35.                 startActivity(moveIntent)
    36.             }
    37.             R.id.btn_move_about -> {
    38.                 val moveIntent = Intent(this@MainActivity, Tentang::class.java)
    39.                 startActivity(moveIntent)
    40.             }
    41.         }
    42.     }
    43. }
  109. Selanjutnya menuju layout "activity_main.xml" ganti jenis layout-nya menjadi "LinearLayout" dan lengkapi source code-nya seperti di bawah ini.
  110. Source code "activity_main.xml" :
    1. <?xml version="1.0" encoding="utf-8"?>
    2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    3.     xmlns:tools="http://schemas.android.com/tools"
    4.     android:layout_width="match_parent"
    5.     android:layout_height="match_parent"
    6.     tools:context=".MainActivity"
    7.     android:orientation="vertical"
    8.     android:background="@drawable/background"
    9.     android:padding="16dp">

    10.     <Button
    11.         android:id="@+id/btn_move_detection"
    12.         android:layout_width="match_parent"
    13.         android:layout_height="wrap_content"
    14.         android:layout_marginTop="64dp"
    15.         android:layout_marginBottom="32dp"
    16.         android:textColor="@android:color/holo_green_dark"
    17.         android:text="@string/pendeteksi"
    18.         android:textStyle="bold"/>

    19.     <Button
    20.         android:id="@+id/btn_move_import"
    21.         android:layout_width="match_parent"
    22.         android:layout_height="wrap_content"
    23.         android:layout_marginBottom="32dp"
    24.         android:textColor="@android:color/holo_green_dark"
    25.         android:text="@string/import_gallery"
    26.         android:textStyle="bold"/>

    27.     <Button
    28.         android:id="@+id/btn_move_description"
    29.         android:layout_width="match_parent"
    30.         android:layout_height="wrap_content"
    31.         android:layout_marginBottom="32dp"
    32.         android:textColor="@android:color/holo_green_dark"
    33.         android:text="@string/deskripsi"
    34.         android:textStyle="bold"/>

    35.     <Button
    36.         android:id="@+id/btn_move_help"
    37.         android:layout_width="match_parent"
    38.         android:layout_height="wrap_content"
    39.         android:layout_marginBottom="32dp"
    40.         android:textColor="@android:color/holo_green_dark"
    41.         android:text="@string/bantuan"
    42.         android:textStyle="bold"/>

    43.     <Button
    44.         android:id="@+id/btn_move_about"
    45.         android:layout_width="match_parent"
    46.         android:layout_height="wrap_content"
    47.         android:layout_marginBottom="32dp"
    48.         android:textColor="@android:color/holo_green_dark"
    49.         android:text="@string/tentang"
    50.         android:textStyle="bold"/>

    51. </LinearLayout>
  111. Setelah itu buat masing-masing nama string yang ditampilkan pada tombol.
  112. Nilai untuk tiap string-nya adalah :
    1. <string name="pendeteksi">Deteksi Beras dengan Kamera</string>
    2. <string name="import_gallery">Deteksi Beras dari Galeri</string>
    3. <string name="deskripsi">Deskripsi Varietas Beras</string>
    4. <string name="bantuan">Bantuan</string>
    5. <string name="tentang">Tentang Aplikasi</string>
  113. Berikutnya menuju "styles.xml" yang terletak tepat di bawah "strings.xml" pada folder values. Kemudian ubah source code-nya menjadi seperti ini.
  114. Source code untuk "styles.xml" :
    1. <resources>

    2.     <!-- Base application theme. -->
    3.     <style name="AppThemeSplashScreen" parent="Theme.AppCompat.Light.NoActionBar">
    4.         <!-- Customize your theme here. -->
    5.         <item name="colorPrimary">@color/colorPrimary</item>
    6.         <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    7.         <item name="colorAccent">@color/colorAccent</item>
    8.     </style>
    9.     <!-- Main application theme. -->
    10.     <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    11.         <!-- Customize your theme here. -->
    12.         <item name="colorPrimary">@android:color/holo_blue_dark</item>
    13.         <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    14.         <item name="colorAccent">@color/colorAccent</item>
    15.     </style>

    16. </resources>
  115. Kembali lagi ke "AndroidManifest.xml" dan lengkapi source code-nya seperti berikut untuk mengatur tampilan aktivitas awal dan orientasi tiap aktivitas.
  116. Source code ditempatkan di dalam tag "<application ...>(di sini)</application>" :
    1. <activity android:name=".SplashScreen"
    2.             android:label="@string/app_name"
    3.             android:noHistory="true"
    4.             android:screenOrientation="portrait"
    5.             android:theme="@style/AppThemeSplashScreen">
    6.             <intent-filter>
    7.                 <action android:name="android.intent.action.MAIN" />

    8.                 <category android:name="android.intent.category.LAUNCHER" />
    9.             </intent-filter>
    10.         </activity>
    11.         <activity android:name=".Bantuan" />
    12.         <activity android:name=".Deskripsi" />
    13.         <activity android:name=".Pendeteksi"
    14.             android:screenOrientation="portrait"
    15.             android:colorMode="wideColorGamut">
    16.         </activity>
    17.         <activity android:name=".DeteksiDariGaleri"
    18.             android:screenOrientation="portrait">
    19.         </activity>
    20.         <activity android:name=".MainActivity"
    21.             android:screenOrientation="portrait">
    22.         </activity>
    23.         <activity android:name=".Tentang" />
  117. Sesudah itu membuat folder "assets" pada direktori "app" di dalam project tersebut. Folder tersebut digunakan untuk menyimpan model hasil pelatihan dari arsitektur CNN dalam format "*.tflite" beserta labelnya berformat "*.txt" dan untuk menyimpan gambar contoh untuk pengujian varietas beras dengan menggunakan fitur import gallery (mengambil gambar dari galeri foto). Cara pembuatannya dapat dilihat langsung pada gambar berikut.
  118. Pilih target sumber "main" kemudian klik "Finish".
  119. Tunggu sinkronisasi gradle pada project Android hingga selesai.
  120. Selanjutnya copy contoh gambar pengujian yang berformat (.jpg), model hasil pelatihan arsitektur CNN berformat (.tflite), dan labelnya berformat (.txt).
  121. Paste-kan di dalam direktori folder "assets" dan samakan namanya.
  122. Anda juga dapat membuat/mengedit isi labelnya secara langsung.
  123. Kembali ke "build.gradle (Module: app)", tambahkan implementasi untuk penampil gambar di dalam tag dependencies seperti pada gambar.
  124. Source code dependency untuk menampilkan custom ImageView :
    1. //menampilkan sebuah custom ImageView dalam bentuk lingkaran
    2.     implementation 'de.hdodenhof:circleimageview:3.0.0'
  125. Kemudian tambahkan perintah sesuai pada gambar di bawah untuk mencegah terjadinya kompresi pada file ".tflite" dan mencegah duplikasi saat proses build. Setelah itu lakukan sinkronisasi kembali pada "build.gradle" untuk menerapkan perunbahan.
  126. Perintah yang perlu ditambahkan pada "build.gradle (Module: app)" :
    1. aaptOptions {
    2.         noCompress "tflite"
    3.         noCompress "lite"
    4.     }
    5.     packagingOptions {//mencegah duplikasi modul kotlin saat build aplikasi
    6.         pickFirst 'META-INF/kotlinx-io.kotlin_module'
    7.         pickFirst 'META-INF/atomicfu.kotlin_module'
    8.         pickFirst 'META-INF/kotlinx-coroutines-io.kotlin_module'
    9.     }
  127. Langkah terakhir adalah menambahkan ikon launcher pada aplikasi Android-nya. Caranya cukup mudah hanya perlu menyalin gambar ke dalam folder mipmap.
  128. Kemudian samakan namanya dengan yang ada pada "AndroidManifest.xml".
  129. Terakhir jalankan aplikasinya pada perangkat Android Anda. Untuk menjalankannya hubungkan HP Android Anda ke Laptop/Komputer dan aktifkan mode USB Debugging-nya yang terletak pada menu pengaturan "Developer Options". Kemudian tunggu nama device Anda sampai terdeteksi di Android Studio. Selanjutnya tekan tombol "Run".
  130. Tunggu sampai proses build dan instalasi aplikasi selesai.
  131. Berikut contoh tampilan aplikasinya setelah dijalankan di perangkat Android.
  132. Jika sudah berhasil dijalankan dan ingin meng-install-nya di perangkat lain, maka dapat dibuat juga file "*.apk"-nya dengan cara seperti berikut.
  133. Tunggu prosesnya hingga selesai, dan klik "locate" untuk menuju direktori dimana file aplikasi Android tersebut disimpan setelah di-build.
  134. File .apk sudah berhasil dibuat, sekarang Anda dapat mengirim/menyalinnya ke perangkat Android lainnya yang ingin Anda coba untuk di-install.
  135. Selesai !!
Keterangan :
  1. Bingkai textbox yang berwarna biru merupakan program Bahasa Kotlin, sedangkan yang berwarna oranye adalah program dalam bahasa ".xml".
  2. Gambar logo dan contoh pengujian bisa Anda buat atau cari sendiri.
  3. Untuk source code lengkapnya dapat diunduh  di sini.
Video tutorial hasil pelatihannya dapat dilihat di bawah.

Terima kasih atas kunjungannya semoga bermanfaat.



    Demikianlah Artikel Klasifikasi Citra Menggunakan Convolutional Neural Network (CNN) dengan Model TensorFlow Lite pada Android

    Sekian Klasifikasi Citra Menggunakan Convolutional Neural Network (CNN) dengan Model TensorFlow Lite pada Android, mudah-mudahan bisa memberi manfaat untuk anda semua.

    Anda sedang membaca artikel Klasifikasi Citra Menggunakan Convolutional Neural Network (CNN) dengan Model TensorFlow Lite pada Android dan artikel ini url permalinknya adalah https://pawang-bisnis.blogspot.com/2020/02/klasifikasi-citra-menggunakan.html Semoga artikel ini bisa bermanfaat.

    Tag : ,