From 365d39da8fec048a43f6cf1c20698ccfb90acb5f Mon Sep 17 00:00:00 2001 From: Galoshi Date: Thu, 2 May 2024 11:56:43 +0200 Subject: [PATCH 1/3] Added timeout parameter to ImageClient and image_viewer.py example --- examples/image_viewer.py | 2 +- source/device/image_client.py | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/examples/image_viewer.py b/examples/image_viewer.py index 5582dbe..37f97e4 100644 --- a/examples/image_viewer.py +++ b/examples/image_viewer.py @@ -17,7 +17,7 @@ address = '192.168.0.69' # create grabber - image_client = ImageClient(address, 50010) + image_client = ImageClient(address=address, port=50010, timeout=None) # create figures figs = [image_client.make_figure(i) for i in range(image_client.number_images)] diff --git a/source/device/image_client.py b/source/device/image_client.py index da43a63..ed467d0 100644 --- a/source/device/image_client.py +++ b/source/device/image_client.py @@ -1,9 +1,8 @@ from __future__ import (absolute_import, division, print_function) from builtins import * -from ..pcic.client import O2x5xxPCICDevice -from ..static.formats import serialization_format -from ..static.configs import images_config -import binascii +from source.pcic import O2x5xxPCICDevice +from source.static.formats import serialization_format +from source.static.configs import images_config import struct import io import enum @@ -12,13 +11,18 @@ import matplotlib.image as mpimg import numpy as np + +SOCKET_TIMEOUT = 10 + + class ChunkType(enum.IntEnum): MONOCHROME_2D_8BIT = 251 JPEG_IMAGE = 260 + class ImageClient(O2x5xxPCICDevice): - def __init__(self, address, port): - super(ImageClient, self).__init__(address, port) + def __init__(self, address, port, timeout=SOCKET_TIMEOUT): + super(ImageClient, self).__init__(address=address, port=port, timeout=timeout) # disable all result output self.turn_process_interface_output_on_or_off(0) From c87a67719cc39ab037e3a22aee53bb9661022677 Mon Sep 17 00:00:00 2001 From: Galoshi Date: Thu, 2 May 2024 11:58:10 +0200 Subject: [PATCH 2/3] Modified I-command in PCIC client and extended create_rawimage_application.py example for grabbing uncompressed images --- examples/create_rawimage_application.py | 40 +++++++++++++++++++++---- source/pcic/client.py | 18 ++++++++--- source/static/formats.py | 7 +++++ 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/examples/create_rawimage_application.py b/examples/create_rawimage_application.py index 828f109..7becbe6 100644 --- a/examples/create_rawimage_application.py +++ b/examples/create_rawimage_application.py @@ -1,8 +1,11 @@ try: - from o2x5xx import O2x5xxRPCDevice + from o2x5xx import O2x5xxRPCDevice, O2x5xxDeviceV2 except ModuleNotFoundError: from source.rpc.client import O2x5xxRPCDevice + from source.device.client import O2x5xxDeviceV2 import sys +import matplotlib.pyplot as plt +import matplotlib.image if __name__ == '__main__': if len(sys.argv) > 1: @@ -22,11 +25,11 @@ with device.editProxy.editApplication(app_index=newApplicationIndex): print("Starting editing application with index: " + str(newApplicationIndex)) - device.application.Name = "My new application" + device.application.Name = "Application Uncompressed Image" print("Changed name of application: " + device.application.Name) - device.application.Description = "My new description" + device.application.Description = "Application for retrieving an uncompressed image" print("Changed description of application: " + device.application.Description) - device.application.TriggerMode = 2 # continuous trigger mode + device.application.TriggerMode = 2 # process interface trigger mode print("Trigger Mode {} set".format(device.application.TriggerMode)) # Setup of image001 @@ -39,7 +42,7 @@ device.imager.startCalculateAutofocus() print("End of calculating autofocus with recommended value(s): " + str( device.imager.getAutofocusDistances())) - device.imager.Name = "My new image001" + device.imager.Name = "Uncompressed Image" print("Changed name of image001: " + device.imager.Name) # Switch to uncompressed images @@ -50,3 +53,30 @@ print("Saving parameter consistent to memory for application: " + device.application.Name) device.switchApplication(applicationIndex=newApplicationIndex) print("Application with new index {} now active".format(newApplicationIndex)) + + # create device + print("Create O2x5xx V2 device.") + with O2x5xxDeviceV2(address) as device: + # Save 10 uncompressed images + for i in range(10): + print("Executing trigger.") + # device.pcic.execute_asynchronous_trigger() + trigger_result = device.pcic.execute_asynchronous_trigger() + if trigger_result != '*': + print(trigger_result) + sys.exit("Trigger failed!") + else: + _ = device.pcic.read_next_answer() + + print("Requesting last image...") + result = device.pcic.request_last_image_taken_deserialized(image_id=2, datatype="ndarray") + if result == "!": + print(result) + sys.exit("Request for last image failed!") + image_uncompressed = result[0][1] + + # Uncomment if you want to see the image + # plt.imshow(image_uncompressed, cmap='gray') + # plt.show() + # matplotlib.image.imsave(fname='image_uncompressed_{}.png'.format(str(i)), + # arr=image_uncompressed, cmap='gray') diff --git a/source/pcic/client.py b/source/pcic/client.py index c287da7..7f4029b 100644 --- a/source/pcic/client.py +++ b/source/pcic/client.py @@ -1,5 +1,6 @@ -from ..static.formats import error_codes, serialization_format +from ..static.formats import error_codes, serialization_format, ChunkType import matplotlib.image as mpimg +import numpy as np import binascii import socket import struct @@ -361,7 +362,8 @@ def request_last_image_taken(self, image_id=1): - (int) char string with exactly 9 digits as decimal number for the image data size in bytes. - (bytearray) image data / result data. The data is encapsulated in an image chunk. - ! No image available - | Wrong ID + | Wrong ID (Applications which transfer uncompressed images are + not able to transfer images as JPG and vise versa) - ? Invalid command length """ if str(image_id).isnumeric(): @@ -385,11 +387,14 @@ def request_last_image_taken_deserialized(self, image_id=1, datatype='ndarray'): - image data / result data. The data is encapsulated in an image chunk if bytes as datatype is selected. - ! No image available - | Wrong ID + | Wrong ID (Applications which transfer uncompressed images are + not able to transfer images as JPG and vise versa) - ? Invalid command length """ results = {} result = self.request_last_image_taken(image_id) + if str(result)[2:3] == "!": + return "!" length = int(result[:9].decode()) data = binascii.unhexlify(result[9:].hex()) counter = 0 @@ -406,9 +411,14 @@ def request_last_image_taken_deserialized(self, image_id=1, datatype='ndarray'): results.setdefault(counter, []).append(header) # append image image_hex = data[header['HEADER_SIZE']:header['CHUNK_SIZE']] - if datatype == 'ndarray': + chunk_type = int(header['CHUNK_TYPE']) + if datatype == 'ndarray' and ChunkType.JPEG_IMAGE: image = mpimg.imread(io.BytesIO(image_hex), format='jpg') results[counter].append(image) + elif image_id == 2 and chunk_type == ChunkType.MONOCHROME_2D_8BIT: + image = np.frombuffer(image_hex, dtype=np.uint8)\ + .reshape((header["IMAGE_HEIGHT"], header["IMAGE_WIDTH"])) + results[counter].append(image) elif datatype == 'bytes': results[counter].append(image_hex) else: diff --git a/source/static/formats.py b/source/static/formats.py index 6418301..0caf581 100644 --- a/source/static/formats.py +++ b/source/static/formats.py @@ -1,3 +1,5 @@ +import enum + # These are the error codes with the corresponding error message error_codes = { 000000000: "No error detected", @@ -78,3 +80,8 @@ 2: "external illumination shall be used", 3: "internal and external illumination shall be used together" } + + +class ChunkType(enum.IntEnum): + MONOCHROME_2D_8BIT = 251 + JPEG_IMAGE = 260 From f2247834615e6fe0fa846a68dc16ffb50526cc14 Mon Sep 17 00:00:00 2001 From: Galoshi Date: Thu, 2 May 2024 15:25:21 +0200 Subject: [PATCH 3/3] Fix in check of chunk type and code restructure for better readability --- source/device/image_client.py | 19 ++++++++++--------- source/pcic/client.py | 20 +++++++++++++------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/source/device/image_client.py b/source/device/image_client.py index ed467d0..ac20a89 100644 --- a/source/device/image_client.py +++ b/source/device/image_client.py @@ -1,12 +1,10 @@ from __future__ import (absolute_import, division, print_function) from builtins import * from source.pcic import O2x5xxPCICDevice -from source.static.formats import serialization_format +from source.static.formats import serialization_format, ChunkType from source.static.configs import images_config import struct import io -import enum -import array import matplotlib.pyplot as plt import matplotlib.image as mpimg import numpy as np @@ -15,11 +13,6 @@ SOCKET_TIMEOUT = 10 -class ChunkType(enum.IntEnum): - MONOCHROME_2D_8BIT = 251 - JPEG_IMAGE = 260 - - class ImageClient(O2x5xxPCICDevice): def __init__(self, address, port, timeout=SOCKET_TIMEOUT): super(ImageClient, self).__init__(address=address, port=port, timeout=timeout) @@ -93,10 +86,18 @@ def _deserialize_image_chunk(data): # append image image_hex = data[header['HEADER_SIZE']:header['CHUNK_SIZE']] chunk_type = int(header['CHUNK_TYPE']) + # check end decode image depending on chunk type if chunk_type == ChunkType.JPEG_IMAGE: + # Check that we have received chunk type JPEG_IMAGE + # Convert jpeg data to image data image = mpimg.imread(io.BytesIO(image_hex), format='jpg') + results[counter].append(image) elif chunk_type == ChunkType.MONOCHROME_2D_8BIT: - image = np.reshape(array.array('B', image_hex), (header['IMAGE_HEIGHT'], header['IMAGE_WIDTH'])) + # Check that we have received chunk type MONOCHROME_2D_8BIT + # Read pixel data and reshape to width/height + image = np.frombuffer(image_hex, dtype=np.uint8) \ + .reshape((header["IMAGE_HEIGHT"], header["IMAGE_WIDTH"])) + results[counter].append(image) else: image = None print("Unknown image chunk type", header['CHUNK_TYPE']) diff --git a/source/pcic/client.py b/source/pcic/client.py index 7f4029b..7c3b4b3 100644 --- a/source/pcic/client.py +++ b/source/pcic/client.py @@ -412,13 +412,19 @@ def request_last_image_taken_deserialized(self, image_id=1, datatype='ndarray'): # append image image_hex = data[header['HEADER_SIZE']:header['CHUNK_SIZE']] chunk_type = int(header['CHUNK_TYPE']) - if datatype == 'ndarray' and ChunkType.JPEG_IMAGE: - image = mpimg.imread(io.BytesIO(image_hex), format='jpg') - results[counter].append(image) - elif image_id == 2 and chunk_type == ChunkType.MONOCHROME_2D_8BIT: - image = np.frombuffer(image_hex, dtype=np.uint8)\ - .reshape((header["IMAGE_HEIGHT"], header["IMAGE_WIDTH"])) - results[counter].append(image) + # check end decode image depending on chunk type + if datatype == 'ndarray': + if chunk_type == ChunkType.JPEG_IMAGE: + # Check that we have received chunk type JPEG_IMAGE + # Convert jpeg data to image data + image = mpimg.imread(io.BytesIO(image_hex), format='jpg') + results[counter].append(image) + elif chunk_type == ChunkType.MONOCHROME_2D_8BIT: + # Check that we have received chunk type MONOCHROME_2D_8BIT + # Read pixel data and reshape to width/height + image = np.frombuffer(image_hex, dtype=np.uint8)\ + .reshape((header["IMAGE_HEIGHT"], header["IMAGE_WIDTH"])) + results[counter].append(image) elif datatype == 'bytes': results[counter].append(image_hex) else: