Skip to content
Kazunari Kudo edited this page Jan 22, 2021 · 39 revisions

How should I distinguish an official version and a development version?

We can pick up one from the Git history but what is an official release and what is a development release?

Answer

I would say if a commit has a Git tag then it's an official release. In general, you should find such a commit is also uploaded to PyPI so that you can install Harvester executing the pip command.

A sophisticated people keep the trunk consistent so that it works without any issue but sometimes I commit a change that breaks something. I will keep trying to make the trunk consistent but there always be a case where I need to excuse myself.

My library/program does not work with Harvester >= version 1.2

Since I upgraded Harvester to version 1.2, my program has stopped working. What's wrong with that version? What should I do to get my program/library working again with Harvester >= 1.2?

Answer

There is a bit wide gap between versions 1.1 and 1.2. It's always awkward to enforce you to have modification on your side but I would like to prioritize the usability and performance rather than backward compatibility. I totally understand such inconvenience is coming from my lack of software development skills. Please excuse me!

In the following sections, I would like to introduce you cases where you need to make modifications to your code. Please feel free to open issue tickets if you are not fully sure what you should do to work with Harvester >= version 1.2.

Identifiers

Since version 1.2, some identifiers have been shortened because the original ones had been lengthy and redundant. Please check how you should change identifiers:

  • Harvester
    • cti_files ---> files
    • add_cti_file() ---> add_file()
    • remove_cti_file() ---> remove_file()
    • remove_cti_files() ---> remove_files()
    • update_device_info_list() ---> update()
  • ImageAcquirer
    • is_acquiring_images() ---> is_acquiring()
    • start_image_acquisition() ---> start_acquisition()
    • stop_image_acquisition() ---> stop_acquisition()

See ticket #127 (https://github.com/genicam/harvesters/issues/127) for details.

Callbacks

Since version 1.2, Harvester has introduced a much more flexible way for callbacks. Just involving callbacks, you can handle some specific events that happen on an ImageAcquier object. So how can we know the defined events?

from harvesters.core import ImageAcquirer
print(ImageAcquirer.Events.__members__)

Then you'd get the following output:

mappingproxy({'TURNED_OBSOLETE': <ImageAcquirer.Events.TURNED_OBSOLETE: 0>,
              'RETURN_ALL_BORROWED_BUFFERS': <ImageAcquirer.Events.RETURN_ALL_BORROWED_BUFFERS: 1>,
              'READY_TO_STOP_ACQUISITION': <ImageAcquirer.Events.READY_TO_STOP_ACQUISITION: 2>,
              'NEW_BUFFER_AVAILABLE': <ImageAcquirer.Events.NEW_BUFFER_AVAILABLE: 3>,
              'INCOMPLETE_BUFFER': <ImageAcquirer.Events.INCOMPLETE_BUFFER: 4>})

So far, three events have been defined. So how can we get a callback working? To get a callback working, you will have to do two things: The first is to know which events are supported. To know the supported events, you can get the answer from the capable_events property of the ImageAcquire class.

TODO:

The second thing to do is to design and implement your own callback class deriving from the Callback class that Harvester defines.

from harvesters.core import Callback

class CallbackOnNewBuffer(Callback):
    def __init__(self, ia: ImageAcquirer):
        #
        super().__init__()
        #
        self._ia = ia

    def emit(self, context):
        # You would implement this method by yourself.
        with self._ia.fetch_buffer() as buffer:
            # Work with the fetched buffer.
            print(buffer)
            ...

When the event happened, the source object will call the emit method passing itself to the context parameter. So almost of the cases, you would have to implement your recipes as a reaction to the event.

Having implemented your callback class, then add the callback object to the target ImageAcquirer object. You can add a callback on a specific event through the add_callback method:

self.on_new_buffer = CallbackOnNewBuffer
ia.add_callback(
    Events.NEW_BUFFER_AVAILABLE,
    self.on_new_buffer
)

