dschandra commited on
Commit
70802d0
·
verified ·
1 Parent(s): f6a6373

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +92 -31
app.py CHANGED
@@ -1,20 +1,25 @@
1
  from flask import Flask, render_template, request, jsonify
2
  import numpy as np
3
  from sklearn.linear_model import LogisticRegression
4
- import json
5
  import os
 
6
 
7
  app = Flask(__name__)
8
 
9
- # Simulated ML model for LBW decision (replace with real model later)
10
- # Features: [pitching_x, pitching_y, impact_x, impact_y, speed, spin]
11
- # Label: 0 (Not Out), 1 (Out)
 
 
 
 
12
  def train_dummy_model():
13
  X = np.array([
14
- [0.5, 0.0, 0.4, 0.5, 30, 0], # Not Out (pitched outside leg)
15
- [0.5, 0.5, 0.5, 0.5, 35, 2], # Out (inline, hits stumps)
16
- [0.6, 0.2, 0.5, 0.6, 32, 1], # Not Out (impact outside off)
17
- [0.5, 0.4, 0.5, 0.4, 34, 0], # Out (inline, hits stumps)
18
  ])
19
  y = np.array([0, 1, 0, 1])
20
  model = LogisticRegression()
@@ -23,20 +28,69 @@ def train_dummy_model():
23
 
24
  model = train_dummy_model()
25
 
26
- # Simulate ball trajectory (red arc) and projection (blue line)
27
- def calculate_trajectory(pitching_x, pitching_y, impact_x, impact_y, speed, spin):
28
- # Dummy trajectory: Linear path from bowler to impact
29
- actual_path = [
30
- {"x": 0, "y": 0}, # Bowler position
31
- {"x": pitching_x, "y": pitching_y}, # Pitching point
32
- {"x": impact_x, "y": impact_y} # Impact point
33
- ]
34
- # Projected path: Linear from impact to stumps (adjusted for spin)
35
- projection = [
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  {"x": impact_x, "y": impact_y},
37
  {"x": impact_x + spin * 0.1, "y": 1.0} # Stumps at y=1.0
38
  ]
39
- return actual_path, projection
 
40
 
41
  @app.route('/')
42
  def index():
@@ -44,17 +98,22 @@ def index():
44
 
45
  @app.route('/analyze', methods=['POST'])
46
  def analyze():
47
- # Get input data from form
48
- data = request.form
49
- pitching_x = float(data.get('pitching_x', 0.5))
50
- pitching_y = float(data.get('pitching_y', 0.0))
51
- impact_x = float(data.get('impact_x', 0.5))
52
- impact_y = float(data.get('impact_y', 0.5))
53
- speed = float(data.get('speed', 30))
54
- spin = float(data.get('spin', 0))
55
-
56
- # Calculate trajectories
57
- actual_path, projected_path = calculate_trajectory(pitching_x, pitching_y, impact_x, impact_y, speed, spin)
 
 
 
 
 
58
 
59
  # Predict LBW decision
60
  features = np.array([[pitching_x, pitching_y, impact_x, impact_y, speed, spin]])
@@ -62,7 +121,9 @@ def analyze():
62
  confidence = model.predict_proba(features)[0][prediction]
63
  decision = "Out" if prediction == 1 else "Not Out"
64
 
