Commit b21040f2 authored by Joel Collins's avatar Joel Collins
Browse files

Better fix for RGB capture memory issues

parent 3e4b1750
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -96,6 +96,9 @@ class BaseCamera(object):
        self.last_access = 0  #: time: Time of last client access to the camera
        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._config = {}  #: dict: Dictionary of base camera settings
        self.paths = {
@@ -257,9 +260,12 @@ class BaseCamera(object):
            self.event.set()  # send signal to clients
            time.sleep(0)

            # if there hasn't been any clients asking for frames in
            # the last 10 seconds then stop the thread
            if time.time() - self.last_access > 20:
            # Handle timeout
            if (
                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()
                break

+16 −25
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@ Camera capture resolution set to video_resolution in frames()
Video port uses that resolution for everything. If a different resolution
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.
"""

@@ -208,7 +208,7 @@ class StreamingCamera(BaseCamera):
            # Pause stream while changing settings
            if self.state['stream_active']:  # If stream is active
                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

            # PiCamera parameters (applied directly to PiCamera object)
@@ -237,7 +237,7 @@ class StreamingCamera(BaseCamera):
            # If stream was paused to update config, unpause
            if paused_stream:
                logging.info("Resuming stream.")
                self.resume_stream_for_capture()
                self.resume_stream()

        else:
            raise Exception(
@@ -355,7 +355,7 @@ class StreamingCamera(BaseCamera):
        # Update state dictionary
        self.state['record_active'] = False

    def pause_stream_for_capture(
    def pause_stream(
            self,
            splitter_port: int=1,
            resolution: Tuple[int, int]=None) -> None:
@@ -377,7 +377,7 @@ class StreamingCamera(BaseCamera):
        # Increase the resolution for taking an image
        self.camera.resolution = resolution

    def resume_stream_for_capture(
    def resume_stream(
            self,
            splitter_port: int=1,
            resolution: Tuple[int, int]=None) -> None:
@@ -388,7 +388,7 @@ class StreamingCamera(BaseCamera):
            splitter_port (int): Splitter port to start recording on
            resolution ((int, int)): Resolution to set the camera to, before starting recording.
        """
        logging.debug("Unpausing stream")
        logging.debug("Resuming stream")
        if not resolution:
            resolution = self.config['video_resolution']

@@ -453,7 +453,7 @@ class StreamingCamera(BaseCamera):
        if not use_video_port:

            # Pause video splitter port 1
            self.pause_stream_for_capture()
            self.pause_stream()

            self.camera.capture(
                target,
@@ -463,7 +463,7 @@ class StreamingCamera(BaseCamera):
                bayer=True)

            # Resume video splitter port 1
            self.resume_stream_for_capture()
            self.resume_stream()

        else:
            self.camera.capture(
@@ -498,7 +498,7 @@ class StreamingCamera(BaseCamera):
            size = resolution

        if not use_video_port:
            self.pause_stream_for_capture(resolution=resolution)
            self.pause_stream(resolution=resolution)

        logging.debug("Creating PiYUVArray")
        with picamera.array.PiYUVArray(self.camera, size=size) as output:
@@ -512,7 +512,7 @@ class StreamingCamera(BaseCamera):
                use_video_port=use_video_port)

            if not use_video_port:
                self.resume_stream_for_capture()
                self.resume_stream()

            if rgb:
                logging.debug("Converting to RGB")
@@ -523,19 +523,13 @@ class StreamingCamera(BaseCamera):
    def array(
            self,
            use_video_port: bool=True,
            resize: Tuple[int, int]=None,
            stop_worker: bool=True) -> np.ndarray:
            resize: Tuple[int, int]=None) -> np.ndarray:
        """Capture an uncompressed still RGB image to a Numpy array.

        Args:
            use_video_port (bool): Capture from the video port used for streaming. Lower resolution, faster.
            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:
            resolution = self.config['video_resolution']
@@ -547,8 +541,8 @@ class StreamingCamera(BaseCamera):
        else:
            size = resolution

        if not use_video_port:
            self.pause_stream_for_capture(resolution=resolution)
        # Always pause stream, to prevent resizer memory issues
        self.pause_stream(resolution=resolution)

        logging.debug("Creating PiRGBArray")
        with picamera.array.PiRGBArray(self.camera, size=size) as output:
@@ -561,11 +555,8 @@ class StreamingCamera(BaseCamera):
                format='rgb',
                use_video_port=use_video_port)

            if not use_video_port:
                self.resume_stream_for_capture()
            
            if restart_worker:
                self.start_worker()
            # Resume stream
            self.resume_stream()

            return output.array

+5 −1
Original line number Diff line number Diff line
@@ -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.
        cam.start_preview()
        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
            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)
            incremental_gains = lens_shading_correction_from_rgb(rgb_image, 64//2)
            gains *= incremental_gains

            # 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.resume_stream()
            time.sleep(2)

        # 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...")
        config.merge_config(settings, safe=True, backup=True)

        #cam.resume_stream_for_capture()


if __name__ == '__main__':
    generate_lens_shading_table_closed_loop()
 No newline at end of file