Then now you are ready to get the things to work. Just start image acquisition with the start_acquisition method but you have to pass a special parameter to enable NEW_BUFFER_AVAILABLE event. To enable that, please pass run_in_background=True to it:

# Note that it's required when you want to catch `NEW_BUFFER_AVAILABLE` event:
ia.start_acquisition(run_in_background=True)

Passing run_in_background=True to the start_acquisition method, the ImageAcquirer object starts to run an image acquisition thread in the background to call the emit method to notify you. One thing you should remember is relying on a callback is not wrong and there actually is such a valid use case. However, it means another additional layer as the dedicated thread in your image acquisition process and it tends to give you a drawback such as latency which might drug you away from the perfect.

If you want to prioritize the performance in the sense of fastness, you should design a program that directly fetches buffers when the program can work. In that case, you must just call start_acquisition(). This has the same effect as calling start_acquisition(run_in_background=False).

TODO: To be documented.

Invalid layout of buffer attached to chunk parser!

I get the following exception once I start image acquisition. Why? What should I do?

2019-06-12 10:28:37,099 :: harvesters.core :: ERROR :: Invalid layout of buffer attached to chunk parser! : RuntimeException thrown (file 'ChunkAdapterGEV.cpp', line 97)
Traceback (most recent call last):
File "/home/mbiernacki/PycharmProjects/Ranger3/venv/lib/python3.6/site-packages/harvesters/core.py", line 1802, in _update_chunk_data
self._chunk_adapter.attach_buffer(buffer.raw_buffer)
File "/home/mbiernacki/PycharmProjects/Ranger3/venv/lib/python3.6/site-packages/genicam2/genapi.py", line 2960, in attach_buffer  return _genapi.ChunkAdapterGEV_attach_buffer(self, pBuffer, pAttachStatistics)
_genapi.RuntimeException: Invalid layout of buffer attached to chunk parser! : RuntimeException thrown (file 'ChunkAdapterGEV.cpp', line 97)

Answer

First, the exception is raised by the GenICam GenApi reference implementation library and Harvester is just passed it to you because the situation is critical and the decision should be made by you.

A typical reason for the invalid layout can be caused by data corruption in the delivered chunk data. Even if a set of data is delivered to you over the transport layer technology, it guarantees that the data has not been altered but it does not the data itself is valid. Such corruption can be made by the source of the data, i.e., a camera itself. Most of the cases you would need to consult with the technical support of the camera manufacturer because such corruption could be made by a defect of the camera design.

If you are not willing to turn on the GenICam chunk data feature, then you should just turn ChunkModeActive off. This will work as a workaround because the camera will not append chunk data that is identified as invalid. However, again, you should understand something is wrong with the camera itself even if you can get rid of the exception.

I think I have loaded a valid GenTL Producer but it says no device is available. Why? (Linux/macOS)

I think I have loaded a valid GenTL Producer on a Harvester object but it says no device is available. Why doesn't Harvester enumerate the devices that I am seeing in person?

Answer

Please review the path that you have set. Doesn't it include the tilde (~) in the path? If so, replace it with the actual path. Harvester does not parse the tilde.

If you set a path as follows:

harvester.add_cti_file('~/path/to/abc.cti')

Rewrite the code as follows (for example):

harvester.add_cti_file('/usr/john/path/to/abc.cti')

I would like to install a specific version of Harvester. How should I do it?

I would like to install a specific version of Harvester. How should I do it?

Answer

If you want to install the latest version in the version 0 line, then execute the following command:

$ pip uninstall harvesters
$ pip install harvesters<1 --no-cache-dir

As always, it is better to learn from the original source:

https://pip.pypa.io/en/stable/reference/pip_install/#id49

Why doesn't the device have the GenICam feature nodes that I want to work with?

I think I'm accessing my camera but it does not have any GenICam feature node that I am expecting to work with.

Answer

Maybe you are accessing a GenTL Device module instead of the physical remote device i.e. the camera.

To get the node map of the remote device, you must code as follows:

node_map = ia.remote_device.node_map

