1# Copyright (c) 2025 NXP 2# 3# SPDX-License-Identifier: Apache-2.0 4 5import cv2 6import numpy as np 7 8 9class UVCCamera: 10 def __init__(self, config): 11 self.device_id = config.get("device_id", 0) 12 self.res_x = config.get("res_x", 1280) 13 self.res_y = config.get("res_y", 720) 14 self.cap = cv2.VideoCapture(self.device_id) 15 self.prev_frame = None 16 self.current_alarms = 0 17 self.alarm_duration = 5 # Alarm duration in frames 18 self.fingerprint_cache = {} # Store video fingerprints 19 self._original_wb = 0 20 21 def initialize(self): 22 if not self.cap.isOpened(): 23 raise Exception(f"Failed to open camera {self.device_id}") 24 self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, self.res_x) # Set resolution 25 self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self.res_y) 26 self.cap.set(cv2.CAP_PROP_AUTOFOCUS, 1) 27 # Read initial 10 frames to stabilize camera 28 for _ in range(10): 29 self.get_frame() 30 31 # Use first 120 frames to optimize focus 32 best_focus_score = 0 33 for i in range(120): 34 ret, frame = self.get_frame() 35 if ret: 36 current_score = self.smart_focus(frame) 37 if current_score > best_focus_score: 38 best_focus_score = current_score 39 if i % 20 == 0: # Periodically adjust focus 40 self.auto_focus(current_score < 0.5) 41 self.auto_white_balance(True) 42 self.print_settings() 43 44 def get_frame(self): 45 ret, frame = self.cap.read() 46 if ret: 47 frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) 48 return ret, frame 49 50 def show_frame(self, frame): 51 cv2.imshow(f"Camera Preview (Device {self.device_id})", frame) 52 cv2.waitKey(1) 53 54 def auto_focus(self, enable: bool): 55 """Auto focus control 56 57 Args: 58 enable: True to enable auto focus, False to disable 59 """ 60 self.cap.set(cv2.CAP_PROP_AUTOFOCUS, 1 if enable else 0) 61 62 def smart_focus(self, frame): 63 """Smart focus algorithm based on image sharpness 64 65 Args: 66 frame: Current video frame 67 68 Returns: 69 Focus score value (0-1) 70 """ 71 if frame is None: 72 return 0 73 74 # Convert to grayscale 75 gray = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY) 76 77 # Calculate Laplacian variance as sharpness metric 78 laplacian = cv2.Laplacian(gray, cv2.CV_64F) 79 focus_score = laplacian.var() / 1000 # Normalized to 0-1 range 80 81 # Adjust focus based on sharpness 82 if focus_score < 0.3: # Image is blurry 83 self.auto_focus(True) 84 elif focus_score > 0.7: # Image is sharp 85 self.auto_focus(False) 86 87 return min(max(focus_score, 0), 1) # Ensure value is within 0-1 range 88 89 def auto_white_balance(self, enable): 90 """Enable/disable auto white balance with algorithm optimization""" 91 if enable: 92 self._original_wb = self.cap.get(cv2.CAP_PROP_WB_TEMPERATURE) 93 94 self.cap.set(cv2.CAP_PROP_AUTO_WB, 1) 95 96 # Sample frames and analyze white balance 97 wb_scores = [] 98 for _ in range(10): # Sample 10 frames for better accuracy 99 ret, frame = self.cap.read() 100 if not ret: 101 break 102 103 # Convert to LAB color space and analyze A/B channels 104 lab = cv2.cvtColor(frame, cv2.COLOR_BGR2LAB) 105 a_channel, b_channel = lab[:, :, 1], lab[:, :, 2] 106 107 # Calculate white balance score (lower is better) 108 wb_score = np.std(a_channel) + np.std(b_channel) 109 wb_scores.append(wb_score) 110 111 # If score improves significantly, keep current WB 112 if len(wb_scores) > 1 and wb_score < min(wb_scores[:-1]) * 0.9: 113 break 114 else: 115 if hasattr(self, "_original_wb"): 116 self.cap.set(cv2.CAP_PROP_AUTO_WB, 0) 117 self.cap.set(cv2.CAP_PROP_WB_TEMPERATURE, self._original_wb) 118 ret, frame = self.cap.read() 119 if ret: 120 cv2.waitKey(1) 121 122 def capture_image(self, save_path=None): 123 """Capture current frame at highest resolution and optionally save to file""" 124 # Set to maximum resolution 125 self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, self.cap.get(cv2.CAP_PROP_FRAME_WIDTH)) 126 self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) 127 128 ret, frame = self.cap.read() 129 if not ret: 130 return None 131 132 if save_path: 133 cv2.imwrite(save_path, frame) 134 return frame 135 136 def analyze_image(self, image): 137 """Perform basic image analysis on captured frame""" 138 if image is None: 139 return None 140 141 analysis = {} 142 # Brightness analysis 143 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 144 analysis["brightness"] = np.mean(gray) 145 146 # Color analysis 147 lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB) 148 analysis["color_balance"] = { 149 "a_channel": np.mean(lab[:, :, 1]), 150 "b_channel": np.mean(lab[:, :, 2]), 151 } 152 153 # Sharpness analysis 154 analysis["sharpness"] = cv2.Laplacian(gray, cv2.CV_64F).var() 155 156 return analysis 157 158 def show_analysis(self, analysis, frame=None): 159 """Display image analysis results on frame if provided""" 160 if analysis is None: 161 print("No analysis results to display") 162 return 163 164 # Print analysis results 165 print("Image Analysis Results:") 166 print(f" Brightness: {analysis['brightness']:.2f}") 167 print(f" Color Balance - A Channel: {analysis['color_balance']['a_channel']:.2f}") 168 print(f" Color Balance - B Channel: {analysis['color_balance']['b_channel']:.2f}") 169 print(f" Sharpness: {analysis['sharpness']:.2f}") 170 171 # 在帧上显示分析结果 172 if frame is not None: 173 text_y = 30 174 cv2.putText( 175 frame, 176 f"Brightness: {analysis['brightness']:.2f}", 177 (10, text_y), 178 cv2.FONT_HERSHEY_SIMPLEX, 179 0.7, 180 (0, 255, 0), 181 2, 182 ) 183 text_y += 30 184 cv2.putText( 185 frame, 186 f"A Channel: {analysis['color_balance']['a_channel']:.2f}", 187 (10, text_y), 188 cv2.FONT_HERSHEY_SIMPLEX, 189 0.7, 190 (0, 255, 0), 191 2, 192 ) 193 text_y += 30 194 cv2.putText( 195 frame, 196 f"B Channel: {analysis['color_balance']['b_channel']:.2f}", 197 (10, text_y), 198 cv2.FONT_HERSHEY_SIMPLEX, 199 0.7, 200 (0, 255, 0), 201 2, 202 ) 203 text_y += 30 204 cv2.putText( 205 frame, 206 f"Sharpness: {analysis['sharpness']:.2f}", 207 (10, text_y), 208 cv2.FONT_HERSHEY_SIMPLEX, 209 0.7, 210 (0, 255, 0), 211 2, 212 ) 213 214 def load_image(self, file_path): 215 """Load a saved image from file 216 217 Args: 218 file_path: Path to the image file 219 220 Returns: 221 The loaded image in BGR format, or None if loading fails 222 """ 223 try: 224 image = cv2.imread(file_path) 225 if image is None: 226 print(f"Failed to load image from {file_path}") 227 return image 228 except Exception as e: 229 print(f"Error loading image: {str(e)}") 230 return None 231 232 def analyze_multiple_frames(self, num_frames=10): 233 """Analyze multiple frames and return average results""" 234 results = [] 235 236 for _ in range(num_frames): 237 frame = self.capture_image() 238 if frame is None: 239 continue 240 241 analysis = self.analyze_image(frame) 242 results.append(analysis) 243 244 if not results: 245 return None 246 247 # Calculate averages 248 avg_analysis = { 249 "brightness": np.mean([r["brightness"] for r in results]), 250 "color_balance": { 251 "a_channel": np.mean([r["color_balance"]["a_channel"] for r in results]), 252 "b_channel": np.mean([r["color_balance"]["b_channel"] for r in results]), 253 }, 254 "sharpness": np.mean([r["sharpness"] for r in results]), 255 } 256 257 return avg_analysis 258 259 def print_settings(self): 260 """Print current camera settings""" 261 print(f"Camera {self.device_id} Settings:") 262 print( 263 f"Resolution: {int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))}\ 264 x{int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))}" 265 ) 266 print(f" FPS: {self.cap.get(cv2.CAP_PROP_FPS):.2f}") 267 print(f" Auto Focus: {'ON' if self.cap.get(cv2.CAP_PROP_AUTOFOCUS) else 'OFF'}") 268 print(f" Auto White Balance: {'ON' if self.cap.get(cv2.CAP_PROP_AUTO_WB) else 'OFF'}") 269 270 def release(self): 271 self.cap.release() 272 cv2.destroyAllWindows() 273