Skip to content

Commit

Permalink
Use raw linear images in imaging pipeline (#260)
Browse files Browse the repository at this point in the history
* Raw output for camera in shared state

* feeding linear image through pipeline

* imx296 working with auto-stretch, removed vestigal double return

* Clean up capture_file

* Works with v2 camera
  • Loading branch information
brickbots authored Dec 21, 2024
1 parent d59cff4 commit 836d0d7
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 10 deletions.
10 changes: 6 additions & 4 deletions python/PiFinder/camera_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down Expand Up @@ -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)
Expand Down
42 changes: 36 additions & 6 deletions python/PiFinder/camera_pi.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from typing import Tuple
import logging
from PiFinder.multiproclogging import MultiprocLogging
import numpy as np

logger = logging.getLogger("Camera.Pi")

Expand Down Expand Up @@ -48,26 +49,55 @@ 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})
self.camera.set_controls({"ExposureTime": self.exposure_time})
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
Expand Down

0 comments on commit 836d0d7

Please sign in to comment.