diff --git a/app/src/main/java/com/example/palmguardapp/data/repository/DiseaseRepository.kt b/app/src/main/java/com/example/palmguardapp/data/repository/DiseaseRepository.kt index 85b79da..45bf2b0 100644 --- a/app/src/main/java/com/example/palmguardapp/data/repository/DiseaseRepository.kt +++ b/app/src/main/java/com/example/palmguardapp/data/repository/DiseaseRepository.kt @@ -4,45 +4,6 @@ import com.example.palmguardapp.data.local.entity.DiseaseDiagnose import com.example.palmguardapp.data.local.room.DiseaseDiagnoseDao import kotlinx.coroutines.flow.Flow -//class DiseaseRepository private constructor( -// private val apiService: ApiService -//) { -// -// suspend fun getDiseaseById(id: String): Flow> = flow { -// emit(Result.Loading) -// val response = apiService.getDiseaseById(id) -// emit(Result.Success(response)) -// }.catch { e -> -// emit(Result.Error(e.message.toString())) -// } -// -// suspend fun getAllDiseaseDetail(): Flow> = flow { -// emit(Result.Loading) -// val response = apiService.getAllDiseaseDetail() -// emit(Result.Success(response)) -// }.catch { e -> -// emit(Result.Error(e.message.toString())) -// } -// -// suspend fun getDiseaseDetailById(id: String): Flow> = flow { -// emit(Result.Loading) -// val response = apiService.getDiseaseDetailById(id) -// emit(Result.Success(response)) -// }.catch { e -> -// emit(Result.Error(e.message.toString())) -// } -// -// companion object { -// @Volatile -// private var instance: DiseaseRepository? = null -// -// fun getInstance(apiService: ApiService): DiseaseRepository = -// instance ?: synchronized(this) { -// instance ?: DiseaseRepository(apiService).also { instance = it } -// } -// } -//} - class DiseaseRepository private constructor( private val diseaseDiagnoseDao: DiseaseDiagnoseDao ) { diff --git a/app/src/main/java/com/example/palmguardapp/foundation/classification/ImageClassifier.kt b/app/src/main/java/com/example/palmguardapp/foundation/classification/ImageClassifier.kt index 9afc5e6..31aae66 100644 --- a/app/src/main/java/com/example/palmguardapp/foundation/classification/ImageClassifier.kt +++ b/app/src/main/java/com/example/palmguardapp/foundation/classification/ImageClassifier.kt @@ -1,3 +1,4 @@ +// Import library yang dibutuhkan untuk context, bitmap, logging, dan TensorFlow Lite import android.content.Context import android.graphics.Bitmap import android.util.Log @@ -9,51 +10,69 @@ import org.tensorflow.lite.support.image.TensorImage import org.tensorflow.lite.support.image.ops.ResizeOp import org.tensorflow.lite.support.tensorbuffer.TensorBuffer - +// Kelas utama untuk klasifikasi gambar menggunakan model ML TFLite class ImageClassifier(private val context: Context) { + // Ukuran input gambar yang dibutuhkan model private val imageSize = 224 + + // Daftar label kelas dari model private val classes = arrayOf("Brown Spots", "Healthy", "Unknown") + // ImageProcessor untuk mengubah ukuran dan menormalisasi gambar agar sesuai dengan input model private val imageProcessor = ImageProcessor.Builder() - .add(ResizeOp(imageSize, imageSize, ResizeOp.ResizeMethod.BILINEAR)) - .add(NormalizeOp(0f, 255f)) + .add(ResizeOp(imageSize, imageSize, ResizeOp.ResizeMethod.BILINEAR)) // Resize gambar ke 224x224 + .add(NormalizeOp(0f, 255f)) // Normalisasi piksel gambar ke range 0–1 .build() + // Fungsi utama untuk mengklasifikasikan gambar fun classifyImage(image: Bitmap): Pair? { + // Membuat instance model val model = Model.newInstance(context) + // Mengonversi gambar bitmap ke TensorImage dengan tipe data FLOAT32 val tensorImage = TensorImage(DataType.FLOAT32) - val convertedBitmap = image.copy(Bitmap.Config.ARGB_8888, true) + val convertedBitmap = image.copy(Bitmap.Config.ARGB_8888, true) // Salin bitmap agar bisa diolah tensorImage.load(convertedBitmap) + + // Proses preprocessing gambar: resize + normalisasi val processedImage = imageProcessor.process(tensorImage) + // Menyiapkan buffer input model dengan shape dan tipe data yang sesuai val inputFeature0 = TensorBuffer.createFixedSize(intArrayOf(1, imageSize, imageSize, 3), DataType.FLOAT32) inputFeature0.loadBuffer(processedImage.buffer) + // Memproses input melalui model dan mendapatkan output val outputs = model.process(inputFeature0) val outputFeature0 = outputs.outputFeature0AsTensorBuffer + // Mengambil array probabilitas prediksi dari hasil output val confidences = outputFeature0.floatArray Log.d("ImageClassifier", "Confidence: ${confidences.size}") + + // Logging setiap confidence untuk tiap kelas for (i in confidences.indices) { Log.d("ImageClassifier", "Class $i (${classes[i]}): ${confidences[i]}") } + // Mencari indeks prediksi dengan confidence tertinggi val maxPos = confidences.indices.maxByOrNull { confidences[it] } ?: -1 - val maxConfidence = (maxOf(confidences[maxPos]) * 100).toFloat() + val maxConfidence = (maxOf(confidences[maxPos]) * 100).toFloat() // Konversi ke persen Log.d("ImageClassifier", "Max Position: $maxPos, Max Confidence: $maxConfidence") + // Menutup instance model untuk membebaskan resource model.close() + // Mengembalikan hasil klasifikasi jika confidence mencukupi dan bukan kelas Unknown return if (maxPos >= 0 && maxConfidence > THRESHOLD_CONFIDENCE && classes[maxPos] != "Unknown") { Pair(classes[maxPos], maxConfidence) } else { - null + null // Tidak ada hasil yang cukup meyakinkan } } companion object { + // Batas minimum confidence yang dianggap valid (dalam persen) private const val THRESHOLD_CONFIDENCE = 0.5f } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/example/palmguardapp/ui/detection/DetectionViewModel.kt b/app/src/main/java/com/example/palmguardapp/ui/detection/DetectionViewModel.kt index eb9f94f..29c6f17 100644 --- a/app/src/main/java/com/example/palmguardapp/ui/detection/DetectionViewModel.kt +++ b/app/src/main/java/com/example/palmguardapp/ui/detection/DetectionViewModel.kt @@ -29,7 +29,6 @@ class DetectionViewModel(private val historyDiagnoseRepository: HistoryDiagnoseR fun deleteHistory(historyDiagnose: HistoryDiagnose) { viewModelScope.launch { historyDiagnoseRepository.delete(historyDiagnose) - // Refresh the list after deletion getDetectionList() } } diff --git a/app/src/main/java/com/example/palmguardapp/ui/home/HomeFragment.kt b/app/src/main/java/com/example/palmguardapp/ui/home/HomeFragment.kt index 50c6f0a..40011de 100644 --- a/app/src/main/java/com/example/palmguardapp/ui/home/HomeFragment.kt +++ b/app/src/main/java/com/example/palmguardapp/ui/home/HomeFragment.kt @@ -49,12 +49,6 @@ class HomeFragment : Fragment(R.layout.fragment_home) { private val diseaseToId = mapOf( "Brown Spots" to "D-001", "Healthy" to "D-002", -// "Bird Eye Spot" to "D-003", -// "Brown Blight" to "D-004", -// "Gray Light" to "D-005", -// "Red Leaf Spot" to "D-006", -// "White Spot" to "D-007", -// "Healthy" to "D-008" ) private lateinit var cameraLauncher: ActivityResultLauncher @@ -219,38 +213,6 @@ class HomeFragment : Fragment(R.layout.fragment_home) { Log.d("saveImageAndFetchData", "Date: $date") val dateNow = formatter.format(date) val diseaseId = diseaseToId[diagnosis] -// diseaseId?.let { id -> -// viewModel.getDiseaseById(id) -// viewModel.dataDisease.collect { result -> -// when (result) { -// is Result.Success -> { -// val diseaseData = result.data -// Log.d("HomeFragment", "Disease Data: $diseaseData") -// val historyDiagnose = HistoryDiagnose( -// name = diagnosis, -// imageUri = imageUri.toString(), -// diagnosis = diseaseData.data?.diseaseExplanation ?: "", -// recommendation = diseaseData.data?.diseaseRecommendation ?: "", -// confidence = confidence.toString(), -// date = dateNow -// ) -// -// viewModel.saveDiagnose(historyDiagnose) -// lastDiagnosis = historyDiagnose -// Log.d("HomeFragment", "History Diagnose: $historyDiagnose") -// binding.progressResult.visibility = View.GONE -// restartFragment() -// navigateToDiagnoseDetail(historyDiagnose) -// } -// is Result.Error -> { -// // Handle error state -// } -// Result.Loading -> { -// binding.progressResult.visibility = View.VISIBLE -// } -// } -// } -// } diseaseId?.let { id -> viewModel.getDiseaseById(id) @@ -317,7 +279,6 @@ class HomeFragment : Fragment(R.layout.fragment_home) { binding.tvHsHistoryEmpty.visibility = View.GONE } - override fun onDestroyView() { super.onDestroyView() _binding = null diff --git a/app/src/main/java/com/example/palmguardapp/ui/listDisease/DiseaseViewModel.kt b/app/src/main/java/com/example/palmguardapp/ui/listDisease/DiseaseViewModel.kt index c0a6645..67c2731 100644 --- a/app/src/main/java/com/example/palmguardapp/ui/listDisease/DiseaseViewModel.kt +++ b/app/src/main/java/com/example/palmguardapp/ui/listDisease/DiseaseViewModel.kt @@ -18,15 +18,6 @@ class DiseaseViewModel(private val diseaseRepository: DiseaseRepository) : ViewM private val _diseaseById = MutableSharedFlow>() val diseaseById: Flow> = _diseaseById.asSharedFlow() -// fun getAllDisease() { -// viewModelScope.launch { -// _listDisease.emit(Result.Loading) -// diseaseRepository.getAllDisease().collect { diseases -> -// _listDisease.emit(Result.Success(diseases)) -// } -// } -// } - fun getDiseaseById(id: String) { viewModelScope.launch { _diseaseById.emit(Result.Loading) diff --git a/app/src/main/ml/model.tflite b/app/src/main/ml/model.tflite index bd40a36..9b67a78 100644 Binary files a/app/src/main/ml/model.tflite and b/app/src/main/ml/model.tflite differ diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index ddf5e0d..cc78df6 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -124,7 +124,7 @@ android:id="@+id/tv_hs_phone_analyze" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="Ambil Gambar" + android:text="Analisis Hasil" android:textColor="@color/greenGeneral" android:textSize="14sp" android:textStyle="bold" diff --git a/app/src/main/res/menu/bottom_nav.xml b/app/src/main/res/menu/bottom_nav.xml index 66d885d..ff39a6d 100644 --- a/app/src/main/res/menu/bottom_nav.xml +++ b/app/src/main/res/menu/bottom_nav.xml @@ -7,5 +7,5 @@ + android:title="Riwayat" /> \ No newline at end of file