65
- # Return data for visualization
 
 
66
  return jsonify({
67
  'actual_path': actual_path,
68
  'projected_path': projected_path,
 
1
  from flask import Flask, render_template, request, jsonify
2
  import numpy as np
3
  from sklearn.linear_model import LogisticRegression
4
+ import cv2
5
  import os
6
+ from werkzeug.utils import secure_filename
7
 
8
  app = Flask(__name__)
9
 
10
+ # Configure upload folder
11
+ UPLOAD_FOLDER = 'uploads'
12
+ os.makedirs(UPLOAD_FOLDER, exist_ok=True)
13
+ app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
14
+ ALLOWED_EXTENSIONS = {'mp4', 'avi', 'mov'}
15
+
16
+ # Dummy ML model for LBW decision
17
  def train_dummy_model():
18
  X = np.array([
19
+ [0.5, 0.0, 0.4, 0.5, 30, 0], # Not Out
20
+ [0.5, 0.5, 0.5, 0.5, 35, 2], # Out
21
+ [0.6, 0.2, 0.5, 0.6, 32, 1], # Not Out
22
+ [0.5, 0.4, 0.5, 0.4, 34, 0], # Out
23
  ])
24
  y = np.array([0, 1, 0, 1])
25
  model = LogisticRegression()
 
28
 
29
  model = train_dummy_model()
30
 
31
+ # Check allowed file extensions
32
+ def allowed_file(filename):
33
+ return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
34
+
35
+ # Process video to extract ball trajectory
36
+ def process_video(video_path):
37
+ cap = cv2.VideoCapture(video_path)
38
+ if not cap.isOpened():
39
+ return None, None, "Failed to open video"
40
+
41
+ # Lists to store trajectory points
42
+ actual_path = []
43
+ frame_count = 0
44
+ total_speed = 0
45
+ spin = 0 # Simplified: Assume no spin for now
46
+
47
+ while cap.isOpened():
48
+ ret, frame = cap.read()
49
+ if not ret:
50
+ break
51
+
52
+ # Convert to HSV and detect ball (assuming a red ball)
53
+ hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
54
+ mask = cv2.inRange(hsv, (0, 120, 70), (10, 255, 255))
55
+ contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
56
+
57
+ if contours:
58
+ c = max(contours, key=cv2.contourArea)
59
+ x, y, w, h = cv2.boundingRect(c)
60
+ center_x = x + w / 2
61
+ center_y = y + h / 2
62
+
63
+ # Normalize coordinates to 0-1 (assuming 1280x720 video resolution)
64
+ norm_x = center_x / 1280
65
+ norm_y = center_y / 720
66
+ actual_path.append({"x": norm_x, "y": norm_y})
67
+
68
+ frame_count += 1
69
+ if frame_count > 30: # Process first 30 frames for simplicity
70
+ break
71
+
72
+ cap.release()
73
+
74
+ if not actual_path:
75
+ return None, None, "No ball detected in video"
76
+
77
+ # Assume last point is impact, calculate pitching as midpoint
78
+ pitching_x = actual_path[len(actual_path)//2]["x"]
79
+ pitching_y = actual_path[len(actual_path)//2]["y"]
80
+ impact_x = actual_path[-1]["x"]
81
+ impact_y = actual_path[-1]["y"]
82
+
83
+ # Simulate speed (frames per second to m/s, rough estimate)
84
+ fps = cap.get(cv2.CAP_PROP_FPS) or 30
85
+ speed = (len(actual_path) / (frame_count / fps)) * 0.5 # Simplified conversion
86
+
87
+ # Projected path (linear from impact to stumps, adjusted for spin)
88
+ projected_path = [
89
  {"x": impact_x, "y": impact_y},
90
  {"x": impact_x + spin * 0.1, "y": 1.0} # Stumps at y=1.0
91
  ]
92
+
93
+ return actual_path, projected_path, pitching_x, pitching_y, impact_x, impact_y, speed, spin
94
 
95
  @app.route('/')
96
  def index():
 
98
 
99
  @app.route('/analyze', methods=['POST'])
100
  def analyze():
101
+ if 'video' not in request.files:
102
+ return jsonify({'error': 'No video uploaded'}), 400
103
+
104
+ file = request.files['video']
105
+ if file.filename == '' or not allowed_file(file.filename):
106
+ return jsonify({'error': 'Invalid file'}), 400
107
+
108
+ # Save the uploaded video
109
+ filename = secure_filename(file.filename)
110
+ video_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
111
+ file.save(video_path)
112
+
113
+ # Process video
114
+ actual_path, projected_path, pitching_x, pitching_y, impact_x, impact_y, speed, spin = process_video(video_path)
115
+ if actual_path is None:
116
+ return jsonify({'error': projected_path}), 400 # projected_path holds error message here
117
 
118
  # Predict LBW decision
119
  features = np.array([[pitching_x, pitching_y, impact_x, impact_y, speed, spin]])
 
121
  confidence = model.predict_proba(features)[0][prediction]
122
  decision = "Out" if prediction == 1 else "Not Out"
123
 
124
+ # Clean up
125
+ os.remove(video_path)
126
+
127
  return jsonify({
128
  'actual_path': actual_path,
129
  'projected_path': projected_path,