Skip to content

Commit 741e6b8

Browse files
andreasgaubjoernrennfanz
authored andcommitted
Merged PR 26069: changes for pylon 7.5 and 3D
2 parents 1c86368 + 022a28c commit 741e6b8

26 files changed

+1494
-370
lines changed

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[build-system]
2-
requires = ["setuptools>=42", "swig>=4.0", "wheel"]
2+
requires = ["setuptools>=42", "swig>=4.2", "wheel"]
33
build-backend = "setuptools.build_meta"
44

55
[tool.cibuildwheel]

samples/datacontainer_load.py

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# ===============================================================================
2+
# This sample shows how to access data containers.
3+
# This is needed when using 3D cameras, e.g., Basler blaze.
4+
# ===============================================================================
5+
import os
6+
from pypylon import pylon
7+
from pypylon import genicam
8+
9+
import sys
10+
11+
# This is used for visualization.
12+
import cv2
13+
import time
14+
15+
# The exit code of the sample application.
16+
exitCode = 0
17+
18+
try:
19+
# Create a pylon data container object.
20+
pylonDataContainer = pylon.PylonDataContainer()
21+
22+
# Load the recipe file.
23+
thisdir = os.path.dirname(__file__)
24+
filename = os.path.join(thisdir, 'images/3D/little_boxes.gendc')
25+
pylonDataContainer.Load(filename)
26+
27+
print("Component Count: ", pylonDataContainer.DataComponentCount);
28+
29+
# Access data components if the component type indicates image data
30+
for componentIndex in range(pylonDataContainer.DataComponentCount):
31+
pylonDataComponent = pylonDataContainer.GetDataComponent(componentIndex);
32+
# Access the component data.
33+
print("ComponentType: ", pylonDataComponent.ComponentType)
34+
print("PixelType: ", pylonDataComponent.PixelType)
35+
print("SizeX: ", pylonDataComponent.Width)
36+
print("SizeY: ", pylonDataComponent.Height)
37+
print("OffsetX: ", pylonDataComponent.OffsetX)
38+
print("OffsetY: ", pylonDataComponent.OffsetY)
39+
print("PaddingX: ", pylonDataComponent.PaddingX)
40+
print("DataSize: ", pylonDataComponent.DataSize)
41+
print("TimeStamp: ", pylonDataComponent.TimeStamp)
42+
img = pylonDataComponent.Array
43+
print("Gray value of first pixel: ", img[0, 0])
44+
if pylonDataComponent.PixelType == pylon.PixelType_Coord3D_ABC32f:
45+
None
46+
else:
47+
cv2.imshow('Image' + str(componentIndex), img)
48+
# Release the data, otherwise it will not be freed
49+
# The data is held by the container and the components until all of them are released.
50+
pylonDataComponent.Release()
51+
52+
for i in range(60):
53+
time.sleep(1)
54+
# Break the endless loop by pressing ESC.
55+
k = cv2.waitKey(5) & 0xFF
56+
if k == 27:
57+
break
58+
59+
# Free the data held by the container
60+
pylonDataContainer.Release()
61+
62+
except genicam.GenericException as e:
63+
# Error handling.
64+
print("An exception occurred.")
65+
print(e)
66+
exitCode = 1
67+
68+
sys.exit(exitCode)

