From 20ef899270567aedacb78ec9f409e7a28aa51bc9 Mon Sep 17 00:00:00 2001 From: Aditya <62930521+adityar224@users.noreply.github.com> Date: Mon, 1 May 2023 23:56:50 +0530 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fixed=20visualization=20size=20i?= =?UTF-8?q?ssues?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/images/fabio_fognini.jpeg | Bin 0 -> 5812 bytes assets/images/rafael_nadal.jpeg | Bin 0 -> 6265 bytes assets/images/roger_federer.jpeg | Bin 0 -> 5611 bytes lib/finals.dart | 3 + lib/models/serve_result.dart | 68 ++++++++++++++-- lib/screens/change_reference_player.dart | 57 +++++++++++++ lib/screens/results_screen.dart | 98 ++++++++++------------- lib/widgets/reference_player_card.dart | 60 ++++++++++++++ lib/widgets/serve_visualizer.dart | 35 ++++---- 9 files changed, 246 insertions(+), 75 deletions(-) create mode 100644 assets/images/fabio_fognini.jpeg create mode 100644 assets/images/rafael_nadal.jpeg create mode 100644 assets/images/roger_federer.jpeg create mode 100644 lib/screens/change_reference_player.dart create mode 100644 lib/widgets/reference_player_card.dart diff --git a/assets/images/fabio_fognini.jpeg b/assets/images/fabio_fognini.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..88d602a58141dddf222663f5f3393c4b48cb5969 GIT binary patch literal 5812 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 Jf%|IqzW}5d)bjuU literal 0 HcmV?d00001 diff --git a/assets/images/rafael_nadal.jpeg b/assets/images/rafael_nadal.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..73f6a4e5f487dd6592dae9b4320678c7f190ad8d GIT binary patch literal 6265 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 literal 0 HcmV?d00001 diff --git a/assets/images/roger_federer.jpeg b/assets/images/roger_federer.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..d12d56d1d10a85d750867909e12c3fc4e7e99fdd GIT binary patch literal 5611 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 D(m!aq literal 0 HcmV?d00001 diff --git a/lib/finals.dart b/lib/finals.dart index a1b9a0a..1700054 100644 --- a/lib/finals.dart +++ b/lib/finals.dart @@ -10,6 +10,7 @@ final ServeResult fabioFognini = ServeResult.fromCompleteInferenceList( "Fabio Fognini", 178, false, + "assets/images/fabio_fognini.jpeg", [ [ [260, 304, 0.23688101768493652], @@ -1176,6 +1177,7 @@ final ServeResult rogerFederer = ServeResult.fromCompleteInferenceList( "Roger Federer", 185, false, + "assets/images/roger_federer.jpeg", [ [ [264, 304, 0.6883679628372192], @@ -2342,6 +2344,7 @@ final ServeResult rafaelNadal = ServeResult.fromCompleteInferenceList( "Rafael Nadal", 185, true, + "assets/images/rafael_nadal.jpeg", [ [ [238, 281, 0.497579962015152], diff --git a/lib/models/serve_result.dart b/lib/models/serve_result.dart index 4fd5f04..4af0a0e 100644 --- a/lib/models/serve_result.dart +++ b/lib/models/serve_result.dart @@ -22,10 +22,14 @@ class InferencePoint { class ServeResult { final String playerName; - final String? playerPhotoUrl; + final String? playerPhotoAssetPath; final int height; //in cm final bool isLeftHanded; + double minWidth = 2000; + double minHeight = 2000; + double maxHeight = 0; + final List leftShoulderAngles = []; final List leftKneeAngles = []; final List leftElbowAngles = []; @@ -52,7 +56,7 @@ class ServeResult { final List rightAnklePoints = []; ServeResult(this.playerName, this.height, this.isLeftHanded, - {this.playerPhotoUrl}); + {this.playerPhotoAssetPath}); ServeResult copyWith({String? playerName, int? height, bool? isLeftHanded}) { return ServeResult(playerName ?? this.playerName, height ?? this.height, @@ -180,6 +184,55 @@ class ServeResult { rightShoulderPoint.point)); rightShoulderAngles.add(getAngle( rightElbowPoint.point, rightShoulderPoint.point, rightHipPoint.point)); + + List pointHeights = [ + nosePoint.point.dy, + leftEyePoint.point.dy, + rightEyePoint.point.dy, + leftEarPoint.point.dy, + rightEarPoint.point.dy, + leftShoulderPoint.point.dy, + rightShoulderPoint.point.dy, + leftElbowPoint.point.dy, + rightElbowPoint.point.dy, + leftWristPoint.point.dy, + rightWristPoint.point.dy, + leftHipPoint.point.dy, + rightHipPoint.point.dy, + leftKneePoint.point.dy, + rightKneePoint.point.dy, + leftAnklePoint.point.dy, + rightAnklePoint.point.dy, + ]; + List pointWidths = [ + nosePoint.point.dx, + leftEyePoint.point.dx, + rightEyePoint.point.dx, + leftEarPoint.point.dx, + rightEarPoint.point.dx, + leftShoulderPoint.point.dx, + rightShoulderPoint.point.dx, + leftElbowPoint.point.dx, + rightElbowPoint.point.dx, + leftWristPoint.point.dx, + rightWristPoint.point.dx, + leftHipPoint.point.dx, + rightHipPoint.point.dx, + leftKneePoint.point.dx, + rightKneePoint.point.dx, + leftAnklePoint.point.dx, + rightAnklePoint.point.dx, + ]; + + if (pointWidths.min < minWidth) { + minWidth = pointWidths.min; + } + if (pointHeights.min < minHeight) { + minHeight = pointHeights.min; + } + if (pointHeights.max > maxHeight) { + maxHeight = pointHeights.max; + } } String heightInFeetAndInches() { @@ -188,9 +241,14 @@ class ServeResult { return "${heightInFeet.floor()}ft ${heightInRemainingInches.round()}in"; } - factory ServeResult.fromCompleteInferenceList(String playerName, int height, - bool isLeftHanded, List completeExtractedInferenceList) { - ServeResult newServeResult = ServeResult(playerName, height, isLeftHanded); + factory ServeResult.fromCompleteInferenceList( + String playerName, + int height, + bool isLeftHanded, + String imageAssetPath, + List completeExtractedInferenceList) { + ServeResult newServeResult = ServeResult(playerName, height, isLeftHanded, + playerPhotoAssetPath: imageAssetPath); for (var inferenceList in completeExtractedInferenceList) { newServeResult.addInferenceFromFrame(inferenceList); } diff --git a/lib/screens/change_reference_player.dart b/lib/screens/change_reference_player.dart new file mode 100644 index 0000000..283b609 --- /dev/null +++ b/lib/screens/change_reference_player.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:tennis_serve_analysis/finals.dart'; +import 'package:tennis_serve_analysis/widgets/reference_player_card.dart'; + +class ChangeReferencePlayerScreen extends StatefulWidget { + final int selectedPlayerIndex; + const ChangeReferencePlayerScreen( + {Key? key, required this.selectedPlayerIndex}) + : super(key: key); + + @override + State createState() => + _ChangeReferencePlayerScreenState(); +} + +class _ChangeReferencePlayerScreenState + extends State { + late int selectedIndex; + + @override + void initState() { + selectedIndex = widget.selectedPlayerIndex; + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Change Reference Player"), + ), + floatingActionButton: FloatingActionButton( + onPressed: () { + Navigator.pop(context, selectedIndex); + }, + child: const Icon(Icons.done), + ), + body: ListView.builder( + itemCount: availableReferencePlayers.length, + itemBuilder: (context, index) => Padding( + padding: const EdgeInsets.only(bottom: 10), + child: GestureDetector( + onTap: () { + setState(() { + selectedIndex = index; + }); + }, + child: ReferencePlayerCard( + referencePlayerResult: availableReferencePlayers[index], + isSelected: index == selectedIndex, + ), + ), + ), + ), + ); + } +} diff --git a/lib/screens/results_screen.dart b/lib/screens/results_screen.dart index f2b3e25..f6ac08b 100644 --- a/lib/screens/results_screen.dart +++ b/lib/screens/results_screen.dart @@ -11,10 +11,13 @@ import 'package:image_picker/image_picker.dart'; import 'package:path_provider/path_provider.dart'; import 'package:image/image.dart' as image_lib; import 'package:tennis_serve_analysis/controllers/user_controller.dart'; +import 'package:tennis_serve_analysis/finals.dart'; import 'package:tennis_serve_analysis/models/serve_result.dart'; +import 'package:tennis_serve_analysis/screens/change_reference_player.dart'; import 'package:tennis_serve_analysis/utility/classifier.dart'; import 'package:tennis_serve_analysis/utility/isolate_utils.dart'; import 'package:tennis_serve_analysis/widgets/analyzing_loading.dart'; +import 'package:tennis_serve_analysis/widgets/reference_player_card.dart'; import 'package:tennis_serve_analysis/widgets/stat_tile.dart'; import 'package:tennis_serve_analysis/widgets/serve_visualizer.dart'; @@ -153,59 +156,25 @@ class _ResultsScreenState extends ConsumerState { ref.watch(selectedPlayerProvider(selectedPlayerIndex)); return Scaffold( appBar: AppBar( - title: const Text("Serve Analysis Result"), + title: const Text("Analysis Result"), actions: [ if (!isLoading) IconButton( onPressed: () async { - await showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text("Change Reference Player"), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - RadioListTile( - title: const Text("Fabio Fognini"), - value: 0, - groupValue: selectedPlayerIndex, - onChanged: (val) { - selectedPlayerIndex = val ?? 2; - setState(() {}); - Navigator.pop(context); - }, - ), - RadioListTile( - title: const Text("Roger Federer"), - value: 1, - groupValue: selectedPlayerIndex, - onChanged: (val) { - selectedPlayerIndex = val ?? 0; - setState(() {}); - Navigator.pop(context); - }, - ), - RadioListTile( - title: const Text("Rafael Nadel"), - value: 2, - groupValue: selectedPlayerIndex, - onChanged: (val) { - selectedPlayerIndex = val ?? 1; - setState(() {}); - Navigator.pop(context); - }, - ), - ], - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text("Ok"), - ), - ], - ), - ); + selectedPlayerIndex = availableReferencePlayers.indexWhere( + (element) => + element.playerName == + selectedPlayerServeResult.playerName); + selectedPlayerIndex = + (selectedPlayerIndex == -1) ? null : selectedPlayerIndex; + selectedPlayerIndex = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ChangeReferencePlayerScreen( + selectedPlayerIndex: selectedPlayerIndex ?? 0))); + setState(() {}); }, + tooltip: "Change Reference Player", icon: const Icon(Icons.change_circle), ) ], @@ -217,21 +186,24 @@ class _ResultsScreenState extends ConsumerState { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + ReferencePlayerCard( + referencePlayerResult: selectedPlayerServeResult, + ), Card( child: Column( children: [ - const SizedBox(height: 10), + const SizedBox(height: 5), Row( children: [ const SizedBox(width: 20), const SizedBox( - height: 20, - width: 20, + height: 15, + width: 15, child: ColoredBox(color: Colors.red), ), const SizedBox(width: 10), Text( - "User Serve", + "User's Serve", style: Theme.of(context).textTheme.titleSmall, ), ], @@ -241,13 +213,13 @@ class _ResultsScreenState extends ConsumerState { children: [ const SizedBox(width: 20), const SizedBox( - height: 20, - width: 20, + height: 15, + width: 15, child: ColoredBox(color: Colors.green), ), const SizedBox(width: 10), Text( - "${selectedPlayerServeResult.playerName} Serve", + "${selectedPlayerServeResult.playerName}'s Serve", style: Theme.of(context).textTheme.titleSmall, ), ], @@ -256,11 +228,25 @@ class _ResultsScreenState extends ConsumerState { children: [ UserServeVisualizer( points: serveResult.completeInferenceList, + minSize: Size( + serveResult.minWidth, serveResult.minHeight), + maxSize: Size( + 500, + serveResult.maxHeight, + ), ), UserServeVisualizer( + key: ValueKey( + selectedPlayerServeResult.playerName), points: selectedPlayerServeResult .completeInferenceList, isReference: true, + minSize: Size(selectedPlayerServeResult.minWidth, + selectedPlayerServeResult.minHeight), + maxSize: Size( + 500, + selectedPlayerServeResult.maxHeight, + ), ), ], ), @@ -268,7 +254,7 @@ class _ResultsScreenState extends ConsumerState { ), ), Padding( - padding: const EdgeInsets.fromLTRB(10, 15, 20, 5), + padding: const EdgeInsets.fromLTRB(10, 5, 20, 5), child: Text( "Average Angles", style: Theme.of(context).textTheme.titleLarge, diff --git a/lib/widgets/reference_player_card.dart b/lib/widgets/reference_player_card.dart new file mode 100644 index 0000000..2691878 --- /dev/null +++ b/lib/widgets/reference_player_card.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:tennis_serve_analysis/models/serve_result.dart'; + +class ReferencePlayerCard extends StatelessWidget { + final ServeResult referencePlayerResult; + final bool isSelected; + const ReferencePlayerCard( + {Key? key, required this.referencePlayerResult, this.isSelected = false}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return Card( + color: (isSelected) ? Colors.green.shade100 : null, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 10), + child: Row( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Image.asset( + referencePlayerResult.playerPhotoAssetPath!, + height: 70, + width: 70, + fit: BoxFit.scaleDown, + ), + ), + const SizedBox(width: 10), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + referencePlayerResult.playerName, + style: Theme.of(context).textTheme.titleLarge, + ), + const SizedBox(height: 10), + Row( + children: [ + const Icon(Icons.straighten), + const SizedBox(width: 4), + Text(referencePlayerResult.heightInFeetAndInches()), + const Spacer(), + const Icon(Icons.sports_tennis), + const SizedBox(width: 4), + Text(referencePlayerResult.isLeftHanded + ? "Left Handed" + : "Right Handed"), + const SizedBox(width: 4), + ], + ) + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/widgets/serve_visualizer.dart b/lib/widgets/serve_visualizer.dart index 4e695e6..d67030c 100644 --- a/lib/widgets/serve_visualizer.dart +++ b/lib/widgets/serve_visualizer.dart @@ -4,10 +4,14 @@ import 'package:flutter/material.dart'; class UserServeVisualizer extends StatefulWidget { final List points; final bool isReference; + final Size minSize; + final Size maxSize; const UserServeVisualizer({ Key? key, required this.points, this.isReference = false, + this.minSize = Size.zero, + this.maxSize = Size.infinite, }) : super(key: key); @override @@ -17,17 +21,17 @@ class UserServeVisualizer extends StatefulWidget { class _UserServeVisualizerState extends State with SingleTickerProviderStateMixin { int userIndex = 0; - late final AnimationController _animationController; + late AnimationController _animationController; @override void initState() { + super.initState(); //50ms because 20frames per second (Each image coordinate persists for 50ms) _animationController = AnimationController( vsync: this, duration: Duration(milliseconds: widget.points.length * 50), upperBound: widget.points.length.toDouble()) ..repeat(); - super.initState(); } @override @@ -44,10 +48,12 @@ class _UserServeVisualizerState extends State return CustomPaint( willChange: true, isComplex: true, - size: const Size(500, 500), + size: Size(500, widget.maxSize.height - widget.minSize.height + 10), painter: RenderLandmarks( - widget.points[_animationController.value.toInt()], - widget.isReference), + widget.points[_animationController.value.toInt()], + widget.isReference, + widget.minSize, + ), ); }, ); @@ -57,8 +63,9 @@ class _UserServeVisualizerState extends State class RenderLandmarks extends CustomPainter { final List inferenceList; final bool isReference; + final Size minSize; - RenderLandmarks(this.inferenceList, this.isReference); + RenderLandmarks(this.inferenceList, this.isReference, this.minSize); final greenPoint = Paint() ..color = Colors.green @@ -118,20 +125,20 @@ class RenderLandmarks extends CustomPainter { for (List point in inferenceList) { if ((point[2] > 0.20)) { if (isReference) { - pointsGreen - .add(Offset(point[0].toDouble() - 70, point[1].toDouble() - 130)); + pointsGreen.add(Offset(point[0].toDouble() - minSize.width + 40, + point[1].toDouble() - minSize.height)); } else { - pointsRed - .add(Offset(point[0].toDouble() - 70, point[1].toDouble() - 130)); + pointsRed.add(Offset(point[0].toDouble() - minSize.width + 40, + point[1].toDouble() - minSize.height)); } } } for (List edge in edges) { - double vertex1X = inferenceList[edge[0]][0] - 70; - double vertex1Y = inferenceList[edge[0]][1] - 130; - double vertex2X = inferenceList[edge[1]][0] - 70; - double vertex2Y = inferenceList[edge[1]][1] - 130; + double vertex1X = inferenceList[edge[0]][0] - minSize.width + 40; + double vertex1Y = inferenceList[edge[0]][1] - minSize.height; + double vertex2X = inferenceList[edge[1]][0] - minSize.width + 40; + double vertex2Y = inferenceList[edge[1]][1] - minSize.height; canvas.drawLine(Offset(vertex1X, vertex1Y), Offset(vertex2X, vertex2Y), (isReference) ? greenEdge : redEdge); }