Fix capture array for raw stream

This commit is contained in:
Julian Stirling 2025-08-22 13:09:46 +01:00
parent 23a3a5b464
commit b124355fed

View file

@ -524,9 +524,22 @@ class StreamingPiCamera2(BaseCamera):
with self._streaming_picamera() as cam: with self._streaming_picamera() as cam:
cam.capture_metadata() cam.capture_metadata()
@contextmanager
def _switch_to_still_capture_mode(self) -> Iterator[Picamera2]:
"""Get the picamera lock, pause stream and switch into still capture config.
Restarts stream when complete.
"""
with self._streaming_picamera(pause_stream=True) as cam:
logging.debug("Reconfiguring camera for full resolution capture")
cam.configure(cam.create_still_configuration(sensor=self._sensor_mode))
cam.start()
time.sleep(0.2)
yield cam
def capture_image( def capture_image(
self, self,
stream_name: Literal["main", "lores", "raw", "full"] = "main", stream_name: Literal["main", "lores", "full"] = "main",
wait: Optional[float] = 0.9, wait: Optional[float] = 0.9,
) -> Image: ) -> Image:
"""Acquire one image from the camera and return it as a PIL Image. """Acquire one image from the camera and return it as a PIL Image.
@ -540,7 +553,8 @@ class StreamingPiCamera2(BaseCamera):
reconfigure the camera to capture a full resolution image. reconfigure the camera to capture a full resolution image.
:param stream_name: (Optional) The PiCamera2 stream to use, should be one of :param stream_name: (Optional) The PiCamera2 stream to use, should be one of
["main", "lores", "raw", "full"]. Default = "main" ["main", "lores", "full"]. Default = "main". Note that "raw" images cannot
be captured as PIL images. Use capture_array
:param wait: (Optional, float) Set a timeout in seconds. Default = 0.9s, :param wait: (Optional, float) Set a timeout in seconds. Default = 0.9s,
lower than the 1s timeout for the camera. This ensures that our code times lower than the 1s timeout for the camera. This ensures that our code times
out and returns before the camera times out. If None is set the default out and returns before the camera times out. If None is set the default
@ -554,11 +568,7 @@ class StreamingPiCamera2(BaseCamera):
with self._streaming_picamera() as cam: with self._streaming_picamera() as cam:
return cam.capture_image(stream_name, wait=wait) return cam.capture_image(stream_name, wait=wait)
elif stream_name == "full": elif stream_name == "full":
with self._streaming_picamera(pause_stream=True) as cam: with self._switch_to_still_capture_mode() as cam:
logging.debug("Reconfiguring camera for full resolution capture")
cam.configure(cam.create_still_configuration())
cam.start()
time.sleep(0.2)
return cam.capture_image(name="main", wait=wait) return cam.capture_image(name="main", wait=wait)
else: else:
raise ValueError(f'Unknown stream name "{stream_name}"') raise ValueError(f'Unknown stream name "{stream_name}"')
@ -584,6 +594,12 @@ class StreamingPiCamera2(BaseCamera):
:raises TimeoutError: if this time is exceeded during capture. :raises TimeoutError: if this time is exceeded during capture.
""" """
if stream_name == "raw":
# Raw cannot used capture_image.
if wait is None:
wait = 0.9
with self._switch_to_still_capture_mode() as cam:
return cam.capture_array(name="raw", wait=wait)
# Note that internally the PiCamera creates a PIL image and then converts to # Note that internally the PiCamera creates a PIL image and then converts to
# numpy with ``np.array(Image.open(io.BytesIO(self.make_buffer(name))))``. # numpy with ``np.array(Image.open(io.BytesIO(self.make_buffer(name))))``.
# As such we use capture_image to get an Image from the picamera and return # As such we use capture_image to get an Image from the picamera and return