Instead of:

node_map = ia.device.node_map

The latter code returns you the node map that the GenTL Device module holds. Their names are very similar but note that they are not identical. The distinguish had been introduced at version 0.2.12 resolving issue #84:

https://github.com/genicam/harvesters/issues/84

Harvester fails to load TLSimu. What's happening?

I'm trying to get Harvester working with TLSimu on Windows but it always gives me the following error message:

2019-12-03 10:13:38,332 :: harvesters.core :: ERROR :: GenTL exception: Failed to load CTI file; The specified module could not be found.
 (ID: -10001)
Traceback (most recent call last):
  File "c:\users\kkudo\appdata\local\programs\python\python37\lib\site-packages\harvesters\core.py", line 2606, in update_device_info_list
    self._open_gentl_producers()
  File "c:\users\kkudo\appdata\local\programs\python\python37\lib\site-packages\harvesters\core.py", line 2483, in _open_gentl_producers
    producer.open(file_path)
  File "c:\users\kkudo\appdata\local\programs\python\python37\lib\site-packages\genicam2\gentl.py", line 2306, in open
    return _gentl.GenTLProducer_open(self, path_name)
_gentl.LoadLibraryException: GenTL exception: Failed to load CTI file; The specified module could not be found.
 (ID: -10001)

Answer

TLSimu is used to test the functionalities of Harvester and TLSimu has a dependency on a DLL called VirtualFG. To get Harvester working with TLSimu, you must make VirtualFG visible from it's DLL search order.

An intuitive solution would be to add the file location to the PATH environment variable.

See also

Dynamic-Link Library Search Order

I'd like to store the downloaded XML/Zip file. How can I do that?

I would like to store the downloaded XML/Zip file of the target devices. How can I do that?

Answer

You can use an environment variable, HARVESTERS_XML_FILE_DIR, to specify the directory where downloaded Zip/XML files are stored. Set a directory to the variable and then execute your program that uses Harvester. You will find the expected file in the specified location when the program tried to create an ImageAcquirer object.

I'm trying to involve 2 or more netowrk interface cards but it corrupts my program. Why?

My program involves 2 or more network interface cards, NICs in short. However, everything is fine as long as I use only a single NIC but my program turns corrupted once I started to use 2 or more network interface cards. Why is this issue happening?

Answer

Assign individual subnet to each NIC. They should not reside in the same subnet.

See also

Microsoft: How multiple adapters on the same network are expected to behave

How can I check the version number of Harvester?

I'm using Harvester and would like to know its version number.

Answer

You can check the version number referring to the __version__ property. The code would like as follows:

from harvesters import __version))
print(__version__)

It would give you a string, for example:

'0.2.8'

Harvester raises ClosedException but I don't know why

I'm just creating ImageAcquirer objects passing a factory method a Harvester object:

class Foo:
    def create_image_acquirer(harvester: Harvester, index: int):
        return harvester.create_image_acquirer(id_=index)

However, Harvester unexpectedly raises ClosedException. Why?

Exception ignored in: <function ImageAcquirer.__del__ at 0x0000019F2A2E8C80>
Traceback (most recent call last):
  File "C:\Python37\lib\site-packages\harvesters\core.py", line 1383, in __del__
    self.destroy()
  File "C:\Python37\lib\site-packages\harvesters\core.py", line 1968, in destroy
    self._parent._destroy_image_acquirer(self)
  File "C:\Python37\lib\site-packages\harvesters\core.py", line 2489, in _destroy_image_acquirer
    id_ = ia._device.id_
  File "C:\Python37\lib\site-packages\genicam2\gentl.py", line 3238, in _get_id_
    return _gentl.Device__get_id_(self)
_gentl.ClosedException: GenTL exception: Tried to call a function but the library has been closed. Call GCInitLib first. (ID: -10002)

Answer

A possible short answer is you don't hold the Harvester object while the created ImageAcquirer objects.