samples/grabdatacontainer.py

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# ===============================================================================
2+
# This sample illustrates how to grab and process data using the CInstantCamera class.
3+
# The data is grabbed and processed asynchronously, i.e.,
4+
# while the application is processing a buffer, the acquisition of the next buffer is done
5+
# in parallel.
6+
#
7+
# Utilizes the API for accessing GenICam Generic Data Container (GenDC).
8+
# This will allow the use of, e.g., Basler blaze 3D cameras.
9+
# ===============================================================================
10+
from pypylon import pylon
11+
from pypylon import genicam
12+
13+
import sys
14+
15+
# Number of results to be grabbed.
16+
countOfResultsToGrab = 100
17+
18+
# The exit code of the sample application.
19+
exitCode = 0
20+
21+
try:
22+
# Create an instant camera object with the camera device found first.
23+
camera = pylon.InstantCamera(pylon.TlFactory.GetInstance().CreateFirstDevice())
24+
camera.Open()
25+
26+
# Print the model name of the camera.
27+
print("Using device ", camera.GetDeviceInfo().GetModelName())
28+
29+
# demonstrate some feature access
30+
new_width = camera.Width.Value - camera.Width.Inc
31+
if new_width >= camera.Width.Min:
32+
camera.Width.Value = new_width
33+
34+
# The parameter MaxNumBuffer can be used to control the count of buffers
35+
# allocated for grabbing. The default value of this parameter is 10.
36+
camera.MaxNumBuffer.Value = 5
37+
38+
# Start the grabbing of c_countOfImagesToGrab grab results.
39+
# The camera device is parameterized with a default configuration which
40+
# sets up free-running continuous acquisition.
41+
camera.StartGrabbingMax(countOfResultsToGrab)
42+
43+
# Camera.StopGrabbing() is called automatically by the RetrieveResult() method
44+
# when c_countOfImagesToGrab grab results have been retrieved.
45+
while camera.IsGrabbing():
46+
# Wait for grabbed data and then retrieve it. A timeout of 5000 ms is used.
47+
grabResult = camera.RetrieveResult(5000, pylon.TimeoutHandling_ThrowException)
48+
49+
# Data grabbed successfully?
50+
if grabResult.GrabSucceeded():
51+
# Get the grab result as a PylonDataContainer, e.g. when working with 3D cameras.
52+
pylonDataContainer = grabResult.GetDataContainer();
53+
print("Component Count: ", pylonDataContainer.DataComponentCount);
54+
# Access data components if the component type indicates image data
55+
for componentIndex in range(pylonDataContainer.DataComponentCount):
56+
pylonDataComponent = pylonDataContainer.GetDataComponent(componentIndex);
57+
if pylonDataComponent.ComponentType == pylon.ComponentType_Intensity:
58+
# Access the component data.
59+
print("PixelType: ", pylonDataComponent.PixelType)
60+
print("SizeX: ", pylonDataComponent.Width)
61+
print("SizeY: ", pylonDataComponent.Height)
62+
print("OffsetX: ", pylonDataComponent.OffsetX)
63+
print("OffsetY: ", pylonDataComponent.OffsetY)
64+
print("PaddingX: ", pylonDataComponent.PaddingX)
65+
print("DataSize: ", pylonDataComponent.DataSize)
66+
print("TimeStamp: ", pylonDataComponent.TimeStamp)
67+
img = pylonDataComponent.Array
68+
print("Gray value of first pixel: ", img[0, 0])
69+
pylonDataComponent.Release()
70+
pylonDataContainer.Release()
71+
else:
72+
print("Error: ", grabResult.ErrorCode, grabResult.ErrorDescription)
73+
grabResult.Release()
74+
camera.Close()
75+
76+
except genicam.GenericException as e:
77+
# Error handling.
78+
print("An exception occurred.")
79+
print(e)
80+
exitCode = 1
81+
82+
sys.exit(exitCode)

samples/images/3D/little_boxes.gendc

300 KB
Binary file not shown.

setup.py

+3-14
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ class BuildSupport(object):
102102
"gentl",
103103
"extra",
104104
"pylondataprocessing",
105-
"cxp",
106105
}
107106

108107
# Global switch to toggle pylon data processing support on or off
@@ -457,18 +456,11 @@ class BuildSupportWindows(BuildSupport):
457456
"gentl": [
458457
("PylonGtc_*.dll", ""),
459458
],
460-
461-
"cxp": [
462-
],
463459
}
464460

465-
GENTL_CXP_PRODUCER_DIR = "pylonCXP"
466461
PYLON_DATA_PROCESSING_VTOOLS_DIR = "pylonDataProcessingPlugins"
467462

