Hi,
I use the camera control code inside a machine that has a PySide6 (QT) UI. To keep the UI from frezzing I need to do all the calculations inside a QThread that runs independently from the main UI thread.
Based on the forum entry “Getting Started with CVBpy” I implemented my blah which also runs and terminates without problems on the main thread of a python script.
However, as soon as I run this thread the application crashes after everything is done. That means in the moment where the thread is cleaned up it comes to a segfault (Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)).
By using gdb I know that it happens exactly when the thread is cleaned up. So I suspect that I am doing something wrong with the camera code and therefore some resource is still open and this then leads to a crash during thread termination.
My environment:
Ubuntu 22.04
Python 3.9.16
CVB 13.04.005
Code of a minimal (not) working example :
camera.py
from dataclasses import dataclass
from pathlib import Path
import cvb
import numpy as np
@dataclass
class Camera:
"""
Class which holds the logic of the camera. Since there is currently only on type of camera deployed the path to
the driver is hardcoded and set to port 0
"""
camera_path = Path(cvb.install_path()) / "drivers" / "GenICam.vin"
def take_image(self) -> np.array:
"""
Calls the CVB driver and retrieves am image from the there stored camera on port 0. Since the image is
provided by an image stream, a copy of the matrix must be done, which is then returned.
:return np.array: captured image from the driver which is stored inside a `np.array
"""
try:
with cvb.DeviceFactory.open(str(self.camera_path), port=0) as device:
stream = device.stream()
stream.start()
image, status = stream.wait()
stream.try_abort()
if status == cvb.WaitStatus.Ok:
image.unlock()
return cvb.as_array(image, copy=True)
else:
print(f"Image acquisition status was not ok. It was {status}")
except Exception as e:
print(f"Exception while taking picture! {e}")
finally:
pass
# del device
# del stream
# del status
runner.py
import time
from PySide6.QtCore import QRunnable, Slot
from cvb_bug.camera import Camera
class Runner(QRunnable):
@Slot()
def run(self) -> None:
try:
camera = Camera()
for x in range(5):
image = camera.take_image()
print(image.shape)
time.sleep(0.5)
except Exception as e:
print(e)
main_threaded.py
import sys
from PySide6.QtCore import QThreadPool
from PySide6.QtWidgets import QMainWindow, QVBoxLayout, QPushButton, QWidget, QApplication
from cvb_bug.runner import Runner
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.threadpool = None
self.runner = None
layout = QVBoxLayout()
btn = QPushButton("Start")
btn.pressed.connect(self.start)
layout.addWidget(btn)
w = QWidget()
w.setLayout(layout)
self.setCentralWidget(w)
self.show()
def start(self):
print("START")
self.threadpool = QThreadPool()
self.runner = Runner()
self.threadpool.start(self.runner)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
app.exec()
Since I described above that it works without thread here is a main script which called my camera control without threads.
import time
from cvb_bug.camera import Camera
if __name__ == "__main__":
camera = Camera()
for x in range(5):
image = camera.take_image()
print(image.shape)
time.sleep(0.5)
Last but not least here is the dump from gdb where you can see the crash when thread 26046 terminates. Since it is lenghtly here is a pastebin link
I hope you have any ideas what I have done with the camera code.
I could also provide the complete example as a github repo if this helps.
Greetings Sebastian