8from PIL
import Image, ImageDraw, ImageFont
10if sys.version_info >= (3, 11):
11 from PySide6.QtCore
import Qt, QThread, Signal, Slot
12 from PySide6.QtGui
import QAction, QImage, QPixmap, QIcon, QStandardItemModel, QStandardItem
13 from PySide6.QtWidgets
import (QApplication, QMainWindow, QPushButton, QSizePolicy,
14 QVBoxLayout, QWidget, QLabel, QTableView, QHeaderView, QHBoxLayout)
16 from PySide2.QtCore
import Qt, QThread, Signal, Slot
17 from PySide2.QtGui
import QAction, QImage, QPixmap, QIcon, QStandardItemModel, QStandardItem
18 from PySide2.QtWidgets
import (QApplication, QMainWindow, QPushButton, QSizePolicy,
19 QVBoxLayout, QWidget, QLabel, QTableView, QHeaderView, QHBoxLayout)
24OUTPUT_SIZE = (600, 600)
28 cvb.CompositePurpose.Custom:
"Custom",
29 cvb.CompositePurpose.Image:
"Image",
30 cvb.CompositePurpose.PointCloud:
"PointCloud",
31 cvb.CompositePurpose.ImageList:
"ImageList"
35def purpose_from_index(index):
36 if 0 <= index < len(purpose_list):
37 return purpose_list[index]
39 return "Incompatible purpose"
42def resize_image(image, target_size):
43 pil_image = Image.fromarray(image)
44 pil_image = pil_image.resize(target_size, Image.LANCZOS)
45 return np.array(pil_image)
48def format_image(image, mode="RGB"):
49 pil_image = Image.fromarray(image)
50 if pil_image.mode != mode:
51 pil_image = pil_image.convert(mode)
52 return np.array(pil_image)
55def prepare_device(device):
56 nm = device.node_maps[
"Device"]
57 node_tlpl = nm.nodes[
"Std::TLParamsLocked"]
60 node_count = nm.nodes[
"Cust::TestGenDCImageCount"]
62 node_mode = nm.nodes[
"Cust::GenDCFlowMappingConfiguration"]
63 node_mode.value =
"MultipleFlow"
65 node_streamingmode = nm.nodes[
"Std::GenDCStreamingMode"]
66 node_streamingmode.value =
"On"
68 node_tlpl = nm.nodes[
"Std::TLParamsLocked"]
72def create_image_with_text(
75 255, 255, 255), text_color=(0, 0, 0)):
76 image = Image.new(
"RGB", image_size, bg_color)
78 font = ImageFont.load_default()
83 draw = ImageDraw.Draw(image)
84 text_width, text_height = draw.textbbox.textsize(text, font)
85 x = (image_size[0] - text_width) // 2
86 y = (image_size[1] - text_height) // 2
87 draw.text((x, y), text, fill=text_color, font=font)
88 image_array = np.array(image)
95def evaluate_composite(composite, id):
99 table.append(f
"Image ID: {id}")
100 table.append(f
"Composite purpose: {purpose_from_index(composite.purpose)}")
101 table.append(f
"Composite element count: {composite.item_count}")
103 for n
in range(composite.item_count):
105 item_type =
"unknown"
114 img = create_image_with_text(
"part is a plane")
116 item_type =
"plane enumerator"
117 img = create_image_with_text(
"part is a plane enumerator")
119 item_type =
"pfnc buffer"
120 img = create_image_with_text(
"part is a PFNC buffer")
122 img = create_image_with_text(
"unknown part type")
124 table.append(f
"Composite item #{n}: {item_type}")
126 img = format_image(img)
132def subdivide_images(images):
133 num_images = len(images)
134 side_length = int(num_images ** 0.5)
135 num_rows = num_cols = side_length
137 if num_rows * num_cols < num_images:
139 if num_rows * num_cols < num_images:
142 sub_image_width = OUTPUT_SIZE[1] // num_cols
143 sub_image_height = OUTPUT_SIZE[0] // num_rows
145 output_image = np.zeros(
146 (OUTPUT_SIZE[0], OUTPUT_SIZE[1], 3), dtype=np.uint8)
148 for idx, image
in enumerate(images):
149 sub_image = resize_image(image, (sub_image_width, sub_image_height))
150 row = idx // num_cols
152 output_image[row * sub_image_height:(row + 1) * sub_image_height,
153 col * sub_image_width:(col + 1) * sub_image_width] = sub_image
159class AcquisitionThread(QThread):
161 updateFrame = Signal(np.ndarray)
162 updateTable = Signal(list)
164 def __init__(self, parent=None):
165 QThread.__init__(self, parent)
171 cvb.DiscoverFlags.IgnoreVins | cvb.DiscoverFlags.IncludeMockTL, time_span=300)
174 cvb.DiscoverFlags.IgnoreVins, time_span=300)
177 device_token = next(iter([dev.access_token
for dev
in devices
if
178 (MOCK
and "MockTL" in dev.access_token)
or
179 (
not MOCK
and "SD" in dev.access_token)]),
None)
182 raise RuntimeError(
"No suitable device found.")
186 prepare_device(device)
192 wait_result = stream.wait()
195 images, table = evaluate_composite(composite, image_count)
197 output_image = subdivide_images(images)
199 output_image = images[0]
201 output_image_copy = output_image.copy()
203 self.updateFrame.emit(output_image_copy)
204 self.updateTable.emit(table)
215class Window(QMainWindow):
219 self.setWindowTitle(
"CVB GenDC Demo")
220 self.setGeometry(0, 0, 800, 700)
221 script_dir = os.path.dirname(os.path.realpath(__file__))
222 icon_path = os.path.join(script_dir,
'Tutorial-Python_32x32.png')
223 self.setWindowIcon(QIcon(icon_path))
225 menu = self.menuBar()
226 menu_file = menu.addMenu(
"File")
227 exit = QAction(
"Exit", self, triggered=qApp.quit)
228 menu_file.addAction(exit)
231 self.label = QLabel(self)
232 self.label.setAlignment(Qt.AlignCenter)
233 self.label.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
235 buttons_layout = QHBoxLayout()
236 self.button1 = QPushButton(
"Start")
237 self.button2 = QPushButton(
"Stop/Close")
238 self.button1.setMaximumWidth(100)
239 self.button2.setMaximumWidth(100)
240 self.button1.clicked.connect(self.start)
241 self.button2.clicked.connect(self.kill_thread)
242 self.button2.setEnabled(
False)
243 buttons_layout.addWidget(self.button1)
244 buttons_layout.addWidget(self.button2)
246 self.table_model = QStandardItemModel(0, 1, self)
247 self.table_view = QTableView(self)
248 self.table_view.setModel(self.table_model)
249 self.table_view.verticalHeader().setVisible(
False)
250 self.table_view.verticalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
253 table_widget = QWidget()
254 table_layout = QVBoxLayout()
255 table_layout.addWidget(self.table_view)
256 table_widget.setLayout(table_layout)
257 table_widget.setSizePolicy(
258 QSizePolicy.Expanding, QSizePolicy.Preferred)
259 image_widget = QWidget()
260 image_layout = QVBoxLayout()
261 image_layout.addWidget(self.label)
262 image_widget.setLayout(image_layout)
263 central_widget = QWidget(self)
264 central_layout = QVBoxLayout()
265 central_layout.addWidget(image_widget)
266 central_layout.addLayout(buttons_layout)
267 central_layout.addWidget(table_widget)
268 central_widget.setLayout(central_layout)
269 self.setCentralWidget(central_widget)
272 self.th = AcquisitionThread(self)
273 self.th.finished.connect(self.close)
274 self.th.updateFrame.connect(self.set_image)
275 self.th.updateTable.connect(self.update_table)
278 dummy_array = np.zeros(
279 (OUTPUT_SIZE[0], OUTPUT_SIZE[1], 3), dtype=np.uint8)
280 self.set_image(dummy_array)
282 dummy_table_data = [
"Press start to begin GenDC streaming"]
283 self.update_table(dummy_table_data)
286 def set_image(self, np_image):
287 h, w, ch = np_image.shape
288 q_img = QImage(np_image.data, w, h, ch * w, QImage.Format_RGB888)
289 scaled_image = QPixmap.fromImage(q_img)
290 self.label.setPixmap(scaled_image)
293 def kill_thread(self):
294 print(
"Finishing...")
295 self.button2.setEnabled(
False)
296 self.button1.setEnabled(
True)
305 text.append(
"Starting...")
306 self.update_table(text)
307 self.button2.setEnabled(
True)
308 self.button1.setEnabled(
False)
312 def update_table(self, data):
313 self.table_model.removeRows(0, self.table_model.rowCount())
314 self.table_model.setHorizontalHeaderLabels([
"Infos"])
317 self.table_model.appendRow(QStandardItem(item))
319 self.table_view.horizontalHeader().setSectionResizeMode(
320 QHeaderView.ResizeToContents)
323if __name__ ==
"__main__":
324 app = QApplication(sys.argv)
326 if sys.platform ==
'win32':
328 myappid =
u'stemmerimaging.commonvisionblox.pystreamdisplay.0'
329 ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
The Common Vision Blox composite.
Definition: __init__.py:804
The composite stream class.
Definition: __init__.py:841
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:1629
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:1609
A GenICam compliant device.
Definition: __init__.py:2081
The Common Vision Blox image.
Definition: __init__.py:2097
PFNC buffer class implementing the IPFNCBuffer interface.
Definition: __init__.py:3917
A collection of planes.
Definition: __init__.py:4269
Plane container.
Definition: __init__.py:4127
numpy.array to_array(Any buffer)
Copies buffer values of a cvb object to a newly created numpy array.
Definition: __init__.py:8588