1+ import cv2 as cv
2+ import numpy as np
3+ import os
4+ import pandas as pd
5+ import matplotlib .pyplot as plt
6+
7+ # =========================
8+ # OUTPUT FOLDER
9+ # =========================
10+ base_folder = "stats"
11+ output_folder = os .path .join (base_folder , "Pseudocolor Mapping Analysis" )
12+
13+ if not os .path .exists (output_folder ):
14+ os .makedirs (output_folder )
15+
16+ # =========================
17+ # MAIN FUNCTION
18+ # =========================
19+ def analyze_pseudocolor_mapping (video_source = 0 ):
20+
21+ cap = cv .VideoCapture (video_source )
22+
23+ if not cap .isOpened ():
24+ print ("Error: Cannot open video source." )
25+ return
26+
27+ prev_gray = None
28+ results = []
29+
30+ frame_count = 0
31+ max_frames = 300 # limit for testing
32+
33+ while frame_count < max_frames :
34+ ret , frame = cap .read ()
35+ if not ret :
36+ break
37+
38+ # =========================
39+ # PREPROCESSING
40+ # =========================
41+ gray = cv .cvtColor (frame , cv .COLOR_BGR2GRAY )
42+ gray = cv .GaussianBlur (gray , (5 , 5 ), 0 )
43+
44+ # =========================
45+ # MOTION DETECTION
46+ # =========================
47+ if prev_gray is None :
48+ prev_gray = gray
49+ continue
50+
51+ diff = cv .absdiff (prev_gray , gray )
52+ _ , mask = cv .threshold (diff , 25 , 255 , cv .THRESH_BINARY )
53+
54+ # Clean noise
55+ kernel = np .ones ((3 ,3 ), np .uint8 )
56+ mask = cv .morphologyEx (mask , cv .MORPH_OPEN , kernel )
57+
58+ prev_gray = gray
59+
60+ # =========================
61+ # PSEUDOCOLOR (HEATMAP)
62+ # =========================
63+ heatmap = cv .applyColorMap (mask , cv .COLORMAP_JET )
64+
65+ # =========================
66+ # ANALYSIS
67+ # =========================
68+ motion = cv .countNonZero (mask )
69+
70+ hsv = cv .cvtColor (heatmap , cv .COLOR_BGR2HSV )
71+ avg_hue = hsv [:, :, 0 ].mean ()
72+
73+ results .append ((motion , avg_hue ))
74+
75+ frame_count += 1
76+
77+ # Optional display
78+ cv .imshow ("Mask" , mask )
79+ cv .imshow ("Heatmap" , heatmap )
80+
81+ if cv .waitKey (1 ) & 0xFF == 27 :
82+ break
83+
84+ cap .release ()
85+ cv .destroyAllWindows ()
86+
87+ # =========================
88+ # SAVE RESULTS
89+ # =========================
90+ df = pd .DataFrame (results , columns = ["Motion" , "Hue" ])
91+
92+ csv_path = os .path .join (output_folder , "mapping_results.csv" )
93+ df .to_csv (csv_path , index = False )
94+
95+ # =========================
96+ # SIMPLE SUMMARY
97+ # =========================
98+ corr = df .corr ().iloc [0 ,1 ]
99+
100+ summary_path = os .path .join (output_folder , "mapping_summary.txt" )
101+ with open (summary_path , "w" ) as f :
102+ f .write ("PSEUDOCOLOR MAPPING ANALYSIS\n \n " )
103+ f .write (f"Total Frames: { len (df )} \n " )
104+ f .write (f"Correlation (Motion vs Hue): { corr :.4f} \n \n " )
105+
106+ if corr < - 0.3 :
107+ f .write ("Strong inverse relationship (Correct mapping)\n " )
108+ elif corr < - 0.1 :
109+ f .write ("Moderate relationship\n " )
110+ else :
111+ f .write ("Weak relationship (Needs improvement)\n " )
112+
113+ print ("✅ Analysis completed" )
114+ print (f"CSV saved at: { csv_path } " )
115+ print (f"Summary saved at: { summary_path } " )
116+
117+ # =========================
118+ # GENERATE SCATTER PLOT
119+ # =========================
120+ # Optional: remove zero motion for clearer visualization
121+ df_plot = df [df ["Motion" ] > 0 ]
122+
123+ plt .figure (figsize = (10 , 6 ))
124+
125+ # Scatter plot
126+ plt .scatter (df_plot ["Motion" ], df_plot ["Hue" ], alpha = 0.6 )
127+
128+ # Trend line
129+ if len (df_plot ) > 1 :
130+ z = np .polyfit (df_plot ["Motion" ], df_plot ["Hue" ], 1 )
131+ p = np .poly1d (z )
132+ plt .plot (df_plot ["Motion" ], p (df_plot ["Motion" ]))
133+
134+ # Labels
135+ plt .xlabel ("Motion Intensity" )
136+ plt .ylabel ("Hue Value" )
137+ plt .title ("Pseudocolor Mapping: Motion vs Hue" )
138+ plt .grid ()
139+
140+ # Save chart
141+ chart_path = os .path .join (output_folder , "mapping_scatter.png" )
142+ plt .savefig (chart_path )
143+
144+ plt .close ()
145+
146+ print (f"✅ Chart saved at: { chart_path } " )
147+
148+
149+ # =========================
150+ # RUN
151+ # =========================
152+ if __name__ == "__main__" :
153+ analyze_pseudocolor_mapping ()
0 commit comments