EcoQuest/Assets/Script/AcakClassifier.cs

368 lines
12 KiB
C#

using System.Collections;
using UnityEngine;
using Unity.Barracuda;
using TMPro;
using UnityEngine.SceneManagement;
using UnityEngine.UI; // Untuk komponen Image
public class AcakClassifier : MonoBehaviour
{
[Header("Model Barracuda")]
public NNModel onnxModel;
private Model runtimeModel;
private IWorker worker;
[Header("UI Text")]
public TextMeshProUGUI outputText;
public TextMeshProUGUI scoreText;
public TextMeshProUGUI titleText;
public TextMeshProUGUI descriptionText;
[Header("UI Image")]
public Image displayImage; // Menampilkan foto hasil kamera
[Header("Initial Display Sprites")]
public Sprite organikSprite;
public Sprite anorganikSprite;
public Sprite bukansampahSprite;
[Header("Feedback Images")]
public Image feedbackCorrectImage;
public Image feedbackWrongImage;
public float feedbackDelay = 0.5f;
[Header("Canvas")]
public GameObject canvasBerhasil;
public GameObject canvasGagal;
[Header("Audio")]
[SerializeField] private AudioSource audioSource;
[SerializeField] private AudioClip correctClip;
[SerializeField] private AudioClip wrongClip;
[SerializeField] private AudioClip awardClip;
private string[] classes = { "anorganik", "bukansampah", "organik" };
private string[] scenarioSequence;
private int currentIndex = 0;
private int inputWidth = 224;
private int inputHeight = 224;
private int currentScore = 0;
private int maxScore = 0;
void Start()
{
runtimeModel = ModelLoader.Load(onnxModel);
worker = WorkerFactory.CreateWorker(WorkerFactory.Type.Auto, runtimeModel);
int selectedLevel = PlayerPrefs.GetInt("selectedLevel", 1);
Debug.Log("Selected Level: " + selectedLevel);
// Set target quest sesuai level yang dipilih
switch (selectedLevel)
{
case 1:
scenarioSequence = new string[] { "organik" };
break;
case 2:
scenarioSequence = new string[] { "bukansampah" };
break;
case 3:
scenarioSequence = new string[] { "anorganik" };
break;
case 4:
scenarioSequence = new string[] { "bukansampah" };
break;
case 5:
scenarioSequence = new string[] { "anorganik" };
break;
case 6:
scenarioSequence = new string[] { "organik" };
break;
default:
scenarioSequence = new string[] { "organik" };
break;
}
maxScore = scenarioSequence.Length;
if (feedbackCorrectImage != null)
feedbackCorrectImage.gameObject.SetActive(false);
if (feedbackWrongImage != null)
feedbackWrongImage.gameObject.SetActive(false);
UpdateUI();
UpdateScoreText();
}
private void UpdateUI()
{
if (currentIndex >= scenarioSequence.Length)
{
titleText.text = "SELESAI!";
descriptionText.text = "Kamu sudah menemukan target.";
return;
}
string target = scenarioSequence[currentIndex];
switch (target)
{
case "organik":
titleText.text = "JELAJAHI SAMPAH ORGANIK";
descriptionText.text = "Cari sampah organik, misalnya kulit buah.";
if (displayImage != null && organikSprite != null)
displayImage.sprite = organikSprite;
break;
case "anorganik":
titleText.text = "JELAJAHI SAMPAH ANORGANIK";
descriptionText.text = "Cari sampah anorganik, misalnya botol plastik.";
if (displayImage != null && anorganikSprite != null)
displayImage.sprite = anorganikSprite;
break;
case "bukansampah":
titleText.text = "JELAJAHI OBJEK BUKAN SAMPAH";
descriptionText.text = "Cari objek non-sampah, misalnya buah apel atau jeruk.";
if (displayImage != null && bukansampahSprite != null)
displayImage.sprite = bukansampahSprite;
break;
}
}
public void TakePicture()
{
NativeCamera.Permission permission = NativeCamera.CheckPermission(true);
if (permission == NativeCamera.Permission.Denied || permission == NativeCamera.Permission.ShouldAsk)
{
NativeCamera.RequestPermission(true);
}
NativeCamera.TakePicture((path) =>
{
if (!string.IsNullOrEmpty(path))
{
Texture2D texture = NativeCamera.LoadImageAtPath(path, inputWidth);
if (texture == null)
{
Debug.LogError("Gagal memuat gambar dari path: " + path);
return;
}
Texture2D readableTexture = MakeTextureReadable(texture);
Texture2D correctedTexture = CorrectCameraImage(readableTexture);
if (displayImage != null)
{
Sprite newSprite = Sprite.Create(correctedTexture,
new Rect(0, 0, correctedTexture.width, correctedTexture.height),
new Vector2(0.5f, 0.5f));
displayImage.sprite = newSprite;
}
RunInference(correctedTexture);
}
}, maxSize: inputWidth);
}
public void RunInference(Texture2D inputTexture)
{
if (inputTexture == null)
{
Debug.LogError("Gambar tidak tersedia untuk inferensi!");
return;
}
Texture2D resized = ResizeTexture(inputTexture, inputWidth, inputHeight);
Color32[] pixels = resized.GetPixels32();
float[] floatValues = new float[inputWidth * inputHeight * 3];
for (int i = 0; i < pixels.Length; i++)
{
floatValues[i * 3 + 0] = (pixels[i].r / 127.5f) - 1.0f;
floatValues[i * 3 + 1] = (pixels[i].g / 127.5f) - 1.0f;
floatValues[i * 3 + 2] = (pixels[i].b / 127.5f) - 1.0f;
}
Tensor inputTensor = new Tensor(1, inputHeight, inputWidth, 3, floatValues);
worker.Execute(inputTensor);
Tensor outputTensor = worker.PeekOutput();
float[] scores = outputTensor.ToReadOnlyArray();
int predictedIndex = ArgMax(scores);
float confidence = scores[predictedIndex];
string predictedClass = classes[predictedIndex];
Debug.Log($"Predicted Class: {predictedClass}\nConfidence: {confidence:F2}");
if (outputText != null)
{
outputText.text = $"Predicted Class: {predictedClass}\nConfidence: {confidence:F2}";
}
// Cek apakah prediksi sesuai dengan target
if (currentIndex < scenarioSequence.Length)
{
string currentTarget = scenarioSequence[currentIndex];
if (predictedClass == currentTarget)
{
currentScore++;
if (audioSource != null && correctClip != null)
{
audioSource.PlayOneShot(correctClip);
}
currentIndex++;
if (currentIndex >= scenarioSequence.Length)
{
StartCoroutine(ShowFeedback(true, true));
}
else
{
StartCoroutine(ShowFeedback(true, false));
}
}
else
{
if (audioSource != null && wrongClip != null)
{
audioSource.PlayOneShot(wrongClip);
}
// Jawaban salah, tampilkan feedback lalu canvas gagal
StartCoroutine(ShowFeedback(false, true));
}
}
inputTensor.Dispose();
outputTensor.Dispose();
}
private IEnumerator ShowFeedback(bool isCorrect, bool isFinal)
{
if (isCorrect)
{
if (feedbackCorrectImage != null)
feedbackCorrectImage.gameObject.SetActive(true);
}
else
{
if (feedbackWrongImage != null)
feedbackWrongImage.gameObject.SetActive(true);
}
yield return new WaitForSeconds(feedbackDelay);
if (isCorrect)
{
if (feedbackCorrectImage != null)
feedbackCorrectImage.gameObject.SetActive(false);
}
else
{
if (feedbackWrongImage != null)
feedbackWrongImage.gameObject.SetActive(false);
}
// Jika isFinal true, tampilkan canvas hasil dan (jika benar) unlock level berikutnya
if (isFinal)
{
if (isCorrect)
{
int selectedLevel = PlayerPrefs.GetInt("selectedLevel", 1);
int maxLevelUnlocked = PlayerPrefs.GetInt("maxLevelUnlocked", 1);
if (selectedLevel >= maxLevelUnlocked)
{
PlayerPrefs.SetInt("maxLevelUnlocked", selectedLevel + 1);
}
if (audioSource != null && awardClip != null)
{
audioSource.PlayOneShot(awardClip);
}
if (canvasBerhasil != null)
canvasBerhasil.SetActive(true);
}
else
{
if (canvasGagal != null)
canvasGagal.SetActive(true);
}
}
else
{
UpdateUI();
}
}
private int ArgMax(float[] array)
{
int index = 0;
float max = array[0];
for (int i = 1; i < array.Length; i++)
{
if (array[i] > max)
{
max = array[i];
index = i;
}
}
return index;
}
private Texture2D ResizeTexture(Texture2D source, int newWidth, int newHeight)
{
RenderTexture rt = RenderTexture.GetTemporary(newWidth, newHeight);
RenderTexture.active = rt;
Graphics.Blit(source, rt);
Texture2D newTexture = new Texture2D(newWidth, newHeight);
newTexture.ReadPixels(new Rect(0, 0, newWidth, newHeight), 0, 0);
newTexture.Apply();
RenderTexture.active = null;
RenderTexture.ReleaseTemporary(rt);
return newTexture;
}
private Texture2D MakeTextureReadable(Texture2D tex)
{
RenderTexture tmp = RenderTexture.GetTemporary(tex.width, tex.height, 0, RenderTextureFormat.Default, RenderTextureReadWrite.Linear);
Graphics.Blit(tex, tmp);
RenderTexture previous = RenderTexture.active;
RenderTexture.active = tmp;
Texture2D readableTex = new Texture2D(tex.width, tex.height);
readableTex.ReadPixels(new Rect(0, 0, tmp.width, tmp.height), 0, 0);
readableTex.Apply();
RenderTexture.active = previous;
RenderTexture.ReleaseTemporary(tmp);
return readableTex;
}
private Texture2D CorrectCameraImage(Texture2D original)
{
int width = original.width;
int height = original.height;
Texture2D rotated = new Texture2D(height, width, original.format, false);
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
rotated.SetPixel(j, width - i - 1, original.GetPixel(i, j));
}
}
rotated.Apply();
return rotated;
}
private void UpdateScoreText()
{
int selectedLevel = PlayerPrefs.GetInt("selectedLevel", 1);
if (scoreText != null)
{
scoreText.text = "Level " + selectedLevel;
}
}
private void OnDestroy()
{
worker?.Dispose();
}
}