Пример #1
0
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
Пример #2
0
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
Пример #3
0
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()
Пример #4
0
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()
Пример #5
0
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()
Пример #6
0
 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()
Пример #7
0
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.")
Пример #8
0
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
Пример #9
0
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
Пример #10
0
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
Пример #11
0
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()
Пример #13
0
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.")
Пример #14
0
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
Пример #15
0
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()
Пример #16
0
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)
Пример #17
0
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()