6from PIL
import Image, ImageDraw, ImageFont
8if sys.version_info >= (3, 11):
9 from PySide6.QtCore
import Qt, QThread, Signal, Slot
10 from PySide6.QtGui
import QAction, QImage, QPixmap, QIcon, QStandardItemModel, QStandardItem
11 from PySide6.QtWidgets
import (QApplication, QMainWindow, QPushButton, QSizePolicy,
12 QVBoxLayout, QWidget, QLabel, QTableView, QHeaderView, QHBoxLayout)
14 from PySide2.QtCore
import Qt, QThread, Signal, Slot
15 from PySide2.QtGui
import QAction, QImage, QPixmap, QIcon, QStandardItemModel, QStandardItem
16 from PySide2.QtWidgets
import (QApplication, QMainWindow, QPushButton, QSizePolicy,
17 QVBoxLayout, QWidget, QLabel, QTableView, QHeaderView, QHBoxLayout)
22OUTPUT_SIZE = (600, 600)
26 cvb.CompositePurpose.Custom:
"Custom",
27 cvb.CompositePurpose.Image:
"Image",
28 cvb.CompositePurpose.PointCloud:
"PointCloud",
29 cvb.CompositePurpose.ImageList:
"ImageList"
33def purpose_from_index(index):
34 if 0 <= index < len(purpose_list):
35 return purpose_list[index]
37 return "Incompatible purpose"
40def resize_image(image, target_size):
41 pil_image = Image.fromarray(image)
42 pil_image = pil_image.resize(target_size, Image.LANCZOS)
43 return np.array(pil_image)
46def format_image(image, mode="RGB"):
47 pil_image = Image.fromarray(image)
48 if pil_image.mode != mode:
49 pil_image = pil_image.convert(mode)
50 return np.array(pil_image)
53def prepare_device(device):
54 nm = device.node_maps[
"Device"]
55 node_tlpl = nm.nodes[
"Std::TLParamsLocked"]
58 node_count = nm.nodes[
"Cust::TestGenDCImageCount"]
60 node_mode = nm.nodes[
"Cust::GenDCFlowMappingConfiguration"]
61 node_mode.value =
"MultipleFlow"
63 node_streamingmode = nm.nodes[
"Std::GenDCStreamingMode"]
64 node_streamingmode.value =
"On"
66 node_tlpl = nm.nodes[
"Std::TLParamsLocked"]
70def create_image_with_text(
73 255, 255, 255), text_color=(0, 0, 0)):
74 image = Image.new(
"RGB", image_size, bg_color)
76 font = ImageFont.load_default()
81 draw = ImageDraw.Draw(image)
82 text_width, text_height = draw.textbbox.textsize(text, font)
83 x = (image_size[0] - text_width) // 2
84 y = (image_size[1] - text_height) // 2
85 draw.text((x, y), text, fill=text_color, font=font)
86 image_array = np.array(image)
93def evaluate_composite(composite, id):
97 table.append(f
"Image ID: {id}")
98 table.append(f
"Composite purpose: {purpose_from_index(composite.purpose)}")
99 table.append(f
"Composite element count: {composite.item_count}")
101 for n
in range(composite.item_count):
103 item_type =
"unknown"
112 img = create_image_with_text(
"part is a plane")
114 item_type =
"plane enumerator"
115 img = create_image_with_text(
"part is a plane enumerator")
117 item_type =
"pfnc buffer"
118 img = create_image_with_text(
"part is a PFNC buffer")
120 img = create_image_with_text(
"unknown part type")
122 table.append(f
"Composite item #{n}: {item_type}")
124 img = format_image(img)
130def subdivide_images(images):
131 num_images = len(images)
132 side_length = int(num_images ** 0.5)
133 num_rows = num_cols = side_length
135 if num_rows * num_cols < num_images:
137 if num_rows * num_cols < num_images:
140 sub_image_width = OUTPUT_SIZE[1] // num_cols
141 sub_image_height = OUTPUT_SIZE[0] // num_rows
143 output_image = np.zeros(
144 (OUTPUT_SIZE[0], OUTPUT_SIZE[1], 3), dtype=np.uint8)
146 for idx, image
in enumerate(images):
147 sub_image = resize_image(image, (sub_image_width, sub_image_height))
148 row = idx // num_cols
150 output_image[row * sub_image_height:(row + 1) * sub_image_height,
151 col * sub_image_width:(col + 1) * sub_image_width] = sub_image
157class AcquisitionThread(QThread):
159 updateFrame = Signal(np.ndarray)
160 updateTable = Signal(list)
162 def __init__(self, parent=None):
163 QThread.__init__(self, parent)
169 cvb.DiscoverFlags.IgnoreVins | cvb.DiscoverFlags.IncludeMockTL, time_span=300)
172 cvb.DiscoverFlags.IgnoreVins, time_span=300)
175 device_token = next(iter([dev.access_token
for dev
in devices
if
176 (MOCK
and "MockTL" in dev.access_token)
or
177 (
not MOCK
and "SD" in dev.access_token)]),
None)
180 raise RuntimeError(
"No suitable device found.")
184 prepare_device(device)
190 wait_result = stream.wait()
193 images, table = evaluate_composite(composite, image_count)
195 output_image = subdivide_images(images)
197 output_image = images[0]
199 output_image_copy = output_image.copy()
201 self.updateFrame.emit(output_image_copy)
202 self.updateTable.emit(table)
213class Window(QMainWindow):
217 self.setWindowTitle(
"CVB GenDC Demo")
218 self.setGeometry(0, 0, 800, 700)
219 script_dir = os.path.dirname(os.path.realpath(__file__))
220 icon_path = os.path.join(script_dir,
'Tutorial-Python_32x32.png')
221 self.setWindowIcon(QIcon(icon_path))
223 menu = self.menuBar()
224 menu_file = menu.addMenu(
"File")
225 exit = QAction(
"Exit", self, triggered=qApp.quit)
226 menu_file.addAction(exit)
229 self.label = QLabel(self)
230 self.label.setAlignment(Qt.AlignCenter)
231 self.label.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
233 buttons_layout = QHBoxLayout()
234 self.button1 = QPushButton(
"Start")
235 self.button2 = QPushButton(
"Stop/Close")
236 self.button1.setMaximumWidth(100)
237 self.button2.setMaximumWidth(100)
238 self.button1.clicked.connect(self.start)
239 self.button2.clicked.connect(self.kill_thread)
240 self.button2.setEnabled(
False)
241 buttons_layout.addWidget(self.button1)
242 buttons_layout.addWidget(self.button2)
244 self.table_model = QStandardItemModel(0, 1, self)
245 self.table_view = QTableView(self)
246 self.table_view.setModel(self.table_model)
247 self.table_view.verticalHeader().setVisible(
False)
248 self.table_view.verticalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
251 table_widget = QWidget()
252 table_layout = QVBoxLayout()
253 table_layout.addWidget(self.table_view)
254 table_widget.setLayout(table_layout)
255 table_widget.setSizePolicy(
256 QSizePolicy.Expanding, QSizePolicy.Preferred)
257 image_widget = QWidget()
258 image_layout = QVBoxLayout()
259 image_layout.addWidget(self.label)
260 image_widget.setLayout(image_layout)
261 central_widget = QWidget(self)
262 central_layout = QVBoxLayout()
263 central_layout.addWidget(image_widget)
264 central_layout.addLayout(buttons_layout)
265 central_layout.addWidget(table_widget)
266 central_widget.setLayout(central_layout)
267 self.setCentralWidget(central_widget)
270 self.th = AcquisitionThread(self)
271 self.th.finished.connect(self.close)
272 self.th.updateFrame.connect(self.set_image)
273 self.th.updateTable.connect(self.update_table)
276 dummy_array = np.zeros(
277 (OUTPUT_SIZE[0], OUTPUT_SIZE[1], 3), dtype=np.uint8)
278 self.set_image(dummy_array)
280 dummy_table_data = [
"Press start to begin GenDC streaming"]
281 self.update_table(dummy_table_data)
284 def set_image(self, np_image):
285 h, w, ch = np_image.shape
286 q_img = QImage(np_image.data, w, h, ch * w, QImage.Format_RGB888)
287 scaled_image = QPixmap.fromImage(q_img)
288 self.label.setPixmap(scaled_image)
291 def kill_thread(self):
292 print(
"Finishing...")
293 self.button2.setEnabled(
False)
294 self.button1.setEnabled(
True)
303 text.append(
"Starting...")
304 self.update_table(text)
305 self.button2.setEnabled(
True)
306 self.button1.setEnabled(
False)
310 def update_table(self, data):
311 self.table_model.removeRows(0, self.table_model.rowCount())
312 self.table_model.setHorizontalHeaderLabels([
"Infos"])
315 self.table_model.appendRow(QStandardItem(item))
317 self.table_view.horizontalHeader().setSectionResizeMode(
318 QHeaderView.ResizeToContents)
321if __name__ ==
"__main__":
322 app = QApplication(sys.argv)
324 if sys.platform ==
'win32':
326 myappid =
u'stemmerimaging.commonvisionblox.pystreamdisplay.0'
327 ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
The Common Vision Blox composite.
Definition: __init__.py:745
The composite stream class.
Definition: __init__.py:782
Union[cvb.GenICamDevice, cvb.VinDevice, cvb.EmuDevice, cvb.VideoDevice, cvb.NonStreamingDevice] open(str provider, int acquisition_stack=cvb.AcquisitionStack.PreferVin)
Opens a device with the given provider and acquisition stack.
Definition: __init__.py:1570
List[cvb.DiscoveryInformation] discover_from_root(int flags=cvb.DiscoverFlags.FindAll, int time_span=300)
Discovers available devices / nodes depending on the given flags.
Definition: __init__.py:1550
A GenICam compliant device.
Definition: __init__.py:2022
The Common Vision Blox image.
Definition: __init__.py:2038
PFNC buffer class implementing the IPFNCBuffer interface.
Definition: __init__.py:3856
A collection of planes.
Definition: __init__.py:4208
Plane container.
Definition: __init__.py:4066
numpy.array to_array(Any buffer)
Copies buffer values of a cvb object to a newly created numpy array.
Definition: __init__.py:8527