class TestHarvesterCoreBase(unittest.TestCase): _cti_file_path = get_cti_file_path() sys.path.append(_cti_file_path) def __init__(self, *args, **kwargs): # super().__init__(*args, **kwargs) # self._harvester = None self._ia = None self._thread = None self._logger = get_logger(name='harvesters', level=DEBUG) self._buffers = [] def setUp(self): # super().setUp() # self._harvester = Harvester(logger=self._logger) self._harvester.add_cti_file(self._cti_file_path) self._harvester.update_device_info_list() def tearDown(self): # if self.ia: self.ia.destroy() # self._harvester.reset() # self._ia = None # super().tearDown() @property def harvester(self): return self._harvester @property def ia(self): return self._ia @ia.setter def ia(self, value): self._ia = value @property def general_purpose_thread(self): return self._thread @general_purpose_thread.setter def general_purpose_thread(self, value): self._thread = value def is_running_with_default_target(self): return True if 'TLSimu.cti' in self._cti_file_path else False
class TestHarvesterCoreBase(unittest.TestCase): _path = 'C:/Users/z1533tel/dev/genicam/bin/Win64_x64/' \ if is_running_on_windows() else \ '/Users/kznr/dev/genicam/bin/Maci64_x64/' _filename = 'TLSimu.cti' sys.path.append(_path) def __init__(self, *args, **kwargs): # super().__init__(*args, **kwargs) # self._harvester = None self._iam = None self._thread = None def setUp(self): # super().setUp() # self._harvester = Harvester() self._harvester.add_cti_file(self._path + self._filename) self._harvester.update_device_info_list() self._iam = None self._thread = None def tearDown(self): # if self.iam: self.iam.destroy() # self._harvester.reset() # super().tearDown() @property def harvester(self): return self._harvester @property def iam(self): return self._iam @iam.setter def iam(self, value): self._iam = value @property def general_purpose_thread(self): return self._thread @general_purpose_thread.setter def general_purpose_thread(self, value): self._thread = value
def main(): h = Harvester() h.add_cti_file('C:/Program Files/JAI/SDK/bin/JaiGevTL.cti') # JaiUSB3vTL JaiGevTL print(h.cti_files) h.update_device_info_list() print("file", h.device_info_list) print("dty", list(dict.fromkeys(h.device_info_list))) # x = unique(h.device_info_list) # print("pp",x) print("devices end") ia = h.create_image_acquirer(0) print("dsssx", ia.device) print("infor", ia.device.node_map.device_info) # ia.device.node_map.Test # ia.device.node_mapdsx key.PixelFormat.value = 'RGB12' # ia.device.node_map.RGB12Packed.value = 'RGB12' # ia.device.node_map.has_node() # ia.device.node_map.TestPattern = 'HorizontalColorBar' # ia.acquirer.remote_device.node_map print(ia.is_acquiring()) try: print("acqui") ia.start_image_acquisition() print("acquired", ia.is_acquiring()) print("acqui 2", ia.fetch_buffer()) i = 0 done = False while not done: with ia.fetch_buffer() as buffer: print("checkr 1") img = buffer.payload.components[0].data img = img.reshape(buffer.payload.components[0].height, buffer.payload.components[0].width) # img_copy = img.copy() img_copy = cv2.cvtColor(img, cv2.COLOR_BayerRG2RGB) cv2.namedWindow("window", cv2.WINDOW_KEEPRATIO | cv2.WINDOW_NORMAL) cv2.imshow("window", img_copy) fps = ia.statistics.fps print("FPS: ", fps) if cv2.waitKey(10) == ord('q'): done = True print('break') i = i + 1 except Exception as e: traceback.print_exc(file=sys.stdout) finally: ia.stop_image_acquisition() ia.destroy() cv2.destroyAllWindows() print('fin') h.reset()
def camera_stream(): global outputFrame, lock h = Harvester() h.add_cti_file('/opt/mvIMPACT_Acquire/lib/x86_64/mvGenTLProducer.cti') h.update_device_info_list() ia = h.create_image_acquirer(0) #ia.device.node_map.PixelFormat.value = 'BayerRG8' #ia.device.node_map.TestPattern = 'HorizontalColorBar' try: ia.start_image_acquisition() i = 0 done = False while not done: with ia.fetch_buffer() as buffer: img = buffer.payload.components[0].data img = img.reshape( buffer.payload.components[0].height, buffer.payload.components[0].width) img_copy = img.copy() img_copy = cv2.cvtColor(img, cv2.COLOR_BayerRG2RGB) if i == 0: first = img_copy.copy() change = np.allclose(first, img_copy, 3) #print(change) if not change: # cv2.namedWindow("window", cv2.WINDOW_KEEPRATIO | cv2.WINDOW_NORMAL) # cv2.imshow("window", img_copy) #cv2.imwrite(f'./images/image_{i}.png', img_copy) outputFrame = img_copy.copy() print(outputFrame) first = img_copy.copy() if cv2.waitKey(10) == ord('q'): fps = ia.statistics.fps print("FPS: ", fps) done = True print('break') i = i + 1 if i == 500: break except Exception as e: traceback.print_exc(file=sys.stdout) finally: ia.stop_image_acquisition() ia.destroy() cv2.destroyAllWindows() print('fin') h.reset()
def run_camera(): # Create a Harvester object: h = Harvester() # Load a GenTL Producer; you can load many more if you want to: ##find producer h.add_file( 'C:\Program Files\Allied Vision\Vimba_4.2\VimbaGigETL\Bin\Win64\VimbaGigETL.cti' ) # Enumerate the available devices that GenTL Producers can handle: h.update() print(h.device_info_list) # Select a target device and create an ImageAcquire object that # controls the device: ia = h.create_image_acquirer(0) # Configure the target device; it looks very small but this is just # for demonstration: # ia.remote_device.node_map.Width.value = 1936 # ia.remote_device.node_map.Height.value = 1216 # ia.remote_device.node_map.PixelFormat.value = 'RGB8Packed' # Allow the ImageAcquire object to start image acquisition: ia.start_acquisition() # We are going to fetch a buffer filled up with an image: # Note that you'll have to queue the buffer back to the # ImageAcquire object once you consumed the buffer; the # with statement takes care of it on behalf of you: with ia.fetch_buffer() as buffer: # Let's create an alias of the 2D image component; it can be # lengthy which is not good for typing. In addition, note that # a 3D camera can give you 2 or more components: component = buffer.payload.components[0] # Reshape the NumPy array into a 2D array: image_rgb = component.data.reshape(component.height, component.width, 3) image_bgr = cv2.cvtColor(image_rgb, cv2.COLOR_RGB2BGR) # img_inference runs both models processing_time, boxes, scores, labels = img_inference(image_bgr) # Stop the ImageAcquier object acquiring images: ia.stop_acquisition() # We're going to leave here shortly: ia.destroy() h.reset()
def run(self): h = Harvester() h.add_file(self._cti_file_path) h.update() try: ia = h.create_image_acquirer(0) except: # Transfer the exception anyway: self._message_queue.put(sys.exc_info()) else: ia.start_acquisition() ia.stop_acquisition() ia.destroy() h.reset()
def main(unused_argv): if not create_output_dir( os.path.join(flags.FLAGS.local_data_dir, IMAGE_DIR_NAME)): print("Cannot create output annotations directory.") return use_s3 = True if flags.FLAGS.s3_bucket_name is not None else False if use_s3: if not s3_bucket_exists(flags.FLAGS.s3_bucket_name): use_s3 = False print( "Bucket: %s either does not exist or you do not have access to it" % flags.FLAGS.s3_bucket_name) else: print("Bucket: %s exists and you have access to it" % flags.FLAGS.s3_bucket_name) h = Harvester() h.add_cti_file(flags.FLAGS.gentl_producer_path) if len(h.cti_files) == 0: print("No valid cti file found at %s" % flags.FLAGS.gentl_producer_path) h.reset() return print("Currently available genTL Producer CTI files: ", h.cti_files) h.update_device_info_list() if len(h.device_info_list) == 0: print("No compatible devices detected.") h.reset() return print("Available devices List: ", h.device_info_list) print("Using device: ", h.device_info_list[0]) cam = h.create_image_acquirer(list_index=0) apply_camera_settings(cam) save_queue = queue.Queue() save_thread = threading.Thread(target=save_images, args=( save_queue, use_s3, )) save_thread.start() acquire_images(cam, save_queue) save_thread.join() # clean up cam.destroy() h.reset() print("Exiting.")
class Camera_harvester(Camera_template): def __init__(self, producer_paths=None): super(Camera_harvester, self).__init__() self.name = "Harvester" ##Harvester object used to communicate with Harvester module self.h = Harvester() ##paths to GenTL producers self.paths = [] if (producer_paths): for path in producer_paths: self.add_gentl_producer(path) ##Image acquifier object used by Harvester self.ia = None def get_camera_list(self, ): """!@brief Connected camera discovery @details Uses Harvester object to discover all connected cameras @return List of Dictionaries cantaining informations about cameras """ self.h.update() self.devices_info = [] for device in self.h.device_info_list: d = { 'id_': device.id_, 'model': device.model, 'vendor': device.vendor } self.devices_info.append(d) return self.devices_info def select_camera(self, selected_device): """!@brief choose camera to connect to @details Select camera you will be using and set Camera object accordingly @param[in] selected_device ID of a camera you want to connect to """ #translate selected device to index in harvester's device info list for index, camera in enumerate(self.devices_info): if camera['id_'] == selected_device: harvester_index = index break self.active_camera = harvester_index self.ia = self.h.create_image_acquirer(harvester_index) try: self.ia.remote_device.node_map.GevSCPSPacketSize.value = 1500 except: pass def get_parameters(self, feature_queue, flag, visibility=Config_level.Unknown): """!@brief Read parameters from camera @details Loads all available camera parameters @param[in] feature_queue each parameter's dictionary is put into this queue @param[in] flag used to signal that the method finished (threading object) @param[in] visibility Defines level of parameters that should be put in the queue @return True if success else False """ features = dir(self.ia.remote_device.node_map) for feature in features: if (feature.startswith('_')): continue try: feature_obj = getattr(self.ia.remote_device.node_map, feature).node feature = getattr(self.ia.remote_device.node_map, feature) #Some information is accessible through harvester feature, #for some information we need to go deeper into Genapi itself feat_acc = feature_obj.get_access_mode() except: continue #according to genicam standard #0 - not implemented #1 - not availablle #3 - write only #4 - read only #5 - read and write if (feat_acc == 0 or feat_acc == 1): continue feat_vis = feature_obj.visibility if (feat_vis < visibility): features_out = {} features_out['name'] = feature_obj.name #disp_name = feature.get_display_name() features_out['attr_name'] = feature_obj.display_name #Set feature's write mode try: if (feat_acc == 5 or feat_acc == 3): attr = False else: attr = True except: attr = None features_out['attr_enabled'] = attr #Get feature's type if it exists #intfIValue = 0 #: IValue interface #intfIBase = 1 #: IBase interface #intfIInteger = 2 #: IInteger interface #intfIBoolean = 3 #: IBoolean interface #intfICommand = 4 #: ICommand interface #intfIFloat = 5 #: IFloat interface #intfIString = 6 #: IString interface #intfIRegister = 7 #: IRegister interface #intfICategory = 8 #: ICategory interface #intfIEnumeration = 9 #: IEnumeration interface #ntfIEnumEntry = 10 #: IEnumEntry interface #intfIPort = 11 #: IPort interface try: attr = feature_obj.principal_interface_type if (attr == 2): attr = "IntFeature" elif (attr == 3): attr = "BoolFeature" elif (attr == 4): attr = "CommandFeature" elif (attr == 5): attr = "FloatFeature" elif (attr == 6): attr = "StringFeature" elif (attr == 9): attr = "EnumFeature" else: attr = None except: attr = None features_out['attr_type'] = attr features_out['attr_enums'] = None features_out['attr_cat'] = None #Get feature's value if it exists try: attr = feature.value except: attr = None features_out['attr_value'] = attr #Get feature's range if it exists try: attr = [feature.min, feature.max] except: attr = None features_out['attr_range'] = attr #Get feature's increment if it exists try: attr = feature.inc except: attr = None features_out['attr_increment'] = attr #Get feature's max length if it exists try: attr = feature.max_length except: attr = None features_out['attr_max_length'] = attr try: attr = feature_obj.tooltip except: attr = None features_out['attr_tooltip'] = attr feature_queue.put(features_out) flag.set() return def read_param_value(self, param_name): """!@brief Used to get value of one parameter based on its name @param[in] param_name Name of the parametr whose value we want to read @return A value of the selected parameter """ try: val = getattr(self.ia.remote_device.node_map, param_name).value return val except: return None def set_parameter(self, parameter_name, new_value): """!@brief Method for setting camera's parameters @details Sets parameter to value defined by new_value @param[in] parameter_name A name of the parameter to be changed @param[in] new_value Variable compatible with value key in parameter @return True if success else returns False """ try: getattr(self.ia.remote_device.node_map, parameter_name).value = new_value except: return False def execute_command(self, command_feature): """@brief Execute command feature type @param[in] command_feature Name of the selected command feature """ try: getattr(self.ia.remote_device.node_map, command_feature).execute() except: pass def get_single_frame(self, ): """!@brief Grab single frame from camera @return Unmodified frame from camera """ self.ia.start_acquisition() with self.ia.fetch_buffer() as buffer: frame = buffer.payload.components[0] pixel_format = self.ia.remote_device.node_map.PixelFormat.value return [frame.data, pixel_format] self.ia.stop_acquisition() def load_config(self, path): """!@brief Load existing camera configuration @param[in] path Defines a path and a name of the file containing the configuration of the camera @return True if success else False """ param = {} val = None attr_type = None with open(path, 'r') as config: config_dense = (line for line in config if line) for line in config_dense: line = line.rstrip('\n') if line.startswith('attr_value') and param: val = line.split('=') if (attr_type[1] == 'IntFeature'): self.set_parameter(param, int(val[1])) elif (attr_type[1] == 'FloatFeature'): self.set_parameter(param, float(val[1])) elif (attr_type[1] == 'EnumFeature'): self.set_parameter(param, val[1]) elif (attr_type[1] == 'BoolFeature'): if (val[1] == 'True'): self.set_parameter(param, True) else: self.set_parameter(param, False) elif (attr_type[1] == 'StringFeature'): self.set_parameter(param, val[1]) val = None param.clear() attr_type = None elif line.startswith('attr_type') and param: attr_type = line.split('=') elif line.startswith('name'): param['name'] = line.split('=')[1] val = None return True def save_config(self, path): """!@brief Saves configuration of a camera to .xml file @param[in] path A path where the file will be saved """ #At the time of writing this code not Harvester nor genapi for Python #supported saving .xml config, so the format of saved data created #here is nonstandard and simplified for now. #More here https://github.com/genicam/harvesters/issues/152 parameters = queue.Queue() tmp_flag = threading.Event() self.get_parameters(parameters, tmp_flag, Config_level.Invisible) with open(path, 'w') as config: while not parameters.empty(): param = parameters.get_nowait() for key, val in param.items(): config.write(key + "=" + str(val) + '\n') config.write('\n') def _frame_producer(self): """!@brief Gets frames from camera while continuous acquisition is active @details Loads frames from camera as they come and stores them in a frame queue for consumer thread to process. The thread runs until stream_stop_switch is set """ self.ia.start_acquisition() while (not self._stream_stop_switch.is_set()): with self.ia.fetch_buffer() as buffer: frame = buffer.payload.components[0] pixel_format = self.ia.remote_device.node_map.PixelFormat.value global_queue.frame_queue[self.cam_id].put_nowait( [frame.data.copy(), pixel_format]) #data should contain numpy array which should be compatible #with opencv image ig not do some conversion here self.ia.stop_acquisition() def disconnect_camera(self): """!@brief Disconnect camera and restores the object to its initial state""" self.stop_recording() self.disconnect_harvester() global_queue.remove_frame_queue(self.cam_id) self.__init__() #______________Unique methods___________________ def disconnect_harvester(self, ): """!@brief Destroys harvester object so other APIs can access cameras """ self.h.reset() def add_gentl_producer(self, producer_path): """!@brief Add a new frame producer to the harvester object @details Adds .cti file specified by producer_path to the harvester object @param[in] producer_path Path to a .cti file @return list of all active producers """ if (not producer_path in self.paths): if (producer_path.endswith(".cti")): self.h.add_file(producer_path) self.paths.append(producer_path) return self.paths def remove_gentl_producer(self, producer_path): """!@brief Remove existing frame producer from the harvester object @details Removes .cti file specified by producer_path from the harvester object @param[in] producer_path Path to a .cti file @return tuple of a list of remaining gentl producers and boolean value signaling whether the removal was succesful """ if (producer_path in self.paths): self.paths.remove(producer_path) self.h.remove_file(producer_path) return (self.paths, True) else: return (None, False) def get_gentl_producers(self): """!@brief Used to get a list of all path used by Harvesters in a present moment @return List of defined cti file paths """ return self.paths
class TestHarvesterCoreBase(unittest.TestCase): name = 'HARVESTER_TEST_TARGET' if name in os.environ: _cti_file = os.getenv(name) else: if is_running_on_windows(): _cti_file = 'C:/Users/z1533tel/dev/genicam/bin/Win64_x64' else: if is_running_on_macos(): _cti_file = '/Users/kznr/dev/genicam/bin/Maci64_x64' else: _cti_file = '/home/vagrant/dev/genicam/bin/Linux64_x64' _cti_file += '/TLSimu.cti' sys.path.append(_cti_file) def __init__(self, *args, **kwargs): # super().__init__(*args, **kwargs) # self._harvester = None self._ia = None self._thread = None self._logger = get_logger(name='harvesters', level=DEBUG) def setUp(self): # super().setUp() # self._harvester = Harvester(logger=self._logger) self._harvester.add_cti_file(self._cti_file) self._harvester.update_device_info_list() def tearDown(self): # if self.ia: self.ia.destroy() # self._harvester.reset() # self._ia = None # super().tearDown() @property def harvester(self): return self._harvester @property def ia(self): return self._ia @ia.setter def ia(self, value): self._ia = value @property def general_purpose_thread(self): return self._thread @general_purpose_thread.setter def general_purpose_thread(self, value): self._thread = value def is_running_with_default_target(self): return True if 'TLSimu.cti' in self._cti_file else False
class Camera: def __init__(self): self.connection_exceptions = () self.__harv = Harvester() self.__img_cap = None pass def connect(self): try: self.__harv.add_file('/usr/lib/ids/cti/ids_gevgentl.cti') self.__harv.update() except Exception as e: print(e) pass def disconnect(self): self.__img_cap.destroy() self.__harv.reset() pass def initialize(self): try: self.__img_cap = self.__harv.create_image_acquirer(list_index=0) self.__img_cap.remote_device.node_map.PixelFormat.value = 'Mono8' except Exception as e: print(e) pass def capture(self) -> str: try: # Start acquisition self.__img_cap.start_acquisition() with self.__img_cap.fetch_buffer() as buffer: component = buffer.payload.components[0] # reshape to a 2D array _2d = component.data.reshape(component.height, component.width) # Stop acquisition self.__img_cap.stop_acquisition() # SERIALIZE _2d _2d_bytes = pickle.dumps(_2d) encoded = base64.b64encode(_2d_bytes) print(_2d) print(_2d_bytes) print(encoded) # MUST RETURN A JSON STRING AS: image = { "filename": "my_image{}".format(randrange(2000)), "image": encoded.decode('ascii') } # To consume #decoded = base64.b64decode(image['image']) #_2d_loaded = pickle.loads(decoded) #print(decoded) #print(_2d_loaded) return json.dumps(image) except Exception as e: print(e) return None def configure(self, parameters): pass
class TestTutorials2(unittest.TestCase): def setUp(self) -> None: # The following block is just for administrative purpose; # you should not include it in your code: self.cti_file_path = get_cti_file_path() if 'TLSimu.cti' not in self.cti_file_path: self.skipTest('The target is not TLSimu.') # Create a Harvester object: self.harvester = Harvester() def tearDown(self) -> None: # self.harvester.reset() def test_traversable_tutorial(self): # Add a CTI file path: self.harvester.add_file(self.cti_file_path) self.harvester.update() # Connect to the first camera in the list: ia = self.harvester.create_image_acquirer(0) # num_images_to_acquire = 0 # Then start image acquisition: ia.start_acquisition() while num_images_to_acquire < 100: # with ia.fetch_buffer() as buffer: # self.do_something(buffer) pass num_images_to_acquire += 1 # We don't need the ImageAcquirer object. Destroy it: ia.destroy() def test_ticket_127(self): # self.harvester.add_cti_file(self.cti_file_path) self.harvester.remove_cti_file(self.cti_file_path) # self.harvester.add_cti_file(self.cti_file_path) self.harvester.remove_cti_files() # self.harvester.add_cti_file(self.cti_file_path) self.assertIsNotNone(self.harvester.cti_files) # self.harvester.update_device_info_list() # Connect to the first camera in the list: ia = self.harvester.create_image_acquirer(0) # ia.start_image_acquisition() self.assertTrue(ia.is_acquiring_images()) ia.stop_image_acquisition() self.assertFalse(ia.is_acquiring_images())
# buffer = ia.fetch_buffer(timeout=5) #time.sleep(1) payload = buffer.payload component = payload.components[0] width = component.width height = component.height data_format = component.data_format # # Reshape the image so that it can be drawn on the VisPy canvas: if data_format in mono_location_formats: content = component.data.reshape(height, width) print(content) png.from_array(content,'L').save("img.png") # png.from_array(_2d,'L').save("img.png") buffer.queue() # buffer = ia.fetch_buffer() # print(buffer+"second attempt") ia.stop_acquisition() ia.destroy() h.reset()
def main(unused_argv): use_s3 = True if flags.FLAGS.s3_bucket_name is not None else False if use_s3: if not s3_bucket_exists(flags.FLAGS.s3_bucket_name): use_s3 = False print( "Bucket: %s either does not exist or you do not have access to it" % flags.FLAGS.s3_bucket_name ) else: print( "Bucket: %s exists and you have access to it" % flags.FLAGS.s3_bucket_name ) if use_s3: # Get the newest model s3_download_highest_numbered_file( flags.FLAGS.s3_bucket_name, "/".join([flags.FLAGS.s3_data_dir, MODEL_STATE_DIR_NAME]), os.path.join(flags.FLAGS.local_data_dir, MODEL_STATE_DIR_NAME), MODEL_STATE_FILE_TYPE, flags.FLAGS.network, ) label_file_path = os.path.join(flags.FLAGS.local_data_dir, LABEL_FILE_NAME) if not os.path.isfile(label_file_path): print("Missing file %s" % label_file_path) return # read in the category labels labels = open(label_file_path).read().splitlines() if len(labels) == 0: print("No label categories found in %s" % label_file_path) return # Add the background as the first class labels.insert(0, "background") print("Labels found:") print(labels) saved_model_file_path = ( flags.FLAGS.model_path if flags.FLAGS.model_path is not None else get_newest_saved_model_path( os.path.join(flags.FLAGS.local_data_dir, MODEL_STATE_DIR_NAME), flags.FLAGS.network, ) ) if saved_model_file_path is None: print("No saved model state found") return h = Harvester() h.add_cti_file(flags.FLAGS.gentl_producer_path) if len(h.cti_files) == 0: print("No valid cti file found at %s" % flags.FLAGS.gentl_producer_path) h.reset() return print("Currently available genTL Producer CTI files: ", h.cti_files) h.update_device_info_list() if len(h.device_info_list) == 0: print("No compatible devices detected.") h.reset() return print("Available devices List: ", h.device_info_list) print("Using device: ", h.device_info_list[0]) cam = h.create_image_acquirer(list_index=0) apply_camera_settings(cam) display_images(cam, labels, saved_model_file_path) # clean up cam.destroy() h.reset() print("Exiting.")
def generate(previewName): """Video streaming generator function.""" if previewName == 'harvesters': h = Harvester() h.add_cti_file('/opt/mvIMPACT_Acquire/lib/x86_64/mvGenTLProducer.cti') h.update_device_info_list() ia = h.create_image_acquirer(0) ia.remote_device.node_map.ExposureTimeRaw.value = 20_000 #ia.dremote_deviceevice.node_map.PixelFormat.value = 'BayerRG8' #ia.remote_device.node_map.TestPattern = 'HorizontalColorBar' time.sleep(1) try: ia.start_image_acquisition() i = 0 done = False while not done: with ia.fetch_buffer() as buffer: img = buffer.payload.components[0].data img = img.reshape(buffer.payload.components[0].height, buffer.payload.components[0].width) img_copy = img.copy() img_copy = cv2.cvtColor(img, cv2.COLOR_BayerRG2RGB) if i == 0: first = img_copy.copy() is_change = np.allclose(first, img_copy, 3) #print(is_change) if not is_change: # cv2.namedWindow("window", cv2.WINDOW_KEEPRATIO | cv2.WINDOW_NORMAL) # cv2.imshow("window", img_copy) # cv2.imwrite(f'./images/image_{i}.png', img_copy) img_copy_ = cv2.resize(img_copy, (640, 480)) frame = cv2.imencode('.jpg', img_copy_)[1].tobytes() yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n') first = img_copy.copy() if cv2.waitKey(10) == ord('q'): fps = ia.statistics.fps print("FPS: ", fps) done = True print('break') i = i + 1 # if i == 200: # break except Exception as e: traceback.print_exc(file=sys.stdout) finally: ia.stop_image_acquisition() ia.destroy() print('fin') h.reset() else: cap = cv2.VideoCapture(0) # Read until video is completed while (cap.isOpened()): # Capture frame-by-frame ret, img = cap.read() if ret == True: img = cv2.resize(img, (0, 0), fx=1, fy=1) frame = cv2.imencode('.jpg', img)[1].tobytes() yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n') time.sleep(0.001) else: break
class ImageAcquirer: # Storage for camera modules GigE = [] # Maximum fetch tries until reconnect and abort fetchTimeout = None fetchSoftReboot = None fetchAbort = None cv2 = None np = None # Function runs when initializing class def __init__(self, SetCameraLighting, Config_module=None, Warnings_module=None): # Misc from time import sleep import sys self.sleep = sleep self.warnings = Warnings_module self.sys = sys # Store custom module self.FileConfig = Config_module # Lights function self.SetCameraLighting = SetCameraLighting # GenICam helper from harvesters.core import Harvester, TimeoutException # Init harvester self.harvester = Harvester() self.TimeoutException = TimeoutException # Temperature self.criticalTemp = self.FileConfig.Get( "Cameras")["Generic"]["Temperature"]["Critical"] self.warningTemp = self.FileConfig.Get( "Cameras")["Generic"]["Temperature"]["Warning"] # Storage for camera modules self.n_camera = self.FileConfig.Get("QuickSettings")["ActiveCameras"] self.ImportCTI() # import cti file self.Scan() # check if producer is available self.Create() # define image Acquirer objects from discovered devices self.Config() # configure image acquirer objects self.ImportOpenCV() # Create opencv module # Import cti file from GenTL producer def ImportCTI(self): # path to GenTL producer CTIPath = self.FileConfig.Get("Cameras")["Generic"]["CTIPath"] from os import path if path.isfile(CTIPath): self.harvester.add_file(CTIPath) else: print( "\nCould not find the GenTL producer for GigE\nCheck the file path given in VQuIT_config.json>Cameras>Generic>CTIPath" ) self.sys.exit(1) def ImportOpenCV(self): if self.cv2 is None: print("Importing OpenCV") import cv2 self.cv2 = cv2 return self.cv2 def ImportNumpy(self): if self.np is None: print("Importing Numpy") import numpy as np self.np = np return self.np # Scan for available producers def Scan(self): tries = 100 for i in range(0, tries): self.harvester.update() foundDevices = len(self.harvester.device_info_list) print('Scanning for available cameras... ' + str(foundDevices) + " of " + str(self.n_camera) + " (Attempt " + str(i + 1) + " of " + str(tries) + ")", end='\r') if foundDevices >= self.n_camera: break self.sleep(1) if len(self.harvester.device_info_list) < self.n_camera: print("Error: Found ", len(self.harvester.device_info_list), " of ", self.n_camera, "requested producers in network") self.sys.exit(1) # print(self.harvester.device_info_list) # Show details of connected devices # Create image acquirer objects def Create(self): cameraInfo = self.FileConfig.Get("Cameras")["Advanced"] for i in range(0, self.n_camera): try: # Create camera instances in order written in VQuIT_Config.json>Cameras>Advanced newIA = self.harvester.create_image_acquirer( id_=cameraInfo[i]["ID"]) self.GigE.append(newIA) except: print( "Error: ID '" + str(cameraInfo[i]["ID"]) + "' not found\nMake sure no other instances are connected to the cameras" ) exit() # Configure image acquirer objects def Config(self): # Load configuration file (Use ["Description"] instead of ["Value"] to get a description of said parameter) qs = self.FileConfig.Get("QuickSettings") c = self.FileConfig.Get("Cameras") cameraInfo = c["Advanced"] imgFormat = c["Generic"]["ImageFormatControl"] acquisition = c["Generic"]["AcquisitionControl"] transport = c["Generic"]["TransportLayerControl"] trigger = c["Generic"]["TimedTriggered_Parameters"] fetchError = c["Generic"]["FetchError"] # Maximum fetch tries per camera self.fetchTimeout = fetchError["Timeout"] self.fetchSoftReboot = fetchError["SoftReboot"] self.fetchAbort = fetchError["Abort"] # Jumbo packets jumboPackets = qs["JumboPackets"] if jumboPackets: print("Jumbo packets Active\n") packetSize = transport["GevSCPSPacketSize"]["Value"][0] else: print("\r") self.warnings.warn( "Running script without jumbo packets can cause quality and reliability issues" ) self.sleep(0.2) packetSize = transport["GevSCPSPacketSize"]["Value"][1] # Binning binning = qs["Binning"] if binning: print("Binning Active") imgWidth = int(imgFormat["Resolution"]["Width"] / 4) imgHeight = int(imgFormat["Resolution"]["Height"] / 4) binningType = imgFormat["BinningType"]["Value"][1] else: imgWidth = imgFormat["Resolution"]["Width"] imgHeight = imgFormat["Resolution"]["Height"] binningType = imgFormat["BinningType"]["Value"][0] # Set standard camera parameters for cameraID in range(0, len(self.GigE)): print("Setting up camera " + cameraInfo[cameraID]["Camera"] + "...", end="\r") # ImageFormatControl self.GigE[ cameraID].remote_device.node_map.PixelFormat.value = imgFormat[ "PixelFormat"]["Value"][0] self.GigE[ cameraID].remote_device.node_map.Binning.value = binningType self.GigE[cameraID].remote_device.node_map.ReverseX.value = False self.GigE[cameraID].remote_device.node_map.ReverseY.value = False # AcquisitionControl self.GigE[ cameraID].remote_device.node_map.ExposureMode.value = acquisition[ "ExposureMode"]["Value"][0] # TransportLayerControl self.GigE[ cameraID].remote_device.node_map.GevSCPSPacketSize.value = packetSize # Stock: 1060 | recommended 8228 # TimedTriggered parameters self.GigE[ cameraID].remote_device.node_map.FrameAverage.value = trigger[ "FrameAverage"]["Value"] self.GigE[ cameraID].remote_device.node_map.MultiExposureNumber.value = trigger[ "MultiExposureNumber"]["Value"] self.GigE[cameraID].remote_device.node_map.MultiExposureInactiveRaw.value = \ trigger["MultiExposureInactive"][ "Value"] # Not in use # AcquisitionPeriod (Integration time - irrelevant when using TimedTriggered) # value: microseconds (min: 102775 µs @4096 x 3008 - BayerRG8 - Binning Disabled (Max frame rate 9.73 Hz) , max: 60s) # Set resolution self.SetROI(imgHeight, imgWidth) # Start image acquisition def Start(self): print("\nStart image acquisition\n") for i in range(0, len(self.GigE)): self.GigE[i].start_acquisition() # Set Region Of Interest resolution and center resulting image (very experimental) def SetROI(self, height, width, disableAcquisition=None): # Check if height and width are valid heightMax = 3000 # Absolute max 3008 widthMax = 3072 # Absolute max 4096 if height <= heightMax and width <= widthMax: # Increment height and width until a valid combination (for which the pixel area is dividable by 4096) is found # (not fool proof but work with most decent aspect ratios that increment with 100) self.warnings.warn( "Dynamic ROI is still an experimental feature and can cause errors" ) rightValue = False heightMaxReached = False while not rightValue: # Try height and width if ((height * width) % 4096) == 0: rightValue = True else: # Try height + 1 and width height += 1 if height > heightMax: heightMaxReached = True height = heightMax if ((height * width) % 4096) == 0: rightValue = True else: # Try height and width + 1 if heightMaxReached is False: height -= 1 width += 1 if width > widthMax: width = widthMax if ((height * width) % 4096) == 0: rightValue = True else: # Set height + 1 and width + 1 and run loop again height += 1 if height > heightMax: heightMaxReached = True height = heightMax print("Dynamic ROI calculator result: " + str(width) + "x" + str(height)) # Change settings for all available cameras for cameraID in range(0, len(self.GigE)): # Check if requested resolution does not exceed the max for each camera widthMax = self.GigE[ cameraID].remote_device.node_map.WidthMax.value heightMax = self.GigE[ cameraID].remote_device.node_map.HeightMax.value widthMin = 512 heightMin = 512 # Check boundaries if width in range(widthMin, (widthMax + 1)) and height in range( heightMin, (heightMax + 1)): # Image acquisition cannot be on when changing this setting if disableAcquisition is True: self.GigE[cameraID].stop_acquisition() # Set width and height self.GigE[cameraID].remote_device.node_map.Width.value = width self.GigE[ cameraID].remote_device.node_map.Height.value = height # Set offsets offsetX = round((widthMax - width) / 2) offsetY = round((widthMax - width) / 2) self.GigE[ cameraID].remote_device.node_map.OffsetX.value = offsetX self.GigE[ cameraID].remote_device.node_map.OffsetY.value = offsetY # Turn image acquisition back on if disableAcquisition is True: self.GigE[cameraID].start_acquisition() else: raise ValueError("Requested ROI (" + str(width) + "x" + str(height) + ") must lie between " + str(widthMin) + "x" + str(heightMin) + " and " + str(widthMax) + "x" + str(heightMax) + " for camera " + str(cameraID)) def SetCameraConfig(self, productInfo): # Stop image acquisition to make changes self.Stop() # Set configuration for all cameras based on acode of product for cameraID in range(0, len(self.GigE)): if (cameraID % 2) == 0: # Camera number is even -> bottom camera cameraPosition = "BottomCameras" else: # Top camera cameraPosition = "TopCameras" cameraConfig = productInfo["Configuration"][cameraPosition] self.camConfig(cameraID, exposure=cameraConfig["ExposureTime"], gain=cameraConfig["Gain"], blackLevel=cameraConfig["BlackLevel"]) # Set ROI self.SetROI(2560, 2560) # Restart image acquisition after changes are made self.Start() # self.data_Top_Lighting = [] # for lights in cameraConfig["Lighting"]["U"]: # self.data_Top_Lighting.append(lights) # for lights in cameraConfig["Lighting"]["D"]: # self.data_Top_Lighting.append(lights) # Tweak camera settings on the go def camConfig(self, camNr, exposure=None, gain=None, blackLevel=None): if exposure: self.GigE[ camNr].remote_device.node_map.ExposureTimeRaw.value = exposure if gain: self.GigE[camNr].remote_device.node_map.GainRaw.value = gain if blackLevel: self.GigE[ camNr].remote_device.node_map.BlackLevelRaw.value = blackLevel # Retrieve camera data def RequestFrame(self, camNr): cv2 = self.ImportOpenCV() # Loop process until successful loop = 0 fetchImage = True while fetchImage: loop += 1 try: if loop > 1 and (loop % 2) is not 0: # Wait before sending new trigger every odd try that is not the first self.sleep(0.5) # Turn on lights self.SetCameraLighting(camNr, 1) # Trigger camera self.GigE[ camNr].remote_device.node_map.TriggerSoftware.execute() # Wait for buffer until timeout print("Camera " + str(camNr) + ": Fetch buffer (try " + str(loop) + ")...", end='\r') with self.GigE[camNr].fetch_buffer( timeout=self.fetchTimeout) as buffer: print("Camera " + str(camNr) + ": Fetched (try " + str(loop) + ")", end='\r') # access the image payload component = buffer.payload.components[0] if component is not None: image = component.data.reshape(component.height, component.width) # Turn off lights self.SetCameraLighting(camNr, 0) # BayerRG -> RGB (Does not work proper when image is already scaled down) image = cv2.cvtColor(image, cv2.COLOR_BayerRG2RGB) # Transpose + flip to rotate fetched images by +-90 deg image = cv2.transpose(image) if camNr % 2 == 0: # Flip x to rotate bottom cameras -90 deg flipCode = 0 else: # Flip y to rotate top cameras +90 deg flipCode = 1 image = cv2.flip(image, flipCode=flipCode) return image except self.TimeoutException: print("Camera " + str(camNr) + ": Fetch timeout (try " + str(loop) + ")") except KeyboardInterrupt: print("Camera " + str(camNr) + ": Fetch interrupted by user (try " + str(loop) + ")") # except: # print("Camera " + str(camNr) + ": Unexpected error (try " + str(loop) + ")") if loop >= self.fetchSoftReboot: print("Camera" + str(camNr) + ": Failed...trying soft reboot (try " + str(loop) + ")") self.SoftReboot() if loop >= self.fetchAbort: print("Check camera" + str(camNr) + ": Too manny tries (try " + str(loop) + " of " + str(self.fetchAbort) + ")") fetchImage = False # Something went wrong return False # Get camera temperature def getTemperature(self, camNr): return float( self.GigE[camNr].remote_device.node_map.DeviceTemperatureRaw.value / 100) # Return thermal performance of the camera def thermalCondition(self): for i in range(0, self.n_camera): temp = self.getTemperature(i) if temp > self.criticalTemp: self.warnings.warn("Camera temperature critical") return "Critical" elif temp > self.warningTemp: self.warnings.warn("Camera temperature above " + str(self.warningTemp)) return "Warning" return "Normal" # Get camera features def getCameraAttributes(self): return dir(self.GigE[0].remote_device.node_map) # Stop image acquisition def Stop(self): print("Stop image acquisition") for i in range(0, len(self.GigE)): self.GigE[i].stop_acquisition() # Stop image acquisition def Destroy(self): print("Destroy image acquire objects") for i in range(0, len(self.GigE)): self.GigE[i].destroy() # Reset harvester def Reset(self): self.harvester.reset() # Soft reboot def SoftReboot(self): self.Stop() self.Start()
class Harvester(QMainWindow): # _signal_update_statistics = pyqtSignal(str) _signal_stop_image_acquisition = pyqtSignal() def __init__(self, *, vsync=True, logger=None): # self._logger = logger or get_logger(name='harvesters') # super().__init__() # self._mutex = QMutex() profile = True if 'HARVESTER_PROFILE' in os.environ else False self._harvester_core = HarvesterCore(profile=profile, logger=self._logger) self._ia = None # Image Acquirer # self._widget_canvas = Canvas2D(vsync=vsync) self._widget_canvas.create_native() self._widget_canvas.native.setParent(self) # self._action_stop_image_acquisition = None # self._observer_widgets = [] # self._widget_device_list = None self._widget_status_bar = None self._widget_main = None self._widget_about = None self._widget_attribute_controller = None # self._signal_update_statistics.connect(self.update_statistics) self._signal_stop_image_acquisition.connect( self._stop_image_acquisition) self._thread_statistics_measurement = _PyQtThread( parent=self, mutex=self._mutex, worker=self._worker_update_statistics, update_cycle_us=250000) # self._initialize_widgets() # for o in self._observer_widgets: o.update() def _stop_image_acquisition(self): self.action_stop_image_acquisition.execute() def update_statistics(self, message): self.statusBar().showMessage(message) def closeEvent(self, QCloseEvent): # if self._widget_attribute_controller: self._widget_attribute_controller.close() # if self._harvester_core: self._harvester_core.reset() def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): self._harvester_core.reset() @property def canvas(self): return self._widget_canvas @property def attribute_controller(self): return self._widget_attribute_controller @property def about(self): return self._widget_about @property def version(self): return self.harvester_core.version @property def device_list(self): return self._widget_device_list @property def cti_files(self): return self.harvester_core.cti_files @property def harvester_core(self): return self._harvester_core def _initialize_widgets(self): # self.setWindowIcon(Icon('genicam_logo_i.png')) # self.setWindowTitle('GenICam.Harvester') self.setFont(get_system_font()) # self.statusBar().showMessage('') self.statusBar().setFont(get_system_font()) # self._initialize_gui_toolbar(self._observer_widgets) # self.setCentralWidget(self.canvas.native) # self.resize(800, 600) # Place it in the center. rectangle = self.frameGeometry() coordinate = QDesktopWidget().availableGeometry().center() rectangle.moveCenter(coordinate) self.move(rectangle.topLeft()) def _initialize_gui_toolbar(self, observers): # group_gentl_info = self.addToolBar('GenTL Information') group_connection = self.addToolBar('Connection') group_device = self.addToolBar('Image Acquisition') group_display = self.addToolBar('Display') group_help = self.addToolBar('Help') # Create buttons: # button_select_file = ActionSelectFile( icon='open_file.png', title='Select file', parent=self, action=self.action_on_select_file, is_enabled=self.is_enabled_on_select_file) shortcut_key = 'Ctrl+o' button_select_file.setToolTip( compose_tooltip('Open a CTI file to load', shortcut_key)) button_select_file.setShortcut(shortcut_key) button_select_file.toggle() observers.append(button_select_file) # button_update = ActionUpdateList( icon='update.png', title='Update device list', parent=self, action=self.action_on_update_list, is_enabled=self.is_enabled_on_update_list) shortcut_key = 'Ctrl+u' button_update.setToolTip( compose_tooltip('Update the device list', shortcut_key)) button_update.setShortcut(shortcut_key) button_update.toggle() observers.append(button_update) # button_connect = ActionConnect(icon='connect.png', title='Connect', parent=self, action=self.action_on_connect, is_enabled=self.is_enabled_on_connect) shortcut_key = 'Ctrl+c' button_connect.setToolTip( compose_tooltip('Connect the selected device to Harvester', shortcut_key)) button_connect.setShortcut(shortcut_key) button_connect.toggle() observers.append(button_connect) # button_disconnect = ActionDisconnect( icon='disconnect.png', title='Disconnect', parent=self, action=self.action_on_disconnect, is_enabled=self.is_enabled_on_disconnect) shortcut_key = 'Ctrl+d' button_disconnect.setToolTip( compose_tooltip('Disconnect the device from Harvester', shortcut_key)) button_disconnect.setShortcut(shortcut_key) button_disconnect.toggle() observers.append(button_disconnect) # button_start_image_acquisition = ActionStartImageAcquisition( icon='start_acquisition.png', title='Start Acquisition', parent=self, action=self.action_on_start_image_acquisition, is_enabled=self.is_enabled_on_start_image_acquisition) shortcut_key = 'Ctrl+j' button_start_image_acquisition.setToolTip( compose_tooltip('Start image acquisition', shortcut_key)) button_start_image_acquisition.setShortcut(shortcut_key) button_start_image_acquisition.toggle() observers.append(button_start_image_acquisition) # button_toggle_drawing = ActionToggleDrawing( icon='pause.png', title='Pause/Resume Drawing', parent=self, action=self.action_on_toggle_drawing, is_enabled=self.is_enabled_on_toggle_drawing) shortcut_key = 'Ctrl+k' button_toggle_drawing.setToolTip( compose_tooltip('Pause/Resume drawing', shortcut_key)) button_toggle_drawing.setShortcut(shortcut_key) button_toggle_drawing.toggle() observers.append(button_toggle_drawing) # button_stop_image_acquisition = ActionStopImageAcquisition( icon='stop_acquisition.png', title='Stop Acquisition', parent=self, action=self.action_on_stop_image_acquisition, is_enabled=self.is_enabled_on_stop_image_acquisition) shortcut_key = 'Ctrl+l' button_stop_image_acquisition.setToolTip( compose_tooltip('Stop image acquisition', shortcut_key)) button_stop_image_acquisition.setShortcut(shortcut_key) button_stop_image_acquisition.toggle() observers.append(button_stop_image_acquisition) self._action_stop_image_acquisition = button_stop_image_acquisition # button_dev_attribute = ActionShowAttributeController( icon='device_attribute.png', title='Device Attribute', parent=self, action=self.action_on_show_attribute_controller, is_enabled=self.is_enabled_on_show_attribute_controller) shortcut_key = 'Ctrl+a' button_dev_attribute.setToolTip( compose_tooltip('Edit device attribute', shortcut_key)) button_dev_attribute.setShortcut(shortcut_key) button_dev_attribute.toggle() observers.append(button_dev_attribute) # Create widgets to add: # self._widget_device_list = ComboBoxDeviceList(self) self._widget_device_list.setSizeAdjustPolicy( QComboBox.AdjustToContents) shortcut_key = 'Ctrl+Shift+d' shortcut = QShortcut(QKeySequence(shortcut_key), self) def show_popup(): self._widget_device_list.showPopup() shortcut.activated.connect(show_popup) self._widget_device_list.setToolTip( compose_tooltip('Select a device to connect', shortcut_key)) observers.append(self._widget_device_list) for d in self.harvester_core.device_info_list: self._widget_device_list.addItem(d) group_connection.addWidget(self._widget_device_list) observers.append(self._widget_device_list) # self._widget_display_rates = ComboBoxDisplayRateList(self) self._widget_display_rates.setSizeAdjustPolicy( QComboBox.AdjustToContents) shortcut_key = 'Ctrl+Shift+r' shortcut = QShortcut(QKeySequence(shortcut_key), self) def show_popup(): self._widget_display_rates.showPopup() shortcut.activated.connect(show_popup) self._widget_display_rates.setToolTip( compose_tooltip('Select a display rate', shortcut_key)) observers.append(self._widget_display_rates) self._widget_display_rates.setEnabled(True) group_display.addWidget(self._widget_display_rates) observers.append(self._widget_display_rates) # self._widget_about = About(self) button_about = ActionShowAbout(icon='about.png', title='About', parent=self, action=self.action_on_show_about) button_about.setToolTip( compose_tooltip('Show information about Harvester')) button_about.toggle() observers.append(button_about) # Configure observers: # button_select_file.add_observer(button_update) button_select_file.add_observer(button_connect) button_select_file.add_observer(button_disconnect) button_select_file.add_observer(button_dev_attribute) button_select_file.add_observer(button_start_image_acquisition) button_select_file.add_observer(button_toggle_drawing) button_select_file.add_observer(button_stop_image_acquisition) button_select_file.add_observer(self._widget_device_list) # button_update.add_observer(self._widget_device_list) button_update.add_observer(button_connect) # button_connect.add_observer(button_select_file) button_connect.add_observer(button_update) button_connect.add_observer(button_disconnect) button_connect.add_observer(button_dev_attribute) button_connect.add_observer(button_start_image_acquisition) button_connect.add_observer(button_toggle_drawing) button_connect.add_observer(button_stop_image_acquisition) button_connect.add_observer(self._widget_device_list) # button_disconnect.add_observer(button_select_file) button_disconnect.add_observer(button_update) button_disconnect.add_observer(button_connect) button_disconnect.add_observer(button_dev_attribute) button_disconnect.add_observer(button_start_image_acquisition) button_disconnect.add_observer(button_toggle_drawing) button_disconnect.add_observer(button_stop_image_acquisition) button_disconnect.add_observer(self._widget_device_list) # button_start_image_acquisition.add_observer(button_toggle_drawing) button_start_image_acquisition.add_observer( button_stop_image_acquisition) # button_toggle_drawing.add_observer(button_start_image_acquisition) button_toggle_drawing.add_observer(button_stop_image_acquisition) # button_stop_image_acquisition.add_observer( button_start_image_acquisition) button_stop_image_acquisition.add_observer(button_toggle_drawing) # Add buttons to groups: # group_gentl_info.addAction(button_select_file) group_gentl_info.addAction(button_update) # group_connection.addAction(button_connect) group_connection.addAction(button_disconnect) # group_device.addAction(button_start_image_acquisition) group_device.addAction(button_toggle_drawing) group_device.addAction(button_stop_image_acquisition) group_device.addAction(button_dev_attribute) # group_help.addAction(button_about) # Connect handler functions: # group_gentl_info.actionTriggered[QAction].connect( self.on_button_clicked_action) group_connection.actionTriggered[QAction].connect( self.on_button_clicked_action) group_device.actionTriggered[QAction].connect( self.on_button_clicked_action) group_display.actionTriggered[QAction].connect( self.on_button_clicked_action) group_help.actionTriggered[QAction].connect( self.on_button_clicked_action) @staticmethod def on_button_clicked_action(action): action.execute() @property def action_stop_image_acquisition(self): return self._action_stop_image_acquisition @property def ia(self): return self._ia @ia.setter def ia(self, value): self._ia = value def action_on_connect(self): # try: self._ia = self.harvester_core.create_image_acquirer( self.device_list.currentIndex()) # We want to hold one buffer to keep the chunk data alive: self._ia.num_buffers += 1 except ( NotInitializedException, InvalidHandleException, InvalidIdException, ResourceInUseException, InvalidParameterException, NotImplementedException, AccessDeniedException, ) as e: self._logger.error(e, exc_info=True) if not self._ia: # The device is not available. return # self.ia.thread_image_acquisition = _PyQtThread(parent=self, mutex=self._mutex) self.ia.signal_stop_image_acquisition = self._signal_stop_image_acquisition try: if self.ia.remote_device.node_map: self._widget_attribute_controller = \ AttributeController( self.ia.remote_device.node_map, parent=self ) except AttributeError: pass # self.canvas.ia = self.ia def is_enabled_on_connect(self): enable = False if self.cti_files: if self.harvester_core.device_info_list: if self.ia is None: enable = True return enable def action_on_disconnect(self): if self.attribute_controller: if self.attribute_controller.isVisible(): self.attribute_controller.close() self._widget_attribute_controller = None # Discard the image acquisition manager. if self.ia: self.ia.destroy() self._ia = None def action_on_select_file(self): # Show a dialog and update the CTI file list. dialog = QFileDialog(self) dialog.setWindowTitle('Select a CTI file to load') dialog.setNameFilter('CTI files (*.cti)') dialog.setFileMode(QFileDialog.ExistingFile) if dialog.exec_() == QDialog.Accepted: # file_path = dialog.selectedFiles()[0] # self.harvester_core.reset() # Update the path to the target GenTL Producer. self.harvester_core.add_cti_file(file_path) # Update the device list. self.harvester_core.update_device_info_list() def is_enabled_on_select_file(self): enable = False if self.ia is None: enable = True return enable def action_on_update_list(self): self.harvester_core.update_device_info_list() def is_enabled_on_update_list(self): enable = False if self.cti_files: if self.ia is None: enable = True return enable def is_enabled_on_disconnect(self): enable = False if self.cti_files: if self.ia: enable = True return enable def action_on_start_image_acquisition(self): if self.ia.is_acquiring_images(): # If it's pausing drawing images, just resume it and # immediately return this method. if self.canvas.is_pausing(): self.canvas.resume_drawing() else: # Start statistics measurement: self.ia.statistics.reset() self._thread_statistics_measurement.start() self.ia.start_image_acquisition() def is_enabled_on_start_image_acquisition(self): enable = False if self.cti_files: if self.ia: if not self.ia.is_acquiring_images() or \ self.canvas.is_pausing(): enable = True return enable def action_on_stop_image_acquisition(self): # Stop statistics measurement: self._thread_statistics_measurement.stop() # Release the preserved buffers, which the we kept chunk data alive, # before stopping image acquisition. Otherwise the preserved buffers # will be dangling after stopping image acquisition: self.canvas.release_buffers() # Then we stop image acquisition: self.ia.stop_image_acquisition() # Initialize the drawing state: self.canvas.pause_drawing(False) def is_enabled_on_stop_image_acquisition(self): enable = False if self.cti_files: if self.ia: if self.ia.is_acquiring_images(): enable = True return enable def action_on_show_attribute_controller(self): if self.ia and self.attribute_controller.isHidden(): self.attribute_controller.show() self.attribute_controller.expand_all() def is_enabled_on_show_attribute_controller(self): enable = False if self.cti_files: if self.ia is not None: enable = True return enable def action_on_toggle_drawing(self): self.canvas.toggle_drawing() def is_enabled_on_toggle_drawing(self): enable = False if self.cti_files: if self.ia: if self.ia.is_acquiring_images(): enable = True return enable def action_on_show_about(self): self.about.setModal(False) self.about.show() def _worker_update_statistics(self): # if self.ia is None: return # message_config = 'W: {0} x H: {1}, {2}, '.format( self.ia.remote_device.node_map.Width.value, self.ia.remote_device.node_map.Height.value, self.ia.remote_device.node_map.PixelFormat.value) # message_statistics = '{0:.1f} fps, elapsed {1}, {2} images'.format( self.ia.statistics.fps, str( datetime.timedelta( seconds=int(self.ia.statistics.elapsed_time_s))), self.ia.statistics.num_images) # self._signal_update_statistics.emit(message_config + message_statistics)
class Harvester(QMainWindow): # _signal_update_statistics = pyqtSignal(str) _signal_stop_image_acquisition = pyqtSignal() def __init__(self): # super().__init__() # self._mutex = QMutex() self._harvester_core = HarvesterCore( frontend=self, profile=False, parent=self ) self._iam = None # Image Acquisition Manager self._widget_canvas = Canvas() self._widget_canvas.set_shaders() # Pass custom shares if needed. self._widget_canvas.create_native() self._widget_canvas.native.setParent(self) # self._action_stop_image_acquisition = None # self._observer_widgets = [] # self._widget_device_list = None self._widget_status_bar = None self._widget_main = None self._widget_about = None self._widget_attribute_controller = None # self._signal_update_statistics.connect(self.update_statistics) self._signal_stop_image_acquisition.connect(self._stop_image_acquisition) # self._initialize_widgets() # for o in self._observer_widgets: o.update() self._is_going_to_terminate = False def _stop_image_acquisition(self): self.action_stop_image_acquisition.execute() def update_statistics(self, message): self.statusBar().showMessage(message) def closeEvent(self, QCloseEvent): self._is_going_to_terminate = True def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): self._harvester_core.reset() @property def canvas(self): return self._widget_canvas @property def attribute_controller(self): return self._widget_attribute_controller @property def about(self): return self._widget_about @property def version(self): return self.harvester_core.version @property def device_list(self): return self._widget_device_list @property def cti_files(self): return self.harvester_core.cti_files @property def harvester_core(self): return self._harvester_core @property def mutex(self): return self._mutex @staticmethod def _get_default_processor(gentl_buffer): processor = None payload_type = gentl_buffer.payload_type if payload_type == PAYLOADTYPE_INFO_IDS.PAYLOAD_TYPE_IMAGE: processor = _ProcessorPayloadTypeImage() elif payload_type == PAYLOADTYPE_INFO_IDS.PAYLOAD_TYPE_MULTI_PART: processor = _ProcessorPayloadTypeMultiPart() return processor def _initialize_widgets(self): # self.setWindowIcon(Icon('genicam_logo_i.png')) # self.setWindowTitle('GenICam.Harvester') self.setFont(get_system_font()) # self.statusBar().showMessage('') self.statusBar().setFont(get_system_font()) # self._initialize_gui_toolbar(self._observer_widgets) # self.setCentralWidget(self.canvas.native) # self.resize(800, 600) # Place it in the center. rectangle = self.frameGeometry() coordinate = QDesktopWidget().availableGeometry().center() rectangle.moveCenter(coordinate) self.move(rectangle.topLeft()) def _initialize_gui_toolbar(self, observers): # group_gentl_info = self.addToolBar('GenTL Information') group_connection = self.addToolBar('Connection') group_device = self.addToolBar('Image Acquisition') group_help = self.addToolBar('Help') # button_select_file = ActionSelectFile( icon='open_file.png', title='Select file', parent=self, action=self.action_on_select_file, is_enabled=self.is_enabled_on_select_file ) shortcut_key = 'Ctrl+o' button_select_file.setToolTip( compose_tooltip('Open a CTI file to load', shortcut_key) ) button_select_file.setShortcut(shortcut_key) button_select_file.toggle() observers.append(button_select_file) # button_update = ActionUpdateList( icon='update.png', title='Update device list', parent=self, action=self.action_on_update_list, is_enabled=self.is_enabled_on_update_list ) shortcut_key = 'Ctrl+u' button_update.setToolTip( compose_tooltip('Update the device list', shortcut_key) ) button_update.setShortcut(shortcut_key) button_update.toggle() observers.append(button_update) # button_connect = ActionConnect( icon='connect.png', title='Connect', parent=self, action=self.action_on_connect, is_enabled=self.is_enabled_on_connect ) shortcut_key = 'Ctrl+c' button_connect.setToolTip( compose_tooltip( 'Connect the selected device to Harvester', shortcut_key ) ) button_connect.setShortcut(shortcut_key) button_connect.toggle() observers.append(button_connect) # button_disconnect = ActionDisconnect( icon='disconnect.png', title='Disconnect', parent=self, action=self.action_on_disconnect, is_enabled=self.is_enabled_on_disconnect ) shortcut_key = 'Ctrl+d' button_disconnect.setToolTip( compose_tooltip( 'Disconnect the device from Harvester', shortcut_key ) ) button_disconnect.setShortcut(shortcut_key) button_disconnect.toggle() observers.append(button_disconnect) # button_start_acquisition = ActionStartImageAcquisition( icon='start_acquisition.png', title='Start Acquisition', parent=self, action=self.action_on_start_image_acquisition, is_enabled=self.is_enabled_on_start_image_acquisition ) shortcut_key = 'Ctrl+j' button_start_acquisition.setToolTip( compose_tooltip('Start image acquisition', shortcut_key) ) button_start_acquisition.setShortcut(shortcut_key) button_start_acquisition.toggle() observers.append(button_start_acquisition) # button_toggle_drawing = ActionToggleDrawing( icon='pause.png', title='Pause/Resume Drawing', parent=self, action=self.action_on_toggle_drawing, is_enabled=self.is_enabled_on_toggle_drawing ) shortcut_key = 'Ctrl+k' button_toggle_drawing.setToolTip( compose_tooltip('Pause/Resume drawing', shortcut_key) ) button_toggle_drawing.setShortcut(shortcut_key) button_toggle_drawing.toggle() observers.append(button_toggle_drawing) # button_stop_acquisition = ActionStopImageAcquisition( icon='stop_acquisition.png', title='Stop Acquisition', parent=self, action=self.action_on_stop_image_acquisition, is_enabled=self.is_enabled_on_stop_image_acquisition ) shortcut_key = 'Ctrl+l' button_stop_acquisition.setToolTip( compose_tooltip('Stop image acquisition', shortcut_key) ) button_stop_acquisition.setShortcut(shortcut_key) button_stop_acquisition.toggle() observers.append(button_stop_acquisition) self._action_stop_image_acquisition = button_stop_acquisition # button_dev_attribute = ActionShowAttributeController( icon='device_attribute.png', title='Device Attribute', parent=self, action=self.action_on_show_attribute_controller, is_enabled=self.is_enabled_on_show_attribute_controller ) shortcut_key = 'Ctrl+a' button_dev_attribute.setToolTip( compose_tooltip('Edit device attribute', shortcut_key) ) button_dev_attribute.setShortcut(shortcut_key) button_dev_attribute.toggle() observers.append(button_dev_attribute) # self._widget_about = About(self) button_about = ActionShowAbout( icon='about.png', title='About', parent=self, action=self.action_on_show_about ) button_about.setToolTip( compose_tooltip('Show information about Harvester') ) button_about.toggle() observers.append(button_about) # self._widget_device_list = ComboBox(self) self._widget_device_list.setSizeAdjustPolicy( QComboBox.AdjustToContents ) shortcut_key = 'Ctrl+Shift+d' shortcut = QShortcut(QKeySequence(shortcut_key), self) def show_popup(): self._widget_device_list.showPopup() shortcut.activated.connect(show_popup) self._widget_device_list.setToolTip( compose_tooltip('Select a device to connect', shortcut_key) ) observers.append(self._widget_device_list) for d in self.harvester_core.device_info_list: self._widget_device_list.addItem(d) group_connection.addWidget(self._widget_device_list) observers.append(self._widget_device_list) # button_select_file.add_observer(button_update) button_select_file.add_observer(button_connect) button_select_file.add_observer(button_disconnect) button_select_file.add_observer(button_dev_attribute) button_select_file.add_observer(button_start_acquisition) button_select_file.add_observer(button_toggle_drawing) button_select_file.add_observer(button_stop_acquisition) button_select_file.add_observer(self._widget_device_list) # button_update.add_observer(self._widget_device_list) button_update.add_observer(button_connect) # button_connect.add_observer(button_select_file) button_connect.add_observer(button_update) button_connect.add_observer(button_disconnect) button_connect.add_observer(button_dev_attribute) button_connect.add_observer(button_start_acquisition) button_connect.add_observer(button_toggle_drawing) button_connect.add_observer(button_stop_acquisition) button_connect.add_observer(self._widget_device_list) # button_disconnect.add_observer(button_select_file) button_disconnect.add_observer(button_update) button_disconnect.add_observer(button_connect) button_disconnect.add_observer(button_dev_attribute) button_disconnect.add_observer(button_start_acquisition) button_disconnect.add_observer(button_toggle_drawing) button_disconnect.add_observer(button_stop_acquisition) button_disconnect.add_observer(self._widget_device_list) # button_start_acquisition.add_observer(button_toggle_drawing) button_start_acquisition.add_observer(button_stop_acquisition) # button_toggle_drawing.add_observer(button_start_acquisition) button_toggle_drawing.add_observer(button_stop_acquisition) # button_stop_acquisition.add_observer(button_start_acquisition) button_stop_acquisition.add_observer(button_toggle_drawing) # group_gentl_info.addAction(button_select_file) group_gentl_info.addAction(button_update) # group_connection.addAction(button_connect) group_connection.addAction(button_disconnect) # group_device.addAction(button_start_acquisition) group_device.addAction(button_toggle_drawing) group_device.addAction(button_stop_acquisition) group_device.addAction(button_dev_attribute) # group_help.addAction(button_about) group_gentl_info.actionTriggered[QAction].connect( self.on_button_clicked_action ) group_connection.actionTriggered[QAction].connect( self.on_button_clicked_action ) group_device.actionTriggered[QAction].connect( self.on_button_clicked_action ) group_help.actionTriggered[QAction].connect( self.on_button_clicked_action ) @staticmethod def on_button_clicked_action(action): action.execute() @property def action_stop_image_acquisition(self): return self._action_stop_image_acquisition @property def iam(self): return self._iam @iam.setter def iam(self, value): self._iam = value def action_on_connect(self): # self._iam = self.harvester_core.create_image_acquisition_manager( self.device_list.currentIndex(), data_type='numpy' # This is just for demonstaration; it's not necessasry here because the default value is 'numpy'. ) if not self._iam: # The device is not available. return # self.iam.user_defined_processors.clear() self.iam.user_defined_processors.append( _ConvertNumpy1DToNumpy2D() ) # self.iam.thread_image_acquisition = PyQtThread( parent=self, mutex=self.mutex ) self.iam.thread_statistics_measurement = PyQtThread( parent=self, mutex=self.mutex ) self.iam.updated_statistics = self._signal_update_statistics self.iam.signal_stop_image_acquisition = self._signal_stop_image_acquisition try: if self.iam.device.node_map: self._widget_attribute_controller = \ AttributeController( self.iam.device.node_map, parent=self ) except AttributeError: pass # self.canvas.iaa = self.iam def is_enabled_on_connect(self): enable = False if self.cti_files: if self.harvester_core.device_info_list: if self.iam is None: enable = True return enable def action_on_disconnect(self): if self.attribute_controller: if self.attribute_controller.isVisible(): self.attribute_controller.close() def action_on_select_file(self): # Show a dialog and update the CTI file list. dialog = QFileDialog(self) dialog.setWindowTitle('Select a CTI file to load') dialog.setNameFilter('CTI files (*.cti)') dialog.setFileMode(QFileDialog.ExistingFile) if dialog.exec_() == QDialog.Accepted: # file_path = dialog.selectedFiles()[0] # self.harvester_core.reset() # Update the path to the target GenTL Producer. self.harvester_core.add_cti_file(file_path) print(file_path) # Update the device list. self.harvester_core.update_device_info_list() def is_enabled_on_select_file(self): enable = False if self.iam is None: enable = True return enable def action_on_update_list(self): self.harvester_core.update_device_info_list() def is_enabled_on_update_list(self): enable = False if self.cti_files: if self.iam is None: enable = True return enable def action_on_disconnect(self): # Close attribute dialog if it's been opened. # Close attribute dialog if it's been opened. if self.attribute_controller: if self.attribute_controller.isVisible(): self.attribute_controller.close() # Discard the image acquisition manager. if self.iam: self.iam.destroy() self._iam = None def is_enabled_on_disconnect(self): enable = False if self.cti_files: if self.iam: enable = True return enable def action_on_start_image_acquisition(self): self.iam.start_image_acquisition() def is_enabled_on_start_image_acquisition(self): enable = False if self.cti_files: if self.iam: if not self.iam.is_acquiring_images or \ self.canvas.is_pausing: enable = True return enable def action_on_stop_image_acquisition(self): self.iam.stop_image_acquisition() self.canvas.pause_drawing(False) def is_enabled_on_stop_image_acquisition(self): enable = False if self.cti_files: if self.iam: if self.iam.is_acquiring_images: enable = True return enable def action_on_show_attribute_controller(self): with QMutexLocker(self.mutex): if self.iam and self.attribute_controller.isHidden(): self.attribute_controller.show() self.attribute_controller.expand_all() def is_enabled_on_show_attribute_controller(self): enable = False if self.cti_files: if self.iam is not None: enable = True return enable def action_on_toggle_drawing(self): self.canvas.toggle_drawing() def is_enabled_on_toggle_drawing(self): enable = False if self.cti_files: if self.iam: if self.iam.is_acquiring_images: enable = True return enable def action_on_show_about(self): self.about.setModal(False) self.about.show()