diff --git a/python/PiFinder/camera_interface.py b/python/PiFinder/camera_interface.py index 3ce55434..0515428e 100644 --- a/python/PiFinder/camera_interface.py +++ b/python/PiFinder/camera_interface.py @@ -13,10 +13,9 @@ import queue import time from PIL import Image -from PiFinder import state_utils +from PiFinder import state_utils, utils from typing import Tuple import logging -from PiFinder import utils logger = logging.getLogger("Camera.Interface") @@ -78,17 +77,20 @@ def get_image_loop( if not debug: base_image = self.capture() base_image = base_image.convert("L") + rotate_amount = 0 if camera_rotation is None: if ( screen_direction == "right" or screen_direction == "straight" or screen_direction == "flat3" ): - base_image = base_image.rotate(90) + rotate_amount = 90 else: - base_image = base_image.rotate(270) + rotate_amount = 270 else: base_image = base_image.rotate(int(camera_rotation) * -1) + + base_image = base_image.rotate(rotate_amount) else: # load image and wait base_image = Image.open(test_image_path) diff --git a/python/PiFinder/camera_pi.py b/python/PiFinder/camera_pi.py index d2182d26..ac5bc9ed 100644 --- a/python/PiFinder/camera_pi.py +++ b/python/PiFinder/camera_pi.py @@ -15,6 +15,7 @@ from typing import Tuple import logging from PiFinder.multiproclogging import MultiprocLogging +import numpy as np logger = logging.getLogger("Camera.Pi") @@ -48,11 +49,14 @@ def initialize(self) -> None: { "size": (512, 512), }, - raw={"size": (1456, 1088)}, + raw={"size": (1456, 1088), "format": "R10"}, ) else: # using this smaller scale auto-selects binning on the sensor... - cam_config = self.camera.create_still_configuration({"size": (512, 512)}) + # cam_config = self.camera.create_still_configuration({"size": (512, 512)}) + cam_config = self.camera.create_still_configuration( + {"size": (512, 512)}, raw={"size": (2028, 1520), "format": "SRGGB12"} + ) self.camera.configure(cam_config) self.camera.set_controls({"AeEnable": False}) self.camera.set_controls({"AnalogueGain": self.gain}) @@ -60,14 +64,40 @@ def initialize(self) -> None: self.camera.start() def capture(self) -> Image.Image: - tmp_capture = self.camera.capture_image() + """ + Captures a raw 10/12bit sensor output and converts + it to an 8 bit mono image stretched to use the maximum + amount of the 255 level space. + """ + _request = self.camera.capture_request() + raw_capture = _request.make_array("raw") + # tmp_image = _request.make_image("main") + _request.release() if self.camera_type == "imx296": + # crop to square and resample to 16 bit from 2 8 bit entries + raw_capture = raw_capture.copy().view(np.uint16)[:, 184:-184] # Sensor orientation is different - tmp_capture = tmp_capture.rotate(180) - return tmp_capture + raw_capture = np.rot90(raw_capture, 2) + else: + # crop to square and resample to 16 bit from 2 8 bit entries + raw_capture = raw_capture.copy().view(np.uint16)[:, 256:-256] + + raw_capture = raw_capture.astype(np.float32) + max_pixel = np.max(raw_capture) + + # if the whitepoint is already below 255, just cast it + # as we don't want to create fake in-between values + if max_pixel < 255: + raw_capture = raw_capture.astype(np.uint8) + else: + raw_capture = (raw_capture / max_pixel * 255).astype(np.uint8) + + raw_image = Image.fromarray(raw_capture).resize((512, 512)) + return raw_image def capture_file(self, filename) -> None: - return self.camera.capture_file(filename) + tmp_capture = self.capture() + tmp_capture.save(filename) def set_camera_config( self, exposure_time: float, gain: float