@ -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 < Array < FloatArray > >
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 < Int > ( )
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 < String > ( )
val topShinyDetections = mutableListOf < Pair < Float , Int > > ( )
// 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