diff --git a/logs/test_results.csv b/logs/test_results.csv index 466abb2..4e84ed7 100644 --- a/logs/test_results.csv +++ b/logs/test_results.csv @@ -607,3 +607,68 @@ Timestamp,Mode,Player,Target_Dir,Up_Votes,Left_Votes,Right_Votes,Total_Strong,Do 00:32:21,SINGLE,PLAYER 1,UP,0,0,639,639,RIGHT,WRONG DIRECTION!,141.0,28.8,1.657,0.0062 00:32:23,SINGLE,PLAYER 1,UP,0,2488,0,2488,LEFT,WRONG DIRECTION!,137.0,10.1,6.7,0.006 00:32:29,SINGLE,PLAYER 1,UP,72,1494,563,2129,LEFT,WRONG DIRECTION!,114.0,31.5,2.544,0.0052 +14:47:10,SINGLE,PLAYER 1,RIGHT,181,1,1357,1539,RIGHT,VALID,105.0,9.2,49.854,0.0034 +14:47:22,SINGLE,PLAYER 1,LEFT,18,4082,0,4100,LEFT,VALID,95.0,9.6,10.347,0.0077 +14:48:06,MULTI,PLAYER 2,UP,0,2327,0,2327,LEFT,WRONG DIRECTION!,119.0,16.0,6.119,0.0049 +14:48:06,MULTI,PLAYER 1,LEFT,549,1814,0,2363,LEFT,VALID,115.0,8.2,9.98,0.0074 +14:48:07,MULTI,PLAYER 1,RIGHT,0,1229,44,1273,LEFT,WRONG DIRECTION!,116.0,5.8,13.586,0.0081 +14:48:08,MULTI,PLAYER 1,RIGHT,1123,1639,811,3573,LEFT,WRONG DIRECTION!,141.0,35.3,3.547,0.0079 +14:48:09,MULTI,PLAYER 1,RIGHT,414,9,2019,2442,RIGHT,VALID,149.0,7.2,3.626,0.0086 +14:48:11,MULTI,PLAYER 1,UP,431,35,0,466,UP,VALID,76.0,3.5,6.749,0.0085 +14:48:11,MULTI,PLAYER 2,UP,0,1306,0,1306,LEFT,WRONG DIRECTION!,151.0,5.3,7.2,0.0073 +14:48:13,MULTI,PLAYER 2,UP,0,0,849,849,RIGHT,WRONG DIRECTION!,87.0,4.0,6.101,0.0072 +14:48:14,MULTI,PLAYER 2,UP,28,506,0,534,LEFT,WRONG DIRECTION!,57.0,7.5,3.98,0.0081 +14:48:14,MULTI,PLAYER 2,UP,1327,0,29,1356,UP,VALID,115.0,7.4,8.134,0.0084 +14:48:15,MULTI,PLAYER 2,RIGHT,28,977,136,1141,LEFT,WRONG DIRECTION!,158.0,16.4,4.591,0.0087 +14:48:16,MULTI,PLAYER 1,RIGHT,287,0,330,617,RIGHT,VALID,137.0,13.2,4.233,0.0074 +14:48:17,MULTI,PLAYER 2,RIGHT,1140,773,0,1913,UP,WRONG DIRECTION!,127.0,6.0,2.415,0.0071 +14:48:17,MULTI,PLAYER 1,UP,1978,104,96,2178,UP,VALID,111.0,6.2,4.546,0.0079 +14:48:18,MULTI,PLAYER 2,RIGHT,320,1491,0,1811,LEFT,WRONG DIRECTION!,144.0,10.4,3.82,0.0064 +14:48:18,MULTI,PLAYER 2,RIGHT,1698,0,553,2251,UP,WRONG DIRECTION!,147.0,24.0,5.511,0.0063 +14:48:19,MULTI,PLAYER 2,RIGHT,151,0,1340,1491,RIGHT,VALID,177.0,21.5,4.639,0.007 +14:48:20,MULTI,PLAYER 2,RIGHT,0,2846,0,2846,LEFT,WRONG DIRECTION!,128.0,8.1,1.742,0.0067 +14:48:21,MULTI,PLAYER 2,RIGHT,87,2626,6,2719,LEFT,WRONG DIRECTION!,125.0,7.5,2.659,0.0076 +14:48:23,MULTI,PLAYER 1,UP,1009,0,0,1009,UP,VALID,118.0,19.5,2.638,0.0059 +14:48:23,MULTI,PLAYER 2,RIGHT,0,0,657,657,RIGHT,VALID,124.0,12.9,2.801,0.0085 +14:48:25,MULTI,PLAYER 1,LEFT,0,994,0,994,LEFT,VALID,105.0,6.2,4.195,0.0071 +14:48:26,MULTI,PLAYER 1,UP,1048,0,141,1189,UP,VALID,99.0,10.5,3.273,0.0081 +14:48:33,MULTI,PLAYER 2,LEFT,1098,2453,66,3617,LEFT,VALID,177.0,42.7,4.016,0.0078 +14:48:37,MULTI,PLAYER 2,RIGHT,483,0,0,483,UP,WRONG DIRECTION!,65.0,1.9,4.665,0.0072 +14:48:37,MULTI,PLAYER 2,RIGHT,460,0,5933,6393,RIGHT,VALID,88.0,5.4,9.341,0.0066 +14:48:40,MULTI,PLAYER 2,LEFT,1135,497,0,1632,UP,WRONG DIRECTION!,131.0,10.3,2.105,0.0078 +14:48:41,MULTI,PLAYER 2,LEFT,0,0,1283,1283,RIGHT,WRONG DIRECTION!,105.0,6.8,1.441,0.0065 +14:48:42,MULTI,PLAYER 2,LEFT,132,773,0,905,LEFT,VALID,122.0,22.7,1.643,0.0065 +14:48:43,MULTI,PLAYER 2,UP,161,4305,0,4466,LEFT,WRONG DIRECTION!,151.0,16.2,10.359,0.0074 +14:48:44,MULTI,PLAYER 2,UP,3,0,1911,1914,RIGHT,WRONG DIRECTION!,183.0,9.5,6.336,0.0074 +14:48:45,MULTI,PLAYER 2,UP,196,297,118,611,LEFT,WRONG DIRECTION!,99.0,28.8,8.838,0.0083 +14:48:45,MULTI,PLAYER 2,UP,20,1117,98,1235,LEFT,WRONG DIRECTION!,174.0,19.4,11.868,0.0054 +14:48:46,MULTI,PLAYER 2,UP,182,535,0,717,LEFT,WRONG DIRECTION!,135.0,27.7,14.788,0.0082 +14:48:49,MULTI,PLAYER 2,UP,823,267,0,1090,UP,VALID,159.0,25.6,2.216,0.0083 +14:48:51,MULTI,PLAYER 2,UP,1209,0,117,1326,UP,VALID,93.0,14.4,3.456,0.0085 +14:48:55,MULTI,PLAYER 2,RIGHT,0,2169,0,2169,LEFT,WRONG DIRECTION!,143.0,7.4,2.129,0.0058 +14:48:58,MULTI,PLAYER 2,RIGHT,57,0,2624,2681,RIGHT,VALID,158.0,13.0,5.299,0.0066 +14:48:59,MULTI,PLAYER 1,LEFT,0,1628,10,1638,LEFT,VALID,140.0,10.8,10.394,0.0078 +14:49:01,MULTI,PLAYER 1,LEFT,2023,1243,153,3419,UP,WRONG DIRECTION!,153.0,14.8,3.522,0.0068 +14:49:02,MULTI,PLAYER 1,LEFT,295,1707,0,2002,LEFT,VALID,161.0,13.0,2.729,0.0077 +14:49:03,MULTI,PLAYER 2,RIGHT,2034,0,0,2034,UP,WRONG DIRECTION!,129.0,9.2,6.531,0.0076 +14:49:04,MULTI,PLAYER 2,RIGHT,0,1244,0,1244,LEFT,WRONG DIRECTION!,74.0,17.9,10.429,0.0078 +14:49:06,MULTI,PLAYER 1,RIGHT,0,1234,0,1234,LEFT,WRONG DIRECTION!,158.0,9.2,14.55,0.0075 +14:49:10,MULTI,PLAYER 2,RIGHT,1,0,1536,1537,RIGHT,VALID,122.0,7.9,4.582,0.0073 +14:49:11,MULTI,PLAYER 1,RIGHT,1445,1088,0,2533,UP,WRONG DIRECTION!,140.0,10.9,4.338,0.0061 +14:49:13,MULTI,PLAYER 2,RIGHT,2080,0,465,2545,UP,WRONG DIRECTION!,109.0,26.7,5.469,0.0065 +14:49:13,MULTI,PLAYER 1,RIGHT,705,1903,0,2608,LEFT,WRONG DIRECTION!,142.0,18.7,6.046,0.0081 +14:49:14,MULTI,PLAYER 1,RIGHT,250,58,142,450,UP,WRONG DIRECTION!,94.0,13.3,3.545,0.0068 +14:49:16,MULTI,PLAYER 1,RIGHT,1455,0,33,1488,UP,WRONG DIRECTION!,73.0,16.0,2.898,0.0077 +14:49:18,MULTI,PLAYER 2,RIGHT,69,36,333,438,RIGHT,VALID,130.0,34.6,2.236,0.0078 +14:49:21,MULTI,PLAYER 2,LEFT,476,2294,0,2770,LEFT,VALID,165.0,74.3,4.021,0.0068 +14:49:32,SINGLE,PLAYER 1,RIGHT,0,178,1591,1769,RIGHT,VALID,105.0,20.8,3.191,0.0071 +15:21:03,SINGLE,PLAYER 1,LEFT,264,356,109,729,LEFT,VALID,128.0,10.6,73.619,0.0059 +15:21:04,SINGLE,PLAYER 1,RIGHT,2491,2344,5073,9908,RIGHT,VALID,138.0,49.1,72.656,0.005 +15:21:08,SINGLE,PLAYER 1,UP,101,2570,601,3272,LEFT,WRONG DIRECTION!,165.0,51.7,2.191,0.0044 +15:21:08,SINGLE,PLAYER 1,UP,915,1527,739,3181,LEFT,WRONG DIRECTION!,152.0,35.7,1.272,0.0046 +15:21:09,SINGLE,PLAYER 1,UP,665,624,220,1509,UP,VALID,158.0,50.5,3.25,0.0062 +15:21:10,SINGLE,PLAYER 1,LEFT,287,147,1330,1764,RIGHT,WRONG DIRECTION!,99.0,5.6,6.353,0.0055 +15:27:03,SINGLE,PLAYER 1,RIGHT,1313,2073,1731,5117,LEFT,WRONG DIRECTION!,131.0,25.0,12.733,0.0057 +15:27:03,SINGLE,PLAYER 1,RIGHT,16,4560,0,4576,LEFT,WRONG DIRECTION!,115.0,9.5,8.146,0.0047 +15:27:04,SINGLE,PLAYER 1,RIGHT,1083,221,4492,5796,RIGHT,VALID,96.0,5.8,13.848,0.0047 +15:27:05,SINGLE,PLAYER 1,LEFT,2858,115,0,2973,UP,WRONG DIRECTION!,114.0,5.6,11.073,0.0065 diff --git a/result.py b/result.py new file mode 100644 index 0000000..5341759 --- /dev/null +++ b/result.py @@ -0,0 +1,71 @@ +import pandas as pd +import matplotlib.pyplot as plt +import os + +# --- 1. Setup --- +csv_path = os.path.join("logs", "test_results.csv") + +def generate_consolidated_objective_1_report(): + """ + Generates a single comprehensive graph validating Objective 1: + - Latency < 100ms + - Frame Rate >= 30 FPS + - Markerless/Standard Hardware efficiency + """ + if not os.path.exists(csv_path): + print(f"Error: {csv_path} not found. Run the game to generate logs first!") + return + + df = pd.read_csv(csv_path) + + # Derive FPS from recorded processing time to prove 'Measurable' criteria + df['RealTime_FPS'] = 1 / df['Proc_Time'] + + # Create figure with twin axes for a single-report focus + fig, ax1 = plt.subplots(figsize=(12, 8)) + + # --- PRIMARY AXIS: Latency (Seconds) --- + color_lat = '#1f77b4' # Tech Blue + ax1.set_xlabel('Punch Sample Sequence (Time)', fontsize=12) + ax1.set_ylabel('Processing Latency (Seconds)', color=color_lat, fontsize=12, fontweight='bold') + ax1.plot(df.index, df['Proc_Time'], color=color_lat, linewidth=2.5, label='Measured Latency') + + # CRITICAL: Target Threshold Line (100ms) per Objective 1 + ax1.axhline(y=0.1, color='#d62728', linestyle='--', linewidth=2, label='Max Target (100ms)') + ax1.tick_params(axis='y', labelcolor=color_lat) + ax1.set_ylim(0, 0.15) # Focused view around the 100ms threshold + ax1.grid(True, linestyle=':', alpha=0.5) + + # --- SECONDARY AXIS: Frame Rate (FPS) --- + ax2 = ax1.twinx() + color_fps = '#2ca02c' # Success Green + ax2.set_ylabel('Frame Rate (FPS)', color=color_fps, fontsize=12, fontweight='bold') + ax2.plot(df.index, df['RealTime_FPS'], color=color_fps, linestyle='-', alpha=0.4, label='Real-time FPS') + + # Target 30 FPS Line per SMART Criteria + ax2.axhline(y=30, color='#1b5e20', linestyle=':', linewidth=2, label='Target 30 FPS') + ax2.tick_params(axis='y', labelcolor=color_fps) + ax2.set_ylim(0, 60) + + # --- Annotations & Styling --- + plt.title('Objective 1 Validation: Vision Pipeline Efficiency\n(Python/OpenCV Markerless Tracking)', pad=20, fontsize=14) + + # Combined Legend + lines1, labels1 = ax1.get_legend_handles_labels() + lines2, labels2 = ax2.get_legend_handles_labels() + ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left', frameon=True, shadow=True) + + # Objective Summary Text Box + avg_lat = df['Proc_Time'].mean() * 1000 + avg_fps = df['RealTime_FPS'].mean() + summary_text = f"Avg Latency: {avg_lat:.1f}ms\nAvg FPS: {avg_fps:.1f}" + plt.gca().text(0.98, 0.02, summary_text, transform=ax1.transAxes, + bbox=dict(facecolor='white', alpha=0.8), ha='right', fontsize=10) + + fig.tight_layout() + plt.savefig('objective_1_performance_validation.png') + print("Success: objective_1_performance_validation.png generated.") + +if __name__ == "__main__": + print("--- Generating Objective 1 Audit ---") + generate_consolidated_objective_1_report() \ No newline at end of file diff --git a/tracker.py b/tracker.py index a3ec355..8233cc1 100644 --- a/tracker.py +++ b/tracker.py @@ -16,9 +16,9 @@ def analyze_punch(self, mask_roi, prev_gray_roi, curr_gray_roi, req_dir, current # Unchained Math: Run it every time a fist is in the box if np.sum(fist_mask) > 15: # Calculate the total area in pixel of the moving object, ignore if less than 15 - flow = cv.calcOpticalFlowFarneback(prev_gray_roi, curr_gray_roi, None, 0.5, 3, 15, 3, 5, 1.2, 0) - dx = flow[..., 0] - dy = flow[..., 1] + flow = cv.calcOpticalFlowFarneback(prev_gray_roi, curr_gray_roi, None, 0.5, 3, 15, 3, 5, 1.2, 0) # The farneback algorithm looks for the pixel in prev_gray_roi and find where the same pixel moved to in curr_gray_roi, the calculate the differences + dx = flow[..., 0] # How many pixel move horizontally + dy = flow[..., 1] # How many pixel move vertically flow_calculated = True # Trigger the Debug Arrow