|
@@ -9,6 +9,7 @@ import 'package:path/path.dart' as p;
|
|
|
import '../services/tflite_service.dart';
|
|
import '../services/tflite_service.dart';
|
|
|
import '../services/database_helper.dart';
|
|
import '../services/database_helper.dart';
|
|
|
import '../models/palm_record.dart';
|
|
import '../models/palm_record.dart';
|
|
|
|
|
+import '../widgets/palm_bounding_box.dart';
|
|
|
|
|
|
|
|
enum DetectionState { searching, locking, capturing, cooldown }
|
|
enum DetectionState { searching, locking, capturing, cooldown }
|
|
|
|
|
|
|
@@ -57,7 +58,7 @@ class _LiveAnalysisScreenState extends State<LiveAnalysisScreen> {
|
|
|
|
|
|
|
|
_controller = CameraController(
|
|
_controller = CameraController(
|
|
|
cameras[0],
|
|
cameras[0],
|
|
|
- ResolutionPreset.low, // Downgraded resolution for performance
|
|
|
|
|
|
|
+ ResolutionPreset.medium, // Upgraded resolution for YOLO26 performance
|
|
|
enableAudio: false,
|
|
enableAudio: false,
|
|
|
imageFormatGroup: Platform.isAndroid ? ImageFormatGroup.yuv420 : ImageFormatGroup.bgra8888,
|
|
imageFormatGroup: Platform.isAndroid ? ImageFormatGroup.yuv420 : ImageFormatGroup.bgra8888,
|
|
|
);
|
|
);
|
|
@@ -149,10 +150,10 @@ class _LiveAnalysisScreenState extends State<LiveAnalysisScreen> {
|
|
|
if (momentumTicks < 0) momentumTicks = 0;
|
|
if (momentumTicks < 0) momentumTicks = 0;
|
|
|
|
|
|
|
|
setState(() {
|
|
setState(() {
|
|
|
- _lockProgress = (momentumTicks / 3.0).clamp(0.0, 1.0); // 3 ticks target
|
|
|
|
|
|
|
+ _lockProgress = (momentumTicks / 2.0).clamp(0.0, 1.0); // 2 ticks target
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- if (momentumTicks >= 3) {
|
|
|
|
|
|
|
+ if (momentumTicks >= 2) {
|
|
|
timer.cancel();
|
|
timer.cancel();
|
|
|
if (_state == DetectionState.locking) {
|
|
if (_state == DetectionState.locking) {
|
|
|
_triggerCapture();
|
|
_triggerCapture();
|
|
@@ -340,7 +341,13 @@ class _LiveAnalysisScreenState extends State<LiveAnalysisScreen> {
|
|
|
builder: (context, constraints) {
|
|
builder: (context, constraints) {
|
|
|
return Stack(
|
|
return Stack(
|
|
|
children: _detections!
|
|
children: _detections!
|
|
|
- .map((d) => _buildOverlayBox(d, constraints))
|
|
|
|
|
|
|
+ .map((d) => PalmBoundingBox(
|
|
|
|
|
+ normalizedRect: d.normalizedBox,
|
|
|
|
|
+ label: d.className,
|
|
|
|
|
+ confidence: d.confidence,
|
|
|
|
|
+ constraints: constraints,
|
|
|
|
|
+ isLocked: (_state == DetectionState.locking || _state == DetectionState.capturing) && d.confidence > _lockThreshold,
|
|
|
|
|
+ ))
|
|
|
.toList(),
|
|
.toList(),
|
|
|
);
|
|
);
|
|
|
},
|
|
},
|
|
@@ -459,36 +466,6 @@ class _LiveAnalysisScreenState extends State<LiveAnalysisScreen> {
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- Widget _buildOverlayBox(DetectionResult detection, BoxConstraints constraints) {
|
|
|
|
|
- final rect = detection.normalizedBox;
|
|
|
|
|
- // Show green only if the system is overall "Locked" and this detection is high confidence
|
|
|
|
|
- final color = ((_state == DetectionState.locking || _state == DetectionState.capturing) && detection.confidence > _lockThreshold) ? Colors.green : Colors.yellow;
|
|
|
|
|
-
|
|
|
|
|
- return Positioned(
|
|
|
|
|
- left: rect.left * constraints.maxWidth,
|
|
|
|
|
- top: rect.top * constraints.maxHeight,
|
|
|
|
|
- width: rect.width * constraints.maxWidth,
|
|
|
|
|
- height: rect.height * constraints.maxHeight,
|
|
|
|
|
- child: Container(
|
|
|
|
|
- decoration: BoxDecoration(
|
|
|
|
|
- border: Border.all(color: color, width: 2),
|
|
|
|
|
- borderRadius: BorderRadius.circular(4),
|
|
|
|
|
- ),
|
|
|
|
|
- child: Align(
|
|
|
|
|
- alignment: Alignment.topLeft,
|
|
|
|
|
- child: Container(
|
|
|
|
|
- padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
|
|
|
|
|
- color: color,
|
|
|
|
|
- child: Text(
|
|
|
|
|
- "${(detection.confidence * 100).toStringAsFixed(0)}%",
|
|
|
|
|
- style: const TextStyle(color: Colors.white, fontSize: 10, fontWeight: FontWeight.bold),
|
|
|
|
|
- ),
|
|
|
|
|
- ),
|
|
|
|
|
- ),
|
|
|
|
|
- ),
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
@override
|
|
@override
|
|
|
void dispose() {
|
|
void dispose() {
|
|
|
_lockTimer?.cancel();
|
|
_lockTimer?.cancel();
|