Better fix for RGB capture memory issues

This commit is contained in:
Joel Collins 2018-11-30 10:33:39 +00:00
parent 3e4b1750ae
commit b21040f22e
3 changed files with 30 additions and 29 deletions

View file

@ -96,6 +96,9 @@ class BaseCamera(object):
self.last_access = 0 #: time: Time of last client access to the camera self.last_access = 0 #: time: Time of last client access to the camera
self.event = CameraEvent() self.event = CameraEvent()
self.stream_timeout = 20 #: int: Number of inactive seconds before timing out the stream
self.stream_timeout_enabled = True #: bool: Enable or disable timing out the stream
self.state = {} #: dict: Dictionary for capture state self.state = {} #: dict: Dictionary for capture state
self._config = {} #: dict: Dictionary of base camera settings self._config = {} #: dict: Dictionary of base camera settings
self.paths = { self.paths = {
@ -257,9 +260,12 @@ class BaseCamera(object):
self.event.set() # send signal to clients self.event.set() # send signal to clients
time.sleep(0) time.sleep(0)
# if there hasn't been any clients asking for frames in # Handle timeout
# the last 10 seconds then stop the thread if (
if time.time() - self.last_access > 20: self.stream_timeout_enabled and # If using timeout
(time.time() - self.last_access > self.stream_timeout) and # And timeout time
not self.state['preview_active'] # And GPU preview is not active
):
self.frames_iterator.close() self.frames_iterator.close()
break break

View file

@ -17,7 +17,7 @@ Camera capture resolution set to video_resolution in frames()
Video port uses that resolution for everything. If a different resolution Video port uses that resolution for everything. If a different resolution
is specified for video capture, this is handled by the resizer. is specified for video capture, this is handled by the resizer.
Still capture (if use_video_port == False) uses pause_stream_for_capture Still capture (if use_video_port == False) uses pause_stream
to temporarily increase the capture resolution. to temporarily increase the capture resolution.
""" """
@ -208,7 +208,7 @@ class StreamingCamera(BaseCamera):
# Pause stream while changing settings # Pause stream while changing settings
if self.state['stream_active']: # If stream is active if self.state['stream_active']: # If stream is active
logging.info("Pausing stream to update config.") logging.info("Pausing stream to update config.")
self.pause_stream_for_capture() # Pause stream self.pause_stream() # Pause stream
paused_stream = True # Remember to unpause stream when done paused_stream = True # Remember to unpause stream when done
# PiCamera parameters (applied directly to PiCamera object) # PiCamera parameters (applied directly to PiCamera object)
@ -237,7 +237,7 @@ class StreamingCamera(BaseCamera):
# If stream was paused to update config, unpause # If stream was paused to update config, unpause
if paused_stream: if paused_stream:
logging.info("Resuming stream.") logging.info("Resuming stream.")
self.resume_stream_for_capture() self.resume_stream()
else: else:
raise Exception( raise Exception(
@ -355,7 +355,7 @@ class StreamingCamera(BaseCamera):
# Update state dictionary # Update state dictionary
self.state['record_active'] = False self.state['record_active'] = False
def pause_stream_for_capture( def pause_stream(
self, self,
splitter_port: int=1, splitter_port: int=1,
resolution: Tuple[int, int]=None) -> None: resolution: Tuple[int, int]=None) -> None:
@ -377,7 +377,7 @@ class StreamingCamera(BaseCamera):
# Increase the resolution for taking an image # Increase the resolution for taking an image
self.camera.resolution = resolution self.camera.resolution = resolution
def resume_stream_for_capture( def resume_stream(
self, self,
splitter_port: int=1, splitter_port: int=1,
resolution: Tuple[int, int]=None) -> None: resolution: Tuple[int, int]=None) -> None:
@ -388,7 +388,7 @@ class StreamingCamera(BaseCamera):
splitter_port (int): Splitter port to start recording on splitter_port (int): Splitter port to start recording on
resolution ((int, int)): Resolution to set the camera to, before starting recording. resolution ((int, int)): Resolution to set the camera to, before starting recording.
""" """
logging.debug("Unpausing stream") logging.debug("Resuming stream")
if not resolution: if not resolution:
resolution = self.config['video_resolution'] resolution = self.config['video_resolution']
@ -453,7 +453,7 @@ class StreamingCamera(BaseCamera):
if not use_video_port: if not use_video_port:
# Pause video splitter port 1 # Pause video splitter port 1
self.pause_stream_for_capture() self.pause_stream()
self.camera.capture( self.camera.capture(
target, target,
@ -463,7 +463,7 @@ class StreamingCamera(BaseCamera):
bayer=True) bayer=True)
# Resume video splitter port 1 # Resume video splitter port 1
self.resume_stream_for_capture() self.resume_stream()
else: else:
self.camera.capture( self.camera.capture(
@ -498,7 +498,7 @@ class StreamingCamera(BaseCamera):
size = resolution size = resolution
if not use_video_port: if not use_video_port:
self.pause_stream_for_capture(resolution=resolution) self.pause_stream(resolution=resolution)
logging.debug("Creating PiYUVArray") logging.debug("Creating PiYUVArray")
with picamera.array.PiYUVArray(self.camera, size=size) as output: with picamera.array.PiYUVArray(self.camera, size=size) as output:
@ -512,7 +512,7 @@ class StreamingCamera(BaseCamera):
use_video_port=use_video_port) use_video_port=use_video_port)
if not use_video_port: if not use_video_port:
self.resume_stream_for_capture() self.resume_stream()
if rgb: if rgb:
logging.debug("Converting to RGB") logging.debug("Converting to RGB")
@ -523,19 +523,13 @@ class StreamingCamera(BaseCamera):
def array( def array(
self, self,
use_video_port: bool=True, use_video_port: bool=True,
resize: Tuple[int, int]=None, resize: Tuple[int, int]=None) -> np.ndarray:
stop_worker: bool=True) -> np.ndarray:
"""Capture an uncompressed still RGB image to a Numpy array. """Capture an uncompressed still RGB image to a Numpy array.
Args: Args:
use_video_port (bool): Capture from the video port used for streaming. Lower resolution, faster. use_video_port (bool): Capture from the video port used for streaming. Lower resolution, faster.
resize ((int, int)): Resize the captured image. resize ((int, int)): Resize the captured image.
stop_worker (bool): Auto-stop worker, to avoid GPU memory issues
""" """
restart_worker = False
if stop_worker is True and self.stop is False:
self.stop_worker()
restart_worker = True
if use_video_port: if use_video_port:
resolution = self.config['video_resolution'] resolution = self.config['video_resolution']
@ -547,8 +541,8 @@ class StreamingCamera(BaseCamera):
else: else:
size = resolution size = resolution
if not use_video_port: # Always pause stream, to prevent resizer memory issues
self.pause_stream_for_capture(resolution=resolution) self.pause_stream(resolution=resolution)
logging.debug("Creating PiRGBArray") logging.debug("Creating PiRGBArray")
with picamera.array.PiRGBArray(self.camera, size=size) as output: with picamera.array.PiRGBArray(self.camera, size=size) as output:
@ -561,11 +555,8 @@ class StreamingCamera(BaseCamera):
format='rgb', format='rgb',
use_video_port=use_video_port) use_video_port=use_video_port)
if not use_video_port: # Resume stream
self.resume_stream_for_capture() self.resume_stream()
if restart_worker:
self.start_worker()
return output.array return output.array

View file

@ -104,7 +104,6 @@ def generate_lens_shading_table_closed_loop(output_fname="shadingtable.npy",
# Open the microscope and start with flat (i.e. no) lens shading correction. # Open the microscope and start with flat (i.e. no) lens shading correction.
cam.start_preview() cam.start_preview()
logging.info("Stopping worker thread during calibration, to avoid GPU memory issues") logging.info("Stopping worker thread during calibration, to avoid GPU memory issues")
cam.stop_worker()
def get_rgb_image(): # shorthand for taking an RGB image def get_rgb_image(): # shorthand for taking an RGB image
return cam.array(use_video_port=True, resize=(max_res[0]//2, max_res[1]//2)) return cam.array(use_video_port=True, resize=(max_res[0]//2, max_res[1]//2))
@ -125,8 +124,11 @@ def generate_lens_shading_table_closed_loop(output_fname="shadingtable.npy",
rgb_image = np.mean(images, axis=0, dtype=np.float) rgb_image = np.mean(images, axis=0, dtype=np.float)
incremental_gains = lens_shading_correction_from_rgb(rgb_image, 64//2) incremental_gains = lens_shading_correction_from_rgb(rgb_image, 64//2)
gains *= incremental_gains gains *= incremental_gains
# Apply this change (actually apply a bit less than the change) # Apply this change (actually apply a bit less than the change)
cam.pause_stream()
cam.camera.lens_shading_table = gains_to_lst(gains*32) cam.camera.lens_shading_table = gains_to_lst(gains*32)
cam.resume_stream()
time.sleep(2) time.sleep(2)
# Fix the AWB gains so the image is neutral # Fix the AWB gains so the image is neutral
@ -158,6 +160,8 @@ def generate_lens_shading_table_closed_loop(output_fname="shadingtable.npy",
logging.debug("Merging config...") logging.debug("Merging config...")
config.merge_config(settings, safe=True, backup=True) config.merge_config(settings, safe=True, backup=True)
#cam.resume_stream_for_capture()
if __name__ == '__main__': if __name__ == '__main__':
generate_lens_shading_table_closed_loop() generate_lens_shading_table_closed_loop()