diff --git a/app/src/main/java/com/quillstudios/pokegoalshelper/YOLOOnnxDetector.kt b/app/src/main/java/com/quillstudios/pokegoalshelper/YOLOOnnxDetector.kt index 0b54a85..7ea6a35 100644 --- a/app/src/main/java/com/quillstudios/pokegoalshelper/YOLOOnnxDetector.kt +++ b/app/src/main/java/com/quillstudios/pokegoalshelper/YOLOOnnxDetector.kt @@ -21,10 +21,10 @@ class YOLOOnnxDetector(private val context: Context) { private const val TAG = "YOLOOnnxDetector" private const val MODEL_FILE = "best.onnx" private const val INPUT_SIZE = 640 - private const val CONFIDENCE_THRESHOLD = 0.25f // Temporarily lowered for shiny icon debugging + private const val CONFIDENCE_THRESHOLD = 0.55f private const val NMS_THRESHOLD = 0.3f // More aggressive merging of overlapping boxes private const val NUM_CHANNELS = 3 - private const val NUM_DETECTIONS = 8400 // YOLOv8 default + private const val NUM_DETECTIONS = 300 // ONNX model exported with NMS enabled private const val NUM_CLASSES = 95 // Your class count // Enhanced accuracy settings for ONNX (fixed input size) - WITH PER-METHOD COORDINATE TRANSFORM @@ -39,8 +39,6 @@ class YOLOOnnxDetector(private val context: Context) { var DEBUG_CLASS_FILTER: String? = null // Set to class name to show only that class var SHOW_ALL_CONFIDENCES = false // Show all detections with their confidences - // Debug flag for troubleshooting detection issues (disable in production) - private const val DEBUG_DETECTION = false fun setCoordinateMode(mode: String) { COORD_TRANSFORM_MODE = mode @@ -405,121 +403,6 @@ class YOLOOnnxDetector(private val context: Context) { val outputTensor = result.get(0).value as Array> val flatOutput = outputTensor[0].flatMap { it.asIterable() }.toFloatArray() - // Debug: Log raw output statistics when looking for shiny icons - if (DEBUG_DETECTION) { - val maxVal = flatOutput.maxOrNull() ?: 0f - val nonZeroCount = flatOutput.count { it > 0.01f } - Log.w(TAG, "🔬 [RAW OUTPUT] Method: $method, FlatOutput size: ${flatOutput.size}, Max value: %.4f, Non-zero (>0.01): $nonZeroCount".format(maxVal)) - - // Log actual tensor dimensions to understand the model output format - Log.w(TAG, "🔬 [TENSOR DIMS] OutputTensor shape: ${outputTensor.size} x ${outputTensor[0].size} x ${outputTensor[0][0].size}") - - // Handle different model output formats - val dim1 = outputTensor[0].size - val dim2 = outputTensor[0][0].size - - if ((dim1 == 300 || dim1 == 500 || dim1 == 1000) && dim2 == 6) { - // NMS-enabled model (1 x N x 6) format where N = max_det - var shinyFound = false - val detectedClasses = mutableSetOf() - - var class50NonZeroCount = 0 - var totalClass50Count = 0 - var class29Count = 0 - for (i in 0 until dim1) { - val detection = outputTensor[0][i] - val confidence = detection[4] - val classId = detection[5].toInt() - - // Count ALL class 50 detections, regardless of confidence - if (classId == 50) { - totalClass50Count++ - if (confidence > 0.000001f) { // Any non-zero confidence - class50NonZeroCount++ - Log.w(TAG, "🔍 [CLASS 50] Index: $i, Confidence: %.6f, Coords: [%.1f,%.1f,%.1f,%.1f]".format(confidence, detection[0], detection[1], detection[2], detection[3])) - } - } - - // Also check class 29 for comparison - if (classId == 29) { - class29Count++ - if (confidence > 0.01f) { // Much lower threshold for known working class - shinyFound = true - Log.w(TAG, "✨ [CLASS 29] Index: $i, Confidence: %.4f, Coords: [%.1f,%.1f,%.1f,%.1f]".format(confidence, detection[0], detection[1], detection[2], detection[3])) - } - } - - if (confidence > 0.1f) { - detectedClasses.add(classId) - } - } - - Log.w(TAG, "🔍 [SUMMARY] Class 29: $class29Count total, Class 50: $totalClass50Count total ($class50NonZeroCount non-zero)") - - Log.w(TAG, "🔬 [NMS CLASSES] Detected classes: ${detectedClasses.sorted()}") - if (!shinyFound) { - Log.w(TAG, "❌ [NO SHINY] Shiny icon (class 50) not found in NMS output") - } - } else if (dim1 == 100 && dim2 == 8400) { - // Raw no-NMS model (1 x 100 x 8400) format: [x,y,w,h,objectness,class0,class1,...,class94] × 8400 detections - Log.w(TAG, "🔬 [RAW MODEL] Detected raw no-NMS format: checking for shiny icons in 8400 detections") - - var shinyFound = false - var maxRawShiny = 0f - var maxSigmoidShiny = 0f - var shinyDetectionCount = 0 - val highConfShinyBoxes = mutableListOf() - val topShinyDetections = mutableListOf>() - - // Class 50 data starts at index 55 (after x,y,w,h,objectness + 50 classes) - val shinyClassRow = 4 + 1 + 50 // row 55 - - for (detectionIdx in 0 until 8400) { - val rawShinyValue = outputTensor[0][shinyClassRow][detectionIdx] - - // Try sigmoid activation to convert logits to probabilities - val shinyConfidence = 1.0f / (1.0f + kotlin.math.exp(-rawShinyValue)) - - if (rawShinyValue > maxRawShiny) { - maxRawShiny = rawShinyValue - } - if (shinyConfidence > maxSigmoidShiny) { - maxSigmoidShiny = shinyConfidence - } - - // Track top detections for debugging - topShinyDetections.add(Pair(shinyConfidence, detectionIdx)) - - if (shinyConfidence > 0.1f) { - shinyDetectionCount++ - shinyFound = true - - // Get bounding box coordinates - val x = outputTensor[0][0][detectionIdx] - val y = outputTensor[0][1][detectionIdx] - val w = outputTensor[0][2][detectionIdx] - val h = outputTensor[0][3][detectionIdx] - - highConfShinyBoxes.add("Detection $detectionIdx: raw=%.4f, sigmoid=%.4f, box=[%.1f,%.1f,%.1f,%.1f]".format(rawShinyValue, shinyConfidence, x, y, w, h)) - } - } - - // Show top shiny detections for debugging - val topShiny = topShinyDetections.sortedByDescending { it.first }.take(3) - - Log.w(TAG, "🔬 [RAW SHINY] Max raw: %.4f, Max sigmoid: %.4f, Count >0.1: $shinyDetectionCount".format(maxRawShiny, maxSigmoidShiny)) - Log.w(TAG, "🔬 [TOP SHINY] Top 3 sigmoid values: ${topShiny.map { "%.4f@${it.second}".format(it.first) }}") - - if (shinyFound) { - Log.w(TAG, "✨ [RAW SHINY FOUND] High-confidence shiny detections:") - highConfShinyBoxes.take(5).forEach { Log.w(TAG, " $it") } - } else { - Log.w(TAG, "❌ [RAW NO SHINY] No high-confidence shiny detections in raw 8400 predictions") - } - } else { - Log.w(TAG, "🔬 [UNKNOWN FORMAT] Unexpected tensor shape: ${outputTensor.size}x${dim1}x${dim2}") - } - } // Post-process results with method-specific coordinate transformation val detections = postprocessWithMethod(flatOutput, inputMat.cols(), inputMat.rows(), INPUT_SIZE, method) @@ -893,10 +776,6 @@ class YOLOOnnxDetector(private val context: Context) { Log.d(TAG, "🔍 [DEBUG] Class: $className (ID: $classId), Confidence: %.3f, Original: %.3f".format(mappedConfidence, confidence)) } - // Special debug logging for shiny icon (class 50) - if (DEBUG_DETECTION && (classId == 50 || className == "shiny_icon") && mappedConfidence > 0.05f) { - Log.w(TAG, "✨ [SHINY DEBUG] Found shiny_icon candidate! ClassID: $classId, Confidence: %.4f (mapped: %.4f), Coords: [%.1f,%.1f,%.1f,%.1f]".format(confidence, mappedConfidence, x1, y1, x2, y2)) - } // Apply class filtering if set val passesClassFilter = DEBUG_CLASS_FILTER == null || DEBUG_CLASS_FILTER == className @@ -1230,10 +1109,6 @@ class YOLOOnnxDetector(private val context: Context) { Log.d(TAG, "🔍 [DEBUG] Class: $className (ID: $classId), Confidence: %.3f, Original: %.3f".format(mappedConfidence, confidence)) } - // Special debug logging for shiny icon (class 50) - if (DEBUG_DETECTION && (classId == 50 || className == "shiny_icon") && mappedConfidence > 0.05f) { - Log.w(TAG, "✨ [SHINY DEBUG] Found shiny_icon candidate! ClassID: $classId, Confidence: %.4f (mapped: %.4f), Coords: [%.1f,%.1f,%.1f,%.1f]".format(confidence, mappedConfidence, x1, y1, x2, y2)) - } // Apply class filtering if set val passesClassFilter = DEBUG_CLASS_FILTER == null || DEBUG_CLASS_FILTER == className