predict method
Implementation
Future<List<DetectionResult>> predict(
Uint8List inputData, {
double confThreshold = 0.25,
}) async {
final tensorData = await PreProcessing.toTensorData(
inputData,
targetWidth: inputWidth,
targetHeight: inputHeight,
);
// Executa a inferência
final outputs = await model.forward([tensorData]);
debugPrint('Inferência concluída no modelo de detecção');
for (var output in outputs) {
debugPrint('Output shape: ${output.shape}');
debugPrint('Output type: ${output.dataType}');
debugPrint('Output data length: ${output.data.length}');
debugPrint(
'Output data (first 10 values): ${output.data.take(10).toList()}',
);
}
if (outputs.isEmpty) return <DetectionResult>[];
final out = outputs[0];
// Expecting shape like [1, channels, num_boxes]
final shape = out.shape;
if (shape.length < 3) return <DetectionResult>[];
final channels = shape[1]!;
final numBoxes = shape[2]!;
// Convert bytes to float32 list (respecting offset)
final floatData = out.data.buffer.asFloat32List(
out.data.offsetInBytes,
out.data.lengthInBytes ~/ 4,
);
debugPrint('Parsed float length: ${floatData.length}');
try {
debugPrint('First 10 floats: ${floatData.take(10).toList()}');
} catch (e) {
debugPrint('Could not print float sample: $e');
}
// Helpers
double sigmoid(double x) => 1.0 / (1.0 + math.exp(-x));
final List<DetectionResult> detections = [];
final expectedWithObj = labels.length + 5;
final hasObjectness = channels == expectedWithObj;
final classCount = hasObjectness ? (channels - 5) : (channels - 4);
debugPrint(
'channels=$channels numBoxes=$numBoxes expectedWithObj=$expectedWithObj hasObjectness=$hasObjectness classCount=$classCount',
);
for (var i = 0; i < numBoxes; i++) {
// index by channel-first layout: index = c * numBoxes + i
double at(int c) => floatData[c * numBoxes + i];
final x = at(0);
final y = at(1);
final w = at(2);
final h = at(3);
double objectness = 1.0;
int classOffset = 4;
if (hasObjectness) {
objectness = sigmoid(at(4));
classOffset = 5;
}
final classScores = List<double>.generate(
classCount,
(j) => at(classOffset + j),
);
if (i < 3)
debugPrint(
'box $i raw x,y,w,h: $x,$y,$w,$h objectness:$objectness classScoresSample:${classScores.take(6).toList()}',
);
final classProbs = classScores.map((s) => sigmoid(s)).toList();
double maxClassProb = classProbs.reduce(math.max);
final classId = classProbs.indexWhere((p) => p == maxClassProb);
final conf = hasObjectness ? (objectness * maxClassProb) : maxClassProb;
if (conf < confThreshold) continue;
// Assume x,y,w,h are normalized center coords (0..1)
final cx = x;
final cy = y;
final bw = w;
final bh = h;
double left = (cx - bw / 2.0) * inputWidth;
double top = (cy - bh / 2.0) * inputHeight;
double right = (cx + bw / 2.0) * inputWidth;
double bottom = (cy + bh / 2.0) * inputHeight;
// Clamp
left = left.clamp(0.0, inputWidth.toDouble());
top = top.clamp(0.0, inputHeight.toDouble());
right = right.clamp(0.0, inputWidth.toDouble());
bottom = bottom.clamp(0.0, inputHeight.toDouble());
final label = (classId >= 0 && classId < labels.length)
? labels[classId]
: 'class_$classId';
detections.add(
DetectionResult(
classId: classId,
label: label,
confidence: conf,
bbox: [left, top, right, bottom],
),
);
}
// Sort by confidence descending
detections.sort((a, b) => b.confidence.compareTo(a.confidence));
return detections;
}