@@ -31,17 +31,32 @@ class FrameGrabber(QObject):
3131 def __init__ (self , node = None ):
3232 super ().__init__ ()
3333 self .node = node
34+ # Camera properties
3435 self .camera = None
3536 self .camera_index = 0
37+ self .frame_width = 640
38+ self .frame_height = 480
39+ self .backend = cv2 .CAP_ANY
40+
41+ # Camera optimization settings
42+ self .target_fps = 30
43+ self .target_exposure = 100 # Auto exposure target (0-255)
44+ self .camera_props = {
45+ cv2 .CAP_PROP_FRAME_WIDTH : self .frame_width ,
46+ cv2 .CAP_PROP_FRAME_HEIGHT : self .frame_height ,
47+ cv2 .CAP_PROP_FPS : self .target_fps ,
48+ cv2 .CAP_PROP_BUFFERSIZE : 1 , # Minimal latency
49+ cv2 .CAP_PROP_AUTOFOCUS : 0 , # Disable autofocus
50+ cv2 .CAP_PROP_AUTO_EXPOSURE : 1 , # Enable auto exposure
51+ cv2 .CAP_PROP_AUTO_WB : 1 , # Enable auto white balance
52+ cv2 .CAP_PROP_EXPOSURE : self .target_exposure ,
53+ }
3654 self .running = False
3755 self .lock = threading .Lock ()
3856 self .capture_thread = None
3957 self .process_thread = None
4058 self .publish_thread = None
41- self .frame_width = 1280 # Default to 720p (16:9)
42- self .frame_height = 720
4359 self .high_quality = False
44- self .backend = cv2 .CAP_ANY # Default backend
4560
4661 # Initialize shared frame buffer
4762 self .current_frame = None
@@ -324,21 +339,40 @@ def stop(self):
324339 self .camera = None
325340
326341 def set_quality (self , high_quality ):
327- """Toggle between low resolution and high resolution"""
328- with self .lock :
329- if high_quality :
330- self .frame_width = 1920
331- self .frame_height = 1080
332- else :
333- # Keep these values low to reduce latency
334- self .frame_width = 1280
335- self .frame_height = 720
336- self .high_quality = high_quality
342+ """Toggle between low resolution and high resolution with optimal settings"""
343+ if high_quality :
344+ self .frame_width = 1280
345+ self .frame_height = 720
346+ self .target_fps = 24 # Lower FPS for higher resolution
347+ else :
348+ self .frame_width = 640
349+ self .frame_height = 480
350+ self .target_fps = 30 # Higher FPS for lower resolution
351+
352+ # Update camera properties
353+ self .camera_props .update ({
354+ cv2 .CAP_PROP_FRAME_WIDTH : self .frame_width ,
355+ cv2 .CAP_PROP_FRAME_HEIGHT : self .frame_height ,
356+ cv2 .CAP_PROP_FPS : self .target_fps
357+ })
358+
359+ if self .camera and self .camera .isOpened ():
360+ # Apply new settings
361+ for prop , value in self .camera_props .items ():
362+ try :
363+ self .camera .set (prop , value )
364+ except :
365+ pass
337366
338- # Re-initialize the camera with the new settings
339- if self .camera and self .camera .isOpened ():
340- self .camera .set (cv2 .CAP_PROP_FRAME_WIDTH , self .frame_width )
341- self .camera .set (cv2 .CAP_PROP_FRAME_HEIGHT , self .frame_height )
367+ # Verify new settings
368+ actual_width = int (self .camera .get (cv2 .CAP_PROP_FRAME_WIDTH ))
369+ actual_height = int (self .camera .get (cv2 .CAP_PROP_FRAME_HEIGHT ))
370+ actual_fps = self .camera .get (cv2 .CAP_PROP_FPS )
371+
372+ print (f"Quality changed to: { actual_width } x{ actual_height } @ { actual_fps :.1f} FPS" )
373+
374+ # Update UI with blank frame of new size
375+ self .frame_ready .emit (np .zeros ((self .frame_height , self .frame_width , 3 ), dtype = np .uint8 ))
342376
343377 def toggle_face_detection (self , enable ):
344378 """Enable or disable face detection"""
@@ -568,17 +602,32 @@ def _capture_loop(self):
568602 self .error .emit (f"Failed to open camera: { error_msg } " )
569603 return
570604
571- # Configure camera
572- self .camera .set (cv2 .CAP_PROP_FRAME_WIDTH , self .frame_width )
573- self .camera .set (cv2 .CAP_PROP_FRAME_HEIGHT , self .frame_height )
574- self .camera .set (cv2 .CAP_PROP_BUFFERSIZE , 1 ) # Minimal latency
605+ # Configure camera with optimal settings
606+ for prop , value in self .camera_props .items ():
607+ try :
608+ self .camera .set (prop , value )
609+ except :
610+ pass # Skip unsupported properties
611+
612+ # Verify and adjust settings
613+ actual_width = int (self .camera .get (cv2 .CAP_PROP_FRAME_WIDTH ))
614+ actual_height = int (self .camera .get (cv2 .CAP_PROP_FRAME_HEIGHT ))
615+ actual_fps = self .camera .get (cv2 .CAP_PROP_FPS )
575616
576- # Optional camera properties
577- try :
578- self .camera .set (cv2 .CAP_PROP_AUTOFOCUS , 0 ) # Disable autofocus
579- self .camera .set (cv2 .CAP_PROP_FPS , 30 ) # Request 30 FPS
580- except :
581- pass # Some cameras don't support these
617+ print (f"Camera configured with: { actual_width } x{ actual_height } @ { actual_fps :.1f} FPS" )
618+
619+ # Warm up the camera
620+ for _ in range (5 ):
621+ self .camera .read ()
622+
623+ # Read a test frame to check actual size
624+ ret , frame = self .camera .read ()
625+ if ret :
626+ frame_h , frame_w = frame .shape [:2 ]
627+ if frame_w != actual_width or frame_h != actual_height :
628+ print (f"Warning: Actual frame size ({ frame_w } x{ frame_h } ) differs from requested ({ actual_width } x{ actual_height } )" )
629+ self .frame_width = frame_w
630+ self .frame_height = frame_h
582631
583632 # Main capture loop
584633 while self .running :
0 commit comments