468463
RuntimeFolders = {
469-
"cxp": [
470-
(GENTL_CXP_PRODUCER_DIR, GENTL_CXP_PRODUCER_DIR, ()),
471-
],
472464
"pylondataprocessing": [
473465
(PYLON_DATA_PROCESSING_VTOOLS_DIR, PYLON_DATA_PROCESSING_VTOOLS_DIR, ("*Editor*.dll",)),
474466
],
@@ -485,7 +477,6 @@ class BuildSupportWindows(BuildSupport):
485477
DefineMacros = [
486478
("UNICODE", None),
487479
("_UNICODE", None),
488-
("GENTL_CXP_PRODUCER_DIR", gentl_dir_fmt % GENTL_CXP_PRODUCER_DIR),
489480

490481
# let swig share its type information between the 'genicam' and the
491482
# 'pylon' module by using the same name for the type table.
@@ -702,8 +693,6 @@ class BuildSupportLinux(BuildSupport):
702693
"usb": [
703694
(r"pylon-libusb-.*\.so", ""),
704695
],
705-
"cxp": [
706-
],
707696
}
708697

709698
# up to one symlink per library -> match shared objects only
@@ -752,11 +741,11 @@ class BuildSupportLinux(BuildSupport):
752741
(r"libpylonutilitypcl\.so\.\d+\.\d+", ""),
753742
],
754743
"gentl": [
755-
("libpylon_TL_gtc\.so", ""),
744+
(r"libpylon_TL_gtc\.so", ""),
756745
],
757746
"pylondataprocessing": [
758747
(r"libPylonDataProcessing\.so\.\d+", ""),
759-
("libPylonDataProcessing.sig", ""),
748+
(r"libPylonDataProcessing.sig", ""),
760749
(r"libPylonDataProcessingCore\.so\.\d+", ""),
761750
],
762751
}
@@ -1019,7 +1008,7 @@ def copy_runtime(self):
10191008
# cleanup double TL entries in pylon 6.2.0
10201009
if self.get_pylon_version() == "6.2.0.18677":
10211010
for p in Path(f"{full_dst}").glob("**/*TL*.so"):
1022-
if re.match(".*TL_[a-z]+\.so", p.name):
1011+
if re.match(r".*TL_[a-z]+\.so", p.name):
10231012
info(f"DELETE {p}")
10241013
os.remove(p)
10251014

src/pylon/GrabResultData.i

-13
Original file line numberDiff line numberDiff line change
@@ -63,19 +63,6 @@
6363
%#endif
6464
}
6565

