Only grab a JPEG from the stream to get scanning working

This commit is contained in:
jaknapper 2025-04-08 17:52:55 +01:00
parent d4247235e3
commit 574aa1c6c0

View file

@ -576,58 +576,8 @@ class SmartScanThing(Thing):
) as f:
json.dump(data, f, ensure_ascii=False, indent=4)
# We will capture images and process them with this function, defined once here.
# Most of the variables it needs will be "baked in" so the arguments are just the ones
# that change each iteration.
# We also pre-calculate a normalisation image based on the LST and white balance
raw_image = cam.capture_array(stream_name="raw")
# TODO: assert the image is 10-bit packed, or deal with other formats!
rgb = rggb2rgb(raw2rggb(raw_image))
lst = dict(cam.lens_shading_tables)
lum = np.array(lst["luminance"])
Cr = np.array(lst["Cr"])
Cb = np.array(lst["Cb"])
gr, gb = cam.colour_gains
G = 1 / lum
R = (
G / Cr / gr * np.min(Cr)
) # The extra /np.max(Cr) emulates the quirky handling of Cr in
B = G / Cb / gb * np.min(Cb) # the picamera2 pipeline
white_norm_lores = np.stack([R, G, B], axis=2)
zoom_factors = [
i / n for i, n in zip(rgb[..., :3].shape, white_norm_lores.shape)
]
white_norm = zoom(white_norm_lores, zoom_factors, order=1)[
: rgb.shape[0], : rgb.shape[1], :
] # Could use some work
colour_correction_matrix = np.array(cam.colour_correction_matrix).reshape(
(3, 3)
)
contrast_algorithm = cam.tuning["algorithms"][9]["rpi.contrast"]
gamma = np.array(contrast_algorithm["gamma_curve"]).reshape((-1, 2))
gamma_8bit = interp1d(gamma[:, 0] / 255, gamma[:, 1] / 255)
def process_raw_image(img):
normed = img / white_norm
corrected = np.dot(
colour_correction_matrix, normed.reshape((-1, 3)).T
).T.reshape(normed.shape)
corrected[corrected < 0] = 0
corrected[corrected > 255] = 255
return gamma_8bit(corrected)
logger.info(
f"Generated normalisation image with shape {white_norm.shape}, "
f"max {white_norm.max(axis=(0, 1))}, min {white_norm.min(axis=(0, 1))}"
)
norm_inputs = {
"luminance": lum,
"Cr": Cr,
"Cb": Cb,
"gain_red": gr,
"gain_blue": gb,
}
# This is the function we'll use to grab (or later capture) an image
# and save it with metadata
def capture_and_save(acquired: Event, name: str) -> None:
"""Capture an image and save it to disk
@ -636,38 +586,60 @@ class SmartScanThing(Thing):
"""
try:
capture_start = time.time()
metadata = metadata_getter()
raw_image = cam.capture_array(stream_name="raw")
image, metadata = capture_image()
acquired.set()
acquisition_time = time.time()
# Save the raw image
np.savez(
os.path.join(raw_images_folder, name + ".npz"),
raw_image=raw_image,
**norm_inputs,
)
# Process it into 8 bit RGB
processed = process_raw_image(rggb2rgb(raw2rggb(raw_image)))
processed[processed > 255] = 255
processed[processed < 0] = 0
img = Image.fromarray(processed.astype(np.uint8), mode="RGB")
img.save(
os.path.join(images_folder, name), quality=95, subsampling=0
)
exif_dict = piexif.load(os.path.join(images_folder, name))
exif_dict["Exif"][piexif.ExifIFD.UserComment] = json.dumps(
metadata
).encode("utf-8")
piexif.insert(
piexif.dump(exif_dict), os.path.join(images_folder, name)
)
save_capture(name, image, metadata)
save_time = time.time()
acquisition_duration = round(acquisition_time - capture_start, 1)
saving_duration = round(save_time - acquisition_time, 1)
logger.info(
f"Acquired {name} in {acquisition_time - capture_start:.1f}s then {save_time - acquisition_time:.1f}s saving to disk"
"Acquired {} in {}s then {}s saving to disk".format(
name, acquisition_duration, saving_duration
)
)
except Exception as e:
logger.error(
f"An error occurred while saving {name}: {e}", exc_info=e
"An error occurred while saving {}: {}".format(name, e),
exc_info=e,
)
def capture_image():
"""Capture an image in memory and return it with metadata
This will set the event `acquired` once the image has been acquired, so
that the stage may be moved while it's saved.
"""
try:
metadata = metadata_getter()
image = cam.capture_array()[..., :3]
return image, metadata
except Exception as e:
logger.error(
"An error occurred while capturing: {}".format(e), exc_info=e
)
return 0, 0
def save_capture(name, image, metadata):
try:
jpeg_path = os.path.join(images_folder, name)
PIL_image = Image.fromarray(image.astype("uint8"), "RGB").save(
jpeg_path, quality=95, subsampling=0
)
try:
exif_dict = piexif.load(os.path.join(images_folder, name))
exif_dict["Exif"][piexif.ExifIFD.UserComment] = json.dumps(
metadata
).encode("utf-8")
piexif.insert(
piexif.dump(exif_dict), os.path.join(images_folder, name)
)
except:
pass
except Exception as e:
logger.error(
"An error occurred while saving {}: {}".format(name, e),
exc_info=e,
)
# At the start of the loop, we simultaneously capture an image and move to the next scan point.