Nothing wrong with creating ImageAcquirer objects calling a factory method but if the Foo object reaches out to its life although the ImageAcquirer objects will keep existing, the C++ objects of each Python ImageAcquirer object will be automatically destructed by design.

Having that destruction, the ImageAcquirer objects turn dangling and any operation on the objects lose meaning because it's C++ object has gone.

Again, please keep holding the Harvester object as long as you keep holding ImageAcquirer objects.

I want to upgrade Harvester to an arbitrary version

How can I upgrade Harvester to an arbitrary version using pip?

Answer

You can upgrade/downgrade Harvester just typing as follows; if you want to upgrade to 0.2.0 then:

$ pip install harvesters==0.2.0

I want to identify the dependency of the installed Python packages

It's not always but sometimes I need to check the dependencies of the Python packages that I installed using pip. Is there any way to easily make it?

Answer

Maybe pipdeptree could help you. You can install pipdeptree typing the following command:

$ pip install pipdeptree

After installed that, type the following command:

$ pipdeptree

It will display the dependency tree.

I pointed out a CTI file but Harvester says the image doesn't exist (Part 2)

Following the "Getting Started" page, I copied a CTI file to my location and actually pointed out the location where my target CTI files are located as follows:

h = Harvester()
h.add_cti_file('my_target.cti')
h.update_device_info_list()
_gentl.LoadLibraryException: GenTL exception: Failed to load CTI file; The specified module could not be found. (ID: -10001)

Answer

A CTI file is a shared library actually. So PLEASE DO NOT USE THE COPIED CTI FILE!! PLEASE!! Library manufacturers provide you CTI files in appropriate locations because the libraries may need to retrieve relevant libraries to link. If you use the copied one, it may be located in an incorrect location where the library can't load other relevant libraries.

I pointed out a CTI file but Harvester says the image doesn't exist (Part 1)

Following the "Getting Started" page, I actually pointed out the location where my target CTI files are located as follows:

h = Harvester()
h.add_cti_file('c:\path\to\my_target.cti')
h.update_device_info_list()
_gentl.LoadLibraryException: GenTL exception: Failed to load CTI file; The specified module could not be found. (ID: -10001)

Answer

If you want to describe a file path using the Windows style directory separator, you will have to use \\ instead of \. I mean you had to code as follows:

h = Harvester()
h.add_cti_file('c:\\path\\to\\my_target.cti')

Or, the UNIX style is also a way to go:

h.add_cti_file('c:/path/to/my_target.cti')

I actually loaded a .cti file but Harvester returns me an error

Following the "Getting Started" page, I actually pointed out the location where my target CTI files are located as follows:

h = Harvester()
h.add_cti_file('/path/to/my_target.cti')
h.update_device_info_list()

However, Harvester raises the following exception.

_gentl.LoadLibraryException: GenTL exception: Failed to load CTI file; /home/server/Desktop/ctifiles/GxGVTL.cti: invalid ELF header (ID: -10001)

Answer

Are you sure the CTI file was generated for your target operating system? In general, CTI files are system dependent and usually don't work on other operating systems; so the Windows version works only on Windows and the others as well. Actually, CTI files are shared objects or DLLs that renamed the file extension to cti. Please make sure if the CTI file is generated for your target operating system.

Images in .rst files are not displayed on my web browser

Any image in .rst files is not correctly displayed on my web browser while I'm trying it at my office. However, they are actually displayed if I browse them on my private laptop. What is the difference?

Answer

Perhaps your company's Proxy server could be blocking you to access the resources in the GitHub domain. In this case, you should browse the .rst file locally.

First, you should clone the repository:

Then install a restructured text file browser called restview:

$ pip install restview

Finally, open the README.rst in your working copy from it:

$ restview README.rst

restview will open your default web browser and show the contents of the .rst file. In the displayed contents the images in the .rst file should be correctly displayed.

Documentation style guide

Which style guide should I follow?

Answer

https://documentation-style-guide-sphinx.readthedocs.io/en/latest/style-guide.html#headings