66-
int GetNumBufferExports(PyObject * omv)
67-
{
68-
// need at least Python 3.3 for memory view
69-
%#if PY_VERSION_HEX >= 0x03030000
70-
PyMemoryViewObject * mv = (PyMemoryViewObject *) omv;
71-
int ret = (int) mv->mbuf->exports;
72-
Py_DECREF(omv);
73-
return ret;
74-
%#else
75-
return 0;
76-
%#endif
77-
}
78-
7966
PyObject * _Unpack10or12BitPacked()
8067
{
8168
// Current pixel type of our data

src/pylon/GrabResultPtr.i

+44-47
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
%ignore operator IImage&;
44
%rename(GrabResult) Pylon::CGrabResultPtr;
55

6+
%pythoncode %{
7+
from contextlib import contextmanager
8+
import sys
9+
%}
10+
611
%extend Pylon::CGrabResultPtr {
712
%pythoncode %{
813
@needs_numpy
@@ -11,7 +16,7 @@
1116
pt = self.GetPixelType()
1217
if IsPacked(pt):
1318
raise ValueError("Packed Formats are not supported with numpy interface")
14-
if pt in ( PixelType_Mono8, PixelType_BayerGR8, PixelType_BayerRG8, PixelType_BayerGB8, PixelType_BayerBG8 ):
19+
if pt in ( PixelType_Mono8, PixelType_BayerGR8, PixelType_BayerRG8, PixelType_BayerGB8, PixelType_BayerBG8, PixelType_Confidence8, PixelType_Coord3D_C8 ):
1520
shape = (self.GetHeight(), self.GetWidth())
1621
format = "B"
1722
dtype = _pylon_numpy.uint8
@@ -23,7 +28,7 @@
2328
shape = (self.GetHeight(), self.GetWidth())
2429
format = "H"
2530
dtype = _pylon_numpy.uint16
26-
elif pt in ( PixelType_Mono16, PixelType_BayerGR16, PixelType_BayerRG16, PixelType_BayerGB16, PixelType_BayerBG16 ):
31+
elif pt in ( PixelType_Mono16, PixelType_BayerGR16, PixelType_BayerRG16, PixelType_BayerGB16, PixelType_BayerBG16, PixelType_Confidence16, PixelType_Coord3D_C16 ):
2732
shape = (self.GetHeight(), self.GetWidth())
2833
format = "H"
2934
dtype = _pylon_numpy.uint16
@@ -35,6 +40,10 @@
3540
shape = (self.GetHeight(), self.GetWidth(), 2)
3641
dtype = _pylon_numpy.uint8
3742
format = "B"
43+
elif pt in ( PixelType_Coord3D_ABC32f, ):
44+
shape = (self.GetHeight(), self.GetWidth(), 3)
45+
dtype = _pylon_numpy.float32
46+
format = "f"
3847
else:
3948
raise ValueError("Pixel format currently not supported")
4049

@@ -115,52 +124,40 @@
115124
def __exit__(self, type, value, traceback):
116125
self.Release()
117126

118-
from sys import version_info as _gazc_python_version_info
119-
# need at least Python 3.3 for memory view
120-
if _gazc_python_version_info >= (3, 3, 0):
121-
from contextlib import contextmanager
122-
@contextmanager
123-
@needs_numpy
124-
def GetArrayZeroCopy(self, raw = False):
125-
'''
126-
Get a numpy array for the image buffer as zero copy reference to the underlying buffer.
127-
Note: The context manager variable MUST be released before leaving the scope.
128-
'''
129-
130-
# For packed formats, we cannot zero-copy, so use GetArray
131-
pt = self.GetPixelType()
132-
if IsPacked(pt):
133-
yield self.GetArray()
134-
return
127+
@contextmanager
128+
@needs_numpy
129+
def GetArrayZeroCopy(self, raw = False):
130+
'''
131+
Get a numpy array for the image buffer as zero copy reference to the underlying buffer.
132+
Note: The context manager variable MUST be released before leaving the scope.
133+
'''
134+
135+
# For packed formats, we cannot zero-copy, so use GetArray
136+
pt = self.GetPixelType()
137+
if IsPacked(pt):
138+
yield self.GetArray()
139+
return
140+
141+
mv = self.GetImageMemoryView()
142+
if not raw:
143+
shape, dtype, format = self.GetImageFormat()
144+
mv = mv.cast(format, shape)
145+
146+
ar = _pylon_numpy.asarray(mv)
147+
148+
# trace external references to array
149+
initial_refcount = sys.getrefcount(ar)
150+
151+
# yield the array to the context code
152+
yield ar
153+
154+
# detect if more refs than the one from the yield are held
155+
if sys.getrefcount(ar) > initial_refcount + 1:
156+
raise RuntimeError("Please remove any references to the array before leaving context manager scope!!!")
157+
158+
# release the memory view
159+
mv.release()
135160

136-
# Here is the procedure:
137-
# 1. prepare and get image format info
138-
# 2. get a memory view for our image buffer and
139-
# cast it to the right shape and data format
140-
# 3. build an array upon the view (zero copy!)
141-
# 4. as context manager, we yield this array
142-
# 5. delete the array and release our memory
143-
# 6. check the number of exports of the encapsuled buffer
144-
# => if this is > 0 => somebody else still has a reference!
145-
146-
mv = self.GetImageMemoryView()
147-
if not raw:
148-
shape, dtype, format = self.GetImageFormat()
149-
mv = mv.cast(format, shape)
150-
151-
ar = _pylon_numpy.asarray(mv)
152-
153-
yield ar
154-
155-
del ar
156-
mv.release() # Only release() so we can check the references
157-
158-
# There will be one outstanding reference for the 'with target'.
159-
# That is OK since that will be released right after this function
160-
# returns.
161-
if self.GetNumBufferExports(mv) > 1:
162-
raise RuntimeError("Please remove any references to the array before leaving context manager scope!!!")
163-
del _gazc_python_version_info
164161
%}
165162
}
166163

0 commit comments

Comments
 (0)