From 0ee90ed1d103668c63951e4b42118ca8d0b4eb08 Mon Sep 17 00:00:00 2001 From: Smith Date: Wed, 28 Aug 2024 14:09:23 -0600 Subject: [PATCH 1/8] Fixed typo. Added gain as option to live view mono basler example. --- example/camera_io/live_view_mono_Basler.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/example/camera_io/live_view_mono_Basler.py b/example/camera_io/live_view_mono_Basler.py index 590e73371..891e19bc4 100644 --- a/example/camera_io/live_view_mono_Basler.py +++ b/example/camera_io/live_view_mono_Basler.py @@ -12,7 +12,7 @@ def main(): parser = argparse.ArgumentParser( - prog='run_and_save_images_Basler_color', description='Shows live view from Basler monochrome camera.' + prog='live_view_mono_Basler', description='Shows live view from Basler monochrome camera.' ) parser.add_argument( 'camera_index', @@ -21,24 +21,29 @@ def main(): help='Camera index (0-indexed in order of camera serial number) to run.', ) parser.add_argument('--calibrate', action='store_true', help='calibrate camera exposure before capture') - parser.add_argument('-e', metavar='exposure', type=float, default=None, help='Camera exposure value') + parser.add_argument('-e', metavar='exposure', type=int, default=None, help='Camera exposure value') + parser.add_argument('-g', metavar='gain', type=int, default=None, help='Camera gain value') args = parser.parse_args() # Connect to camera cam = ImageAcquisitionMono(args.camera_index, 'Mono12') # Calibrate exposure and set frame rate - cam.frame_rate = 10 if args.calibrate: cam.calibrate_exposure() if args.e is not None: cam.exposure_time = args.e - print('Exposure time:', cam.exposure_time) - print('Frame rate:', cam.frame_rate) - print('Gain:', cam.gain) - print('') + if args.g is not None: + print(args.g) + cam.gain = args.g + + print('Exposure time range: ', cam.cap.ExposureTimeRaw.Min, '-', cam.cap.ExposureTimeRaw.Max) + print('Gain range: ', cam.cap.GainRaw.Min, '-', cam.cap.GainRaw.Max) + + print('Exposure time set:', cam.exposure_time) + print('Gain set:', cam.gain) # Show live view image LiveView(cam, highlight_saturation=False) From caf1f610867e954bbadaa7c1e04b3d91a1181d37 Mon Sep 17 00:00:00 2001 From: Smith Date: Wed, 28 Aug 2024 14:10:16 -0600 Subject: [PATCH 2/8] Created run and save images basler mono example. --- .../run_and_save_images_Basler_mono.py | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 example/camera_io/run_and_save_images_Basler_mono.py diff --git a/example/camera_io/run_and_save_images_Basler_mono.py b/example/camera_io/run_and_save_images_Basler_mono.py new file mode 100644 index 000000000..c92e5dea1 --- /dev/null +++ b/example/camera_io/run_and_save_images_Basler_mono.py @@ -0,0 +1,52 @@ +"""Example program that captures images from a 12 bit monochrome Basler +camera and saves the images in TIFF format. +""" + +import argparse +import imageio.v3 as imageio + +from opencsp.common.lib.camera.ImageAcquisition_DCAM_mono import ImageAcquisition + + +def main(): + parser = argparse.ArgumentParser( + prog='run_and_save_images_Basler_mono', + description='Captures N frames from a Basler camera. Saves images as 16 bit integers in TIFF format with filenames of the form: xx.tiff', + ) + parser.add_argument( + 'camera_index', type=int, help='Camera index (0-indexed in order of camera serial number) to run.' + ) + parser.add_argument('num_images', type=int, help='Number of images to capture and save.') + parser.add_argument('--calibrate', action='store_true', help='Calibrate camera exposure before capture.') + parser.add_argument( + '-p', + '--prefix', + metavar='prefix', + default='', + type=str, + help='Image save prefix to be appended before the filename.', + ) + args = parser.parse_args() + + # Connect to camera + cam = ImageAcquisition(args.camera_index, 'Mono12') + + # Calibrate exposure and set frame rate + if args.calibrate: + cam.calibrate_exposure() + + print('Exposure time:', cam.exposure_time) + print('Gain:', cam.gain) + + # Capture and save frames + for idx in range(args.num_images): + frame = cam.get_frame() + # Save by packing 12 bit image into 16 bit image + imageio.imwrite(f'{args.prefix}{idx:02d}.tiff', frame * 2**4) + + # Close camera + cam.close() + + +if __name__ == '__main__': + main() From f4511fbdb03e4819a4474e7bfbad63d06f135b49 Mon Sep 17 00:00:00 2001 From: Smith Date: Wed, 28 Aug 2024 14:10:49 -0600 Subject: [PATCH 3/8] Edited timeout and added multiple of 25 exposure rule for certain basler models. --- .../common/lib/camera/ImageAcquisition_DCAM_mono.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/opencsp/common/lib/camera/ImageAcquisition_DCAM_mono.py b/opencsp/common/lib/camera/ImageAcquisition_DCAM_mono.py index 27e7fd24c..c05c10394 100644 --- a/opencsp/common/lib/camera/ImageAcquisition_DCAM_mono.py +++ b/opencsp/common/lib/camera/ImageAcquisition_DCAM_mono.py @@ -75,7 +75,13 @@ def __init__(self, instance: int = 0, pixel_format: str = 'Mono8'): # Set exposure values to be stepped over when performing exposure calibration shutter_min = self.cap.ExposureTimeRaw.Min shutter_max = self.cap.ExposureTimeRaw.Max - self._shutter_cal_values = np.linspace(shutter_min, shutter_max, 2**13).astype(int) + + self._shutter_cal_values: np.ndarray = np.linspace(shutter_min, shutter_max, 2**13).astype(int) + + # Apply model-specific processing for Basler mono cameras + if devices[instance].GetModelName() == 'acA3088-16gm': + # If type acA3088-16gm, make sure shutter values are multiple of 25 + self._shutter_cal_values = (self._shutter_cal_values.astype(float) / 25).astype(int) * 25 @classmethod def _check_pypylon_version(cls): @@ -104,7 +110,9 @@ def instance_matches(self, possible_matches: list[ImageAcquisitionAbstract]) -> def get_frame(self) -> np.ndarray: # Start frame capture self.cap.StartGrabbingMax(1) - grabResult = self.cap.RetrieveResult(5000, pylon.TimeoutHandling_ThrowException) + grabResult = self.cap.RetrieveResult( + int(self.cap.ExposureTimeRaw.Max / 1000 * 1.5), pylon.TimeoutHandling_ThrowException + ) # Access image data if grabResult.GrabSucceeded(): From dd06e97f85e6ce86537644073fff9bb6cb21b72c Mon Sep 17 00:00:00 2001 From: Smith Date: Wed, 28 Aug 2024 14:11:04 -0600 Subject: [PATCH 4/8] Added more logging to iamge acq Abstract --- opencsp/common/lib/camera/ImageAcquisitionAbstract.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/opencsp/common/lib/camera/ImageAcquisitionAbstract.py b/opencsp/common/lib/camera/ImageAcquisitionAbstract.py index 25d212043..e1ede1f03 100644 --- a/opencsp/common/lib/camera/ImageAcquisitionAbstract.py +++ b/opencsp/common/lib/camera/ImageAcquisitionAbstract.py @@ -152,12 +152,14 @@ def _check_saturated(im): # Checks that the minimum value is under-exposed self.exposure_time = exposure_values[0] + lt.debug(f'Trying minimum exposure: {exposure_values[0]}') im = self.get_frame() if _check_saturated(im): lt.error_and_raise(ValueError, 'Minimum exposure value is too high; image still saturated.') # Checks that the maximum value is over-exposed self.exposure_time = exposure_values[-1] + lt.debug(f'Trying maximum exposure: {exposure_values[-1]}') im = self.get_frame() if not _check_saturated(im): lt.error_and_raise(ValueError, 'Maximum exposure value is too low; image not saturated.') From 538f360ea9ab4b6ea82e5b063e6c5a8ebfd17e40 Mon Sep 17 00:00:00 2001 From: Smith Date: Wed, 28 Aug 2024 14:15:10 -0600 Subject: [PATCH 5/8] Updated docs to run and save images basler mnoo --- example/camera_io/run_and_save_images_Basler_mono.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/camera_io/run_and_save_images_Basler_mono.py b/example/camera_io/run_and_save_images_Basler_mono.py index c92e5dea1..f57bed73e 100644 --- a/example/camera_io/run_and_save_images_Basler_mono.py +++ b/example/camera_io/run_and_save_images_Basler_mono.py @@ -1,5 +1,5 @@ """Example program that captures images from a 12 bit monochrome Basler -camera and saves the images in TIFF format. +camera and saves the images in TIFF format. Camera is run at minimum gain. """ import argparse From e9eba53605f4fe711a6d65e020744fc9bf90c9d3 Mon Sep 17 00:00:00 2001 From: Smith Date: Wed, 28 Aug 2024 14:16:31 -0600 Subject: [PATCH 6/8] Removed test line from live view mono Basler --- example/camera_io/live_view_mono_Basler.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/example/camera_io/live_view_mono_Basler.py b/example/camera_io/live_view_mono_Basler.py index 891e19bc4..cec800bc9 100644 --- a/example/camera_io/live_view_mono_Basler.py +++ b/example/camera_io/live_view_mono_Basler.py @@ -28,17 +28,18 @@ def main(): # Connect to camera cam = ImageAcquisitionMono(args.camera_index, 'Mono12') - # Calibrate exposure and set frame rate - if args.calibrate: - cam.calibrate_exposure() - + # Set exposure if args.e is not None: cam.exposure_time = args.e + # Set gain if args.g is not None: - print(args.g) cam.gain = args.g + # Calibrate exposure and set frame rate + if args.calibrate: + cam.calibrate_exposure() + print('Exposure time range: ', cam.cap.ExposureTimeRaw.Min, '-', cam.cap.ExposureTimeRaw.Max) print('Gain range: ', cam.cap.GainRaw.Min, '-', cam.cap.GainRaw.Max) From 9751fac7452414e71bcc9e078d72f14b00bc6003 Mon Sep 17 00:00:00 2001 From: Smith Date: Wed, 28 Aug 2024 14:17:15 -0600 Subject: [PATCH 7/8] Updated docs in live view mono basler --- example/camera_io/live_view_mono_Basler.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/example/camera_io/live_view_mono_Basler.py b/example/camera_io/live_view_mono_Basler.py index cec800bc9..00ddb9343 100644 --- a/example/camera_io/live_view_mono_Basler.py +++ b/example/camera_io/live_view_mono_Basler.py @@ -1,7 +1,4 @@ -""" -Example script that connects to and shows a live view from an -8 bit Basler monochrome camera. - +"""Example script that connects to and shows a live view from a 12 bit Basler monochrome camera. """ import argparse From e6455e92fd76f45eddf9948602f0c3c7d64dff47 Mon Sep 17 00:00:00 2001 From: Braden Date: Wed, 9 Oct 2024 16:27:56 -0600 Subject: [PATCH 8/8] Added docs to IA DCAM mono --- opencsp/common/lib/camera/ImageAcquisition_DCAM_mono.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/opencsp/common/lib/camera/ImageAcquisition_DCAM_mono.py b/opencsp/common/lib/camera/ImageAcquisition_DCAM_mono.py index c05c10394..36a33ec6c 100644 --- a/opencsp/common/lib/camera/ImageAcquisition_DCAM_mono.py +++ b/opencsp/common/lib/camera/ImageAcquisition_DCAM_mono.py @@ -110,9 +110,10 @@ def instance_matches(self, possible_matches: list[ImageAcquisitionAbstract]) -> def get_frame(self) -> np.ndarray: # Start frame capture self.cap.StartGrabbingMax(1) - grabResult = self.cap.RetrieveResult( - int(self.cap.ExposureTimeRaw.Max / 1000 * 1.5), pylon.TimeoutHandling_ThrowException - ) + exposure_time_ms = self.cap.ExposureTimeRaw.Max / 1000 # exposure time, ms + # Grab the frame + # After 1.5 times the expected image acquisition time, throw a pylon.TimeoutHandling_ThrowException + grabResult = self.cap.RetrieveResult(int(exposure_time_ms * 1.5), pylon.TimeoutHandling_ThrowException) # Access image data if grabResult.GrabSucceeded():