From 50a3ad341de277728b27c9138c958e4ef86d6da8 Mon Sep 17 00:00:00 2001
From: boris
Ready. Select folder(s) to process...
") + self.label_8.setIndent(10) + + self.horizontalLayout_17.addWidget(self.label_8) + + self.pushButton_10 = QPushButton(self.verticalLayoutWidget) + self.pushButton_10.setObjectName(u"pushButton_10") + self.pushButton_10.setEnabled(False) +#if QT_CONFIG(tooltip) + self.pushButton_10.setToolTip(u"Open selected item in File Explorer") +#endif // QT_CONFIG(tooltip) + self.pushButton_10.setText(u"") + icon20 = QIcon() + icon20.addFile(u":/icons/icons8-file-explorer-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.pushButton_10.setIcon(icon20) + self.pushButton_10.setIconSize(QSize(20, 20)) + self.pushButton_10.setAutoDefault(False) + self.pushButton_10.setFlat(False) + + self.horizontalLayout_17.addWidget(self.pushButton_10) + + + self.gridLayout.addLayout(self.horizontalLayout_17, 3, 0, 1, 1) + + self.line = QFrame(self.verticalLayoutWidget) + self.line.setObjectName(u"line") + self.line.setFrameShadow(QFrame.Plain) + self.line.setFrameShape(QFrame.VLine) + + self.gridLayout.addWidget(self.line, 0, 1, 5, 1) + + self.progressBar = QProgressBar(self.verticalLayoutWidget) + self.progressBar.setObjectName(u"progressBar") + self.progressBar.setEnabled(False) + sizePolicy3.setHeightForWidth(self.progressBar.sizePolicy().hasHeightForWidth()) + self.progressBar.setSizePolicy(sizePolicy3) + font6 = QFont() + font6.setFamily(u"Segoe UI") + font6.setPointSize(10) + self.progressBar.setFont(font6) + self.progressBar.setMinimum(0) + self.progressBar.setMaximum(10) + self.progressBar.setValue(0) + self.progressBar.setAlignment(Qt.AlignCenter) + self.progressBar.setTextVisible(True) + self.progressBar.setOrientation(Qt.Horizontal) + self.progressBar.setTextDirection(QProgressBar.TopToBottom) + self.progressBar.setFormat(u"Completed %v of %m") + + self.gridLayout.addWidget(self.progressBar, 4, 0, 1, 1) + + self.horizontalLayout = QHBoxLayout() + self.horizontalLayout.setSpacing(5) + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.lineEdit = QLineEdit(self.verticalLayoutWidget) + self.lineEdit.setObjectName(u"lineEdit") + self.lineEdit.setEnabled(False) + sizePolicy3.setHeightForWidth(self.lineEdit.sizePolicy().hasHeightForWidth()) + self.lineEdit.setSizePolicy(sizePolicy3) + self.lineEdit.setMaximumSize(QSize(16777215, 24)) + self.lineEdit.setFont(font6) +#if QT_CONFIG(statustip) + self.lineEdit.setStatusTip(u"Path to main folder with data sub-folders...") +#endif // QT_CONFIG(statustip) +#if QT_CONFIG(whatsthis) + self.lineEdit.setWhatsThis(u"Path to main folder with data sub-folders...") +#endif // QT_CONFIG(whatsthis) + self.lineEdit.setPlaceholderText(u"Data location...") + + self.horizontalLayout.addWidget(self.lineEdit) + + self.pushButton = QPushButton(self.verticalLayoutWidget) + self.pushButton.setObjectName(u"pushButton") + self.pushButton.setEnabled(False) + sizePolicy4.setHeightForWidth(self.pushButton.sizePolicy().hasHeightForWidth()) + self.pushButton.setSizePolicy(sizePolicy4) + self.pushButton.setMinimumSize(QSize(0, 30)) + self.pushButton.setMaximumSize(QSize(16777215, 30)) + self.pushButton.setCursor(QCursor(Qt.PointingHandCursor)) +#if QT_CONFIG(statustip) + self.pushButton.setStatusTip(u"Data location (root folder with sub-folders containing data)") +#endif // QT_CONFIG(statustip) + self.pushButton.setText(u"Browse") + icon21 = QIcon() + icon21.addFile(u":/icons/icons8-browse-folder-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.pushButton.setIcon(icon21) + self.pushButton.setIconSize(QSize(20, 20)) + + self.horizontalLayout.addWidget(self.pushButton) + + self.pushButton_4 = QPushButton(self.verticalLayoutWidget) + self.pushButton_4.setObjectName(u"pushButton_4") + sizePolicy4.setHeightForWidth(self.pushButton_4.sizePolicy().hasHeightForWidth()) + self.pushButton_4.setSizePolicy(sizePolicy4) + self.pushButton_4.setMinimumSize(QSize(0, 30)) + self.pushButton_4.setMaximumSize(QSize(16777215, 30)) + self.pushButton_4.setCursor(QCursor(Qt.PointingHandCursor)) + self.pushButton_4.setText(u"Refresh") + icon22 = QIcon() + icon22.addFile(u":/icons/icons8-available-updates-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.pushButton_4.setIcon(icon22) + self.pushButton_4.setIconSize(QSize(20, 20)) + + self.horizontalLayout.addWidget(self.pushButton_4) + + + self.gridLayout.addLayout(self.horizontalLayout, 1, 0, 1, 1) + + self.label_16 = QLabel(self.verticalLayoutWidget) + self.label_16.setObjectName(u"label_16") + sizePolicy1.setHeightForWidth(self.label_16.sizePolicy().hasHeightForWidth()) + self.label_16.setSizePolicy(sizePolicy1) + self.label_16.setMaximumSize(QSize(16777215, 20)) + self.label_16.setFont(font6) + self.label_16.setFrameShape(QFrame.StyledPanel) + self.label_16.setText(u"Selected: 0
") + self.label_16.setIndent(10) + + self.gridLayout.addWidget(self.label_16, 3, 2, 1, 1) + + self.tabWidget = QTabWidget(self.verticalLayoutWidget) + self.tabWidget.setObjectName(u"tabWidget") + sizePolicy2.setHeightForWidth(self.tabWidget.sizePolicy().hasHeightForWidth()) + self.tabWidget.setSizePolicy(sizePolicy2) + self.tabWidget.setMinimumSize(QSize(300, 0)) + self.tabWidget.setMaximumSize(QSize(300, 16777215)) + self.tabWidget.setIconSize(QSize(20, 20)) + self.tabWidget.setDocumentMode(True) + self.tab = QWidget() + self.tab.setObjectName(u"tab") + self.layoutWidget = QWidget(self.tab) + self.layoutWidget.setObjectName(u"layoutWidget") + self.layoutWidget.setGeometry(QRect(0, 10, 301, 561)) + self.gridLayout_3 = QGridLayout(self.layoutWidget) + self.gridLayout_3.setSpacing(5) + self.gridLayout_3.setContentsMargins(10, 10, 10, 10) + self.gridLayout_3.setObjectName(u"gridLayout_3") + self.gridLayout_3.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_8 = QHBoxLayout() + self.horizontalLayout_8.setSpacing(5) + self.horizontalLayout_8.setObjectName(u"horizontalLayout_8") + self.cbChunkSettings = QComboBox(self.layoutWidget) + icon23 = QIcon() + icon23.addFile(u":/icons/icons8-add-tab-50.png", QSize(), QIcon.Normal, QIcon.Off) + icon24 = QIcon() + icon24.addFile(u":/icons/kalota_m.png", QSize(), QIcon.Normal, QIcon.Off) + icon25 = QIcon() + icon25.addFile(u":/icons/stopnca_o.png", QSize(), QIcon.Normal, QIcon.Off) + icon26 = QIcon() + icon26.addFile(u":/icons/stopnca_s.png", QSize(), QIcon.Normal, QIcon.Off) + for section in autoftg_main.chunk_sections: + menu_icon = autoftg_main.menuCfg.get(section, "menu_icon") + menu_icon_path = u":/icons/" + autoftg_main.icoCfg.get("ICONS", menu_icon) + setticon = QIcon() + setticon.addFile(menu_icon_path, QSize(), QIcon.Normal, QIcon.Off) + self.cbChunkSettings.addItem(setticon, section) + + self.cbChunkSettings.setCurrentText(self.itemDef) + self.cbChunkSettings.setObjectName(u"cbChunkSettings") + sizePolicy7 = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed) + sizePolicy7.setHorizontalStretch(0) + sizePolicy7.setVerticalStretch(0) + sizePolicy7.setHeightForWidth(self.cbChunkSettings.sizePolicy().hasHeightForWidth()) + self.cbChunkSettings.setSizePolicy(sizePolicy7) + self.cbChunkSettings.setMinimumSize(QSize(200, 0)) + self.cbChunkSettings.setFont(font6) + self.cbChunkSettings.setCursor(QCursor(Qt.PointingHandCursor)) +#if QT_CONFIG(statustip) + self.cbChunkSettings.setStatusTip(u"Choose settings used for chunk creation...") +#endif // QT_CONFIG(statustip) + self.cbChunkSettings.setIconSize(QSize(20, 20)) + + self.horizontalLayout_8.addWidget(self.cbChunkSettings) + + self.btnDefChunk = QPushButton(self.layoutWidget) + self.btnDefChunk.setObjectName(u"btnDefChunk") + self.btnDefChunk.setCursor(QCursor(Qt.PointingHandCursor)) +#if QT_CONFIG(tooltip) + self.btnDefChunk.setToolTip(u"Set as default") +#endif // QT_CONFIG(tooltip) + self.btnDefChunk.setText(u"") + icon27 = QIcon() + icon27.addFile(u":/icons/icons8-christmas-star-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.btnDefChunk.setIcon(icon27) + self.btnDefChunk.setIconSize(QSize(20, 20)) + self.btnDefChunk.setAutoDefault(False) + self.btnDefChunk.setFlat(True) + + self.horizontalLayout_8.addWidget(self.btnDefChunk) + + + self.gridLayout_3.addLayout(self.horizontalLayout_8, 6, 0, 1, 1) + + self.line_3 = QFrame(self.layoutWidget) + self.line_3.setObjectName(u"line_3") + self.line_3.setFrameShadow(QFrame.Plain) + self.line_3.setFrameShape(QFrame.HLine) + + self.gridLayout_3.addWidget(self.line_3, 15, 0, 1, 1) + + self.label_5 = QLabel(self.layoutWidget) + self.label_5.setObjectName(u"label_5") + sizePolicy5.setHeightForWidth(self.label_5.sizePolicy().hasHeightForWidth()) + self.label_5.setSizePolicy(sizePolicy5) + self.label_5.setMinimumSize(QSize(0, 26)) + self.label_5.setMaximumSize(QSize(16777215, 26)) + font7 = QFont() + font7.setFamily(u"Segoe UI") + font7.setPointSize(11) + font7.setBold(True) + font7.setWeight(75) + self.label_5.setFont(font7) + self.label_5.setText(u"Markers") + self.label_5.setIndent(5) + + self.gridLayout_3.addWidget(self.label_5, 21, 0, 1, 1) + + self.horizontalLayout_13 = QHBoxLayout() + self.horizontalLayout_13.setSpacing(5) + self.horizontalLayout_13.setObjectName(u"horizontalLayout_13") + self.horizontalLayout_13.setContentsMargins(5, -1, -1, -1) + self.checkBox_mesh = QCheckBox(self.layoutWidget) + self.checkBox_mesh.setObjectName(u"checkBox_mesh") + self.checkBox_mesh.setEnabled(True) + sizePolicy5.setHeightForWidth(self.checkBox_mesh.sizePolicy().hasHeightForWidth()) + self.checkBox_mesh.setSizePolicy(sizePolicy5) + self.checkBox_mesh.setCursor(QCursor(Qt.PointingHandCursor)) +#if QT_CONFIG(tooltip) + self.checkBox_mesh.setToolTip(u"Enable to run 'Build Mesh/Build Textures' processing for selected items.
") +#endif // QT_CONFIG(tooltip) + self.checkBox_mesh.setText(u"Build Mesh && Textures") + self.checkBox_mesh.setIcon(icon5) + self.checkBox_mesh.setIconSize(QSize(18, 18)) + self.checkBox_mesh.setCheckable(True) + self.checkBox_mesh.setChecked(False) + self.checkBox_mesh.setTristate(False) + + self.horizontalLayout_13.addWidget(self.checkBox_mesh) + + self.pushButton_setMesh = QPushButton(self.layoutWidget) + self.pushButton_setMesh.setObjectName(u"pushButton_setMesh") + self.pushButton_setMesh.setEnabled(True) + sizePolicy4.setHeightForWidth(self.pushButton_setMesh.sizePolicy().hasHeightForWidth()) + self.pushButton_setMesh.setSizePolicy(sizePolicy4) + self.pushButton_setMesh.setCursor(QCursor(Qt.PointingHandCursor)) + icon28 = QIcon() + icon28.addFile(u":/icons/icons8-adjust-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.pushButton_setMesh.setIcon(icon28) + self.pushButton_setMesh.setFlat(True) + + self.horizontalLayout_13.addWidget(self.pushButton_setMesh) + + + self.gridLayout_3.addLayout(self.horizontalLayout_13, 32, 0, 1, 1) + + self.horizontalLayout_15 = QHBoxLayout() + self.horizontalLayout_15.setSpacing(5) + self.horizontalLayout_15.setObjectName(u"horizontalLayout_15") + self.horizontalLayout_15.setContentsMargins(5, -1, -1, -1) + self.checkBox_export = QCheckBox(self.layoutWidget) + self.checkBox_export.setObjectName(u"checkBox_export") + self.checkBox_export.setEnabled(True) + sizePolicy5.setHeightForWidth(self.checkBox_export.sizePolicy().hasHeightForWidth()) + self.checkBox_export.setSizePolicy(sizePolicy5) + self.checkBox_export.setCursor(QCursor(Qt.PointingHandCursor)) +#if QT_CONFIG(tooltip) + self.checkBox_export.setToolTip(u"Enable to export data for selected items after build is complete.
") +#endif // QT_CONFIG(tooltip) + self.checkBox_export.setText(u"Export Data") + icon29 = QIcon() + icon29.addFile(u":/icons/icons8-share-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.checkBox_export.setIcon(icon29) + self.checkBox_export.setIconSize(QSize(18, 18)) + self.checkBox_export.setCheckable(True) + self.checkBox_export.setChecked(False) + self.checkBox_export.setTristate(False) + + self.horizontalLayout_15.addWidget(self.checkBox_export) + + self.pushButton_setExport = QPushButton(self.layoutWidget) + self.pushButton_setExport.setObjectName(u"pushButton_setExport") + self.pushButton_setExport.setEnabled(False) + sizePolicy4.setHeightForWidth(self.pushButton_setExport.sizePolicy().hasHeightForWidth()) + self.pushButton_setExport.setSizePolicy(sizePolicy4) + self.pushButton_setExport.setCursor(QCursor(Qt.PointingHandCursor)) + icon30 = QIcon() + icon30.addFile(u":/icons/icons8-true-false-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.pushButton_setExport.setIcon(icon30) + self.pushButton_setExport.setFlat(True) + + self.horizontalLayout_15.addWidget(self.pushButton_setExport) + + + self.gridLayout_3.addLayout(self.horizontalLayout_15, 35, 0, 1, 1) + + self.line_6 = QFrame(self.layoutWidget) + self.line_6.setObjectName(u"line_6") + self.line_6.setFrameShape(QFrame.HLine) + self.line_6.setFrameShadow(QFrame.Sunken) + + self.gridLayout_3.addWidget(self.line_6, 30, 0, 1, 1) + + self.horizontalLayout_20 = QHBoxLayout() + self.horizontalLayout_20.setSpacing(5) + self.horizontalLayout_20.setObjectName(u"horizontalLayout_20") + self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) + + self.horizontalLayout_20.addItem(self.horizontalSpacer) + + self.pushButton_resetSet = QPushButton(self.layoutWidget) + self.pushButton_resetSet.setObjectName(u"pushButton_resetSet") + sizePolicy4.setHeightForWidth(self.pushButton_resetSet.sizePolicy().hasHeightForWidth()) + self.pushButton_resetSet.setSizePolicy(sizePolicy4) +#if QT_CONFIG(tooltip) + self.pushButton_resetSet.setToolTip(u"Reset settings to definition values.") +#endif // QT_CONFIG(tooltip) + self.pushButton_resetSet.setText(u"Reset") + icon31 = QIcon() + icon31.addFile(u":/icons/icons8-rotate-48.png", QSize(), QIcon.Normal, QIcon.Off) + self.pushButton_resetSet.setIcon(icon31) + self.pushButton_resetSet.setIconSize(QSize(20, 20)) + self.pushButton_resetSet.setFlat(True) + + self.horizontalLayout_20.addWidget(self.pushButton_resetSet) + + self.pushButton_saveSet = QPushButton(self.layoutWidget) + self.pushButton_saveSet.setObjectName(u"pushButton_saveSet") + sizePolicy4.setHeightForWidth(self.pushButton_saveSet.sizePolicy().hasHeightForWidth()) + self.pushButton_saveSet.setSizePolicy(sizePolicy4) +#if QT_CONFIG(tooltip) + self.pushButton_saveSet.setToolTip(u"Save current settings to selected definition.") +#endif // QT_CONFIG(tooltip) + self.pushButton_saveSet.setText(u"Save") + icon32 = QIcon() + icon32.addFile(u":/icons/icons8-save-all-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.pushButton_saveSet.setIcon(icon32) + self.pushButton_saveSet.setIconSize(QSize(20, 20)) + self.pushButton_saveSet.setAutoDefault(False) + self.pushButton_saveSet.setFlat(True) + + self.horizontalLayout_20.addWidget(self.pushButton_saveSet) + + + self.gridLayout_3.addLayout(self.horizontalLayout_20, 38, 0, 1, 1) + + self.horizontalLayout_11 = QHBoxLayout() + self.horizontalLayout_11.setSpacing(5) + self.horizontalLayout_11.setObjectName(u"horizontalLayout_11") + self.horizontalLayout_11.setContentsMargins(5, -1, -1, -1) + self.checkBox_align = QCheckBox(self.layoutWidget) + self.checkBox_align.setObjectName(u"checkBox_align") + self.checkBox_align.setEnabled(True) + sizePolicy5.setHeightForWidth(self.checkBox_align.sizePolicy().hasHeightForWidth()) + self.checkBox_align.setSizePolicy(sizePolicy5) + self.checkBox_align.setCursor(QCursor(Qt.PointingHandCursor)) +#if QT_CONFIG(tooltip) + self.checkBox_align.setToolTip(u"Enable to run 'Align Photos' process for selected items.
") +#endif // QT_CONFIG(tooltip) + self.checkBox_align.setText(u"Align Photos") + self.checkBox_align.setIcon(icon4) + self.checkBox_align.setIconSize(QSize(18, 18)) + self.checkBox_align.setCheckable(True) + self.checkBox_align.setChecked(False) + self.checkBox_align.setTristate(False) + + self.horizontalLayout_11.addWidget(self.checkBox_align) + + self.pushButton_setAlign = QPushButton(self.layoutWidget) + self.pushButton_setAlign.setObjectName(u"pushButton_setAlign") + self.pushButton_setAlign.setEnabled(True) + sizePolicy4.setHeightForWidth(self.pushButton_setAlign.sizePolicy().hasHeightForWidth()) + self.pushButton_setAlign.setSizePolicy(sizePolicy4) + self.pushButton_setAlign.setCursor(QCursor(Qt.PointingHandCursor)) + self.pushButton_setAlign.setIcon(icon28) + self.pushButton_setAlign.setFlat(True) + + self.horizontalLayout_11.addWidget(self.pushButton_setAlign) + + + self.gridLayout_3.addLayout(self.horizontalLayout_11, 31, 0, 1, 1) + + self.horizontalLayout_10 = QHBoxLayout() + self.horizontalLayout_10.setSpacing(5) + self.horizontalLayout_10.setObjectName(u"horizontalLayout_10") + self.label_18 = QLabel(self.layoutWidget) + self.label_18.setObjectName(u"label_18") + font8 = QFont() + font8.setFamily(u"Segoe UI") + font8.setPointSize(9) + font8.setBold(False) + font8.setWeight(50) + self.label_18.setFont(font8) + self.label_18.setText(u"Name Format:") + self.label_18.setIndent(5) + + self.horizontalLayout_10.addWidget(self.label_18) + + self.label_19 = QLabel(self.layoutWidget) + self.label_19.setObjectName(u"label_19") + sizePolicy6.setHeightForWidth(self.label_19.sizePolicy().hasHeightForWidth()) + self.label_19.setSizePolicy(sizePolicy6) + self.label_19.setMinimumSize(QSize(0, 20)) + self.label_19.setMaximumSize(QSize(16777215, 20)) + font9 = QFont() + font9.setFamily(u"Segoe UI") + font9.setPointSize(8) + self.label_19.setFont(font9) + self.label_19.setFrameShape(QFrame.NoFrame) + self.label_19.setText(u"") + + self.horizontalLayout_10.addWidget(self.label_19) + + + self.gridLayout_3.addLayout(self.horizontalLayout_10, 9, 0, 1, 1) + + self.horizontalLayout_21 = QHBoxLayout() + self.horizontalLayout_21.setSpacing(5) + self.horizontalLayout_21.setObjectName(u"horizontalLayout_21") + self.horizontalLayout_21.setContentsMargins(5, -1, -1, -1) + self.checkBox = QCheckBox(self.layoutWidget) + self.checkBox.setObjectName(u"checkBox") + sizePolicy1.setHeightForWidth(self.checkBox.sizePolicy().hasHeightForWidth()) + self.checkBox.setSizePolicy(sizePolicy1) + self.checkBox.setCursor(QCursor(Qt.PointingHandCursor)) +#if QT_CONFIG(tooltip) + self.checkBox.setToolTip(u"Enabled: Marker coordinates will be imported after target detection. *
Disabled: Coordinates are not imported. User must manually import coordinates.
* Automatic importing of marker coordinates only works if point file name is the same as it's parent folder name, and contains a header with metadata. Point coordinates should start at row #7.
") +#endif // QT_CONFIG(tooltip) + self.checkBox.setText(u"Import Marker Coordinates") + icon33 = QIcon() + icon33.addFile(u":/icons/icons8-map-marker-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.checkBox.setIcon(icon33) + self.checkBox.setIconSize(QSize(18, 18)) + self.checkBox.setChecked(True) + + self.horizontalLayout_21.addWidget(self.checkBox) + + + self.gridLayout_3.addLayout(self.horizontalLayout_21, 26, 0, 1, 1) + + self.horizontalLayout_16 = QHBoxLayout() + self.horizontalLayout_16.setSpacing(5) + self.horizontalLayout_16.setObjectName(u"horizontalLayout_16") + self.horizontalLayout_16.setContentsMargins(5, -1, -1, -1) + self.checkBox_pcloud = QCheckBox(self.layoutWidget) + self.checkBox_pcloud.setObjectName(u"checkBox_pcloud") + self.checkBox_pcloud.setEnabled(True) + sizePolicy5.setHeightForWidth(self.checkBox_pcloud.sizePolicy().hasHeightForWidth()) + self.checkBox_pcloud.setSizePolicy(sizePolicy5) + self.checkBox_pcloud.setCursor(QCursor(Qt.PointingHandCursor)) +#if QT_CONFIG(tooltip) + self.checkBox_pcloud.setToolTip(u"Enable to run 'Build Point Cloud' processing for selected items.
") +#endif // QT_CONFIG(tooltip) + self.checkBox_pcloud.setText(u"Build Point Cloud") + self.checkBox_pcloud.setIcon(icon6) + self.checkBox_pcloud.setIconSize(QSize(18, 18)) + self.checkBox_pcloud.setCheckable(True) + self.checkBox_pcloud.setChecked(False) + self.checkBox_pcloud.setTristate(False) + + self.horizontalLayout_16.addWidget(self.checkBox_pcloud) + + self.pushButton_setPCloud = QPushButton(self.layoutWidget) + self.pushButton_setPCloud.setObjectName(u"pushButton_setPCloud") + self.pushButton_setPCloud.setEnabled(True) + sizePolicy4.setHeightForWidth(self.pushButton_setPCloud.sizePolicy().hasHeightForWidth()) + self.pushButton_setPCloud.setSizePolicy(sizePolicy4) + self.pushButton_setPCloud.setCursor(QCursor(Qt.PointingHandCursor)) + self.pushButton_setPCloud.setIcon(icon28) + self.pushButton_setPCloud.setFlat(True) + + self.horizontalLayout_16.addWidget(self.pushButton_setPCloud) + + + self.gridLayout_3.addLayout(self.horizontalLayout_16, 34, 0, 1, 1) + + self.horizontalLayout_3 = QHBoxLayout() + self.horizontalLayout_3.setSpacing(5) + self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") + self.label_10 = QLabel(self.layoutWidget) + self.label_10.setObjectName(u"label_10") + self.label_10.setFont(font8) + self.label_10.setText(u"Suffix:") + self.label_10.setIndent(5) + + self.horizontalLayout_3.addWidget(self.label_10) + + self.label_7 = QLabel(self.layoutWidget) + self.label_7.setObjectName(u"label_7") + sizePolicy6.setHeightForWidth(self.label_7.sizePolicy().hasHeightForWidth()) + self.label_7.setSizePolicy(sizePolicy6) + self.label_7.setMinimumSize(QSize(0, 20)) + self.label_7.setMaximumSize(QSize(16777215, 20)) + self.label_7.setFont(font9) + self.label_7.setFrameShape(QFrame.NoFrame) + self.label_7.setText(u"") + + self.horizontalLayout_3.addWidget(self.label_7) + + + self.gridLayout_3.addLayout(self.horizontalLayout_3, 8, 0, 1, 1) + + self.horizontalLayout_14 = QHBoxLayout() + self.horizontalLayout_14.setSpacing(5) + self.horizontalLayout_14.setObjectName(u"horizontalLayout_14") + self.horizontalLayout_14.setContentsMargins(5, -1, -1, -1) + self.checkBox_3 = QCheckBox(self.layoutWidget) + self.checkBox_3.setObjectName(u"checkBox_3") + sizePolicy5.setHeightForWidth(self.checkBox_3.sizePolicy().hasHeightForWidth()) + self.checkBox_3.setSizePolicy(sizePolicy5) + self.checkBox_3.setCursor(QCursor(Qt.PointingHandCursor)) +#if QT_CONFIG(tooltip) + self.checkBox_3.setToolTip(u"Checked: Enable new chunk creation and data import.
Not Checked: Disable new chunk creation. Used when processing existing chunks.
") +#endif // QT_CONFIG(tooltip) + self.checkBox_3.setText(u"Auto Import Processing") + icon34 = QIcon() + icon34.addFile(u":/icons/icons8-in-progress-96.png", QSize(), QIcon.Normal, QIcon.Off) + self.checkBox_3.setIcon(icon34) + self.checkBox_3.setIconSize(QSize(18, 18)) + self.checkBox_3.setCheckable(True) + self.checkBox_3.setChecked(True) + + self.horizontalLayout_14.addWidget(self.checkBox_3) + + + self.gridLayout_3.addLayout(self.horizontalLayout_14, 29, 0, 1, 1) + + self.horizontalLayout_19 = QHBoxLayout() + self.horizontalLayout_19.setSpacing(5) + self.horizontalLayout_19.setObjectName(u"horizontalLayout_19") + self.label_20 = QLabel(self.layoutWidget) + self.label_20.setObjectName(u"label_20") + sizePolicy3.setHeightForWidth(self.label_20.sizePolicy().hasHeightForWidth()) + self.label_20.setSizePolicy(sizePolicy3) + self.label_20.setMinimumSize(QSize(0, 20)) + self.label_20.setMaximumSize(QSize(16777215, 20)) + font10 = QFont() + font10.setFamily(u"Segoe UI") + font10.setPointSize(9) + font10.setBold(True) + font10.setWeight(75) + self.label_20.setFont(font10) + self.label_20.setText(u"Data Export Location:") + self.label_20.setIndent(5) + + self.horizontalLayout_19.addWidget(self.label_20) + + self.pushButton_5 = QPushButton(self.layoutWidget) + self.pushButton_5.setObjectName(u"pushButton_5") + sizePolicy4.setHeightForWidth(self.pushButton_5.sizePolicy().hasHeightForWidth()) + self.pushButton_5.setSizePolicy(sizePolicy4) +#if QT_CONFIG(tooltip) + self.pushButton_5.setToolTip(u"Change data export location.
* Temporary only, will not be saved.
To change default location go to 'Chunk Definition Settings'.
Enable automatic target detection when new chunk is created...
") +#endif // QT_CONFIG(tooltip) + self.checkBox_2.setText(u"Automatic Target Detection") + self.checkBox_2.setIcon(icon15) + self.checkBox_2.setIconSize(QSize(18, 18)) + self.checkBox_2.setChecked(True) + + self.horizontalLayout_18.addWidget(self.checkBox_2) + + + self.gridLayout_3.addLayout(self.horizontalLayout_18, 23, 0, 1, 1) + + self.line_2 = QFrame(self.layoutWidget) + self.line_2.setObjectName(u"line_2") + self.line_2.setFrameShadow(QFrame.Plain) + self.line_2.setFrameShape(QFrame.HLine) + + self.gridLayout_3.addWidget(self.line_2, 27, 0, 1, 1) + + self.line_7 = QFrame(self.layoutWidget) + self.line_7.setObjectName(u"line_7") + self.line_7.setFrameShape(QFrame.HLine) + self.line_7.setFrameShadow(QFrame.Sunken) + + self.gridLayout_3.addWidget(self.line_7, 10, 0, 1, 1) + + self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) + + self.gridLayout_3.addItem(self.verticalSpacer, 39, 0, 1, 1) + + icon36 = QIcon() + icon36.addFile(u":/icons/icons8-project-setup-50-2.png", QSize(), QIcon.Normal, QIcon.Off) + self.tabWidget.addTab(self.tab, icon36, "") + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), u"Chunk Settings") + self.tab_2 = QWidget() + self.tab_2.setObjectName(u"tab_2") + self.verticalLayoutWidget_2 = QWidget(self.tab_2) + self.verticalLayoutWidget_2.setObjectName(u"verticalLayoutWidget_2") + self.verticalLayoutWidget_2.setGeometry(QRect(0, 10, 301, 161)) + self.verticalLayout = QVBoxLayout(self.verticalLayoutWidget_2) + self.verticalLayout.setSpacing(5) + self.verticalLayout.setContentsMargins(10, 10, 10, 10) + self.verticalLayout.setObjectName(u"verticalLayout") + self.verticalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_12 = QHBoxLayout() + self.horizontalLayout_12.setSpacing(5) + self.horizontalLayout_12.setObjectName(u"horizontalLayout_12") + self.comboBox_2 = QComboBox(self.verticalLayoutWidget_2) + icon37 = QIcon() + icon37.addFile(u":/icons/icons8-full-page-view-50.png", QSize(), QIcon.Normal, QIcon.Off) + icon38 = QIcon() + icon38.addFile(u":/icons/icons8-video-wall-50.png", QSize(), QIcon.Normal, QIcon.Off) + icon39 = QIcon() + icon39.addFile(u":/icons/icons8-live-photos-96.png", QSize(), QIcon.Normal, QIcon.Off) + icon40 = QIcon() + icon40.addFile(u":/icons/icons8-aperture-50.png", QSize(), QIcon.Normal, QIcon.Off) + icon41 = QIcon() + icon41.addFile(u":/icons/icons8-video-stabilization-50.png", QSize(), QIcon.Normal, QIcon.Off) + icon42 = QIcon() + icon42.addFile(u":/icons/icons8-quadcopter-50.png", QSize(), QIcon.Normal, QIcon.Off) + cicon = QIcon() + cicon.addFile(u":/icons/icons8-full-page-view-50.png", QSize(), QIcon.Normal, QIcon.Off) + cicon1 = QIcon() + cicon1.addFile(u":/icons/icons8-panorama-50.png", QSize(), QIcon.Normal, QIcon.Off) + cicon2 = QIcon() + cicon2.addFile(u":/icons/icons8-aperture-50.png", QSize(), QIcon.Normal, QIcon.Off) + cicon3 = QIcon() + cicon3.addFile(u":/icons/icons8-video-stabilization-50.png", QSize(), QIcon.Normal, QIcon.Off) + cicon4 = QIcon() + cicon4.addFile(u":/icons/icons8-touchscreen-48.png", QSize(), QIcon.Normal, QIcon.Off) + cicon5 = QIcon() + cicon5.addFile(u":/icons/icons8-quadcopter-50.png", QSize(), QIcon.Normal, QIcon.Off) + cicon5a = QIcon() + cicon5a.addFile(u":/icons/icons8-ios-application-placeholder-50.png", QSize(), QIcon.Normal, QIcon.Off) + cicoTripod = QIcon() + cicoTripod.addFile(u":/icons/icons8-camera-on-tripod-96.png", QSize(), QIcon.Normal, QIcon.Off) + for cam in autoftg_main.cam_list: + icon_type = autoftg_main.camCfg.get(cam, "Type") + icon_subtype = autoftg_main.camCfg.get(cam, "SubType") + if icon_subtype == "SmartPhone": + self.comboBox_2.addItem(cicon4, cam) + elif icon_subtype == "Drone": + self.comboBox_2.addItem(cicon5, cam) + elif icon_subtype == "Special": + self.comboBox_2.addItem(cicoTripod, cam) + else: + if icon_type == "Fisheye": + self.comboBox_2.addItem(cicon1, cam) + elif icon_type == "Spherical": + self.comboBox_2.addItem(cicon3, cam) + elif icon_type == "Cylindrical": + self.comboBox_2.addItem(cicon2, cam) + elif icon_type == "RPC": + self.comboBox_2.addItem(cicon5a, cam) + else: + self.comboBox_2.addItem(cicon, cam) + + self.comboBox_2.setCurrentText(autoftg_main.selected_camera) + self.comboBox_2.setObjectName(u"comboBox_2") + sizePolicy8 = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Maximum) + sizePolicy8.setHorizontalStretch(0) + sizePolicy8.setVerticalStretch(0) + sizePolicy8.setHeightForWidth(self.comboBox_2.sizePolicy().hasHeightForWidth()) + self.comboBox_2.setSizePolicy(sizePolicy8) + self.comboBox_2.setMinimumSize(QSize(200, 0)) + self.comboBox_2.setFont(font6) + self.comboBox_2.setCursor(QCursor(Qt.PointingHandCursor)) +#if QT_CONFIG(statustip) + self.comboBox_2.setStatusTip(u"Choose camera settings to be applied when creating new chunk...") +#endif // QT_CONFIG(statustip) + self.comboBox_2.setIconSize(QSize(20, 20)) + + self.horizontalLayout_12.addWidget(self.comboBox_2) + + self.btnDefCam = QPushButton(self.verticalLayoutWidget_2) + self.btnDefCam.setObjectName(u"btnDefCam") + self.btnDefCam.setCursor(QCursor(Qt.PointingHandCursor)) +#if QT_CONFIG(tooltip) + self.btnDefCam.setToolTip(u"Set as default") +#endif // QT_CONFIG(tooltip) + self.btnDefCam.setText(u"") + self.btnDefCam.setIcon(icon27) + self.btnDefCam.setIconSize(QSize(20, 20)) + self.btnDefCam.setAutoDefault(False) + self.btnDefCam.setFlat(True) + + self.horizontalLayout_12.addWidget(self.btnDefCam) + + + self.verticalLayout.addLayout(self.horizontalLayout_12) + + self.horizontalLayout_6 = QHBoxLayout() + self.horizontalLayout_6.setSpacing(5) + self.horizontalLayout_6.setObjectName(u"horizontalLayout_6") + self.label_9 = QLabel(self.verticalLayoutWidget_2) + self.label_9.setObjectName(u"label_9") + self.label_9.setFont(font8) + self.label_9.setFrameShape(QFrame.NoFrame) + self.label_9.setText(u"Type:") + self.label_9.setIndent(5) + + self.horizontalLayout_6.addWidget(self.label_9) + + self.label_12 = QLabel(self.verticalLayoutWidget_2) + self.label_12.setObjectName(u"label_12") + sizePolicy6.setHeightForWidth(self.label_12.sizePolicy().hasHeightForWidth()) + self.label_12.setSizePolicy(sizePolicy6) + self.label_12.setMinimumSize(QSize(0, 20)) + self.label_12.setMaximumSize(QSize(16777215, 20)) + self.label_12.setFont(font9) + self.label_12.setFrameShape(QFrame.NoFrame) + self.label_12.setText(u"") + + self.horizontalLayout_6.addWidget(self.label_12) + + + self.verticalLayout.addLayout(self.horizontalLayout_6) + + self.horizontalLayout_7 = QHBoxLayout() + self.horizontalLayout_7.setSpacing(5) + self.horizontalLayout_7.setObjectName(u"horizontalLayout_7") + self.label_13 = QLabel(self.verticalLayoutWidget_2) + self.label_13.setObjectName(u"label_13") + self.label_13.setFont(font8) + self.label_13.setText(u"SubType:") + self.label_13.setIndent(5) + + self.horizontalLayout_7.addWidget(self.label_13) + + self.label_14 = QLabel(self.verticalLayoutWidget_2) + self.label_14.setObjectName(u"label_14") + sizePolicy6.setHeightForWidth(self.label_14.sizePolicy().hasHeightForWidth()) + self.label_14.setSizePolicy(sizePolicy6) + self.label_14.setMinimumSize(QSize(0, 20)) + self.label_14.setMaximumSize(QSize(16777215, 20)) + self.label_14.setFont(font9) + self.label_14.setFrameShape(QFrame.NoFrame) + self.label_14.setText(u"") + + self.horizontalLayout_7.addWidget(self.label_14) + + + self.verticalLayout.addLayout(self.horizontalLayout_7) + + self.verticalSpacer_2 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) + + self.verticalLayout.addItem(self.verticalSpacer_2) + + icon43 = QIcon() + icon43.addFile(u":/icons/icons8-slr-small-lens-96.png", QSize(), QIcon.Normal, QIcon.Off) + self.tabWidget.addTab(self.tab_2, icon43, "") + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), u"Camera Settings") + + self.gridLayout.addWidget(self.tabWidget, 0, 2, 3, 1) + + + self.verticalLayout_2.addLayout(self.gridLayout) + + self.checkBox_mesh.setEnabled(True) + self.checkBox_export.setEnabled(True) + self.checkBox_pcloud.setEnabled(True) + + defChk = self.cbChunkSettings.currentText() + self.label_6.setText(autoftg_main.menuCfg.get(defChk, "chunk_name_prefix")) + self.label_7.setText(autoftg_main.menuCfg.get(defChk, "chunk_name_suffix")) + + defCam = self.comboBox_2.currentText() + self.label_12.setText(autoftg_main.camCfg.get(defCam, "type")) + self.label_14.setText(autoftg_main.camCfg.get(defCam, "subtype")) + + self.checkBox_4.toggled.connect(self.pushButton.setDisabled) + self.checkBox_4.toggled.connect(self.lineEdit.setDisabled) + self.checkBox_2.toggled.connect(self.checkBox.toggle) + self.cbChunkSettings.currentTextChanged.connect(self.setCurrentSettings) + self.cbChunkSettings.currentTextChanged.connect(self.updateFolders) + self.comboBox_2.currentTextChanged.connect(self.setCurrentCamera) + self.pushButton_2.clicked.connect(self.quitChunkBatch) + self.pushButton_3.clicked.connect(self.progressBar.reset) + self.pushButton_3.clicked.connect(self.processBatch) + self.pushButton_4.clicked.connect(self.updateFolders) + self.pushButton.clicked.connect(self.browseFolder) + self.treeWidget.itemSelectionChanged.connect(self.updateSelected) + self.btnDefChunk.clicked.connect(self.setDefaultChunk) + self.btnDefCam.clicked.connect(self.setDefaultCam) + self.pushButton_10.clicked.connect(self.openFileExplorer) + self.pushButton_setAlign.clicked.connect(self.diaSettingsAlign) + self.pushButton_setMesh.setEnabled(True) + self.pushButton_setMesh.clicked.connect(self.diaSettingsMesh) + self.pushButton_setPCloud.clicked.connect(self.diaSettingsPoint) + # self.pushButton_setExport.clicked.connect() + self.pushButton_saveSet.clicked.connect(self.saveCurrentSettings) + self.pushButton_resetSet.clicked.connect(self.resetCurrentSettings) + + self.tabWidget.setCurrentIndex(0) + + projDoc = Metashape.app.document + self.projDocFile = str(projDoc).replace("Chunk definition settings loaded...
") + + + + def setCurrentCamera(self): + chunkCam = self.comboBox_2.currentText() + self.label_12.setText(autoftg_main.camCfg.get(chunkCam, "type")) + self.label_14.setText(autoftg_main.camCfg.get(chunkCam, "subtype")) + + + def updateFolders(self): + self.setCurrentSettings() + self.logReadArchive() + + iconReload = QIcon() + iconReload.addFile(u":/icons/icons8-update-left-rotation-50.png", QSize(), QIcon.Normal, QIcon.Off) + iconLoading = QIcon() + iconLoading.addFile(u":/icons/icons8-loading-96.png", QSize(), QIcon.Normal, QIcon.Off) + font6 = QFont() + font6.setBold(True) + font6.setWeight(75) + iconFolderTree = QIcon() + iconFolderTree.addFile(u":/icons/icons8-folder-tree-50.png", QSize(), QIcon.Normal, QIcon.Off) + iconFolder = QIcon() + iconFolder.addFile(u":/icons/icons8-folder-50.png", QSize(), QIcon.Normal, QIcon.Off) + iconDone = QIcon() + iconDone.addFile(u":/icons/icons8-done-50.png", QSize(), QIcon.Normal, QIcon.Off) + iconDoneFile = QIcon() + iconDoneFile.addFile(u":/icons/icons8-check-file-50.png", QSize(), QIcon.Normal, QIcon.Off) + iconNoCam = QIcon() + iconNoCam.addFile(u":/icons/icons8-no-camera-96.png", QSize(), QIcon.Normal, QIcon.Off) + font7 = QFont() + font7.setFamily(u"Segoe UI") + iconClose = QIcon() + iconClose.addFile(u":/icons/icons8-close-50.png", QSize(), QIcon.Normal, QIcon.Off) + iconAddCam = QIcon() + iconAddCam.addFile(u":/icons/icons8-add-camera-50.png", QSize(), QIcon.Normal, QIcon.Off) + iconStart = QIcon() + iconStart.addFile(u":/icons/icons8-synchronize-50.png", QSize(), QIcon.Normal, QIcon.Off) + iconProcess = QIcon() + iconProcess.addFile(u":/icons/icons8-loading-96.png", QSize(), QIcon.Normal, QIcon.Off) + iconProcess.addFile(u":/icons/icons8-loading-96.png", QSize(), QIcon.Disabled, QIcon.Off) + iconError = QIcon() + iconError.addFile(u":/icons/icons8-error-48.png", QSize(), QIcon.Normal, QIcon.Off) + iconError.addFile(u":/icons/icons8-error-48.png", QSize(), QIcon.Disabled, QIcon.Off) + iconOk = QIcon() + iconOk.addFile(u":/icons/icons8-ok-50.png", QSize(), QIcon.Normal, QIcon.Off) + iconOk.addFile(u":/icons/icons8-ok-50.png", QSize(), QIcon.Disabled, QIcon.Off) + iconLocOff = QIcon() + iconLocOff.addFile(u":/icons/icons8-location-off-48.png", QSize(), QIcon.Normal, QIcon.Off) + iconToDo = QIcon() + iconToDo.addFile(u":/icons/icons8-microsoft-todo-2019-48.png", QSize(), QIcon.Normal, QIcon.Off) + iconProgDone = QIcon() + iconProgDone.addFile(u":/icons/icons8-in-progress-96.png", QSize(), QIcon.Normal, QIcon.Off) + iconReadyProc = QIcon() + iconReadyProc.addFile(u":/icons/icons8-submit-progress-96.png", QSize(), QIcon.Normal, QIcon.Off) + + self.pushButton_4.setIcon(iconLoading) + + self.treeWidget.clear() + + itemCurFolder = str(self.lineEdit.text()).split("/")[-1] + + open_folder = self.lineEdit.text() + "\\" + + qtreewidgetitem_top = QTreeWidgetItem(self.treeWidget) + qtreewidgetitem_top.setText(0, itemCurFolder) + qtreewidgetitem_top.setFont(0, font6) + qtreewidgetitem_top.setIcon(0, iconFolderTree) + qtreewidgetitem_top.setExpanded(True) + + folder_list = [] + folder_list = next(os.walk(open_folder))[1]; + + # chunks_list = Metashape.app.document.chunks + # chunks_list.replace("Folder contents reloaded...
") + self.progressBar.setMinimum(1) + self.progressBar.setMaximum(1) + self.progressBar.setValue(0) + self.progressBar.setTextVisible(False) + self.progressBar.setDisabled(True) + self.treeWidget.resizeColumnToContents(0) + self.treeWidget.resizeColumnToContents(1) + self.treeWidget.resizeColumnToContents(2) + self.treeWidget.resizeColumnToContents(3) + self.treeWidget.resizeColumnToContents(4) + self.treeWidget.resizeColumnToContents(5) + self.treeWidget.resizeColumnToContents(6) + self.treeWidget.resizeColumnToContents(7) + self.treeWidget.sortItems(0, Qt.AscendingOrder) + self.treeWidget.scrollToBottom() + self.pushButton_4.setIcon(iconReload) + + + def setDefaultChunk(self): + current_chunkdef = self.cbChunkSettings.currentText() + autoftg_main.projCfg.set("PROJECT SETTINGS", "default_chunk_def", current_chunkdef) + with open(autoftg_main.projCfgFilePath, 'w') as configfile: + autoftg_main.projCfg.write(configfile) + + self.label_8.setText(u"Default definition set to: " + current_chunkdef + "
") + + + def setDefaultCam(self): + current_cam = self.comboBox_2.currentText() + autoftg_main.projCfg.set("PROJECT SETTINGS", "default_camera", current_cam) + with open(autoftg_main.projCfgFilePath, 'w') as configfile: + autoftg_main.projCfg.write(configfile) + + self.label_8.setText(u"Default camera set to: " + current_cam + "
") + + + def saveCurrentSettings(self): + autoftg_main.menuCfg.set(self.cbChunkSettings.currentText(), "auto_process", str(self.checkBox_3.isChecked())) + autoftg_main.menuCfg.set(self.cbChunkSettings.currentText(), "align_photos", str(self.checkBox_align.isChecked())) + autoftg_main.menuCfg.set(self.cbChunkSettings.currentText(), "mesh_build", str(self.checkBox_mesh.isChecked())) + autoftg_main.menuCfg.set(self.cbChunkSettings.currentText(), "pointcloud_build", str(self.checkBox_pcloud.isChecked())) + autoftg_main.menuCfg.set(self.cbChunkSettings.currentText(), "export_data", str(self.checkBox_export.isChecked())) + + with open(autoftg_main.menuCfgFilePath, 'w') as configfile: + autoftg_main.menuCfg.write(configfile) + + print("Settings saved...\nChunk def.: " + self.cbChunkSettings.currentText()) + + + def resetCurrentSettings(self): + self.checkBox_3.setChecked(autoftg_main.menuCfg.getboolean(self.cbChunkSettings.currentText(), "auto_process")) + self.checkBox_align.setChecked(autoftg_main.menuCfg.getboolean(self.cbChunkSettings.currentText(), "align_photos")) + self.checkBox_mesh.setChecked(autoftg_main.menuCfg.getboolean(self.cbChunkSettings.currentText(), "mesh_build")) + self.checkBox_pcloud.setChecked(autoftg_main.menuCfg.getboolean(self.cbChunkSettings.currentText(), "pointcloud_build")) + self.checkBox_export.setChecked(autoftg_main.menuCfg.getboolean(self.cbChunkSettings.currentText(), "export_data")) + + print("Settings reset...") + + + def browseFolder(self): + defFolder = Metashape.app.getExistingDirectory("Data folder") + self.lineEdit.setText(defFolder) + self.updateFolders() + + + def updateSelected(self): + iconStart = QIcon() + iconStart.addFile(u":/icons/icons8-synchronize-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.pushButton_3.setIcon(iconStart) + self.pushButton_3.setEnabled(True) + sel_items = self.treeWidget.selectedItems() + sel_count = len(sel_items) + if sel_count > 0: + self.pushButton_3.setEnabled(True) + self.pushButton_3.setText(u"Process") + self.pushButton_10.setEnabled(True) + self.label_16.setText(u"Selected: " + str(sel_count) + "
") + else: + self.pushButton_3.setDisabled(True) + self.pushButton_3.setText(u"Ready") + self.pushButton_10.setDisabled(True) + self.label_16.setText(u"Select items to process...") + + + def openFileExplorer(self): + selected_path = self.lineEdit.text() + "\\" + self.treeWidget.currentItem().text(0) + + # explorer would choke on forward slashes + path = os.path.normpath(selected_path) + + if os.path.isdir(path): + subprocess.run([FILEBROWSER_PATH, path]) + else: + print("Nothing selected?!?") + + + def loadingTime(self, string): + + for i in string: + print(i, end="") + + # adding two second of time delay + time.sleep(0.5) + + + # Process selected folders automatically (no user interaction) + def processBatchAuto(self): + timeProcStart = datetime.now() + self.sel_items = self.treeWidget.selectedItems() + sel_count = len(self.sel_items) + item_menu = self.cbChunkSettings.currentText() + item_pre = autoftg_main.menuCfg.get(item_menu, "chunk_name_prefix") + item_suf = autoftg_main.menuCfg.get(item_menu, "chunk_name_suffix") + item_cam = self.comboBox_2.currentText() + output_folder = autoftg_main.menuCfg.get(item_menu, "export_folder").replace("\\", "/") + + + iconStart = QIcon() + iconStart.addFile(u":/icons/icons8-synchronize-50.png", QSize(), QIcon.Normal, QIcon.Off) + iconProcess = QIcon() + iconProcess.addFile(u":/icons/icons8-loading-96.png", QSize(), QIcon.Normal, QIcon.Off) + iconProcess.addFile(u":/icons/icons8-loading-96.png", QSize(), QIcon.Disabled, QIcon.Off) + iconError = QIcon() + iconError.addFile(u":/icons/icons8-error-48.png", QSize(), QIcon.Normal, QIcon.Off) + iconError.addFile(u":/icons/icons8-error-48.png", QSize(), QIcon.Disabled, QIcon.Off) + iconOk = QIcon() + iconOk.addFile(u":/icons/icons8-ok-50.png", QSize(), QIcon.Normal, QIcon.Off) + iconOk.addFile(u":/icons/icons8-ok-50.png", QSize(), QIcon.Disabled, QIcon.Off) + iconDone = QIcon() + iconDone.addFile(u":/icons/icons8-done-50.png", QSize(), QIcon.Normal, QIcon.Off) + iconToDo = QIcon() + iconToDo.addFile(u":/icons/icons8-microsoft-todo-2019-48.png", QSize(), QIcon.Normal, QIcon.Off) + iconProgDone = QIcon() + iconProgDone.addFile(u":/icons/icons8-in-progress-96.png", QSize(), QIcon.Normal, QIcon.Off) + + if sel_count > 0: + i_cnt = 0 + self.progressBar.setEnabled(True) + self.progressBar.setMinimum(i_cnt) + self.progressBar.setMaximum(sel_count) + self.progressBar.setValue(i_cnt) + self.progressBar.setTextVisible(True) + self.progressBar.setAlignment(Qt.AlignCenter) + self.pushButton_3.setEnabled(False) + self.pushButton_3.setIcon(iconProcess) + self.pushButton_3.setText(u"Processing...") + num = 6 + + for item in self.sel_items: + timeItemStart = datetime.now() + i_cnt = i_cnt + 1 + self.progressBar.setFormat(u"Completed %v of %m") + self.pushButton_3.setEnabled(False) + self.pushButton_3.setIcon(iconProcess) + self.pushButton_3.setText(u"Processing...") + + updItem = QTreeWidgetItem + updItem.setIcon(item, 3, iconProcess) + updItem.setText(item, 7, u"Processing...") + self.treeWidget.resizeColumnToContents(3) + + doc = Metashape.app.document + netpath = Metashape.app.document.path + netroot = self.lineEdit.text() + image_folder = str(netroot).replace("\\", "/") + "/" + item.text(0) + photos = autoftg_main.find_files(image_folder, [".jpg", ".jpeg", ".png", ".tif", ".tiff"]) + chunk = doc.addChunk() + chunk_key = str(chunk.key) + self.label_8.setText(u"Processing folder " + str(i_cnt) + " of " + str(sel_count) + " | Current: " + str(item.text(0)) + " (" + chunk_key + ") - Data Import...") + chunk.addPhotos(photos) + self.loadingTime('*****') + chunk_name = item_pre + item.text(0) + item_suf + chunk.label = chunk_name + doc.chunk = chunk + doc.save(netpath) + Metashape.app.update() + self.loadingTime('***') + autoftg_main.readCameraSettings(item_cam) + autoftg_main.useCameraSettings() + if self.checkBox_2.isChecked() == True: + self.label_8.setText(u"Processing folder " + str(i_cnt) + " of " + str(sel_count) + " | Current: " + str(item.text(0)) + " (" + chunk_key + ") - Processing Markers...") + chunk.detectMarkers(target_type=Metashape.CircularTarget12bit, tolerance=98) + doc.save(netpath) + Metashape.app.update() + + if self.checkBox.isChecked() == True: + self.label_8.setText(u"Processing folder " + str(i_cnt) + " of " + str(sel_count) + " | Current: " + str(item.text(0)) + " (" + chunk_key + ") - Coordinates Import...") + points_file = image_folder + "/" + item.text(0) + ".txt" + points_file_exists = os.path.isfile(points_file) + if points_file_exists == True: + chunk.importReference(points_file, format=Metashape.ReferenceFormatCSV, columns='nxyz', delimiter=',', skip_rows=6, create_markers=True) + chunk.updateTransform() + ms_pntfile = item.text(0) + ".txt" + else: + ms_pntfile = "None" + + updItem.setIcon(item, 3, iconProgDone) + doc.save(netpath) + Metashape.app.update() + + + align_done = "" + # Metashape.ReferencePreselectionMode.[ReferencePreselectionSource, ReferencePreselectionEstimated, ReferencePreselectionSequential] + if self.checkBox_align.isChecked() == True: + updItem.setIcon(item, 4, iconProcess) + align_quality_text = autoftg_main.menuCfg.get(chunkSet, "align_quality") + if align_quality_text == "Highest": + align_quality = 0 + elif align_quality_text == "High": + align_quality = 1 + elif align_quality_text == "Medium": + align_quality = 2 + elif align_quality_text == "Low": + align_quality = 3 + elif align_quality_text == "Lowest": + align_quality = 4 + else: + align_quality = 0 + + align_gen_presel = autoftg_main.menuCfg.getboolean(chunkSet, "align_gen_presel") + align_ref_presel = autoftg_main.menuCfg.getboolean(chunkSet, "align_ref_presel") + align_ref_presel_mode_text = autoftg_main.menuCfg.get(chunkSet, "align_ref_presel_mode") + if align_ref_presel_mode_text == "Source": + align_ref_presel_mode = Metashape.ReferencePreselectionMode.ReferencePreselectionSource + elif align_ref_presel_mode_text == "Estimated": + align_ref_presel_mode = Metashape.ReferencePreselectionMode.ReferencePreselectionEstimated + elif align_ref_presel_mode_text == "Sequential": + align_ref_presel_mode = Metashape.ReferencePreselectionMode.ReferencePreselectionSequential + else: + align_ref_presel_mode = Metashape.ReferencePreselectionMode.ReferencePreselectionSource + + align_ref_presel_mode = Metashape.ReferencePreselectionMode.ReferencePreselectionSource + align_key_limit = autoftg_main.menuCfg.getint(chunkSet, "align_key_limit") + align_tie_limit = autoftg_main.menuCfg.getint(chunkSet, "align_tie_limit") + align_filter_mask = autoftg_main.menuCfg.getboolean(chunkSet, "align_filter_mask") + align_mask_tiepoint = autoftg_main.menuCfg.getboolean(chunkSet, "align_mask_tiepoint") + align_filter_stationary = autoftg_main.menuCfg.getboolean(chunkSet, "align_filter_stationary") + align_keep_keypoints = autoftg_main.menuCfg.getboolean(chunkSet, "align_keep_keypoints") + align_guided_matching = autoftg_main.menuCfg.getboolean(chunkSet, "align_guided_matching") + align_reset_current = autoftg_main.menuCfg.getboolean(chunkSet, "align_reset_current") + + self.label_8.setText(u"Processing folder " + str(i_cnt) + " of " + str(sel_count) + " | Current: " + str(item.text(0)) + " (" + chunk_key + ") - Align Photos...") + chunk.matchPhotos(downscale=align_quality, keypoint_limit=align_key_limit, tiepoint_limit=align_tie_limit, generic_preselection=align_gen_presel, reference_preselection=align_ref_presel, reference_preselection_mode=align_ref_presel_mode, filter_mask=align_filter_mask, mask_tiepoints=align_mask_tiepoint, filter_stationary_points=align_filter_stationary, keep_keypoints=align_keep_keypoints, guided_matching=align_guided_matching, reset_matches=align_reset_current, subdivide_task=True) + doc.save(netpath) + chunk.alignCameras(subdivide_task = True) + doc.save(netpath) + align_done = "A" + updItem.setIcon(item, 4, iconProgDone) + Metashape.app.update() + + + mesh_done = '' + if self.checkBox_mesh.isChecked() == True: + self.label_8.setText(u"Processing folder " + str(i_cnt) + " of " + str(sel_count) + " | Current: " + str(item.text(0)) + " (" + chunk_key + ") - Building Model...") + updItem.setIcon(item, 5, iconProcess) + + if self.mesh_depthmaps == "Ultra High": + depth_quality = 0 + elif self.mesh_depthmaps == "High": + depth_quality = 2 + elif self.mesh_depthmaps == "Medium": + depth_quality = 4 + elif self.mesh_depthmaps == "Low": + depth_quality = 8 + elif self.mesh_depthmaps == "Lowest": + depth_quality = 16 + else: + depth_quality = 4 + + if self.mesh_depthfilter == "Aggressive": + filter_mode = Metashape.AggressiveFiltering + elif self.mesh_depthfilter == "Moderate": + filter_mode = Metashape.ModerateFiltering + elif self.mesh_depthfilter == "Mild": + filter_mode = Metashape.MildFiltering + else: + filter_mode = Metashape.NoFiltering + + + chunk.buildDepthMaps(downscale=depth_quality, filter_mode=filter_mode) + + doc.save(netpath) + + if self.mesh_interpolation == True: + mesh_int = Metashape.Interpolation.EnabledInterpolation + else: + mesh_int = Metashape.Interpolation.DisabledInterpolation + + mesh_facecount = "" + mesh_facecount_custom = 0 + if self.mesh_face_count == "High": + mesh_facecount = Metashape.FaceCount.HighFaceCount + elif self.mesh_face_count == "Medium": + mesh_facecount = Metashape.FaceCount.MediumFaceCount + elif self.mesh_face_count == "Low": + mesh_facecount = Metashape.FaceCount.LowFaceCount + elif self.mesh_face_count == "Custom": + mesh_facecount = Metashape.FaceCount.CustomFaceCount + mesh_facecount_custom = int(self.mesh_face_count_custom) + + if self.mesh_type == "Arbitrary": + mesh_type = Metashape.SurfaceType.Arbitrary + else: + mesh_type = Metashape.SurfaceType.HeightField + + chunk.buildModel(surface_type=mesh_type, interpolation=mesh_int, face_count=mesh_facecount, face_count_custom=mesh_facecount_custom, source_data=Metashape.DepthMapsData, vertex_colors =self.mesh_vertex_color, vertex_confidence=self.mesh_vertex_confidence, subdivide_task=True) + + mesh_buildModel = 'M' + doc.save(netpath) + + model_buildTex = '' + if self.texture_build == True: + self.label_8.setText(u"Processing folder " + str(i_cnt) + " of " + str(sel_count) + " | Current: " + str(item.text(0)) + " (" + chunk_key + ") - Building Texture...") + chunk.buildUV(page_count = self.texture_levels, texture_size = int(self.texture_size)) + doc.save(netpath) + chunk.buildTexture(texture_size = int(self.texture_size), fill_holes = self.texture_fill, ghosting_filter = self.texture_ghosting) + + model_buildTex = '+T' + doc.save(netpath) + + mesh_done = mesh_buildModel + model_buildTex + updItem.setIcon(item, 5, iconProgDone) + Metashape.app.update() + + + ptcloud_done = "" + if self.checkBox_pcloud.isChecked() == True: + updItem.setIcon(item, 6, iconProcess) + source_data = Metashape.DataSource.DepthMapsData + point_colors = True + point_confidence = False + keep_depth = True + uniform_sampling = False + points_spacing = 0.02 + subdivide_task = True + + self.label_8.setText(u"Processing folder " + str(i_cnt) + " of " + str(sel_count) + " | Current: " + str(item.text(0)) + " (" + chunk_key + ") - Building Point Cloud...") + chunk.buildPointCloud(source_data=source_data, point_color=point_colors, point_confidence=point_confidence, keep_depth=keep_depth, uniform_sampling=uniform_sampling, points_spacing=points_spacing, subdivide_task=subdivide_task) + doc.save(netpath) + ptcloud_done = 'PC' + updItem.setIcon(item, 6, iconProgDone) + Metashape.app.update() + + + chunk_emodel = "" + chunk_eptc = "" + if self.checkBox_export.isChecked() == True: + self.label_8.setText(u"Processing folder " + str(i_cnt) + " of " + str(sel_count) + " | Current: " + str(item.text(0)) + " (" + chunk_key + ") - Exporting Data...") + if chunk.model: + chunk.exportModel(path=output_folder + "/" + chunk_name + ".obj", binary=True, precision=4, texture_format=Metashape.ImageFormat.ImageFormatJPEG, save_texture=True, save_uv=True, save_normals=True, save_colors=True, save_confidence=False, save_cameras=True, save_markers=True, save_udim=False, save_alpha=False, embed_texture=False, strip_extensions=False, colors_rgb_8bit=True, comment=chunk_name, save_comment=True) + chunk_emodel = chunk_name + ".obj" + Metashape.app.update() + + if chunk.point_cloud: + chunk.exportPointCloud(path=output_folder + "/" + chunk_name + ".laz", source_data=Metashape.PointCloudData, save_point_color=True, save_point_normal=True, save_point_confidence=True) + chunk_eptc = chunk_name + ".laz" + Metashape.app.update() + + + timeItemEnd = datetime.now() + timeItemDelta = (timeItemEnd - timeItemStart) + timeItemText = str(timeItemDelta).split('.')[0] + dt_string = timeItemEnd.strftime("%d.%m.%Y") + tm_string = timeItemEnd.strftime("%H:%M:%S") + ms_data = [dt_string, tm_string, chunk_name, chunk_key, str(len(photos)), ms_pntfile, item_cam, align_done, mesh_done, ptcloud_done, image_folder, output_folder, chunk_emodel, chunk_eptc] + self.logWriteArchive(ms_data) + updItem.setIcon(item, 3, iconDone) + updItem.setText(item, 7, timeItemText) + self.label_8.setText(u"Processing folder " + str(i_cnt) + " of " + str(sel_count) + " | Current: " + str(item.text(0)) + " (" + chunk_key + ") done in " + timeItemText) + self.treeWidget.setItemSelected(item, False) + self.progressBar.setValue(i_cnt) + Metashape.app.update() + doc.save(netpath) + self.loadingTime('**') + + timeProcEnd = datetime.now() + timeProcDelta = timeProcEnd - timeProcStart + timeProcText = str(timeProcDelta).split('.')[0] + self.progressBar.setFormat(u"Completed %v of %m chunk(s) in " + timeProcText) + + if i_cnt < sel_count: + updItem.setIcon(item, 3, iconError) + self.pushButton_3.setIcon(iconError) + self.pushButton_3.setText(u"Error!") + self.label_8.setText(u"
Processing error! / Imported " + str(i_cnt) + " of " + str(sel_count) + " / Could not import " + str(item.text(0)) + "
") + else: + self.pushButton_3.setIcon(iconOk) + self.pushButton_3.setText(u"Finished") + self.label_8.setText(u"Processing done! / Imported " + str(i_cnt) + " chunks in " + str(timeProcText) + ".
") + + + Metashape.app.update() + doc.save(netpath) + + + + + # Process selected folders manually (user must confirm chunk name, camera settings, marker detection, and show point file) +# def processBatchManual(self): +# self.sel_items = self.treeWidget.selectedItems() +# sel_count = len(self.sel_items) +# item_menu = self.cbChunkSettings.currentText() +# item_pre = autoftg_main.menuCfg.get(item_menu, "chunk_name_prefix") +# item_suf = autoftg_main.menuCfg.get(item_menu, "chunk_name_suffix") +# item_cam = self.comboBox_2.currentText() +# output_folder = autoftg_main.menuCfg.get(item_menu, "export_folder").replace("\\", "/") +# +# iconStart = QIcon() +# iconStart.addFile(u":/icons/icons8-synchronize-50.png", QSize(), QIcon.Normal, QIcon.Off) +# iconProcess = QIcon() +# iconProcess.addFile(u":/icons/icons8-loading-96.png", QSize(), QIcon.Normal, QIcon.Off) +# iconProcess.addFile(u":/icons/icons8-loading-96.png", QSize(), QIcon.Disabled, QIcon.Off) +# iconError = QIcon() +# iconError.addFile(u":/icons/icons8-error-48.png", QSize(), QIcon.Normal, QIcon.Off) +# iconError.addFile(u":/icons/icons8-error-48.png", QSize(), QIcon.Disabled, QIcon.Off) +# iconOk = QIcon() +# iconOk.addFile(u":/icons/icons8-ok-50.png", QSize(), QIcon.Normal, QIcon.Off) +# iconOk.addFile(u":/icons/icons8-ok-50.png", QSize(), QIcon.Disabled, QIcon.Off) +# iconDone = QIcon() +# iconDone.addFile(u":/icons/icons8-done-50.png", QSize(), QIcon.Normal, QIcon.Off) +# iconToDo = QIcon() +# iconToDo.addFile(u":/icons/icons8-microsoft-todo-2019-48.png", QSize(), QIcon.Normal, QIcon.Off) +## +# if sel_count > 0: +# i_cnt = 0 +# self.progressBar.setEnabled(True) +# self.progressBar.setMinimum(i_cnt) +# self.progressBar.setMaximum(sel_count) +# self.progressBar.setValue(i_cnt) +# self.pushButton_3.setDisabled(True) +# self.pushButton_3.setIcon(iconProcess) +# self.pushButton_3.setText(u"Processing...") +# +# for item in self.sel_items: +# i_cnt = i_cnt + 1 +# self.progressBar.setFormat(u"Completed %v/%m") +# self.label_8.setText(u"Processing folder " + str(i_cnt) + " of " + str(sel_count) + " | Current: " + str(item.text(0)) + "") +# updItem = QTreeWidgetItem +# doc = Metashape.app.document +# netpath = Metashape.app.document.path +# netroot = self.lineEdit.text() +# image_folder = str(netroot).replace("\\", "/") + "/" + item.text(0) +# photos = autoftg_main.find_files(image_folder, [".jpg", ".jpeg", ".png", ".tif", ".tiff"]) +# chunk = doc.addChunk() +# chunk.addPhotos(photos) +# chunk_name = item_pre + item.text(0) + item_suf +# chunk.label = Metashape.app.getString("Chunk Name", chunk_name) +# chunk.label = chunk_name +# doc.chunk = chunk +# doc.save(netpath) +# autoftg_main.readCameraSettings(item_cam) +# autoftg_main.useCameraSettings() +# if self.checkBox_2.isChecked() == True: +# chunk.detectMarkers(target_type=Metashape.CircularTarget12bit, tolerance=98) +# Metashape.app.update() +# +# if self.checkBox.isChecked() == True: +# points_file = image_folder + "/" + item.text(0) + ".txt" +# points_file_exists = os.path.isfile(points_file) +# if points_file_exists == True: +# chunk.importReference(points_file, format=Metashape.ReferenceFormatCSV, columns='nxyz', delimiter=',', skip_rows=6, create_markers=True) +# chunk.updateTransform() +# ms_pntfile = item.text(0) + ".txt" +# else: +# ms_pntfile = "None" +# +# Metashape.app.update() +# doc.save(netpath) +# updItem.setIcon(item, 3, iconDone) +# +# +# align_done = "" +# if self.checkBox_align.isChecked() == True: +# chunk.matchPhotos(downscale = 0, keypoint_limit = 40000, tiepoint_limit = 10000, generic_preselection = False, reference_preselection = False) +# doc.save(netpath) +# chunk.alignCameras(subdivide_task = True) +# doc.save(netpath) +# align_done = item.text(0) + "_aligned" +# updItem.setIcon(item, 4, iconToDo) +# Metashape.app.update() +# +# +# mesh_done = "" +# if self.checkBox_mesh.isChecked() == True: +# chunk.buildDepthMaps(downscale = 2, filter_mode = Metashape.MildFiltering) +# doc.save(netpath) +# chunk.buildModel(source_data = Metashape.DepthMapsData) +# doc.save(netpath) +# chunk.buildUV(page_count = 1, texture_size = 4096) +# doc.save(netpath) +# chunk.buildTexture(texture_size=4096, fill_holes=True, ghosting_filter=True) +# doc.save(netpath) +# mesh_done = item.text(0) + "_mesh" +# updItem.setIcon(item, 5, iconToDo) +# Metashape.app.update() +# +# +# ptcloud_done = "" +# if self.checkBox_export.isChecked() == True: +# chunk.buildPointCloud() +# doc.save(netpath) +# ptcloud_done = item.text(0) + "_pointcloud" +# updItem.setIcon(item, 6, iconToDo) +# Metashape.app.update() +# +# +# chunk_emodel = "" +# chunk_eptc = "" +# export_done = "" +# if self.checkBox_pcloud.isChecked() == True: +# if chunk.model: +# chunk.exportModel(path=output_folder + "/" + chunk_name + ".obj", binary=True, precision=4, texture_format='ImageFormatJPEG', save_texture=True, save_uv=True, save_normals=True, save_colors=True, save_confidence=False, save_cameras=True, save_markers=True, save_udim=False, save_alpha=False, embed_texture=False, strip_extensions=False, colors_rgb_8bit=True, comment=chunk_name, save_comment=True) +# chunk_emodel = "(M)" +# Metashape.app.update() +# +# if chunk.point_cloud: +# chunk.exportPointCloud(output_folder + "/" + chunk_name + ".laz", source_data = Metashape.PointCloudData, save_point_color=True, save_point_normal=True, save_point_confidence=True) +# chunk_eptc = "(PC)" +# Metashape.app.update() +# +# export_done = chunk_emodel + chunk_eptc + "," + output_folder +# +# +# now = datetime.now() +# dt_string = now.strftime("%d.%m.%Y") +# tm_string = now.strftime("%H:%M") +# ms_data = list(dt_string, tm_string, chunk_name, str(len(photos)), ms_pntfile, item_cam, image_folder, align_done, mesh_done, ptcloud_done, export_done) +# self.logWriteArchive(ms_data) +# +# self.treeWidget.setItemSelected(item, False) +# self.progressBar.setValue(i_cnt) +# Metashape.app.update() +# doc.save(netpath) +# +# +# if i_cnt < sel_count: +# self.pushButton_3.setIcon(iconError) +# self.pushButton_3.setText(u"Error!") +# self.label_8.setText(u"Processing error! / Imported " + str(i_cnt) + " of " + str(sel_count) + " / Could not import " + str(item.text(0)) + "
") +# else: +# self.pushButton_3.setIcon(iconOk) +# self.pushButton_3.setText(u"Finished") +# self.label_8.setText(u"Processing Finished! / Imported " + str(i_cnt) + " of " + str(sel_count) + "
") +# +# +# Metashape.app.update() +# doc.save(netpath) + + + def processBatch(self): + if self.checkBox_3.isChecked() == True: + self.processBatchAuto() + else: + # self.processBatchManual() + Metashape.app.messageBox("Feature in development. Coming soon.") + + + def quitChunkBatch(self): + self.reject() + + + def diaSettingsMesh(self): + app_inst = QtWidgets.QApplication.instance() + parent = app_inst.activeWindow() + setMeshDia = Ui_DialogSettingsMesh(parent) + self.setCurrentSettings() + + + def diaSettingsAlign(self): + app_inst = QtWidgets.QApplication.instance() + parent = app_inst.activeWindow() + setAlignDia = Ui_DialogAlignPhotos(parent) + self.setCurrentSettings() + + + def diaSettingsPoint(self): + app_inst = QtWidgets.QApplication.instance() + parent = app_inst.activeWindow() + setPointDia = Ui_DialogPCloudSet(parent) + self.setCurrentSettings() + diff --git a/AutoFTG/autoftg_batch_setalign.py b/AutoFTG/autoftg_batch_setalign.py new file mode 100644 index 0000000..c46e16b --- /dev/null +++ b/AutoFTG/autoftg_batch_setalign.py @@ -0,0 +1,326 @@ +# AutoFTG - Scripts for Agisoft Metashape Pro +# +# Dialog: Batch Chunk Creator - Align Photos Settings +# ---------------------------------------------------------------- + + +import os +import shutil +import sys +import time +import subprocess +from configparser import ConfigParser +from datetime import datetime +from os import path + +import Metashape +from PySide2 import QtCore, QtGui, QtWidgets +from PySide2.QtCore import * +from PySide2.QtGui import * +from PySide2.QtWidgets import * + +import AutoFTG.autoftg_main as autoftg_main +from AutoFTG.qtresources_rc2 import * +import AutoFTG.autoftg_batch as autoftg_batch +from AutoFTG.autoftg_batch import * + + +class Ui_DialogAlignPhotos(QtWidgets.QDialog): + def __init__(self, parent): + QtWidgets.QDialog.__init__(self, parent) + self.setObjectName(u"DialogAlignPhotos") + self.resize(290, 460) + self.setWindowTitle(u"Align Photos Settings") + self.formLayoutWidget = QWidget(self) + self.formLayoutWidget.setObjectName(u"formLayoutWidget") + self.formLayoutWidget.setGeometry(QRect(0, 0, 291, 461)) + self.formLayout = QFormLayout(self.formLayoutWidget) + self.formLayout.setObjectName(u"formLayout") + self.formLayout.setContentsMargins(10, 10, 10, 10) + self.label_4 = QLabel(self.formLayoutWidget) + self.label_4.setObjectName(u"label_4") + sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_4.sizePolicy().hasHeightForWidth()) + self.label_4.setSizePolicy(sizePolicy) + font = QFont() + font.setFamily(u"Segoe UI") + font.setPointSize(14) + font.setBold(True) + font.setWeight(75) + self.label_4.setFont(font) + self.label_4.setText(u"Align Photos Settings") + + self.formLayout.setWidget(0, QFormLayout.SpanningRole, self.label_4) + + self.line = QFrame(self.formLayoutWidget) + self.line.setObjectName(u"line") + self.line.setFrameShape(QFrame.HLine) + self.line.setFrameShadow(QFrame.Sunken) + + self.formLayout.setWidget(1, QFormLayout.SpanningRole, self.line) + + self.label = QLabel(self.formLayoutWidget) + self.label.setObjectName(u"label") + font1 = QFont() + font1.setFamily(u"Segoe UI") + font1.setPointSize(11) + self.label.setFont(font1) + self.label.setText(u"Quality") + + self.formLayout.setWidget(2, QFormLayout.LabelRole, self.label) + + self.comboBox_quality = QComboBox(self.formLayoutWidget) + self.comboBox_quality.addItem(u"Highest") + self.comboBox_quality.addItem(u"High") + self.comboBox_quality.addItem(u"Medium") + self.comboBox_quality.addItem(u"Low") + self.comboBox_quality.addItem(u"Lowest") + self.comboBox_quality.setObjectName(u"comboBox_quality") + self.comboBox_quality.setCurrentText(u"Highest") + + self.formLayout.setWidget(2, QFormLayout.FieldRole, self.comboBox_quality) + + self.line_2 = QFrame(self.formLayoutWidget) + self.line_2.setObjectName(u"line_2") + self.line_2.setFrameShape(QFrame.HLine) + self.line_2.setFrameShadow(QFrame.Sunken) + + self.formLayout.setWidget(3, QFormLayout.SpanningRole, self.line_2) + + self.label_2 = QLabel(self.formLayoutWidget) + self.label_2.setObjectName(u"label_2") + self.label_2.setFont(font1) + self.label_2.setText(u"Pre-selection") + + self.formLayout.setWidget(4, QFormLayout.LabelRole, self.label_2) + + self.checkBox_gen = QCheckBox(self.formLayoutWidget) + self.checkBox_gen.setObjectName(u"checkBox_gen") + self.checkBox_gen.setText(u"Generic") + + self.formLayout.setWidget(4, QFormLayout.FieldRole, self.checkBox_gen) + + self.checkBox_ref = QCheckBox(self.formLayoutWidget) + self.checkBox_ref.setObjectName(u"checkBox_ref") + self.checkBox_ref.setText(u"Reference") + + self.formLayout.setWidget(5, QFormLayout.FieldRole, self.checkBox_ref) + + self.comboBox_ref = QComboBox(self.formLayoutWidget) + self.comboBox_ref.addItem(u"Source") + self.comboBox_ref.addItem(u"Estimated") + self.comboBox_ref.addItem(u"Sequential") + self.comboBox_ref.setObjectName(u"comboBox_ref") + self.comboBox_ref.setEnabled(False) + self.comboBox_ref.setCurrentText(u"Source") + + self.formLayout.setWidget(6, QFormLayout.FieldRole, self.comboBox_ref) + + self.line_5 = QFrame(self.formLayoutWidget) + self.line_5.setObjectName(u"line_5") + self.line_5.setFrameShape(QFrame.HLine) + self.line_5.setFrameShadow(QFrame.Sunken) + + self.formLayout.setWidget(7, QFormLayout.SpanningRole, self.line_5) + + self.label_3 = QLabel(self.formLayoutWidget) + self.label_3.setObjectName(u"label_3") + self.label_3.setFont(font1) + self.label_3.setText(u"Point Limit") + + self.formLayout.setWidget(8, QFormLayout.LabelRole, self.label_3) + + self.horizontalLayout_2 = QHBoxLayout() + self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") + self.label_6 = QLabel(self.formLayoutWidget) + self.label_6.setObjectName(u"label_6") + sizePolicy.setHeightForWidth(self.label_6.sizePolicy().hasHeightForWidth()) + self.label_6.setSizePolicy(sizePolicy) + self.label_6.setText(u"Key") + + self.horizontalLayout_2.addWidget(self.label_6) + + self.label_5 = QLabel(self.formLayoutWidget) + self.label_5.setObjectName(u"label_5") + sizePolicy.setHeightForWidth(self.label_5.sizePolicy().hasHeightForWidth()) + self.label_5.setSizePolicy(sizePolicy) + self.label_5.setText(u"Tie") + + self.horizontalLayout_2.addWidget(self.label_5) + + + self.formLayout.setLayout(8, QFormLayout.FieldRole, self.horizontalLayout_2) + + self.horizontalLayout = QHBoxLayout() + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.lineEdit_keypoints = QLineEdit(self.formLayoutWidget) + self.lineEdit_keypoints.setObjectName(u"lineEdit_keypoints") + self.lineEdit_keypoints.setPlaceholderText(u"40000") + + self.horizontalLayout.addWidget(self.lineEdit_keypoints) + + self.lineEdit_tiepoints = QLineEdit(self.formLayoutWidget) + self.lineEdit_tiepoints.setObjectName(u"lineEdit_tiepoints") + self.lineEdit_tiepoints.setPlaceholderText(u"10000") + + self.horizontalLayout.addWidget(self.lineEdit_tiepoints) + + + self.formLayout.setLayout(9, QFormLayout.FieldRole, self.horizontalLayout) + + self.line_4 = QFrame(self.formLayoutWidget) + self.line_4.setObjectName(u"line_4") + self.line_4.setFrameShape(QFrame.HLine) + self.line_4.setFrameShadow(QFrame.Sunken) + + self.formLayout.setWidget(10, QFormLayout.SpanningRole, self.line_4) + + self.label_7 = QLabel(self.formLayoutWidget) + self.label_7.setObjectName(u"label_7") + self.label_7.setFont(font1) + self.label_7.setText(u"Other") + + self.formLayout.setWidget(11, QFormLayout.LabelRole, self.label_7) + + self.checkBox_filtmask = QCheckBox(self.formLayoutWidget) + self.checkBox_filtmask.setObjectName(u"checkBox_filtmask") + self.checkBox_filtmask.setText(u"Filter Masked") + + self.formLayout.setWidget(11, QFormLayout.FieldRole, self.checkBox_filtmask) + + self.checkBox_masktie = QCheckBox(self.formLayoutWidget) + self.checkBox_masktie.setObjectName(u"checkBox_masktie") + self.checkBox_masktie.setText(u"Mask Tie Points") + + self.formLayout.setWidget(13, QFormLayout.FieldRole, self.checkBox_masktie) + + self.checkBox_keepkey = QCheckBox(self.formLayoutWidget) + self.checkBox_keepkey.setObjectName(u"checkBox_keepkey") + self.checkBox_keepkey.setText(u"Keep Key Points") + + self.formLayout.setWidget(14, QFormLayout.FieldRole, self.checkBox_keepkey) + + self.checkBox_guided = QCheckBox(self.formLayoutWidget) + self.checkBox_guided.setObjectName(u"checkBox_guided") + self.checkBox_guided.setText(u"Guided Matching") + + self.formLayout.setWidget(15, QFormLayout.FieldRole, self.checkBox_guided) + + self.checkBox_reset = QCheckBox(self.formLayoutWidget) + self.checkBox_reset.setObjectName(u"checkBox_reset") + self.checkBox_reset.setText(u"Reset Alignement") + + self.formLayout.setWidget(16, QFormLayout.FieldRole, self.checkBox_reset) + + self.verticalSpacer = QSpacerItem(20, 5, QSizePolicy.Minimum, QSizePolicy.Expanding) + + self.formLayout.setItem(17, QFormLayout.FieldRole, self.verticalSpacer) + + self.horizontalLayout_3 = QHBoxLayout() + self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") + self.pushButton_save = QPushButton(self.formLayoutWidget) + self.pushButton_save.setObjectName(u"pushButton_save") + self.pushButton_save.setText(u"Save") + icon = QIcon() + icon.addFile(u":/icons/icons8-save-as-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.pushButton_save.setIcon(icon) + self.pushButton_save.setIconSize(QSize(20, 20)) + + self.horizontalLayout_3.addWidget(self.pushButton_save) + + self.pushButton_cancel = QPushButton(self.formLayoutWidget) + self.pushButton_cancel.setObjectName(u"pushButton_cancel") + self.pushButton_cancel.setText(u"Cancel") + icon1 = QIcon() + icon1.addFile(u":/icons/icons8-close-window-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.pushButton_cancel.setIcon(icon1) + self.pushButton_cancel.setIconSize(QSize(20, 20)) + + self.horizontalLayout_3.addWidget(self.pushButton_cancel) + + + self.formLayout.setLayout(18, QFormLayout.FieldRole, self.horizontalLayout_3) + + self.checkBox_filtsta = QCheckBox(self.formLayoutWidget) + self.checkBox_filtsta.setObjectName(u"checkBox_filtsta") + self.checkBox_filtsta.setText(u"Filter Stationary Points") + + self.formLayout.setWidget(12, QFormLayout.FieldRole, self.checkBox_filtsta) + + self.pushButton_cancel.clicked.connect(self.reject) + self.pushButton_save.clicked.connect(self.saveSettingsAlign) + + self.currentChkDef = autoftg_batch.chunkSet + + self.loadSettingsAlign() + + + self.exec_() + + + def loadSettingsAlign(self): + align_quality = autoftg_main.menuCfg.get(self.currentChkDef, "align_quality") + align_gen_presel = autoftg_main.menuCfg.getboolean(self.currentChkDef, "align_gen_presel") + align_ref_presel = autoftg_main.menuCfg.getboolean(self.currentChkDef, "align_ref_presel") + align_ref_presel_mode = autoftg_main.menuCfg.get(self.currentChkDef, "align_ref_presel_mode") + align_key_limit = autoftg_main.menuCfg.getint(self.currentChkDef, "align_key_limit") + align_tie_limit = autoftg_main.menuCfg.getint(self.currentChkDef, "align_tie_limit") + align_filter_mask = autoftg_main.menuCfg.getboolean(self.currentChkDef, "align_filter_mask") + align_mask_tiepoint = autoftg_main.menuCfg.getboolean(self.currentChkDef, "align_mask_tiepoint") + align_filter_stationary = autoftg_main.menuCfg.getboolean(self.currentChkDef, "align_filter_stationary") + align_keep_keypoints = autoftg_main.menuCfg.getboolean(self.currentChkDef, "align_keep_keypoints") + align_guided_matching = autoftg_main.menuCfg.getboolean(self.currentChkDef, "align_guided_matching") + align_reset_current = autoftg_main.menuCfg.getboolean(self.currentChkDef, "align_reset_current") + + self.comboBox_quality.setCurrentText(align_quality) + self.checkBox_gen.setChecked(align_gen_presel) + self.checkBox_ref.setChecked(align_ref_presel) + self.comboBox_ref.setCurrentText(align_ref_presel_mode) + self.lineEdit_keypoints.setText(str(align_key_limit)) + self.lineEdit_tiepoints.setText(str(align_tie_limit)) + self.checkBox_filtmask.setChecked(align_filter_mask) + self.checkBox_masktie.setChecked(align_mask_tiepoint) + self.checkBox_filtsta.setChecked(align_filter_stationary) + self.checkBox_keepkey.setChecked(align_keep_keypoints) + self.checkBox_guided.setChecked(align_guided_matching) + self.checkBox_reset.setChecked(align_reset_current) + + print("Align Photos settings loaded...") + + + def saveSettingsAlign(self): + align_quality = self.comboBox_quality.currentText() + align_gen_presel = self.checkBox_gen.isChecked() + align_ref_presel = self.checkBox_ref.isChecked() + align_ref_presel_mode = self.comboBox_ref.currentText() + align_key_limit = self.lineEdit_keypoints.text() + align_tie_limit = self.lineEdit_tiepoints.text() + align_filter_mask = self.checkBox_filtmask.isChecked() + align_mask_tiepoint = self.checkBox_masktie.isChecked() + align_filter_stationary = self.checkBox_filtsta.isChecked() + align_keep_keypoints = self.checkBox_keepkey.isChecked() + align_guided_matching = self.checkBox_guided.isChecked() + align_reset_current = self.checkBox_reset.isChecked() + + autoftg_main.menuCfg.set(self.currentChkDef, "align_quality", str(align_quality)) + autoftg_main.menuCfg.set(self.currentChkDef, "align_gen_presel", str(align_gen_presel)) + autoftg_main.menuCfg.set(self.currentChkDef, "align_ref_presel", str(align_ref_presel)) + autoftg_main.menuCfg.set(self.currentChkDef, "align_ref_presel_mode", str(align_ref_presel_mode)) + autoftg_main.menuCfg.set(self.currentChkDef, "align_key_limit", str(align_key_limit)) + autoftg_main.menuCfg.set(self.currentChkDef, "align_tie_limit", str(align_tie_limit)) + autoftg_main.menuCfg.set(self.currentChkDef, "align_filter_mask", str(align_filter_mask)) + autoftg_main.menuCfg.set(self.currentChkDef, "align_mask_tiepoint", str(align_mask_tiepoint)) + autoftg_main.menuCfg.set(self.currentChkDef, "align_filter_stationary", str(align_filter_stationary)) + autoftg_main.menuCfg.set(self.currentChkDef, "align_keep_keypoints", str(align_keep_keypoints)) + autoftg_main.menuCfg.set(self.currentChkDef, "align_guided_matching", str(align_guided_matching)) + autoftg_main.menuCfg.set(self.currentChkDef, "align_reset_current", str(align_reset_current)) + + with open(autoftg_main.menuCfgFilePath, 'w') as configfile: + autoftg_main.menuCfg.write(configfile) + + print("Align Photos settings saved...") + + self.accept() + diff --git a/AutoFTG/autoftg_batch_setmesh.py b/AutoFTG/autoftg_batch_setmesh.py new file mode 100644 index 0000000..a157ff9 --- /dev/null +++ b/AutoFTG/autoftg_batch_setmesh.py @@ -0,0 +1,485 @@ +import os +import shutil +import sys +import time +import subprocess +from configparser import ConfigParser +from datetime import datetime +from os import path + +import Metashape +from PySide2 import QtCore, QtGui, QtWidgets +from PySide2.QtCore import * +from PySide2.QtGui import * +from PySide2.QtWidgets import * + +import AutoFTG.autoftg_main as autoftg_main +from AutoFTG.qtresources_rc2 import * +import AutoFTG.autoftg_batch as autoftg_batch +from AutoFTG.autoftg_batch import * +from AutoFTG.autoftg_settingsmain import * + + +class Ui_DialogSettingsMesh(QtWidgets.QDialog): + def __init__(self, parent): + QtWidgets.QDialog.__init__(self, parent) + self.currentChkDef = autoftg_batch.chunkSet + self.setObjectName(u"DialogSettingsMesh") + self.resize(350, 510) + self.setWindowTitle(u"Settings: Mesh & Textures") + icon = QIcon() + icon.addFile(u":/icons/AutoFTG-appicon.png", QSize(), QIcon.Normal, QIcon.Off) + self.setWindowIcon(icon) + self.formLayoutWidget = QWidget(self) + self.formLayoutWidget.setObjectName(u"formLayoutWidget") + self.formLayoutWidget.setGeometry(QRect(0, 0, 351, 511)) + self.formLayout = QFormLayout(self.formLayoutWidget) + self.formLayout.setObjectName(u"formLayout") + self.formLayout.setContentsMargins(10, 5, 10, 10) + self.horizontalLayout_2 = QHBoxLayout() + self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") + self.label_11 = QLabel(self.formLayoutWidget) + self.label_11.setObjectName(u"label_11") + sizePolicy = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_11.sizePolicy().hasHeightForWidth()) + self.label_11.setSizePolicy(sizePolicy) + self.label_11.setMaximumSize(QSize(24, 24)) + self.label_11.setFrameShape(QFrame.NoFrame) + self.label_11.setText(u"") + self.label_11.setPixmap(QPixmap(u":/icons/icons8-geodesic-dome-48.png")) + self.label_11.setScaledContents(True) + + self.horizontalLayout_2.addWidget(self.label_11) + + self.label = QLabel(self.formLayoutWidget) + self.label.setObjectName(u"label") + font = QFont() + font.setFamily(u"Segoe UI") + font.setPointSize(12) + font.setBold(True) + font.setWeight(75) + self.label.setFont(font) + self.label.setText(u"Depth Maps") + + self.horizontalLayout_2.addWidget(self.label) + + + self.formLayout.setLayout(0, QFormLayout.SpanningRole, self.horizontalLayout_2) + + self.label_8 = QLabel(self.formLayoutWidget) + self.label_8.setObjectName(u"label_8") + + self.formLayout.setWidget(1, QFormLayout.LabelRole, self.label_8) + + self.comboBox_depthQuality = QComboBox(self.formLayoutWidget) + icon1 = QIcon() + icon1.addFile(u":/icons/icons8-connection-status-on-48.png", QSize(), QIcon.Normal, QIcon.Off) + self.comboBox_depthQuality.addItem(icon1, u"Ultra High") + icon2 = QIcon() + icon2.addFile(u":/icons/icons8-signal-full-48.png", QSize(), QIcon.Normal, QIcon.Off) + self.comboBox_depthQuality.addItem(icon2, u"HIgh") + icon3 = QIcon() + icon3.addFile(u":/icons/icons8-signal-48.png", QSize(), QIcon.Normal, QIcon.Off) + self.comboBox_depthQuality.addItem(icon3, u"Medium") + icon4 = QIcon() + icon4.addFile(u":/icons/icons8-low-connection-48.png", QSize(), QIcon.Normal, QIcon.Off) + self.comboBox_depthQuality.addItem(icon4, u"Low") + icon5 = QIcon() + icon5.addFile(u":/icons/icons8-no-connection-48.png", QSize(), QIcon.Normal, QIcon.Off) + self.comboBox_depthQuality.addItem(icon5, u"Lowest") + self.comboBox_depthQuality.setObjectName(u"comboBox_depthQuality") + self.comboBox_depthQuality.setMinimumSize(QSize(0, 26)) + self.comboBox_depthQuality.setMaximumSize(QSize(16777215, 26)) + self.comboBox_depthQuality.setCurrentText(u"Medium") + + self.formLayout.setWidget(1, QFormLayout.FieldRole, self.comboBox_depthQuality) + + self.label_9 = QLabel(self.formLayoutWidget) + self.label_9.setObjectName(u"label_9") + + self.formLayout.setWidget(2, QFormLayout.LabelRole, self.label_9) + + self.comboBox_depthFilter = QComboBox(self.formLayoutWidget) + self.comboBox_depthFilter.addItem(u"Mild") + self.comboBox_depthFilter.addItem(u"Moderate") + self.comboBox_depthFilter.addItem(u"Aggresive") + self.comboBox_depthFilter.setObjectName(u"comboBox_depthFilter") + self.comboBox_depthFilter.setMinimumSize(QSize(0, 26)) + self.comboBox_depthFilter.setMaximumSize(QSize(16777215, 26)) + self.comboBox_depthFilter.setCurrentText(u"Moderate") + + self.formLayout.setWidget(2, QFormLayout.FieldRole, self.comboBox_depthFilter) + + self.line_3 = QFrame(self.formLayoutWidget) + self.line_3.setObjectName(u"line_3") + self.line_3.setFrameShape(QFrame.HLine) + self.line_3.setFrameShadow(QFrame.Sunken) + + self.formLayout.setWidget(3, QFormLayout.SpanningRole, self.line_3) + + self.horizontalLayout_4 = QHBoxLayout() + self.horizontalLayout_4.setObjectName(u"horizontalLayout_4") + self.label_12 = QLabel(self.formLayoutWidget) + self.label_12.setObjectName(u"label_12") + sizePolicy.setHeightForWidth(self.label_12.sizePolicy().hasHeightForWidth()) + self.label_12.setSizePolicy(sizePolicy) + self.label_12.setMaximumSize(QSize(24, 24)) + self.label_12.setFrameShape(QFrame.NoFrame) + self.label_12.setText(u"") + self.label_12.setPixmap(QPixmap(u":/icons/icons8-mesh-48.png")) + self.label_12.setScaledContents(True) + + self.horizontalLayout_4.addWidget(self.label_12) + + self.label_10 = QLabel(self.formLayoutWidget) + self.label_10.setObjectName(u"label_10") + self.label_10.setFont(font) + self.label_10.setText(u"Mesh Options") + + self.horizontalLayout_4.addWidget(self.label_10) + + + self.formLayout.setLayout(4, QFormLayout.SpanningRole, self.horizontalLayout_4) + + self.label_2 = QLabel(self.formLayoutWidget) + self.label_2.setObjectName(u"label_2") + self.label_2.setText(u"Surface Type") + + self.formLayout.setWidget(5, QFormLayout.LabelRole, self.label_2) + + self.cbMeshType = QComboBox(self.formLayoutWidget) + icon6 = QIcon() + icon6.addFile(u":/icons/icons8-3d-48.png", QSize(), QIcon.Normal, QIcon.Off) + self.cbMeshType.addItem(icon6, u"Arbitrary") + icon7 = QIcon() + icon7.addFile(u":/icons/icons8-national-park-48.png", QSize(), QIcon.Normal, QIcon.Off) + self.cbMeshType.addItem(icon7, u"Height Field") + self.cbMeshType.setObjectName(u"cbMeshType") + self.cbMeshType.setMinimumSize(QSize(0, 26)) + self.cbMeshType.setMaximumSize(QSize(16777215, 26)) +#if QT_CONFIG(tooltip) + self.cbMeshType.setToolTip(u"Choose type of model reconstruction") +#endif // QT_CONFIG(tooltip) + + self.formLayout.setWidget(5, QFormLayout.FieldRole, self.cbMeshType) + + self.label_3 = QLabel(self.formLayoutWidget) + self.label_3.setObjectName(u"label_3") + self.label_3.setText(u"Face Count") + + self.formLayout.setWidget(6, QFormLayout.LabelRole, self.label_3) + + self.cbFaceCount = QComboBox(self.formLayoutWidget) + self.cbFaceCount.addItem(icon2, u"High") + self.cbFaceCount.addItem(icon3, u"Medium") + self.cbFaceCount.addItem(icon4, u"Low") + icon8 = QIcon() + icon8.addFile(u":/icons/icons8-rename-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.cbFaceCount.addItem(icon8, u"Custom") + self.cbFaceCount.setObjectName(u"cbFaceCount") + self.cbFaceCount.setMinimumSize(QSize(0, 26)) + self.cbFaceCount.setMaximumSize(QSize(16777215, 26)) +#if QT_CONFIG(tooltip) + self.cbFaceCount.setToolTip(u"Choose face count density") +#endif // QT_CONFIG(tooltip) + self.cbFaceCount.setCurrentText(u"Medium") + + self.formLayout.setWidget(6, QFormLayout.FieldRole, self.cbFaceCount) + + self.lineEditFaceCount = QLineEdit(self.formLayoutWidget) + self.lineEditFaceCount.setObjectName(u"lineEditFaceCount") + self.lineEditFaceCount.setEnabled(False) + self.lineEditFaceCount.setPlaceholderText(u"Custom face count") + + self.formLayout.setWidget(7, QFormLayout.FieldRole, self.lineEditFaceCount) + + self.checkBox_inter = QCheckBox(self.formLayoutWidget) + self.checkBox_inter.setObjectName(u"checkBox_inter") +#if QT_CONFIG(tooltip) + self.checkBox_inter.setToolTip(u"Enable interpolation") +#endif // QT_CONFIG(tooltip) + self.checkBox_inter.setText(u"Interpolation") + + self.formLayout.setWidget(8, QFormLayout.FieldRole, self.checkBox_inter) + + self.checkBox_vcol = QCheckBox(self.formLayoutWidget) + self.checkBox_vcol.setObjectName(u"checkBox_vcol") +#if QT_CONFIG(tooltip) + self.checkBox_vcol.setToolTip(u"Calculate vertex colors") +#endif // QT_CONFIG(tooltip) + self.checkBox_vcol.setText(u"Vertex Colors") + self.checkBox_vcol.setChecked(True) + + self.formLayout.setWidget(9, QFormLayout.FieldRole, self.checkBox_vcol) + + self.checkBox_vcon = QCheckBox(self.formLayoutWidget) + self.checkBox_vcon.setObjectName(u"checkBox_vcon") +#if QT_CONFIG(tooltip) + self.checkBox_vcon.setToolTip(u"Calculate vertex confidence") +#endif // QT_CONFIG(tooltip) + self.checkBox_vcon.setText(u"Vertex Confidence") + + self.formLayout.setWidget(10, QFormLayout.FieldRole, self.checkBox_vcon) + + self.line = QFrame(self.formLayoutWidget) + self.line.setObjectName(u"line") + self.line.setFrameShape(QFrame.HLine) + self.line.setFrameShadow(QFrame.Sunken) + + self.formLayout.setWidget(11, QFormLayout.SpanningRole, self.line) + + self.horizontalLayout_5 = QHBoxLayout() + self.horizontalLayout_5.setObjectName(u"horizontalLayout_5") + self.label_13 = QLabel(self.formLayoutWidget) + self.label_13.setObjectName(u"label_13") + sizePolicy.setHeightForWidth(self.label_13.sizePolicy().hasHeightForWidth()) + self.label_13.setSizePolicy(sizePolicy) + self.label_13.setMaximumSize(QSize(24, 24)) + self.label_13.setFrameShape(QFrame.NoFrame) + self.label_13.setText(u"") + self.label_13.setPixmap(QPixmap(u":/icons/icons8-video-wall-50.png")) + self.label_13.setScaledContents(True) + + self.horizontalLayout_5.addWidget(self.label_13) + + self.label_5 = QLabel(self.formLayoutWidget) + self.label_5.setObjectName(u"label_5") + self.label_5.setFont(font) + self.label_5.setText(u"Textures Options") + + self.horizontalLayout_5.addWidget(self.label_5) + + + self.formLayout.setLayout(12, QFormLayout.SpanningRole, self.horizontalLayout_5) + + self.groupBox_buildTex = QGroupBox(self.formLayoutWidget) + self.groupBox_buildTex.setObjectName(u"groupBox_buildTex") + self.groupBox_buildTex.setMinimumSize(QSize(0, 90)) + self.groupBox_buildTex.setTitle(u"Build Textures") + self.groupBox_buildTex.setCheckable(True) + self.gridLayoutWidget = QWidget(self.groupBox_buildTex) + self.gridLayoutWidget.setObjectName(u"gridLayoutWidget") + self.gridLayoutWidget.setGeometry(QRect(10, 30, 311, 52)) + self.gridLayout = QGridLayout(self.gridLayoutWidget) + self.gridLayout.setObjectName(u"gridLayout") + self.gridLayout.setContentsMargins(0, 0, 0, 0) + self.label_4 = QLabel(self.gridLayoutWidget) + self.label_4.setObjectName(u"label_4") + self.label_4.setText(u"Size") + + self.gridLayout.addWidget(self.label_4, 0, 2, 1, 1) + + self.checkBox_texFillHoles = QCheckBox(self.gridLayoutWidget) + self.checkBox_texFillHoles.setObjectName(u"checkBox_texFillHoles") + sizePolicy1 = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) + sizePolicy1.setHorizontalStretch(0) + sizePolicy1.setVerticalStretch(0) + sizePolicy1.setHeightForWidth(self.checkBox_texFillHoles.sizePolicy().hasHeightForWidth()) + self.checkBox_texFillHoles.setSizePolicy(sizePolicy1) + self.checkBox_texFillHoles.setText(u"Fill Holes") + self.checkBox_texFillHoles.setChecked(True) + + self.gridLayout.addWidget(self.checkBox_texFillHoles, 0, 0, 1, 1) + + self.lineEdit_texSize = QLineEdit(self.gridLayoutWidget) + self.lineEdit_texSize.setObjectName(u"lineEdit_texSize") + sizePolicy2 = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) + sizePolicy2.setHorizontalStretch(0) + sizePolicy2.setVerticalStretch(0) + sizePolicy2.setHeightForWidth(self.lineEdit_texSize.sizePolicy().hasHeightForWidth()) + self.lineEdit_texSize.setSizePolicy(sizePolicy2) + self.lineEdit_texSize.setMaximumSize(QSize(60, 16777215)) + self.lineEdit_texSize.setText(u"4096") + + self.gridLayout.addWidget(self.lineEdit_texSize, 1, 2, 1, 1) + + self.label_6 = QLabel(self.gridLayoutWidget) + self.label_6.setObjectName(u"label_6") + self.label_6.setText(u"Levels") + + self.gridLayout.addWidget(self.label_6, 0, 4, 1, 1) + + self.checkBox_texGhostFilt = QCheckBox(self.gridLayoutWidget) + self.checkBox_texGhostFilt.setObjectName(u"checkBox_texGhostFilt") + sizePolicy1.setHeightForWidth(self.checkBox_texGhostFilt.sizePolicy().hasHeightForWidth()) + self.checkBox_texGhostFilt.setSizePolicy(sizePolicy1) + self.checkBox_texGhostFilt.setText(u"Ghosting Filter") + self.checkBox_texGhostFilt.setChecked(True) + + self.gridLayout.addWidget(self.checkBox_texGhostFilt, 1, 0, 1, 1) + + self.lineEdit_texLevels = QLineEdit(self.gridLayoutWidget) + self.lineEdit_texLevels.setObjectName(u"lineEdit_texLevels") + sizePolicy2.setHeightForWidth(self.lineEdit_texLevels.sizePolicy().hasHeightForWidth()) + self.lineEdit_texLevels.setSizePolicy(sizePolicy2) + self.lineEdit_texLevels.setMaximumSize(QSize(50, 16777215)) + self.lineEdit_texLevels.setText(u"1") + self.lineEdit_texLevels.setMaxLength(2) + + self.gridLayout.addWidget(self.lineEdit_texLevels, 1, 4, 1, 1) + + self.label_7 = QLabel(self.gridLayoutWidget) + self.label_7.setObjectName(u"label_7") + sizePolicy3 = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred) + sizePolicy3.setHorizontalStretch(0) + sizePolicy3.setVerticalStretch(0) + sizePolicy3.setHeightForWidth(self.label_7.sizePolicy().hasHeightForWidth()) + self.label_7.setSizePolicy(sizePolicy3) + self.label_7.setText(u"x") + + self.gridLayout.addWidget(self.label_7, 1, 3, 1, 1) + + self.horizontalSpacer = QSpacerItem(20, 5, QSizePolicy.Expanding, QSizePolicy.Minimum) + + self.gridLayout.addItem(self.horizontalSpacer, 1, 1, 1, 1) + + + self.formLayout.setWidget(13, QFormLayout.SpanningRole, self.groupBox_buildTex) + + self.line_2 = QFrame(self.formLayoutWidget) + self.line_2.setObjectName(u"line_2") + self.line_2.setFrameShape(QFrame.HLine) + self.line_2.setFrameShadow(QFrame.Sunken) + + self.formLayout.setWidget(15, QFormLayout.SpanningRole, self.line_2) + + self.horizontalLayout = QHBoxLayout() + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.pushButton_Save = QPushButton(self.formLayoutWidget) + self.pushButton_Save.setObjectName(u"pushButton_Save") + self.pushButton_Save.setText(u"Save") + icon9 = QIcon() + icon9.addFile(u":/icons/icons8-save-close-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.pushButton_Save.setIcon(icon9) + self.pushButton_Save.setIconSize(QSize(20, 20)) + + self.horizontalLayout.addWidget(self.pushButton_Save) + + self.pushButton_Cancel = QPushButton(self.formLayoutWidget) + self.pushButton_Cancel.setObjectName(u"pushButton_Cancel") + self.pushButton_Cancel.setText(u"Cancel") + icon10 = QIcon() + icon10.addFile(u":/icons/icons8-close-window-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.pushButton_Cancel.setIcon(icon10) + self.pushButton_Cancel.setIconSize(QSize(20, 20)) + + self.horizontalLayout.addWidget(self.pushButton_Cancel) + + + self.formLayout.setLayout(16, QFormLayout.FieldRole, self.horizontalLayout) + + self.verticalSpacer = QSpacerItem(20, 20, QSizePolicy.Minimum, QSizePolicy.Expanding) + + self.formLayout.setItem(14, QFormLayout.FieldRole, self.verticalSpacer) + + QWidget.setTabOrder(self.comboBox_depthQuality, self.comboBox_depthFilter) + QWidget.setTabOrder(self.comboBox_depthFilter, self.cbMeshType) + QWidget.setTabOrder(self.cbMeshType, self.cbFaceCount) + QWidget.setTabOrder(self.cbFaceCount, self.lineEditFaceCount) + QWidget.setTabOrder(self.lineEditFaceCount, self.checkBox_inter) + QWidget.setTabOrder(self.checkBox_inter, self.checkBox_vcol) + QWidget.setTabOrder(self.checkBox_vcol, self.checkBox_vcon) + QWidget.setTabOrder(self.checkBox_vcon, self.groupBox_buildTex) + QWidget.setTabOrder(self.groupBox_buildTex, self.checkBox_texFillHoles) + QWidget.setTabOrder(self.checkBox_texFillHoles, self.checkBox_texGhostFilt) + QWidget.setTabOrder(self.checkBox_texGhostFilt, self.lineEdit_texSize) + QWidget.setTabOrder(self.lineEdit_texSize, self.lineEdit_texLevels) + QWidget.setTabOrder(self.lineEdit_texLevels, self.pushButton_Save) + QWidget.setTabOrder(self.pushButton_Save, self.pushButton_Cancel) + + self.pushButton_Cancel.clicked.connect(self.reject) + self.pushButton_Save.clicked.connect(self.saveSettingsMesh) + self.cbFaceCount.currentTextChanged.connect(self.customFaceCount) + + + self.cbFaceCount.setCurrentIndex(1) + self.comboBox_depthQuality.setCurrentIndex(2) + self.comboBox_depthFilter.setCurrentIndex(1) + self.cbFaceCount.setCurrentIndex(1) + self.pushButton_Save.setDefault(True) + + + QMetaObject.connectSlotsByName(self) + + self.loadSettingsMesh() + + self.exec_() + + + def customFaceCount(self): + if self.cbFaceCount.currentText() == "Custom": + self.lineEditFaceCount.setEnabled(True) + else: + self.lineEditFaceCount.setEnabled(False) + + + def loadSettingsMesh(self): + depth_quality = autoftg_main.menuCfg.get(self.currentChkDef, "mesh_depthmaps") + depth_filter = autoftg_main.menuCfg.get(self.currentChkDef, "mesh_depthfilter") + mesh_type = autoftg_main.menuCfg.get(self.currentChkDef, "mesh_type") + mesh_face_count = autoftg_main.menuCfg.get(self.currentChkDef, "mesh_face_count") + mesh_face_count_custom = autoftg_main.menuCfg.get(self.currentChkDef, "mesh_face_count_custom") + mesh_interpolation = autoftg_main.menuCfg.getboolean(self.currentChkDef, "mesh_interpolation") + mesh_vertex_color = autoftg_main.menuCfg.getboolean(self.currentChkDef, "mesh_vertex_color") + mesh_vertex_confidence = autoftg_main.menuCfg.getboolean(self.currentChkDef, "mesh_vertex_confidence") + texture_build = autoftg_main.menuCfg.getboolean(self.currentChkDef, "texture_build") + texture_size = autoftg_main.menuCfg.get(self.currentChkDef, "texture_size") + texture_levels = autoftg_main.menuCfg.get(self.currentChkDef, "texture_levels") + texture_fill = autoftg_main.menuCfg.getboolean(self.currentChkDef, "texture_fill") + texture_ghosting = autoftg_main.menuCfg.getboolean(self.currentChkDef, "texture_ghosting") + + self.comboBox_depthQuality.setCurrentText(depth_quality) + self.comboBox_depthFilter.setCurrentText(depth_filter) + self.cbMeshType.setCurrentText(mesh_type) + self.cbFaceCount.setCurrentText(mesh_face_count) + self.lineEditFaceCount.setText(mesh_face_count_custom) + self.checkBox_inter.setChecked(mesh_interpolation) + self.checkBox_vcol.setChecked(mesh_vertex_color) + self.checkBox_vcon.setChecked(mesh_vertex_confidence) + self.groupBox_buildTex.setChecked(texture_build) + self.checkBox_texFillHoles.setChecked(texture_fill) + self.checkBox_texGhostFilt.setChecked(texture_ghosting) + self.lineEdit_texSize.setText(texture_size) + self.lineEdit_texLevels.setText(texture_levels) + + print("Mesh and textures settings loaded...") + + + def saveSettingsMesh(self): + depth_quality = self.comboBox_depthQuality.currentText() + depth_filter = self.comboBox_depthFilter.currentText() + mesh_type = self.cbMeshType.currentText() + mesh_face_count = self.cbFaceCount.currentText() + mesh_face_count_custom = self.lineEditFaceCount.text() + mesh_interpolation = self.checkBox_inter.isChecked() + mesh_vertex_color = self.checkBox_vcol.isChecked() + mesh_vertex_confidence = self.checkBox_vcon.isChecked() + texture_build = self.groupBox_buildTex.isChecked() + texture_size = self.lineEdit_texSize.text() + texture_levels = self.lineEdit_texLevels.text() + texture_fill = self.checkBox_texFillHoles.isChecked() + texture_ghosting = self.checkBox_texGhostFilt.isChecked() + + autoftg_main.menuCfg.set(self.currentChkDef, "mesh_depthmaps", depth_quality) + autoftg_main.menuCfg.set(self.currentChkDef, "mesh_depthfilter", depth_filter) + autoftg_main.menuCfg.set(self.currentChkDef, "mesh_type", mesh_type) + autoftg_main.menuCfg.set(self.currentChkDef, "mesh_face_count", mesh_face_count) + autoftg_main.menuCfg.set(self.currentChkDef, "mesh_face_count_custom", mesh_face_count_custom) + autoftg_main.menuCfg.set(self.currentChkDef, "mesh_interpolation", str(mesh_interpolation)) + autoftg_main.menuCfg.set(self.currentChkDef, "mesh_vertex_color", str(mesh_vertex_color)) + autoftg_main.menuCfg.set(self.currentChkDef, "mesh_vertex_confidence", str(mesh_vertex_confidence)) + autoftg_main.menuCfg.set(self.currentChkDef, "texture_build", str(texture_build)) + autoftg_main.menuCfg.set(self.currentChkDef, "texture_size", texture_size) + autoftg_main.menuCfg.set(self.currentChkDef, "texture_levels", texture_levels) + autoftg_main.menuCfg.set(self.currentChkDef, "texture_fill", str(texture_fill)) + autoftg_main.menuCfg.set(self.currentChkDef, "texture_ghosting", str(texture_ghosting)) + + with open(autoftg_main.menuCfgFilePath, 'w') as configfile: + autoftg_main.menuCfg.write(configfile) + + print("Mesh and textures settings saved...") + + self.accept() + diff --git a/AutoFTG/autoftg_batch_setpointc.py b/AutoFTG/autoftg_batch_setpointc.py new file mode 100644 index 0000000..5704a78 --- /dev/null +++ b/AutoFTG/autoftg_batch_setpointc.py @@ -0,0 +1,202 @@ +# AutoFTG - Scripts for Agisoft Metashape Pro +# +# Dialog: Batch Chunk Creator - Point Cloud Settings +# ---------------------------------------------------------------- +from configparser import ConfigParser +from datetime import datetime +from os import path + +import Metashape +from PySide2 import QtCore, QtGui, QtWidgets +from PySide2.QtCore import * +from PySide2.QtGui import * +from PySide2.QtWidgets import * + +import AutoFTG.autoftg_batch as autoftg_batch +import AutoFTG.autoftg_main as autoftg_main +from AutoFTG.autoftg_batch import * +from AutoFTG.qtresources_rc2 import * + + +class Ui_DialogPCloudSet(QtWidgets.QDialog): + def __init__(self, parent): + QtWidgets.QDialog.__init__(self, parent) + self.setObjectName(u"DialogPointCloud") + self.resize(320, 240) + self.setWindowTitle(u"Point Cloud Settings") + icon = QIcon() + icon.addFile(u":/icons/icons8-live-photos-96.png", QSize(), QIcon.Normal, QIcon.Off) + self.gridLayoutWidget = QWidget(self) + self.gridLayoutWidget.setObjectName(u"gridLayoutWidget") + self.gridLayoutWidget.setGeometry(QRect(0, 0, 321, 243)) + self.gridLayout = QGridLayout(self.gridLayoutWidget) + self.gridLayout.setSpacing(5) + self.gridLayout.setContentsMargins(10, 10, 10, 10) + self.gridLayout.setObjectName(u"gridLayout") + self.gridLayout.setHorizontalSpacing(10) + self.gridLayout.setContentsMargins(10, 10, 10, 10) + self.checkBox_2 = QCheckBox(self.gridLayoutWidget) + self.checkBox_2.setObjectName(u"checkBox_2") + self.checkBox_2.setLayoutDirection(Qt.RightToLeft) + self.checkBox_2.setText(u"Calculate Confidence") + + self.gridLayout.addWidget(self.checkBox_2, 3, 0, 1, 1) + + self.line = QFrame(self.gridLayoutWidget) + self.line.setObjectName(u"line") + self.line.setFrameShape(QFrame.HLine) + self.line.setFrameShadow(QFrame.Sunken) + + self.gridLayout.addWidget(self.line, 1, 0, 1, 2) + + self.label_3 = QLabel(self.gridLayoutWidget) + self.label_3.setObjectName(u"label_3") + self.label_3.setText(u"Regular") + + self.gridLayout.addWidget(self.label_3, 4, 1, 1, 1) + + self.lineEdit = QLineEdit(self.gridLayoutWidget) + self.lineEdit.setObjectName(u"lineEdit") + self.lineEdit.setPlaceholderText(u"0.05") + self.lineEdit.setClearButtonEnabled(True) + + self.gridLayout.addWidget(self.lineEdit, 5, 1, 1, 1) + + self.checkBox_3 = QCheckBox(self.gridLayoutWidget) + self.checkBox_3.setObjectName(u"checkBox_3") + self.checkBox_3.setLayoutDirection(Qt.RightToLeft) + self.checkBox_3.setText(u"Point Sampling") + + self.gridLayout.addWidget(self.checkBox_3, 4, 0, 1, 1) + + self.label = QLabel(self.gridLayoutWidget) + self.label.setObjectName(u"label") + self.label.setText(u"Enabled") + + self.gridLayout.addWidget(self.label, 2, 1, 1, 1) + + self.label_4 = QLabel(self.gridLayoutWidget) + self.label_4.setObjectName(u"label_4") + self.label_4.setText(u"Point spacing (m)") + self.label_4.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter) + + self.gridLayout.addWidget(self.label_4, 5, 0, 1, 1) + + self.label_2 = QLabel(self.gridLayoutWidget) + self.label_2.setObjectName(u"label_2") + self.label_2.setText(u"Disabled") + + self.gridLayout.addWidget(self.label_2, 3, 1, 1, 1) + + self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) + + self.gridLayout.addItem(self.verticalSpacer, 6, 1, 1, 1) + + self.checkBox = QCheckBox(self.gridLayoutWidget) + self.checkBox.setObjectName(u"checkBox") + self.checkBox.setLayoutDirection(Qt.RightToLeft) + self.checkBox.setText(u"Calculate Colors") + self.checkBox.setChecked(True) + + self.gridLayout.addWidget(self.checkBox, 2, 0, 1, 1) + + self.label_5 = QLabel(self.gridLayoutWidget) + self.label_5.setObjectName(u"label_5") + font = QFont() + font.setFamily(u"Segoe UI") + font.setPointSize(14) + self.label_5.setFont(font) + self.label_5.setText(u"Point Cloud Settings") + + self.gridLayout.addWidget(self.label_5, 0, 0, 1, 2) + + self.horizontalLayout = QHBoxLayout() + self.horizontalLayout.setSpacing(5) + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.pushButton = QPushButton(self.gridLayoutWidget) + self.pushButton.setObjectName(u"pushButton") + sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.pushButton.sizePolicy().hasHeightForWidth()) + self.pushButton.setSizePolicy(sizePolicy) + self.pushButton.setText(u"Cancel") + icon1 = QIcon() + icon1.addFile(u":/icons/icons8-close-window-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.pushButton.setIcon(icon1) + self.pushButton.setIconSize(QSize(20, 20)) + + self.horizontalLayout.addWidget(self.pushButton) + + self.pushButton_2 = QPushButton(self.gridLayoutWidget) + self.pushButton_2.setObjectName(u"pushButton_2") + sizePolicy.setHeightForWidth(self.pushButton_2.sizePolicy().hasHeightForWidth()) + self.pushButton_2.setSizePolicy(sizePolicy) + self.pushButton_2.setText(u"Save") + icon2 = QIcon() + icon2.addFile(u":/icons/icons8-save-as-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.pushButton_2.setIcon(icon2) + self.pushButton_2.setIconSize(QSize(20, 20)) + + self.horizontalLayout.addWidget(self.pushButton_2) + + + self.gridLayout.addLayout(self.horizontalLayout, 7, 0, 1, 2) + + self.label_4.setBuddy(self.lineEdit) + QWidget.setTabOrder(self.checkBox, self.checkBox_2) + QWidget.setTabOrder(self.checkBox_2, self.checkBox_3) + QWidget.setTabOrder(self.checkBox_3, self.lineEdit) + QWidget.setTabOrder(self.lineEdit, self.pushButton_2) + QWidget.setTabOrder(self.pushButton_2, self.pushButton) + + self.pushButton_2.clicked.connect(self.saveSetPCloud) + self.pushButton.clicked.connect(self.reject) + self.checkBox_3.toggled.connect(self.actionSetPointSampling.setVisible) + + self.setWindowTitle(u"Dialog") + + self.currentChkDef = autoftg_batch.chunkSet + + self.loadSetPCloud() + + self.exec_() + + + + def loadSetPCloud(self): + self.pointcloud_source_data = autoftg_main.menuCfg.get(self.currentChkDef, "pointcloud_source_data") + if self.pointcloud_source_data == "DepthMaps": + self.source_data = Metashape.DataSource.DepthMapsData + elif self.pointcloud_source_data == "Mesh": + self.source_data = Metashape.DataSource.ModelData + else: + self.source_data = Metashape.DataSource.DepthMapsData + + pointcloud_point_colors = autoftg_main.menuCfg.getboolean(self.currentChkDef, "pointcloud_point_colors") + self.checkBox.setChecked(pointcloud_point_colors) + + pointcloud_point_confidence = autoftg_main.menuCfg.getboolean(self.currentChkDef, "pointcloud_point_confidence") + self.checkBox_2.setChecked(pointcloud_point_confidence) + + pointcloud_uniform_sam = autoftg_main.menuCfg.getboolean(self.currentChkDef, "pointcloud_uniform_sampling") + self.checkBox_3.setChecked(pointcloud_uniform_sam) + + pointcloud_points_spacing = autoftg_main.menuCfg.get(self.currentChkDef, "pointcloud_points_spacing") + self.lineEdit.setText(str(pointcloud_points_spacing)) + + print("Point Cloud settings loaded...") + + + def saveSetPCloud(self): + autoftg_main.menuCfg.set(self.currentChkDef, "pointcloud_source_data", str(self.pointcloud_source_data)) + autoftg_main.menuCfg.set(self.currentChkDef, "pointcloud_point_colors", str(self.checkBox.isChecked)) + autoftg_main.menuCfg.set(self.currentChkDef, "pointcloud_point_confidence", str(self.checkBox_2.isChecked)) + autoftg_main.menuCfg.set(self.currentChkDef, "pointcloud_uniform_sampling", str(self.checkBox_3.isChecked)) + autoftg_main.menuCfg.set(self.currentChkDef, "pointcloud_points_spacing", str(self.lineEdit.text)) + with open(autoftg_main.menuCfgFilePath, 'w') as configfile: + autoftg_main.menuCfg.write(configfile) + + print("Point Cloud settings saved...") + + self.accept() \ No newline at end of file diff --git a/AutoFTG/autoftg_chunkquickadd.py b/AutoFTG/autoftg_chunkquickadd.py new file mode 100644 index 0000000..6c57dd8 --- /dev/null +++ b/AutoFTG/autoftg_chunkquickadd.py @@ -0,0 +1,176 @@ +# Class for settings editing UI +import os +import pydoc +import shutil +import sys +import time +from configparser import ConfigParser +from datetime import datetime +from os import path + +import Metashape +from PySide2 import QtCore, QtGui, QtWidgets +from PySide2.QtCore import * +from PySide2.QtGui import * +from PySide2.QtWidgets import * + +import AutoFTG.autoftg_main as autoftg_main +from AutoFTG.qtresources_rc2 import * + + +class Ui_DialogAddChunkQuick(QtWidgets.QDialog): + def __init__(self, parent): + QtWidgets.QDialog.__init__(self, parent) + self.setObjectName(u"DialogAddChunkQuick") + self.resize(310, 155) + appIcon = QIcon() + appIcon.addFile(u":/icons/AutoFTG-appicon.png", QSize(), QIcon.Normal, QIcon.Off) + self.setWindowIcon(appIcon) + sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) + self.setSizePolicy(sizePolicy) + self.setMinimumSize(QSize(310, 155)) + self.setMaximumSize(QSize(310, 155)) + font = QFont() + font.setFamily(u"Segoe UI") + font.setPointSize(9) + self.setFont(font) + self.setWindowTitle(u"Create New Chunk") + self.verticalLayoutWidget = QWidget(self) + self.verticalLayoutWidget.setObjectName(u"verticalLayoutWidget") + self.verticalLayoutWidget.setGeometry(QRect(9, 9, 295, 141)) + self.verticalLayout = QVBoxLayout(self.verticalLayoutWidget) + self.verticalLayout.setSpacing(5) + self.verticalLayout.setContentsMargins(10, 10, 10, 10) + self.verticalLayout.setObjectName(u"verticalLayout") + self.verticalLayout.setContentsMargins(0, 0, 0, 0) + self.labelQuickAdd = QLabel(self.verticalLayoutWidget) + self.labelQuickAdd.setObjectName(u"labelQuickAdd") + sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.labelQuickAdd.sizePolicy().hasHeightForWidth()) + self.labelQuickAdd.setSizePolicy(sizePolicy) + font1 = QFont() + font1.setFamily(u"Segoe UI") + font1.setPointSize(11) + font1.setBold(True) + font1.setWeight(75) + self.labelQuickAdd.setFont(font1) + self.labelQuickAdd.setText(u"Create New Chunk") + + self.verticalLayout.addWidget(self.labelQuickAdd) + + self.line_2 = QFrame(self.verticalLayoutWidget) + self.line_2.setObjectName(u"line_2") + self.line_2.setFrameShape(QFrame.HLine) + self.line_2.setFrameShadow(QFrame.Sunken) + + self.verticalLayout.addWidget(self.line_2) + + self.label = QLabel(self.verticalLayoutWidget) + self.label.setObjectName(u"label") + sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) + self.label.setSizePolicy(sizePolicy) + self.label.setText(u"Select chunk creation settings:") + self.label.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft) + + self.verticalLayout.addWidget(self.label) + + self.cbChunkSettings = QComboBox(self.verticalLayoutWidget) + for section in autoftg_main.chunk_sections: + menu_icon = autoftg_main.menuCfg.get(section, "menu_icon") + menu_icon_path = u":/icons/" + autoftg_main.icoCfg.get("ICONS", menu_icon) + seticon = QIcon() + seticon.addFile(menu_icon_path, QSize(), QIcon.Normal, QIcon.Off) + self.cbChunkSettings.addItem(seticon, section) + + + self.cbChunkSettings.setObjectName(u"cbChunkSettings") + sizePolicy.setHeightForWidth(self.cbChunkSettings.sizePolicy().hasHeightForWidth()) + self.cbChunkSettings.setSizePolicy(sizePolicy) + font2 = QFont() + font2.setFamily(u"Segoe UI") + font2.setPointSize(11) + self.cbChunkSettings.setFont(font2) + self.cbChunkSettings.setCursor(QCursor(Qt.PointingHandCursor)) + + self.cbChunkSettings.setCurrentText(u"GENERAL") + self.cbChunkSettings.setIconSize(QSize(20, 20)) + + self.verticalLayout.addWidget(self.cbChunkSettings) + + self.line = QFrame(self.verticalLayoutWidget) + self.line.setObjectName(u"line") + self.line.setFrameShape(QFrame.HLine) + self.line.setFrameShadow(QFrame.Sunken) + + self.verticalLayout.addWidget(self.line) + + self.horizontalLayout = QHBoxLayout() + self.horizontalLayout.setSpacing(5) + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.btnCreate = QPushButton(self.verticalLayoutWidget) + self.btnCreate.setObjectName(u"btnCreate") + sizePolicy3 = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) + sizePolicy3.setHorizontalStretch(0) + sizePolicy3.setVerticalStretch(0) + sizePolicy3.setHeightForWidth(self.btnCreate.sizePolicy().hasHeightForWidth()) + self.btnCreate.setSizePolicy(sizePolicy3) + self.btnCreate.setText(u"Create") + icon4 = QIcon() + icon4.addFile(u":/icons/icons8-add-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.btnCreate.setIcon(icon4) + self.btnCreate.setIconSize(QSize(20, 20)) + + self.horizontalLayout.addWidget(self.btnCreate) + + self.checkBoxAutoProc = QCheckBox(self.verticalLayoutWidget) + self.checkBoxAutoProc.setObjectName(u"checkBoxAutoProc") + self.checkBoxAutoProc.setText(u"Auto Processing") + icon5 = QIcon() + icon5.addFile(u":/icons/icons8-in-progress-96.png", QSize(), QIcon.Normal, QIcon.Off) + self.checkBoxAutoProc.setIcon(icon5) + self.checkBoxAutoProc.setChecked(True) + + self.horizontalLayout.addWidget(self.checkBoxAutoProc) + + self.btnCancel = QPushButton(self.verticalLayoutWidget) + self.btnCancel.setObjectName(u"btnCancel") + sizePolicy3.setHeightForWidth(self.btnCancel.sizePolicy().hasHeightForWidth()) + self.btnCancel.setSizePolicy(sizePolicy3) + self.btnCancel.setText(u"Close") + icon6 = QIcon() + icon6.addFile(u":/icons/icons8-enter-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.btnCancel.setIcon(icon6) + self.btnCancel.setIconSize(QSize(20, 20)) + + self.horizontalLayout.addWidget(self.btnCancel) + + self.verticalLayout.addLayout(self.horizontalLayout) + + + QtCore.QObject.connect(self.btnCreate, QtCore.SIGNAL("clicked()"), self.startProcess) + QtCore.QObject.connect(self.btnCancel, QtCore.SIGNAL("clicked()"), self, QtCore.SLOT("reject()")) + + self.exec() + + + def startProcess(self): + # global selected_pre + # global selected_suf + autoftg_main.selected_menu = self.cbChunkSettings.currentText() + autoftg_main.selected_pre = autoftg_main.menuCfg.get(autoftg_main.selected_menu, "chunk_name_prefix") + autoftg_main.selected_suf = autoftg_main.menuCfg.get(autoftg_main.selected_menu, "chunk_name_suffix") + selected_workfolder = autoftg_main.menuCfg.get(autoftg_main.selected_menu, "work_folder") + + if self.checkBoxAutoProc.isChecked == False: + self.accept() + autoftg_main.newchunk_manual(autoftg_main.selected_pre, autoftg_main.selected_suf, selected_workfolder) + else: + self.accept() + autoftg_main.newchunk_auto(autoftg_main.selected_pre, autoftg_main.selected_suf, selected_workfolder) + + diff --git a/AutoFTG/autoftg_copyregion.py b/AutoFTG/autoftg_copyregion.py new file mode 100644 index 0000000..603367f --- /dev/null +++ b/AutoFTG/autoftg_copyregion.py @@ -0,0 +1,118 @@ +# Class for Copy Region UI +import os +import pydoc +import shutil +import sys +import time +from configparser import ConfigParser +from datetime import datetime +from os import path + +import Metashape +from PySide2 import QtCore, QtGui, QtWidgets +from PySide2.QtCore import * +from PySide2.QtGui import * +from PySide2.QtWidgets import * + +from AutoFTG.autoftg_batch import * +from AutoFTG.autoftg_settingschunk import * +from AutoFTG.autoftg_settingsmain import * +from AutoFTG.qtresources_rc2 import * + + +class CopyBoundingBoxDlg(QtWidgets.QDialog): + + def __init__(self, parent): + + QtWidgets.QDialog.__init__(self, parent) + self.setWindowTitle("Copy Region (Bounding Box)") + appIcon = QIcon() + appIcon.addFile(u":/icons/AutoFTG-appicon.png", QSize(), QIcon.Normal, QIcon.Off) + self.setWindowIcon(appIcon) + + self.labelFrom = QtWidgets.QLabel("From") + self.labelTo = QtWidgets.QLabel("To") + + self.fromChunk = QtWidgets.QComboBox() + for chunk in Metashape.app.document.chunks: + self.fromChunk.addItem(chunk.label) + + self.toChunks = QtWidgets.QListWidget() + self.toChunks.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) + for chunk in Metashape.app.document.chunks: + self.toChunks.addItem(chunk.label) + + self.btnOk = QtWidgets.QPushButton("Copy") + self.btnOk.setFixedSize(120, 36) + self.btnOk.setToolTip("Copy region from one chunk to multiple chunks.:") + + self.btnQuit = QtWidgets.QPushButton("Cancel") + self.btnQuit.setFixedSize(80, 36) + + layout = QtWidgets.QGridLayout() # creating layout + layout.setColumnMinimumWidth(0, 80) # minimum column width + layout.setColumnMinimumWidth(1, 180) # minimum column width + layout.addWidget(self.labelFrom, 0, 0) + layout.addWidget(self.fromChunk, 0, 1) + + layout.addWidget(self.labelTo, 1, 0) + layout.addWidget(self.toChunks, 1, 1, 20, 2) + + layout.addWidget(self.btnQuit, 30, 0) + layout.addWidget(self.btnOk, 30, 1) + + self.setLayout(layout) + + QtCore.QObject.connect(self.btnOk, QtCore.SIGNAL("clicked()"), self.copyBoundingBox) + QtCore.QObject.connect(self.btnQuit, QtCore.SIGNAL("clicked()"), self, QtCore.SLOT("reject()")) + + self.exec() + + + def copyBoundingBox(self): + print("Copy region bounding box...") + + doc = Metashape.app.document + + fromChunk = doc.chunks[self.fromChunk.currentIndex()] + + toChunks = [] + for i in range(self.toChunks.count()): + if self.toChunks.item(i).isSelected(): + toChunks.append(doc.chunks[i]) + + print("Copy region from/to: '" + fromChunk.label + "' to " + str(len(toChunks))) + + T0 = fromChunk.transform.matrix + + region = fromChunk.region + R0 = region.rot + C0 = region.center + s0 = region.size + + for chunk in toChunks: + + if chunk == fromChunk: + continue + + T = chunk.transform.matrix.inv() * T0 + + R = Metashape.Matrix([[T[0, 0], T[0, 1], T[0, 2]], + [T[1, 0], T[1, 1], T[1, 2]], + [T[2, 0], T[2, 1], T[2, 2]]]) + + scale = R.row(0).norm() + R = R * (1 / scale) + + new_region = Metashape.Region() + new_region.rot = R * R0 + c = T.mulp(C0) + new_region.center = c + new_region.size = s0 * scale / 1. + + chunk.region = new_region + + print("Process complete!\n\nFrom: " + fromChunk.label + " / To: " + str(len(toChunks)) + "\n") + self.reject() + + diff --git a/AutoFTG/autoftg_main.py b/AutoFTG/autoftg_main.py new file mode 100644 index 0000000..fbf0a60 --- /dev/null +++ b/AutoFTG/autoftg_main.py @@ -0,0 +1,825 @@ +# AutoFTG - Scripts for Agisoft Metashape Pro +# +# This is an assembly of python scripts for process automation, and some existing scripts from other users +# +# Scripts were written for use in work process on project 2TDK, construction of railroad tunnels in Slovenia, +# but were later modified to support any kind of project where lots of processing is needed. +# +# Author: Boris Bilc +# +# Script repository (GitHub): +# --------------------------- +# URL: https://github.com/bilkos/AutoFTG-Scripts_Metashape-Pro +# +# +# References: +# ----------- +# +# Copy Bounding Box Script: +# - https://github.com/agisoft-llc/metashape-scripts/blob/master/src/copy_bounding_box_dialog.py +# Copies bounding boxes from chunk to other chunks. +# +# +# If you add or change resorces (icons, images, etc... in qtresorces.qrc), then you need to re-compile qtresorces.qrc file. +# To do that you need to navigate to script folder and run following command: +# +# pyside2-rcc -o resource.py qtresources.qrc +# +# If you are using VSCode that you can modify and compile UI elements with PySide2-VSC extension. +# +# Scripts are free to use for commercial or non-commercial use. +# +# Please use 'Issues' page in GitHub repository to report any bugs, and suggestions for improvements. +# Link to issues page: https://github.com/bilkos/AutoFTG-Scripts_Metashape-Pro/issues + + + +import os +import pydoc +import shutil +import sys +import time +from configparser import ConfigParser +from datetime import datetime +from os import path + +import Metashape +from PySide2 import QtCore, QtGui, QtWidgets +from PySide2.QtCore import * +from PySide2.QtGui import * +from PySide2.QtWidgets import * + +import AutoFTG.autoftg_batch +import AutoFTG.autoftg_chunkquickadd +import AutoFTG.autoftg_copyregion +import AutoFTG.autoftg_settingscamedit +import AutoFTG.autoftg_settingschunk +import AutoFTG.autoftg_settingsmain +import AutoFTG.qtresources_rc2 +from AutoFTG.autoftg_batch import * +from AutoFTG.autoftg_chunkquickadd import * +from AutoFTG.autoftg_copyregion import * +from AutoFTG.autoftg_settingscamedit import * +from AutoFTG.autoftg_settingschunk import * +from AutoFTG.autoftg_settingsmain import * +from AutoFTG.qtresources_rc2 import * + +# App info +app_name = "AutoFTG" +app_ver = "2.6.4" +appsettings_ver = "6" +app_author = "Author: Boris Bilc\n\n" +app_repo = "Repository URL:\nhttps://github.com/bilkos/AutoFTG-Scripts_Metashape-Pro" +ref_repo = "Agisoft GitHub repository:\nhttps://github.com/agisoft-llc/metashape-scripts" +ref_scripts = "Copy Bounding Box Script:\nhttps://github.com/agisoft-llc/metashape-scripts/blob/master/src/copy_bounding_box_dialog.py" +app_about = "Scripts for process automation in Agisoft Metashape Pro\n\nThis is an assembly of existing scripts from other users,\nand some additional scripts written for use in work process at project 2TIR, tunnel T8-KP in Slovenia." + + +# Check compatibility with Metashape +compatible_major_version = "2.0" +found_major_version = ".".join(Metashape.app.version.split('.')[:2]) +if found_major_version != compatible_major_version: + raise Exception("Incompatible Metashape version: {} != {}".format(found_major_version, compatible_major_version)) + + +projectOpened = False +settingsRebuild = False +selected_data_folder = '' +selected_camera = "No Calibration - Frame (Default)" +selected_pre = '' +selected_suf = '' +selected_menu = '' + + +# Load icons settings +icoCfg = ConfigParser() +icoCfgFile = 'settings_icons.ini' +icoCfgPath = os.path.expanduser('~\AppData\Local\Agisoft\Metashape Pro\scripts\AutoFTG\\').replace("\\", "/") +icoCfgFilePath = icoCfgPath + icoCfgFile +icons_list = [] + + +def loadIcoSettings(): + global icons_list + icoCfgFileExists = os.path.isfile(icoCfgFilePath) # Check if settings file exists + if icoCfgFileExists == False: + icoCfg.add_section("ICONS") + icoCfg.set("ICONS", "ico-0", "icons8-xbox-cross-96.png") + icoCfg.set("ICONS", "ico-1", "icons8-product-documents-50.png") + icoCfg.set("ICONS", "ico-2", "icons8-documents-folder-50-2.png") + icoCfg.set("ICONS", "ico-3", "icons8-documents-folder-50.png") + icoCfg.set("ICONS", "ico-4", "icons8-dossier-50.png") + icoCfg.set("ICONS", "ico-5", "icons8-pictures-folder-50-2.png") + icoCfg.set("ICONS", "ico-6", "icons8-folded-booklet-50.png") + icoCfg.set("ICONS", "ico-7", "icons8-images-folder-50.png") + icoCfg.set("ICONS", "ico-8", "icons8-full-image-50.png") + icoCfg.set("ICONS", "ico-9", "icons8-video-folder-50.png") + icoCfg.set("ICONS", "ico-10", "icons8-ftp-50.png") + icoCfg.set("ICONS", "ico-11", "icons8-web-camera-50.png") + icoCfg.set("ICONS", "ico-12", "icons8-camera-on-tripod-96.png") + icoCfg.set("ICONS", "ico-13", "icons8-sd-50.png") + icoCfg.set("ICONS", "ico-14", "icons8-quadcopter-50.png") + icoCfg.set("ICONS", "ico-15", "icons8-plane-48.png") + icoCfg.set("ICONS", "ico-16", "icons8-national-park-48.png") + icoCfg.set("ICONS", "ico-17", "icons8-ground-48.png") + icoCfg.set("ICONS", "ico-18", "icons8-country-48.png") + icoCfg.set("ICONS", "ico-19", "icons8-subway-50.png") + icoCfg.set("ICONS", "ico-20", "icons8-underground-50.png") + icoCfg.set("ICONS", "ico-21", "icons8-land-surveying-48.png") + icoCfg.set("ICONS", "ico-22", "icons8-drawing-compass-48.png") + icoCfg.set("ICONS", "ico-23", "icons8-camera-50.png") + icoCfg.set("ICONS", "ico-24", "menu_kalota-modra.png") + icoCfg.set("ICONS", "ico-25", "menu_kalota-oranzna.png") + icoCfg.set("ICONS", "ico-26", "template_kalota-modra.png") + icoCfg.set("ICONS", "ico-27", "template_kalota-oranzna.png") + icoCfg.set("ICONS", "ico-28", "template_kalota-rdeca.png") + icoCfg.set("ICONS", "ico-29", "template_kalota-vijola.png") + icoCfg.set("ICONS", "ico-30", "template_kalota-zelena.png") + icoCfg.set("ICONS", "ico-31", "template_stopnica-modra.png") + icoCfg.set("ICONS", "ico-32", "template_stopnica-oranzna.png") + icoCfg.set("ICONS", "ico-33", "template_stopnica-rdeca.png") + icoCfg.set("ICONS", "ico-34", "template_stopnica-vijola.png") + icoCfg.set("ICONS", "ico-35", "template_stopnica-zelena.png") + + with open(icoCfgFilePath, 'w') as icoconfig: + camCfg.write(icoconfig) + + icoCfgFileExists = True + + icoCfg.read(icoCfgFilePath) + icons_list = icoCfg.options("ICONS") + print("Loading chunk definition icons... OK.") + + +# Load main app settings +appCfg = ConfigParser() +appCfgFile = 'settings_autoftg.ini' +appCfgPath = os.path.expanduser('~\AppData\Local\Agisoft\Metashape Pro\scripts\AutoFTG\\').replace("\\", "/") +appCfgFilePath = appCfgPath + appCfgFile +appCfgFileExists = os.path.isfile(appCfgFilePath) # Check if settings file exists + + +# Load custom menu settings +menuCfg = ConfigParser() +menuCfgFile = "settings_newchunk.ini" +menuCfgPath = os.path.expanduser('~\AppData\Local\Agisoft\Metashape Pro\scripts\AutoFTG').replace("\\", "/") +menuCfgFilePath = menuCfgPath + "/" + menuCfgFile +menuCfgFilePathExists = os.path.isfile(menuCfgFilePath) +chunk_sections = [] + + +# Init configparser for camera settings. Set empty camera variables for global use. +camCfg = ConfigParser() +cam_name = '' +cam_desc = '' +cam_type = '' +cam_subtype = '' +cam_res = '' +cam_file = '' + +cameraXmlSource = '' +cameraXmlDest = '' + +camCfgFile = "settings_cam.ini" +camCfgPath = os.path.expanduser('~\AppData\Local\Agisoft\Metashape Pro\scripts\AutoFTG\cameras\\').replace("\\", "/") +camCfgFilePath = camCfgPath + camCfgFile +camCfgFilePathExists = os.path.isfile(camCfgFilePath) +cam_list = [] + +projCfg = ConfigParser() # INICALIZACIJA NASTAVITEV + + +def camCfgLoad(): + global cam_list + + if camCfgFilePathExists == False: + defcam_name = 'No Calibration - Frame (Default)' + defcam_description = 'Default Metashape camera settings for type FRAME. Calibration is calculated On-The-Fly.' + defcam_type = 'Frame' + defcam_subtype = 'Standard' + defcam_resolution = '0' + defcam_file = 'None' + + defcam2_name = 'No Calibration - Fisheye' + defcam2_description = 'Default Metashape camera settings for type FISHEYE. Calibration is calculated On-The-Fly.' + defcam2_type = 'Fisheye' + defcam2_subtype = 'Standard' + defcam2_resolution = '0' + defcam2_file = 'None' + + camCfg.add_section(defcam_name) + camCfg.set(defcam_name, "description", defcam_description) + camCfg.set(defcam_name, "type", defcam_type) + camCfg.set(defcam_name, "subtype", defcam_subtype) + camCfg.set(defcam_name, "resolution", defcam_resolution) + camCfg.set(defcam_name, "file", defcam_file) + camCfg.add_section(defcam2_name) + camCfg.set(defcam2_name, "description", defcam2_description) + camCfg.set(defcam2_name, "type", defcam2_type) + camCfg.set(defcam2_name, "subtype", defcam2_subtype) + camCfg.set(defcam2_name, "resolution", defcam2_resolution) + camCfg.set(defcam2_name, "file", defcam2_file) + + with open(camCfgFilePath, 'w') as camconfigfile: + camCfg.write(camconfigfile) + + camCfg.read(camCfgFilePath) + cam_list = camCfg.sections() + print("Camera settings loaded...") + + +# Read camera settings from INI config file +def readCameraSettings(cam_section): + global cam_name + global cam_desc + global cam_type + global cam_subtype + global cam_res + global cam_file + + # Read settings for requested camera + cam_name = cam_section + cam_desc = camCfg.get(cam_section, "Description") + cam_type = camCfg.get(cam_section, "Type") + cam_subtype = camCfg.get(cam_section, "SubType") + cam_res = camCfg.get(cam_section, "Resolution") + cam_file = camCfg.get(cam_section, "File") + print("Using camera\n" + "Name: " + cam_name + "\nDesc.: " + cam_desc + "\nType: " + cam_type + "\nSubType: " + cam_subtype + "\nResolution: " + cam_res + "\nFile: " + cam_file) + + +# Called to apply camera settings when creating new chunk +def useCameraSettings(): + # Init document + doc = Metashape.app.document + chunk = doc.chunk + # readCameraSettings(settings.defaultCamera) + camera_path = camCfgPath + cam_file + + # Sensor to which we will apply settings + chunk_sensor = chunk.sensors[0] + + # Set sensor type from camera + if cam_type == "Fisheye": + chunk_sensor.type = Metashape.Sensor.Type.Fisheye + elif cam_type == "Frame": + chunk_sensor.type = Metashape.Sensor.Type.Frame + elif cam_type == "Spherical": + chunk_sensor.type = Metashape.Sensor.Type.Spherical + elif cam_type == "Cylindrical": + chunk_sensor.type = Metashape.Sensor.Type.Cylindrical + elif cam_type == "RPC": + chunk_sensor.type = Metashape.Sensor.Type.RPC + else: + Metashape.app.messagBox("Camera Type not recognized.\nPlease check camera settings...") + + # Init calibration and import settings from camera calibration file (Metashape XML) + chunk_calib = Metashape.Calibration() + if cam_file != "None": + chunk_calib.load(path=camera_path, format=Metashape.CalibrationFormatXML) + chunk_sensor.user_calib = chunk_calib + + # Save document and show message with applied settings + doc.save() + # Metashape.app.messageBox("Camera settings applied.\n\nCamera: " + cam_name + "\nType: " + cam_type + "\nFilename: " + cam_file) + Metashape.app.update() + + +def selectCamChunk(): + camCfgLoad() + diaSelectCamera() + if selected_camera == None: + print("No camera chosen. Using default camera.") + else: + readCameraSettings(selected_camera) + useCameraSettings() + print("\n\nApplied custom camera: " + selected_camera) + + +# Routine for adding/editing camera configuration +def saveCamConfig(camorig, camname, camdesc, camtype, camsub, camres, camfile): + if camCfg.has_section(camorig) == True: + camCfg.remove_section(camorig) + camCfg.add_section(camname) + camCfg.set(camname, "Description", camdesc) + camCfg.set(camname, "Type", camtype) + camCfg.set(camname, "SubType", camsub) + camCfg.set(camname, "Resolution", camres) + camCfg.set(camname, "File", camfile) + Metashape.app.messageBox("Camera Updated\n\n" + "Name: " + camname + "\nDesc.: " + camdesc + "\nType: " + camtype + "\nSubType: " + camsub + "\nRes.:: " + camres + " MP\nFile: " + camfile) + else: + camCfg.add_section(camname) + camCfg.set(camname, "Description", camdesc) + camCfg.set(camname, "Type", camtype) + camCfg.set(camname, "SubType", camsub) + camCfg.set(camname, "Resolution", camres) + camCfg.set(camname, "File", camfile) + Metashape.app.messageBox("Camera Created\n\n" + "Name: " + camname + "\nDesc.: " + camdesc + "\nType: " + camtype + "\nSubType: " + camsub + "\nRes.:: " + camres + " MP\nFile: " + camfile) + + with open(camCfgFilePath, 'w') as configfile: + camCfg.write(configfile) + + camCfgLoad() + + +# Routine for adding/editing camera configuration +def removeCamConfig(camname): + cam_xmlmsg = '' + if camCfg.has_section(camname) == True: + if camCfg.get(camname, "File") != "": + cameraXml = camCfgPath + camCfg.get(camname, "File") + if os.path.isfile(cameraXml): + os.remove(cameraXml) + cam_xmlmsg = "\nXML file " + cameraXml + " deleted." + + camCfg.remove_section(camname) + cam_secmsg = "Camera [" + camname + "] removed from settings." + cam_xmlmsg + + with open(camCfgFilePath, 'w') as configfile: + camCfg.write(configfile) + + camCfgLoad() + + Metashape.app.messageBox(cam_secmsg) + else: + Metashape.app.messageBox("Error! No camera named (" + str(camname) + ") was found.\n\nDid you manualy edit comaera configuration?") + + +def chunksCfgLoad(): + global chunk_sections + if menuCfgFilePathExists == False: + menu_section_m = "GENERAL" + menuCfg.add_section(menu_section_m) + menuCfg.set(menu_section_m, "menu_icon", "ico-0") + menuCfg.set(menu_section_m, "chunk_name_format", "metashape") + menuCfg.set(menu_section_m, "chunk_name_prefix", "") + menuCfg.set(menu_section_m, "chunk_name_suffix", "") + menuCfg.set(menu_section_m, "work_folder", str(Metashape.app.getExistingDirectory("Project data folder (batch)"))) + menuCfg.set(menu_section_m, "export_folder", str(Metashape.app.getExistingDirectory("Project data export folder (batch)"))) + + with open(menuCfgFilePath, 'w') as menuconfig: + menuCfg.write(menuconfig) + + menuCfg.read(menuCfgFilePath) + chunk_sections = menuCfg.sections() + print("Custom chunk settings loaded...\nFile: " + menuCfgFile) + + +def appCfgLoad(): + global selected_data_folder + global selected_camera + appCfgFileExists = os.path.isfile(appCfgFilePath) # Check if settings file exists + if appCfgFileExists == False: + print("\nSettings initialization...\nPlease choose data folder, and default camera.") + Metashape.app.messageBox("Settings file not found...\nPlease choose default data folder, and default camera.") + foldeData = str(Metashape.app.getExistingDirectory("Working data folder")) + #selectCamDefault() + diaSelectCamera() + appCfg.add_section('APP SETTINGS') + appCfg.set('APP SETTINGS', 'settings_version', appsettings_ver) + appCfg.set('APP SETTINGS', 'folder_data', foldeData) + appCfg.set('APP SETTINGS', 'default_camera', selected_camera) + appCfg.set('APP SETTINGS', 'default_chunk_def', "GENERAL") + + # Writing our configuration file to 'example.cfg' + with open(appCfgFilePath, 'w') as configfile: + appCfg.write(configfile) + + appCfg.read(appCfgFilePath) + checkSettingsVer() + selected_data_folder = appCfg.get('APP SETTINGS', 'folder_data') + selected_camera = appCfg.get('APP SETTINGS', 'default_camera') + + +# Project settings initialization (used when .psx project is loaded) +def projCfgLoad(): + global settingsRebuild + global projDoc + global projCfgFilePath + global projCfgFilePathExists + global projCfg + global projectOpened + global selected_camera + global selected_data_folder + + projDoc = Metashape.app.document + projDocFile = str(projDoc).replace("Processing error!
+ if lcam_stype == "Drone": + self.listWidgetCamItem.setIcon(menuico5) + self.listWidgetCamItem.setToolTip("Type: " + lcam_type + "
SubType: " + lcam_stype + "
Res.: " + lcam_res + "MP" + "
Desc.: " + lcam_desc)
+ elif lcam_stype == "SmartPhone":
+ self.listWidgetCamItem.setIcon(menuico4)
+ self.listWidgetCamItem.setToolTip("
Type: " + lcam_type + "
SubType: " + lcam_stype + "
Res.: " + lcam_res + "MP" + "
Desc.: " + lcam_desc)
+ elif lcam_stype == "Special":
+ self.listWidgetCamItem.setIcon(icoTripod)
+ self.listWidgetCamItem.setToolTip("
Type: " + lcam_type + "
SubType: " + lcam_stype + "
Res.: " + lcam_res + "MP" + "
Desc.: " + lcam_desc)
+ elif lcam_type == "Fisheye":
+ self.listWidgetCamItem.setIcon(menuico1)
+ self.listWidgetCamItem.setToolTip("
Type: " + lcam_type + "
SubType: " + lcam_stype + "
Res.: " + lcam_res + "MP" + "
Desc.: " + lcam_desc)
+ elif lcam_type == "Cylindrical":
+ self.listWidgetCamItem.setIcon(menuico2)
+ self.listWidgetCamItem.setToolTip("
Type: " + lcam_type + "
SubType: " + lcam_stype + "
Res.: " + lcam_res + "MP" + "
Desc.: " + lcam_desc)
+ elif lcam_type == "Spherical":
+ self.listWidgetCamItem.setIcon(menuico3)
+ self.listWidgetCamItem.setToolTip("
Type: " + lcam_type + "
SubType: " + lcam_stype + "
Res.: " + lcam_res + "MP" + "
Desc.: " + lcam_desc)
+ elif lcam_type == "RPC":
+ self.listWidgetCamItem.setIcon(menuico9)
+ self.listWidgetCamItem.setToolTip("
Type: " + lcam_type + "
SubType: " + lcam_stype + "
Res.: " + lcam_res + "MP" + "
Desc.: " + lcam_desc)
+ else:
+ self.listWidgetCamItem.setIcon(menuico00)
+ self.listWidgetCamItem.setToolTip("
Type: " + lcam_type + "
SubType: " + lcam_stype + "
Res.: " + lcam_res + "MP" + "
Desc.: " + lcam_desc)
+
+ self.hLayoutCamEdit.addWidget(self.listWidgetCam)
+
+ self.vLayout_CamBtn = QVBoxLayout()
+ self.vLayout_CamBtn.setObjectName(u"vLayout_CamBtn")
+ sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+
+ self.btnRemoveCam = QPushButton(self.verticalLayoutWidget_2)
+ self.btnRemoveCam.setObjectName(u"btnRemoveCam")
+ sizePolicy.setHeightForWidth(self.btnRemoveCam.sizePolicy().hasHeightForWidth())
+ self.btnRemoveCam.setSizePolicy(sizePolicy)
+ self.btnRemoveCam.setText(u" Remove")
+ self.btnRemoveCam.setIcon(menuico8)
+ self.btnRemoveCam.setIconSize(QSize(24, 24))
+
+ self.vLayout_CamBtn.addWidget(self.btnRemoveCam)
+
+ self.btnEditCam = QPushButton(self.verticalLayoutWidget_2)
+ self.btnEditCam.setObjectName(u"btnEditCam")
+ sizePolicy.setHeightForWidth(self.btnEditCam.sizePolicy().hasHeightForWidth())
+ self.btnEditCam.setSizePolicy(sizePolicy)
+ self.btnEditCam.setText(u" Edit")
+ self.btnEditCam.setIcon(menuico7)
+ self.btnEditCam.setIconSize(QSize(24, 24))
+
+ self.vLayout_CamBtn.addWidget(self.btnEditCam)
+
+ self.btnAddNewCam = QPushButton(self.verticalLayoutWidget_2)
+ self.btnAddNewCam.setObjectName(u"btnAddNewCam")
+ sizePolicy.setHeightForWidth(self.btnAddNewCam.sizePolicy().hasHeightForWidth())
+ self.btnAddNewCam.setSizePolicy(sizePolicy)
+ self.btnAddNewCam.setText(u" Add")
+ self.btnAddNewCam.setIcon(menuico6)
+ self.btnAddNewCam.setIconSize(QSize(24, 24))
+
+ self.vLayout_CamBtn.addWidget(self.btnAddNewCam)
+
+ self.hLayoutCamEdit.addLayout(self.vLayout_CamBtn)
+
+ layoutMain.addLayout(self.hLayoutCamEdit)
+
+ self.hLayout_MainBtn = QHBoxLayout()
+ self.hLayout_MainBtn.setObjectName(u"hLayout_MainBtn")
+ self.btnMainClose = QPushButton(self.verticalLayoutWidget_2)
+ self.btnMainClose.setObjectName(u"btnMainClose")
+ sizePolicy1 = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Minimum)
+ sizePolicy1.setHorizontalStretch(0)
+ sizePolicy1.setVerticalStretch(0)
+ sizePolicy1.setHeightForWidth(self.btnMainClose.sizePolicy().hasHeightForWidth())
+ self.btnMainClose.setSizePolicy(sizePolicy1)
+ self.btnMainClose.setText(u"Close")
+
+ self.hLayout_MainBtn.addWidget(self.btnMainClose)
+
+ layoutMain.addLayout(self.hLayout_MainBtn)
+
+ self.setLayout(layoutMain)
+
+ QtCore.QObject.connect(self.btnAddNewCam, QtCore.SIGNAL("clicked()"), self.addNewCam)
+ QtCore.QObject.connect(self.btnEditCam, QtCore.SIGNAL("clicked()"), self.editSelCamera)
+ QtCore.QObject.connect(self.btnRemoveCam, QtCore.SIGNAL("clicked()"), self.removeSelCamera)
+ QtCore.QObject.connect(self.btnMainClose, QtCore.SIGNAL("clicked()"), self, QtCore.SLOT("reject()"))
+
+ self.exec()
+
+
+ def refreshCamList(self):
+ self.listWidgetCam.clear()
+ menuico00 = QIcon()
+ menuico00.addFile(u":/icons/icons8-full-page-view-50.png", QSize(), QIcon.Normal, QIcon.Off)
+ menuico1 = QIcon()
+ menuico1.addFile(u":/icons/icons8-panorama-50.png", QSize(), QIcon.Normal, QIcon.Off)
+ menuico2 = QIcon()
+ menuico2.addFile(u":/icons/icons8-aperture-50.png", QSize(), QIcon.Normal, QIcon.Off)
+ menuico3 = QIcon()
+ menuico3.addFile(u":/icons/icons8-video-stabilization-50.png", QSize(), QIcon.Normal, QIcon.Off)
+ menuico4 = QIcon()
+ menuico4.addFile(u":/icons/icons8-touchscreen-48.png", QSize(), QIcon.Normal, QIcon.Off)
+ menuico5 = QIcon()
+ menuico5.addFile(u":/icons/icons8-quadcopter-50.png", QSize(), QIcon.Normal, QIcon.Off)
+ menuico6 = QIcon()
+ menuico6.addFile(u":/icons/icons8-add-camera-50.png", QSize(), QIcon.Normal, QIcon.Off)
+ menuico7 = QIcon()
+ menuico7.addFile(u":/icons/icons8-design-50.png", QSize(), QIcon.Normal, QIcon.Off)
+ menuico8 = QIcon()
+ menuico8.addFile(u":/icons/icons8-no-camera-96.png", QSize(), QIcon.Normal, QIcon.Off)
+ menuico9 = QIcon()
+ menuico9.addFile(u":/icons/icons8-ios-application-placeholder-50.png", QSize(), QIcon.Normal, QIcon.Off)
+ icoTripod = QIcon()
+ icoTripod.addFile(u":/icons/icons8-camera-on-tripod-96.png", QSize(), QIcon.Normal, QIcon.Off)
+ for camera in autoftg_main.cam_list:
+ lcam_type = str(autoftg_main.camCfg.get(camera, 'Type'))
+ lcam_stype = str(autoftg_main.camCfg.get(camera, "SubType"))
+ lcam_res = str(autoftg_main.camCfg.get(camera, 'Resolution'))
+ lcam_desc = str(autoftg_main.camCfg.get(camera, 'Description'))
+ self.listWidgetCamItem = QListWidgetItem(camera, self.listWidgetCam)
+ self.listWidgetCamItem.setText(str(camera))
+ #
Processing error!
+ if lcam_stype == "Drone": + self.listWidgetCamItem.setIcon(menuico5) + self.listWidgetCamItem.setToolTip("Type: " + lcam_type + "
SubType: " + lcam_stype + "
Res.: " + lcam_res + "MP" + "
Desc.: " + lcam_desc)
+ elif lcam_stype == "SmartPhone":
+ self.listWidgetCamItem.setIcon(menuico4)
+ self.listWidgetCamItem.setToolTip("
Type: " + lcam_type + "
SubType: " + lcam_stype + "
Res.: " + lcam_res + "MP" + "
Desc.: " + lcam_desc)
+ elif lcam_stype == "Special":
+ self.listWidgetCamItem.setIcon(icoTripod)
+ self.listWidgetCamItem.setToolTip("
Type: " + lcam_type + "
SubType: " + lcam_stype + "
Res.: " + lcam_res + "MP" + "
Desc.: " + lcam_desc)
+ elif lcam_type == "Fisheye":
+ self.listWidgetCamItem.setIcon(menuico1)
+ self.listWidgetCamItem.setToolTip("
Type: " + lcam_type + "
SubType: " + lcam_stype + "
Res.: " + lcam_res + "MP" + "
Desc.: " + lcam_desc)
+ elif lcam_type == "Cylindrical":
+ self.listWidgetCamItem.setIcon(menuico2)
+ self.listWidgetCamItem.setToolTip("
Type: " + lcam_type + "
SubType: " + lcam_stype + "
Res.: " + lcam_res + "MP" + "
Desc.: " + lcam_desc)
+ elif lcam_type == "Spherical":
+ self.listWidgetCamItem.setIcon(menuico3)
+ self.listWidgetCamItem.setToolTip("
Type: " + lcam_type + "
SubType: " + lcam_stype + "
Res.: " + lcam_res + "MP" + "
Desc.: " + lcam_desc)
+ elif lcam_type == "RPC":
+ self.listWidgetCamItem.setIcon(menuico9)
+ self.listWidgetCamItem.setToolTip("
Type: " + lcam_type + "
SubType: " + lcam_stype + "
Res.: " + lcam_res + "MP" + "
Desc.: " + lcam_desc)
+ else:
+ self.listWidgetCamItem.setIcon(menuico00)
+ self.listWidgetCamItem.setToolTip("
Type: " + lcam_type + "
SubType: " + lcam_stype + "
Res.: " + lcam_res + "MP" + "
Desc.: " + lcam_desc)
+
+
+
+ def addNewCam(self):
+ autoftg_main.addCameraDialog(camnew=True, camname="")
+ self.refreshCamList()
+
+
+ def editSelCamera(self):
+ # defaultItem = self.listWidgetCam.isItemSelected("Default")
+ if self.listWidgetCam.currentRow() > 1:
+ selCamName = self.listWidgetCam.currentItem().text()
+ autoftg_main.addCameraDialog(camnew=False, camname=selCamName)
+ self.refreshCamList()
+
+ elif self.listWidgetCam.currentRow() <= 1:
+ Metashape.app.messageBox("Default cameras can not be edited.")
+
+ else:
+ Metashape.app.messageBox("No camera selected...")
+
+
+ def removeSelCamera(self):
+ if self.listWidgetCam.currentRow() > 1:
+ del_cam = self.listWidgetCam.currentItem().text()
+ remove_confirm = Metashape.app.getBool("Remove selected camera?\n\nSelected: " + del_cam)
+ if remove_confirm == True:
+ autoftg_main.removeCamConfig(del_cam)
+ self.refreshCamList()
+
+ elif self.listWidgetCam.currentRow() <= 1:
+ Metashape.app.messageBox("Default cameras can not be removed.")
+
+ else:
+ Metashape.app.messageBox("No camera selected...")
+
+
+class Ui_dialogChooseCamera(QtWidgets.QDialog):
+ def __init__(self, parent):
+ QtWidgets.QDialog.__init__(self, parent)
+ self.setObjectName(u"dialogChooseCamera")
+ self.resize(320, 300)
+ self.setWindowTitle(u"Choose Camera")
+ appIcon = QIcon()
+ appIcon.addFile(u":/icons/AutoFTG-appicon.png", QSize(), QIcon.Normal, QIcon.Off)
+ self.setWindowIcon(appIcon)
+ sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
+ self.setSizePolicy(sizePolicy)
+ self.setMinimumSize(QSize(320, 300))
+ self.setMaximumSize(QSize(320, 300))
+ self.setWindowTitle(u"Choose Camera")
+ self.verticalLayoutWidget = QWidget(self)
+ self.verticalLayoutWidget.setObjectName(u"verticalLayoutWidget")
+ self.verticalLayoutWidget.setGeometry(QRect(10, 10, 301, 281))
+ self.verticalLayout = QVBoxLayout(self.verticalLayoutWidget)
+ self.verticalLayout.setSpacing(5)
+ self.verticalLayout.setContentsMargins(10, 10, 10, 10)
+ self.verticalLayout.setObjectName(u"verticalLayout")
+ self.verticalLayout.setSizeConstraint(QLayout.SetDefaultConstraint)
+ self.verticalLayout.setContentsMargins(0, 0, 0, 0)
+ self.label = QLabel(self.verticalLayoutWidget)
+ self.label.setObjectName(u"label")
+ font = QFont()
+ font.setPointSize(11)
+ self.label.setFont(font)
+ self.label.setText(u"Select Camera")
+
+ self.verticalLayout.addWidget(self.label)
+
+ self.listWidget = QListWidget(self.verticalLayoutWidget)
+ icon = QIcon()
+ icon.addFile(u":/icons/icons8-full-page-view-50.png", QSize(), QIcon.Normal, QIcon.Off)
+ icon1 = QIcon()
+ icon1.addFile(u":/icons/icons8-panorama-50.png", QSize(), QIcon.Normal, QIcon.Off)
+ icon2 = QIcon()
+ icon2.addFile(u":/icons/icons8-aperture-50.png", QSize(), QIcon.Normal, QIcon.Off)
+ icon3 = QIcon()
+ icon3.addFile(u":/icons/icons8-video-stabilization-50.png", QSize(), QIcon.Normal, QIcon.Off)
+ icon4 = QIcon()
+ icon4.addFile(u":/icons/icons8-touchscreen-48.png", QSize(), QIcon.Normal, QIcon.Off)
+ icon5 = QIcon()
+ icon5.addFile(u":/icons/icons8-quadcopter-50.png", QSize(), QIcon.Normal, QIcon.Off)
+ icon5a = QIcon()
+ icon5a.addFile(u":/icons/icons8-ios-application-placeholder-50.png", QSize(), QIcon.Normal, QIcon.Off)
+ icoTripod = QIcon()
+ icoTripod.addFile(u":/icons/icons8-camera-on-tripod-96.png", QSize(), QIcon.Normal, QIcon.Off)
+ font1 = QFont()
+ font1.setPointSize(10)
+ for cam in autoftg_main.cam_list:
+ icon_type = autoftg_main.camCfg.get(cam, "Type")
+ icon_subtype = autoftg_main.camCfg.get(cam, "SubType")
+ self.listwidget = QListWidgetItem(self.listWidget)
+ self.listwidget.setText(cam)
+ if icon_subtype == "SmartPhone":
+ self.listwidget.setIcon(icon4)
+ elif icon_subtype == "Drone":
+ self.listwidget.setIcon(icon5)
+ elif icon_subtype == "Special":
+ self.listwidget.setIcon(icoTripod)
+ else:
+ if icon_type == "Fisheye":
+ self.listwidget.setIcon(icon1)
+ elif icon_type == "Spherical":
+ self.listwidget.setIcon(icon3)
+ elif icon_type == "Cylindrical":
+ self.listwidget.setIcon(icon2)
+ elif icon_type == "RPC":
+ self.listwidget.setIcon(icon5a)
+ else:
+ self.listwidget.setIcon(icon)
+
+ self.listWidget.setObjectName(u"listWidget")
+ self.listWidget.setFont(font1)
+ self.listWidget.setFrameShape(QFrame.StyledPanel)
+ self.listWidget.setFrameShadow(QFrame.Plain)
+ self.listWidget.setDefaultDropAction(Qt.IgnoreAction)
+ self.listWidget.setIconSize(QSize(20, 20))
+
+ self.verticalLayout.addWidget(self.listWidget)
+
+ self.horizontalLayout_2 = QHBoxLayout()
+ self.horizontalLayout_2.setSpacing(5)
+ self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
+ self.pushButton_2 = QPushButton(self.verticalLayoutWidget)
+ self.pushButton_2.setObjectName(u"pushButton_2")
+ icon5 = QIcon()
+ icon5.addFile(u":/icons/icons8-close-50.png", QSize(), QIcon.Normal, QIcon.Off)
+ self.pushButton_2.setIcon(icon5)
+ self.pushButton_2.setText(u"Cancel")
+
+ self.horizontalLayout_2.addWidget(self.pushButton_2)
+
+ self.pushButton = QPushButton(self.verticalLayoutWidget)
+ self.pushButton.setObjectName(u"pushButton")
+ icon6 = QIcon()
+ icon6.addFile(u":/icons/icons8-done-50.png", QSize(), QIcon.Normal, QIcon.Off)
+ self.pushButton.setIcon(icon6)
+ self.pushButton.setText(u"Ok")
+
+ self.horizontalLayout_2.addWidget(self.pushButton)
+
+ self.verticalLayout.addLayout(self.horizontalLayout_2)
+
+ self.listWidget.setCurrentRow(autoftg_main.cam_list.index(autoftg_main.selected_camera))
+
+ self.listWidget.setSortingEnabled(False)
+
+ QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL("clicked()"), self.selectCam)
+ QtCore.QObject.connect(self.pushButton_2, QtCore.SIGNAL("clicked()"), self, QtCore.SLOT("reject()"))
+
+ self.exec()
+
+ def selectCam(self):
+ autoftg_main.selected_camera = self.listWidget.currentItem().text()
+ self.close()
+
+
diff --git a/AutoFTG/autoftg_settingschunk.py b/AutoFTG/autoftg_settingschunk.py
new file mode 100644
index 0000000..158d157
--- /dev/null
+++ b/AutoFTG/autoftg_settingschunk.py
@@ -0,0 +1,889 @@
+import os
+import shutil
+import sys
+import time
+from configparser import ConfigParser
+from datetime import datetime
+from os import path
+
+import Metashape
+from PySide2 import QtCore, QtGui, QtWidgets
+from PySide2.QtCore import *
+from PySide2.QtGui import *
+from PySide2.QtWidgets import *
+
+import AutoFTG.autoftg_main as autoftg_main
+from AutoFTG.qtresources_rc2 import *
+
+
+class Ui_DialogChunkSettings(QtWidgets.QDialog):
+ def __init__(self, parent):
+ QtWidgets.QDialog.__init__(self, parent)
+ self.setObjectName(u"DialogChunkSettings")
+ self.setWindowModality(Qt.WindowModal)
+ self.resize(720, 360)
+ self.setWindowTitle(u"Chunk Definition Settings")
+ sizePolicy0 = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
+ sizePolicy0.setHorizontalStretch(0)
+ sizePolicy0.setVerticalStretch(0)
+ sizePolicy0.setHeightForWidth(self.sizePolicy().hasHeightForWidth())
+ self.setSizePolicy(sizePolicy0)
+ self.setMinimumSize(QSize(720, 480))
+ self.setMaximumSize(QSize(720, 480))
+ icon = QIcon()
+ icon.addFile(u":/icons/AutoFTG-appicon.png", QSize(), QIcon.Normal, QIcon.Off)
+ self.setWindowIcon(icon)
+ self.gridLayoutWidget = QWidget(self)
+ self.gridLayoutWidget.setObjectName(u"gridLayoutWidget")
+ self.gridLayoutWidget.setGeometry(QRect(9, 10, 701, 461))
+ self.gridLayout = QGridLayout(self.gridLayoutWidget)
+ self.gridLayout.setSpacing(5)
+ self.gridLayout.setContentsMargins(10, 10, 10, 10)
+ self.gridLayout.setObjectName(u"gridLayout")
+ self.gridLayout.setContentsMargins(0, 0, 0, 0)
+ self.label_menuSet_2 = QLabel(self.gridLayoutWidget)
+ self.label_menuSet_2.setObjectName(u"label_menuSet_2")
+ sizePolicy1 = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum)
+ sizePolicy1.setHorizontalStretch(0)
+ sizePolicy1.setVerticalStretch(0)
+ sizePolicy1.setHeightForWidth(self.label_menuSet_2.sizePolicy().hasHeightForWidth())
+ self.label_menuSet_2.setSizePolicy(sizePolicy1)
+ font = QFont()
+ font.setFamily(u"Segoe UI")
+ font.setPointSize(12)
+ font.setBold(True)
+ font.setWeight(75)
+ self.label_menuSet_2.setFont(font)
+ self.label_menuSet_2.setFrameShape(QFrame.StyledPanel)
+ self.label_menuSet_2.setText(u"Chunk Definitions List")
+
+ self.gridLayout.addWidget(self.label_menuSet_2, 0, 0, 1, 1)
+
+ self.listWidgetChunkDefs = QListWidget(self.gridLayoutWidget)
+ self.listWidgetChunkDefs.setObjectName(u"listWidgetChunkDefs")
+ sizePolicy2 = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
+ sizePolicy2.setHorizontalStretch(0)
+ sizePolicy2.setVerticalStretch(0)
+ sizePolicy2.setHeightForWidth(self.listWidgetChunkDefs.sizePolicy().hasHeightForWidth())
+ self.listWidgetChunkDefs.setSizePolicy(sizePolicy2)
+ font1 = QFont()
+ font1.setFamily(u"Segoe UI")
+ font1.setPointSize(11)
+ self.listWidgetChunkDefs.setFont(font1)
+ self.listWidgetChunkDefs.setAutoScrollMargin(20)
+ self.listWidgetChunkDefs.setEditTriggers(QAbstractItemView.NoEditTriggers)
+ self.listWidgetChunkDefs.setProperty("showDropIndicator", False)
+ self.listWidgetChunkDefs.setSelectionBehavior(QAbstractItemView.SelectItems)
+ self.listWidgetChunkDefs.setIconSize(QSize(24, 24))
+ self.listWidgetChunkDefs.setViewMode(QListView.ListMode)
+ self.listWidgetChunkDefs.setUniformItemSizes(True)
+ self.listWidgetChunkDefs.setSelectionRectVisible(True)
+ self.listWidgetChunkDefs.setSortingEnabled(False)
+
+ self.gridLayout.addWidget(self.listWidgetChunkDefs, 1, 0, 1, 1)
+
+ self.horizontalLayout_6 = QHBoxLayout()
+ self.horizontalLayout_6.setSpacing(5)
+ self.horizontalLayout_6.setObjectName(u"horizontalLayout_6")
+ self.pushButton_sremove = QPushButton(self.gridLayoutWidget)
+ self.pushButton_sremove.setObjectName(u"pushButton_sremove")
+ self.pushButton_sremove.setEnabled(True)
+ sizePolicy3 = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
+ sizePolicy3.setHorizontalStretch(0)
+ sizePolicy3.setVerticalStretch(0)
+ sizePolicy3.setHeightForWidth(self.pushButton_sremove.sizePolicy().hasHeightForWidth())
+ self.pushButton_sremove.setSizePolicy(sizePolicy3)
+ self.pushButton_sremove.setMinimumSize(QSize(0, 30))
+#if QT_CONFIG(tooltip)
+ self.pushButton_sremove.setToolTip(u"
Remove
Remove selected definition
Edit
Edit selected chunk definition
Use date and time found in first image file that is imported from work folder.
") +#endif // QT_CONFIG(tooltip) + self.radioButton_5.setText(u"Image date-time") + + self.gridLayout_2.addWidget(self.radioButton_5, 1, 1, 1, 1) + + self.radioButton_3 = QRadioButton(self.gridLayoutWidget_2) + self.radioButton_3.setObjectName(u"radioButton_3") + sizePolicy8.setHeightForWidth(self.radioButton_3.sizePolicy().hasHeightForWidth()) + self.radioButton_3.setSizePolicy(sizePolicy8) + self.radioButton_3.setFont(font5) + self.radioButton_3.setCursor(QCursor(Qt.PointingHandCursor)) +#if QT_CONFIG(tooltip) + self.radioButton_3.setToolTip(u"Use metadata string from point file that must be located in imported data folder, and must also have the same name as data folder..
Info: String must be in metadata format at the beginnig of point file, as described in help.
") +#endif // QT_CONFIG(tooltip) + self.radioButton_3.setText(u"Point File Metadata") + + self.gridLayout_2.addWidget(self.radioButton_3, 2, 0, 1, 1) + + self.radioButton_6 = QRadioButton(self.gridLayoutWidget_2) + self.radioButton_6.setObjectName(u"radioButton_6") + sizePolicy8.setHeightForWidth(self.radioButton_6.sizePolicy().hasHeightForWidth()) + self.radioButton_6.setSizePolicy(sizePolicy8) + self.radioButton_6.setFont(font5) + self.radioButton_6.setCursor(QCursor(Qt.PointingHandCursor)) +#if QT_CONFIG(tooltip) + self.radioButton_6.setToolTip(u"Use date and time at which chunk is created in custom provided format.
") +#endif // QT_CONFIG(tooltip) + self.radioButton_6.setText(u"Custom date-time") + + self.gridLayout_2.addWidget(self.radioButton_6, 2, 1, 1, 1) + + self.radioButton_2 = QRadioButton(self.gridLayoutWidget_2) + self.radioButton_2.setObjectName(u"radioButton_2") + sizePolicy8.setHeightForWidth(self.radioButton_2.sizePolicy().hasHeightForWidth()) + self.radioButton_2.setSizePolicy(sizePolicy8) + self.radioButton_2.setFont(font5) + self.radioButton_2.setCursor(QCursor(Qt.PointingHandCursor)) +#if QT_CONFIG(tooltip) + self.radioButton_2.setToolTip(u"Uses the name of folder from which data is beeing imported from.
* Recommended naming format.
") +#endif // QT_CONFIG(tooltip) + self.radioButton_2.setText(u"Data Folder Name") + + self.gridLayout_2.addWidget(self.radioButton_2, 1, 0, 1, 1) + + self.radioButton_1 = QRadioButton(self.gridLayoutWidget_2) + self.radioButton_1.setObjectName(u"radioButton_1") + sizePolicy8.setHeightForWidth(self.radioButton_1.sizePolicy().hasHeightForWidth()) + self.radioButton_1.setSizePolicy(sizePolicy8) + self.radioButton_1.setFont(font5) + self.radioButton_1.setCursor(QCursor(Qt.PointingHandCursor)) +#if QT_CONFIG(tooltip) + self.radioButton_1.setToolTip(u"Use default naming format provided by Metashape.
Example: Chunk 1, Chunk 2,...
") +#endif // QT_CONFIG(tooltip) + self.radioButton_1.setText(u"Metashape Default") + + self.gridLayout_2.addWidget(self.radioButton_1, 0, 0, 1, 1) + + self.radioButton_4 = QRadioButton(self.gridLayoutWidget_2) + self.radioButton_4.setObjectName(u"radioButton_4") + sizePolicy8.setHeightForWidth(self.radioButton_4.sizePolicy().hasHeightForWidth()) + self.radioButton_4.setSizePolicy(sizePolicy8) + self.radioButton_4.setFont(font5) + self.radioButton_4.setCursor(QCursor(Qt.PointingHandCursor)) +#if QT_CONFIG(tooltip) + self.radioButton_4.setToolTip(u"Use date and time at which chunk is created.
") +#endif // QT_CONFIG(tooltip) + self.radioButton_4.setText(u"Creation date-time") + + self.gridLayout_2.addWidget(self.radioButton_4, 0, 1, 1, 1) + + self.horizontalLayout_8 = QHBoxLayout() + self.horizontalLayout_8.setSpacing(5) + self.horizontalLayout_8.setObjectName(u"horizontalLayout_8") + self.horizontalSpacer_4 = QSpacerItem(225, 0, QSizePolicy.Fixed, QSizePolicy.Minimum) + + self.horizontalLayout_8.addItem(self.horizontalSpacer_4) + + self.lineEdit = QLineEdit(self.gridLayoutWidget_2) + self.lineEdit.setObjectName(u"lineEdit") + self.lineEdit.setEnabled(False) + sizePolicy8.setHeightForWidth(self.lineEdit.sizePolicy().hasHeightForWidth()) + self.lineEdit.setSizePolicy(sizePolicy8) + self.lineEdit.setMinimumSize(QSize(140, 0)) + self.lineEdit.setFont(font5) +#if QT_CONFIG(tooltip) + self.lineEdit.setToolTip(u"Enter format string in python format.
*For details please check help first.
") +#endif // QT_CONFIG(tooltip) + self.lineEdit.setPlaceholderText(u"%Y%m%d-%H%M%S") + + self.horizontalLayout_8.addWidget(self.lineEdit) + + self.horizontalSpacer_5 = QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) + + self.horizontalLayout_8.addItem(self.horizontalSpacer_5) + + + self.gridLayout_2.addLayout(self.horizontalLayout_8, 3, 0, 1, 2) + + + self.horizontalLayout_7.addWidget(self.groupBoxChunkName) + + + self.formLayout.setLayout(4, QFormLayout.SpanningRole, self.horizontalLayout_7) + + self.label_wfolder_2 = QLabel(self.gridLayoutWidget) + self.label_wfolder_2.setObjectName(u"label_wfolder_2") + self.label_wfolder_2.setFont(font3) + self.label_wfolder_2.setText(u"Prefix/Suffix") + self.label_wfolder_2.setIndent(5) + + self.formLayout.setWidget(5, QFormLayout.LabelRole, self.label_wfolder_2) + + self.horizontalLayout_5 = QHBoxLayout() + self.horizontalLayout_5.setSpacing(5) + self.horizontalLayout_5.setObjectName(u"horizontalLayout_5") + self.lineEdit_pre = QLineEdit(self.gridLayoutWidget) + self.lineEdit_pre.setObjectName(u"lineEdit_pre") + self.lineEdit_pre.setEnabled(False) + sizePolicy4.setHeightForWidth(self.lineEdit_pre.sizePolicy().hasHeightForWidth()) + self.lineEdit_pre.setSizePolicy(sizePolicy4) +#if QT_CONFIG(tooltip) + self.lineEdit_pre.setToolTip(u"Leave empty to disable prefix.") +#endif // QT_CONFIG(tooltip) + self.lineEdit_pre.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter) + self.lineEdit_pre.setPlaceholderText(u"PREFIX_") + + self.horizontalLayout_5.addWidget(self.lineEdit_pre) + + self.label = QLabel(self.gridLayoutWidget) + self.label.setObjectName(u"label") + self.label.setStyleSheet(u"color: rgb(157, 158, 149);") + self.label.setText(u"Select location with working data for this definition.
") +#endif // QT_CONFIG(tooltip) + self.pushButton_browsewf.setText(u"") + icon9 = QIcon() + icon9.addFile(u":/icons/icons8-opened-folder-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.pushButton_browsewf.setIcon(icon9) + self.pushButton_browsewf.setIconSize(QSize(20, 20)) + self.pushButton_browsewf.setAutoDefault(False) + + self.horizontalLayout.addWidget(self.pushButton_browsewf) + + + self.formLayout.setLayout(6, QFormLayout.FieldRole, self.horizontalLayout) + + self.label_efolder = QLabel(self.gridLayoutWidget) + self.label_efolder.setObjectName(u"label_efolder") + self.label_efolder.setFont(font3) + self.label_efolder.setText(u"Export Folder") + self.label_efolder.setIndent(5) + + self.formLayout.setWidget(7, QFormLayout.LabelRole, self.label_efolder) + + self.horizontalLayout_10 = QHBoxLayout() + self.horizontalLayout_10.setSpacing(5) + self.horizontalLayout_10.setObjectName(u"horizontalLayout_10") + self.lineEdit_efolder = QLineEdit(self.gridLayoutWidget) + self.lineEdit_efolder.setObjectName(u"lineEdit_efolder") + self.lineEdit_efolder.setPlaceholderText(u"Path to folder for exporting...") + + self.horizontalLayout_10.addWidget(self.lineEdit_efolder) + + self.pushButton_browseef = QPushButton(self.gridLayoutWidget) + self.pushButton_browseef.setObjectName(u"pushButton_browseef") + sizePolicy3.setHeightForWidth(self.pushButton_browseef.sizePolicy().hasHeightForWidth()) + self.pushButton_browseef.setSizePolicy(sizePolicy3) +#if QT_CONFIG(tooltip) + self.pushButton_browseef.setToolTip(u"Select location with working data for this definition.
") +#endif // QT_CONFIG(tooltip) + self.pushButton_browseef.setText(u"") + self.pushButton_browseef.setIcon(icon9) + self.pushButton_browseef.setIconSize(QSize(20, 20)) + self.pushButton_browseef.setAutoDefault(False) + + self.horizontalLayout_10.addWidget(self.pushButton_browseef) + + + self.formLayout.setLayout(7, QFormLayout.FieldRole, self.horizontalLayout_10) + + self.horizontalLayout_2 = QHBoxLayout() + self.horizontalLayout_2.setSpacing(5) + self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") + self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) + + self.horizontalLayout_2.addItem(self.horizontalSpacer_2) + + self.pushButton_save = QPushButton(self.gridLayoutWidget) + self.pushButton_save.setObjectName(u"pushButton_save") + self.pushButton_save.setEnabled(False) + sizePolicy3.setHeightForWidth(self.pushButton_save.sizePolicy().hasHeightForWidth()) + self.pushButton_save.setSizePolicy(sizePolicy3) + self.pushButton_save.setMinimumSize(QSize(0, 30)) +#if QT_CONFIG(tooltip) + self.pushButton_save.setToolTip(u"Save currently selected chunk definition
") +#endif // QT_CONFIG(tooltip) + self.pushButton_save.setText(u"Save") + icon10 = QIcon() + icon10.addFile(u":/icons/icons8-save-as-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.pushButton_save.setIcon(icon10) + self.pushButton_save.setIconSize(QSize(20, 20)) +#if QT_CONFIG(shortcut) + self.pushButton_save.setShortcut(u"S") +#endif // QT_CONFIG(shortcut) + self.pushButton_save.setAutoDefault(False) + + self.horizontalLayout_2.addWidget(self.pushButton_save) + + self.pushButton_add = QPushButton(self.gridLayoutWidget) + self.pushButton_add.setObjectName(u"pushButton_add") + sizePolicy3.setHeightForWidth(self.pushButton_add.sizePolicy().hasHeightForWidth()) + self.pushButton_add.setSizePolicy(sizePolicy3) + self.pushButton_add.setMinimumSize(QSize(0, 30)) +#if QT_CONFIG(tooltip) + self.pushButton_add.setToolTip(u"Add new
Add new chunk settings definition
*Crates new chunk definition with current options.
**Definition Name must be unique.
Shortcuts: [A] Add New / [E] Edit / [R] Remove / [S] Save / [C] Close
") + + self.horizontalLayout_3.addWidget(self.label_2) + + self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) + + self.horizontalLayout_3.addItem(self.horizontalSpacer) + + self.pushButton_close = QPushButton(self.gridLayoutWidget) + self.pushButton_close.setObjectName(u"pushButton_close") + sizePolicy3.setHeightForWidth(self.pushButton_close.sizePolicy().hasHeightForWidth()) + self.pushButton_close.setSizePolicy(sizePolicy3) + self.pushButton_close.setMinimumSize(QSize(0, 30)) +#if QT_CONFIG(tooltip) + self.pushButton_close.setToolTip(u"Close Chunk Settings Editor") +#endif // QT_CONFIG(tooltip) + self.pushButton_close.setText(u"Close") + icon12 = QIcon() + icon12.addFile(u":/icons/icons8-close-window-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.pushButton_close.setIcon(icon12) + self.pushButton_close.setIconSize(QSize(20, 20)) +#if QT_CONFIG(shortcut) + self.pushButton_close.setShortcut(u"C") +#endif // QT_CONFIG(shortcut) + + self.horizontalLayout_3.addWidget(self.pushButton_close) + + + self.gridLayout.addLayout(self.horizontalLayout_3, 4, 0, 1, 2) + + QWidget.setTabOrder(self.listWidgetChunkDefs, self.pushButton_sremove) + QWidget.setTabOrder(self.pushButton_sremove, self.pushButton_sedit) + QWidget.setTabOrder(self.pushButton_sedit, self.lineEdit_name) + QWidget.setTabOrder(self.lineEdit_name, self.comboBox_icon) + QWidget.setTabOrder(self.comboBox_icon, self.radioButton_1) + QWidget.setTabOrder(self.radioButton_1, self.radioButton_2) + QWidget.setTabOrder(self.radioButton_2, self.radioButton_3) + QWidget.setTabOrder(self.radioButton_3, self.radioButton_4) + QWidget.setTabOrder(self.radioButton_4, self.radioButton_5) + QWidget.setTabOrder(self.radioButton_5, self.radioButton_6) + QWidget.setTabOrder(self.radioButton_6, self.lineEdit) + QWidget.setTabOrder(self.lineEdit, self.lineEdit_pre) + QWidget.setTabOrder(self.lineEdit_pre, self.lineEdit_suf) + QWidget.setTabOrder(self.lineEdit_suf, self.lineEdit_wfolder) + QWidget.setTabOrder(self.lineEdit_wfolder, self.pushButton_browsewf) + QWidget.setTabOrder(self.pushButton_browsewf, self.lineEdit_efolder) + QWidget.setTabOrder(self.lineEdit_efolder, self.pushButton_browseef) + QWidget.setTabOrder(self.pushButton_browseef, self.pushButton_save) + QWidget.setTabOrder(self.pushButton_save, self.pushButton_add) + QWidget.setTabOrder(self.pushButton_add, self.pushButton_close) + + self.btnAction = True + self.selFormat = str("metashape") + + self.pushButton_sremove.clicked.connect(self.removeSelectedItem) + self.pushButton_add.clicked.connect(self.addBtnAction) + self.pushButton_close.clicked.connect(self.reject) + self.listWidgetChunkDefs.currentItemChanged.connect(self.pushButton_sedit.setEnabled(True)) + self.listWidgetChunkDefs.currentItemChanged.connect(self.pushButton_sremove.setEnabled(True)) + self.pushButton_sedit.clicked.connect(self.editSelectedItem) + self.pushButton_browsewf.clicked.connect(self.selectWorkFolder) + self.pushButton_browseef.clicked.connect(self.selectExportFolder) + self.pushButton_save.clicked.connect(self.saveSelectedItem) + self.radioButton_1.toggled.connect(self.lineEdit_pre.setDisabled) + self.radioButton_1.toggled.connect(self.lineEdit_suf.setDisabled) + self.radioButton_2.toggled.connect(self.lineEdit_pre.setEnabled) + self.radioButton_2.toggled.connect(self.lineEdit_suf.setEnabled) + self.radioButton_3.toggled.connect(self.lineEdit_pre.setEnabled) + self.radioButton_3.toggled.connect(self.lineEdit_suf.setEnabled) + self.radioButton_4.toggled.connect(self.lineEdit_pre.setEnabled) + self.radioButton_4.toggled.connect(self.lineEdit_suf.setEnabled) + self.radioButton_5.toggled.connect(self.lineEdit_pre.setEnabled) + self.radioButton_5.toggled.connect(self.lineEdit_suf.setEnabled) + self.radioButton_6.toggled.connect(self.lineEdit_pre.setEnabled) + self.radioButton_6.toggled.connect(self.lineEdit_suf.setEnabled) + self.radioButton_6.toggled.connect(self.lineEdit.setEnabled) + self.radioButton_1.toggled.connect(self.updateChunkFormat) + self.radioButton_2.toggled.connect(self.updateChunkFormat) + self.radioButton_3.toggled.connect(self.updateChunkFormat) + self.radioButton_4.toggled.connect(self.updateChunkFormat) + self.radioButton_5.toggled.connect(self.updateChunkFormat) + self.radioButton_6.toggled.connect(self.updateChunkFormat) + + self.pushButton_close.setDefault(True) + + self.listChunkDefs() + self.readIconsIni() + self.selectChunkFormat() + + + self.exec() + + # Dialog setup end + + def updateChunkFormat(self): + selected_format = self.sender() + + if selected_format.isChecked(): + sel_name = selected_format.text() + self.selFormat = str(sel_name).split(" ")[0].lower() + self.selectChunkFormat() + + + + def selectChunkFormat(self): + if self.selFormat == "metashape": + self.radioButton_1.setChecked(True) + elif self.selFormat == "data": + self.radioButton_2.setChecked(True) + elif self.selFormat == "point": + self.radioButton_3.setChecked(True) + elif self.selFormat == "creation": + self.radioButton_4.setChecked(True) + elif self.selFormat == "image": + self.radioButton_5.setChecked(True) + elif self.selFormat == "custom": + self.radioButton_6.setChecked(True) + + + def listChunkDefs(self): + self.lineEdit_wfolder.setText(autoftg_main.selected_data_folder) + self.pushButton_save.setDisabled(True) + self.pushButton_sremove.setEnabled(True) + self.listWidgetChunkDefs.clear() + for section in autoftg_main.chunk_sections: + menu_icon = autoftg_main.menuCfg.get(section, "menu_icon") + menu_icon_path = u":/icons/" + autoftg_main.icoCfg.get("ICONS", menu_icon) + seticon = QIcon() + seticon.addFile(menu_icon_path, QSize(), QIcon.Normal, QIcon.Off) + self.qlistwidgetitem = QListWidgetItem(self.listWidgetChunkDefs) + self.qlistwidgetitem.setText(section) + self.qlistwidgetitem.setIcon(seticon) + + + def readIconsIni(self): + ico_count = 0 + for iconitem in autoftg_main.icons_list: + aicon_name = "ico-" + str(ico_count) + aicon_path = u":/icons/" + autoftg_main.icoCfg.get("ICONS", iconitem) + aicon = QIcon() + aicon.addFile(aicon_path, QSize(), QIcon.Normal, QIcon.Off) + self.comboBox_icon.addItem(aicon, aicon_name) + ico_count += 1 + + + def editSelectedItem(self): + selected_item = self.listWidgetChunkDefs.currentItem().text() + self.lineEdit_name.setText(selected_item) + self.comboBox_icon.setCurrentText(str(autoftg_main.menuCfg.get(selected_item, "menu_icon"))) + self.selFormat = str(autoftg_main.menuCfg.get(selected_item, "chunk_name_format")) + self.selectChunkFormat() + self.lineEdit_wfolder.setText(str(autoftg_main.menuCfg.get(selected_item, "work_folder"))) + self.lineEdit_efolder.setText(str(autoftg_main.menuCfg.get(selected_item, "export_folder"))) + self.lineEdit_pre.setText(str(autoftg_main.menuCfg.get(selected_item, "chunk_name_prefix"))) + self.lineEdit_suf.setText(str(autoftg_main.menuCfg.get(selected_item, "chunk_name_suffix"))) + self.lineEdit_name.setDisabled(True) + self.listWidgetChunkDefs.setDisabled(True) + self.pushButton_sedit.setDisabled(True) + self.pushButton_sremove.setDisabled(True) + self.pushButton_save.setEnabled(True) + self.pushButton_add.setText(u"Cancel") + abanicon = QIcon() + abanicon.addFile(u":/icons/icons8-unavailable-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.pushButton_add.setIcon(abanicon) + self.btnAction = False + + + def removeSelectedItem(self): + selected_item = self.listWidgetChunkDefs.currentItem().text() + confirm_remove = Metashape.app.getBool("Remove (" + selected_item + ")?") + + if confirm_remove == True: + self.backupSettings() + autoftg_main.menuCfg.remove_section(selected_item) + + with open(autoftg_main.menuCfgFilePath, 'w') as menuconfig: + autoftg_main.menuCfg.write(menuconfig) + + self.lineEdit_name.clear + self.comboBox_icon.setCurrentIndex(0) + self.lineEdit_wfolder.clear + self.lineEdit_efolder.clear + self.lineEdit_pre.clear + self.lineEdit_suf.clear + self.pushButton_sedit.setEnabled(True) + self.pushButton_save.setDisabled(True) + self.pushButton_add.setEnabled(True) + self.lineEdit_name.setEnabled(True) + self.listWidgetChunkDefs.takeItem(self.listWidgetChunkDefs.currentRow()) + print("Chunk definition removed from settings...\nRemoved: " + str(selected_item) + "\n") + + + def saveSelectedItem(self): + edit_section = self.lineEdit_name.text() + autoftg_main.menuCfg.set(edit_section, "menu_icon", self.comboBox_icon.currentText()) + autoftg_main.menuCfg.set(edit_section, "chunk_name_format", self.selFormat) + autoftg_main.menuCfg.set(edit_section, "chunk_name_prefix", self.lineEdit_pre.text()) + autoftg_main.menuCfg.set(edit_section, "chunk_name_suffix", self.lineEdit_suf.text()) + autoftg_main.menuCfg.set(edit_section, "work_folder", self.lineEdit_wfolder.text()) + autoftg_main.menuCfg.set(edit_section, "export_folder", self.lineEdit_efolder.text()) + + with open(autoftg_main.menuCfgFilePath, 'w') as menuconfig: + autoftg_main.menuCfg.write(menuconfig) + + autoftg_main.chunksCfgLoad() + + self.listWidgetChunkDefs.setEnabled(True) + self.lineEdit_name.setEnabled(True) + self.lineEdit_name.clear() + self.lineEdit_wfolder.clear() + self.lineEdit_efolder.clear() + self.lineEdit_pre.clear() + self.lineEdit_suf.clear() + self.comboBox_icon.setCurrentIndex(0) + self.pushButton_save.setDisabled(True) + self.pushButton_sedit.setEnabled(True) + self.pushButton_add.setEnabled(True) + self.pushButton_add.setText(u"Add New") + addicon = QIcon() + addicon.addFile(u":/icons/icons8-add-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.pushButton_add.setIcon(addicon) + self.pushButton_add_action = False + self.btnAction = True + print("Chunk definition updated...\nUpdated: " + str(edit_section) + "\n") + self.selFormat = str("metashape") + self.selectChunkFormat() + self.listChunkDefs() + + + def addBtnAction(self): + if self.btnAction == True: + self.backupSettings() + new_section = self.lineEdit_name.text() + autoftg_main.menuCfg.add_section(new_section) + autoftg_main.menuCfg.set(new_section, "menu_icon", self.comboBox_icon.currentText()) + autoftg_main.menuCfg.set(new_section, "chunk_name_format", self.selFormat) + autoftg_main.menuCfg.set(new_section, "chunk_name_prefix", self.lineEdit_pre.text()) + autoftg_main.menuCfg.set(new_section, "chunk_name_suffix", self.lineEdit_suf.text()) + autoftg_main.menuCfg.set(new_section, "work_folder", self.lineEdit_wfolder.text()) + autoftg_main.menuCfg.set(new_section, "export_folder", self.lineEdit_efolder.text()) + + with open(autoftg_main.menuCfgFilePath, 'w') as menuconfig: + autoftg_main.menuCfg.write(menuconfig) + + autoftg_main.chunksCfgLoad() + + self.listWidgetChunkDefs.setEnabled(True) + self.lineEdit_name.clear() + self.lineEdit_wfolder.clear() + self.lineEdit_efolder.clear() + self.lineEdit_pre.clear() + self.lineEdit_suf.clear() + self.comboBox_icon.setCurrentIndex(0) + self.pushButton_save.setDisabled(True) + print("New chunk definition added...\nAdded: " + str(new_section) + "\n") + self.btnAction = True + self.selFormat = str("metashape") + self.selectChunkFormat() + self.listChunkDefs() + + else: + self.listWidgetChunkDefs.setEnabled(True) + self.pushButton_sedit.setEnabled(True) + self.lineEdit_name.setEnabled(True) + self.pushButton_save.setEnabled(True) + self.pushButton_add.setText(u"Add New") + addicon = QIcon() + addicon.addFile(u":/icons/icons8-add-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.pushButton_add.setIcon(addicon) + self.pushButton_add_action = False + self.lineEdit_name.clear() + self.lineEdit_wfolder.clear() + self.lineEdit_efolder.clear() + self.lineEdit_pre.clear() + self.lineEdit_suf.clear() + self.comboBox_icon.setCurrentIndex(0) + print("Aborted editing chunk definition...") + self.btnAction = True + self.selFormat = str("metashape") + self.selectChunkFormat() + self.listChunkDefs() + + + def backupSettings(self): + menuCfgFileBackup = "settings_newchunk.old" + menuCfgFileBackupPath = autoftg_main.menuCfgPath + "/" + menuCfgFileBackup + shutil.copy2(autoftg_main.menuCfgFilePath, menuCfgFileBackupPath) + print("Creating backup of chunk definitions...\nBackup file: " + str(menuCfgFileBackup) + "\n") + + + def selectWorkFolder(self): + if self.lineEdit_wfolder.text() == "" or self.lineEdit_wfolder.text() == None: + sel_folder = Metashape.app.getExistingDirectory("Choose Work Folder", autoftg_main.selected_data_folder) + else: + cur_folder = self.lineEdit_wfolder.text() + sel_folder = Metashape.app.getExistingDirectory("Choose Work Folder", cur_folder) + + if sel_folder == "": + self.lineEdit_wfolder.setText(str(cur_folder)) + print("Work folder not changed!") + else: + self.lineEdit_wfolder.setText(str(sel_folder)) + print("Work folder location selected!") + + + def selectExportFolder(self): + if self.lineEdit_efolder.text() == "" or self.lineEdit_efolder.text() == None: + sel_folder = Metashape.app.getExistingDirectory("Choose Export Folder", autoftg_main.selected_data_folder) + else: + cur_folder = self.lineEdit_efolder.text() + sel_folder = Metashape.app.getExistingDirectory("Choose Export Folder", cur_folder) + + if sel_folder == "": + self.lineEdit_efolder.setText(str(cur_folder)) + print("Export folder not changed!") + else: + self.lineEdit_efolder.setText(str(sel_folder)) + print("Export folder location selected!") + diff --git a/AutoFTG/autoftg_settingsmain.py b/AutoFTG/autoftg_settingsmain.py new file mode 100644 index 0000000..5e9dd77 --- /dev/null +++ b/AutoFTG/autoftg_settingsmain.py @@ -0,0 +1,161 @@ +# Class for settings editing UI +import os +import shutil +import subprocess +import sys +import time +from configparser import ConfigParser +from datetime import datetime +from os import path + +import Metashape +from PySide2 import QtCore, QtGui, QtWidgets +from PySide2.QtCore import * +from PySide2.QtGui import * +from PySide2.QtWidgets import * + +import AutoFTG.autoftg_main as autoftg_main +from AutoFTG.qtresources_rc2 import * + + +class Ui_settingsDialog(QtWidgets.QDialog): + def __init__(self, parent): + QtWidgets.QDialog.__init__(self, parent) + self.setObjectName(u"settingsDialog") + self.resize(300, 100) + self.setWindowTitle(u"AutoFTG Settings") + appIcon = QIcon() + appIcon.addFile(u":/icons/AutoFTG-appicon.png", QSize(), QIcon.Normal, QIcon.Off) + self.setWindowIcon(appIcon) + + icon = QIcon() + icon.addFile(u":/icons/icons8-opened-folder-50.png", QSize(), QIcon.Normal, QIcon.Off) + icon0 = QIcon() + icon0.addFile(u":/icons/icons8-full-page-view-50.png", QSize(), QIcon.Normal, QIcon.Off) + icon1 = QIcon() + icon1.addFile(u":/icons/icons8-panorama-50.png", QSize(), QIcon.Normal, QIcon.Off) + icon2 = QIcon() + icon2.addFile(u":/icons/icons8-aperture-50.png", QSize(), QIcon.Normal, QIcon.Off) + icon3 = QIcon() + icon3.addFile(u":/icons/icons8-video-stabilization-50.png", QSize(), QIcon.Normal, QIcon.Off) + icon4 = QIcon() + icon4.addFile(u":/icons/icons8-touchscreen-48.png", QSize(), QIcon.Normal, QIcon.Off) + icon5 = QIcon() + icon5.addFile(u":/icons/icons8-quadcopter-50.png", QSize(), QIcon.Normal, QIcon.Off) + icon5a = QIcon() + icon5a.addFile(u":/icons/icons8-ios-application-placeholder-50.png", QSize(), QIcon.Normal, QIcon.Off) + icoTripod = QIcon() + icoTripod.addFile(u":/icons/icons8-camera-on-tripod-96.png", QSize(), QIcon.Normal, QIcon.Off) + self.label_2 = QtWidgets.QLabel() + self.label_2.setObjectName(u"label_2") + self.label_2.setGeometry(QRect(10, 40, 80, 16)) + self.label_2.setText("Data Folder:") + self.lineDataFolder = QtWidgets.QLineEdit() + self.lineDataFolder.setObjectName(u"lineDataFolder") + self.lineDataFolder.setGeometry(QRect(10, 40, 280, 24)) + self.lineDataFolder.setText(str(autoftg_main.selected_data_folder)) + self.lineDataFolder.setClearButtonEnabled(True) + self.btnDataFolder = QtWidgets.QPushButton() + self.btnDataFolder.setObjectName(u"btnDataFolder") + self.btnDataFolder.setGeometry(QRect(300, 40, 80, 24)) + self.btnDataFolder.setText(u" Browse") + self.btnDataFolder.setIcon(icon) + self.btnDataFolder.setIconSize(QSize(21, 21)) + + self.label_3 = QtWidgets.QLabel() + self.label_3.setObjectName(u"label_3") + self.label_3.setGeometry(QRect(10, 70, 90, 16)) + self.label_3.setText("Default Camera:") + self.comboBoxCamera = QtWidgets.QComboBox() + self.comboBoxCamera.setObjectName(u"comboBoxCamera") + self.comboBoxCamera.setGeometry(QRect(10, 70, 280, 24)) + for cam in autoftg_main.cam_list: + icon_type = autoftg_main.camCfg.get(cam, "Type") + icon_subtype = autoftg_main.camCfg.get(cam, "SubType") + if icon_subtype == "SmartPhone": + self.comboBoxCamera.addItem(icon4, cam) + elif icon_subtype == "Drone": + self.comboBoxCamera.addItem(icon5, cam) + elif icon_subtype == "Special": + self.comboBoxCamera.addItem(icoTripod, cam) + else: + if icon_type == "Fisheye": + self.comboBoxCamera.addItem(icon1, cam) + elif icon_type == "Spherical": + self.comboBoxCamera.addItem(icon3, cam) + elif icon_type == "Cylindrical": + self.comboBoxCamera.addItem(icon2, cam) + elif icon_type == "RPC": + self.comboBoxCamera.addItem(icon5a, cam) + else: + self.comboBoxCamera.addItem(icon0, cam) + + self.comboBoxCamera.setCurrentText(str(autoftg_main.selected_camera)) + + self.btnClose = QtWidgets.QPushButton() + self.btnClose.setObjectName(u"btnClose") + self.btnClose.setGeometry(QRect(220, 90, 75, 24)) + self.btnClose.setText(u"Close") + icon1 = QIcon() + icon1.addFile(u":/icons/icons8-close-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.btnClose.setIcon(icon1) + + self.btnSave = QtWidgets.QPushButton() + self.btnSave.setObjectName(u"btnSave") + self.btnSave.setGeometry(QRect(300, 90, 75, 24)) + self.btnSave.setText(u" Save") + icon2 = QIcon() + icon2.addFile(u":/icons/icons8-save-as-50.png", QSize(), QIcon.Normal, QIcon.Off) + self.btnSave.setIcon(icon2) + self.btnSave.setIconSize(QSize(12, 12)) + + layout = QtWidgets.QGridLayout() # creating layout + layout.setRowMinimumHeight(0, 24) + layout.setRowMinimumHeight(1, 24) + layout.setRowMinimumHeight(2, 24) + layout.setVerticalSpacing(1) + + layout.setColumnMinimumWidth(1, 250) # minimum column width + layout.setColumnMinimumWidth(2, 80) # minimum column width + + layout.addWidget(self.label_2, 0, 0) + layout.addWidget(self.lineDataFolder, 0, 1) + layout.addWidget(self.btnDataFolder, 0, 2) + + layout.addWidget(self.label_3, 1, 0) + layout.addWidget(self.comboBoxCamera, 1, 1) + + layout.addWidget(self.btnClose, 2, 2) + layout.addWidget(self.btnSave, 2, 1) + + self.setLayout(layout) + + QtCore.QObject.connect(self.btnDataFolder, QtCore.SIGNAL("clicked()"), self.dataFolderChange) + QtCore.QObject.connect(self.btnSave, QtCore.SIGNAL("clicked()"), self.saveSettingsDialog) + QtCore.QObject.connect(self.btnClose, QtCore.SIGNAL("clicked()"), self, QtCore.SLOT("reject()")) + + self.exec() + + def dataFolderChange(self): + foldeData = Metashape.app.getExistingDirectory("Data folder") + self.lineDataFolder.setText(foldeData) + + def saveSettingsDialog(self): + if autoftg_main.projectOpened == False: + # settings.folderProject = self.lineProjFolder.text() + autoftg_main.appCfg.set('APP SETTINGS', 'folder_data', self.lineDataFolder.text()) + autoftg_main.appCfg.set('APP SETTINGS', 'default_camera', self.comboBoxCamera.currentText()) + with open(autoftg_main.appCfgFilePath, 'w') as configfile: + autoftg_main.projCfg.write(configfile) + autoftg_main.appCfgLoad() + else: + autoftg_main.projCfg.set('PROJECT SETTINGS', 'folder_data', self.lineDataFolder.text()) + autoftg_main.projCfg.set('PROJECT SETTINGS', 'default_camera', self.comboBoxCamera.currentText()) + with open(autoftg_main.projCfgFilePath, 'w') as configfile: + autoftg_main.projCfg.write(configfile) + autoftg_main.projCfgLoad + + print("New settings stored.") + self.close() + + diff --git a/AutoFTG/cameras/Nokia-XR20_48MP_2022-12.xml b/AutoFTG/cameras/Nokia-XR20_48MP_2022-12.xml new file mode 100644 index 0000000..fe7c510 --- /dev/null +++ b/AutoFTG/cameras/Nokia-XR20_48MP_2022-12.xml @@ -0,0 +1,15 @@ + +2.6.3
¶2.6.1
¶2.6.0
¶2.5.6
... 2.5.9
¶2.5.5
¶2.5.4
¶2.5.3
¶2.5.2
¶2.5.1
¶2.5.0
¶2.4.6-RC
¶2.4.5-RC
¶2.4.4-RC
¶2.4.3-RC
¶2.4.2-RC
¶Added option SubType
and Resolution
to camera settings configuration (cam_settings.ini)
Replaced easygui dialogs for Qt PySide2 custom dialog:
+class Ui_dialogChooseCamera()
Function definitions using new camera selection dialog:
+def cam_calibrationSettings()
def cam_calibrationChunk()
def newchunk_aero()
Updated camera list in Camera Editor to use new icons
+Updated def appAbout()
to use PySide2 message box dialog
2.4.1-beta
¶2.4.0-beta
¶2.3.3-beta
¶2.3.2-beta
¶2.3.1-beta
¶2.3.0-beta
¶2.2.0-beta
¶2.1.1-beta
¶2.1.0-beta
¶2.0.x-beta
¶1.7.6
¶1.7.5
¶1.1
¶1.0
¶EA{G^GSW zFVaht7O9~~4G?-LAvsZ>=RN1F^{)5BS?hfJ=Sz03Tzk*nvu9?{{ATvQMh1@<>95fP z002fE?FYsHz96(F-^9z=KhVJ!1i0_y^$f(T19or$8G{_0 zf_!>GDgeN_09Vte{!jJwlpVdm;ts#x5r=}kDZK#z6?Le$gQGjhpZ6Ka#nn@lAK%cz z&+F=>%5N^GFRAaX33~3T9qbD-2{tfw40d-^a^hE4<5htwQw9Ko{2h3qU=L3}WvD9u zpK+Bb?ca|j_<8@l;_t4?|94VP^^JHny?jBua^muL9HnICcomeyrQ~H~m6XJIr6r{l zB_tIkq-5?$$t%lBDoacA{^!F_q2}x4tZe+?;eTjReyQ?5_xJZ!mXHVx3=|KP5%= D0Res7$ z|1JUSt*`&T2KMy(52Gk7lYlySOGt@JN`S$?*Y)RZKYwG;|2>WW?c08)LEaz-b+nK_<|1+WAFH&ZsZ0PGs*%Swl2VRa4Fv!zi=Yc9e 08cN8RLL3fm%$v?Xz@8IO@?BEPiQgl@O?>PUv{+bVDrDZiAXed2=_&`cZ z>w%JzmXwyX!UIhiC3!`~2TK3#tK;eC@8IbO`Y&x)3hn>&z5jpgtE}k@a`5-^HTClH z_^%WgJ@@kW@_X*(&8w;Td)JkCZ=1V%I(Y^93IE=vzpH)#@^uXWIX(3C0`vaiv$E^| zW)4zLPL49Nj#76V6hV%6K=QImcNC@NKzF2^6`kc}WfbM)BtiWD>F@Oam46bHNlE+` zmj8$F{Pz(>B7Zmkmnu+x{4Zq!c~UgUm!c}A`Yu}lYWo Xf{E9j~!f`&) zW_|KgL5S3%);7@hCbsGOI67#?j!VPnj~)X6my_mM{?m+(0Wkk V};{Dt5ZlwiK{b`1udkCQY`|yS&^}WBXx$r9h>c7p4vHvrqJx%yuX8aE?DdP4& zLi9h{1Ni^NY^3_oZC@|4Ym=u=yYffjZirCdBVJu&C(a0{%-@Z8@#o>(2WG%R?F03t z7515UT65SV=D+sqGBp)1?9#p*o` Pt #tk zODF!vlB%4e(1;;FI$LaSsh(~Qo9Z&ZId5l!8Gm4r>T0p8qA)(mdck(4&`(_OypO6n zgJvQ?l63n;ZiCO_!{<}-->{KKRd3Nnnw*5|zuwbQ{W0FHUT^1F=4^Zgi6e_LZq3Kb znHzTG6Z2-<3c>23Y`+3R^FU>(+Z1xWzMMNMZ`MP;su{mh`Mk`f^4r0$z`e}?t8RS% zsYtnbA8u{Ul@q(7Kk{pQa${kkz3ZUV^jaT@Od_-xc7KI?{NWRzh0_$UV3SX{N=J^R zfirQdd>KNOB1G MN1@rs!X(b~PMb3?R)_Kw+o3L!VI>)xww|)hQSM25`3Booe zk(*0E7-b&yuGiRG@Dvu`>WCYgX$UM>Ptd*hhsJiM7T|SY*HZ_A_W3yi7Vd??)f~*O zu
j3X8T4qe#jt;vFrY(>@qBv#0UFiee-R z5r{mTa#(0+sQ^tWZc_N#U+D?QN)8IFLyIr2vdL3TTmlsJsne0A>B#b#`d8GG5G@+N zhx%2sT3?=sUU27zr|RDO2kug!C(&HE*@a%>Gi `8)HPOH;zl}{D1zpFi zxl~!)0>03CvLDmg{+RY?!X UCO3xb2hkbFc%f zxm_5@Yr4(>PC8y`=P-Hd-aqJUBX{OITX(U$tOee1sfdT6T IU??%i SUU6YXJ?XX(j(Be1hJcl8qw z$-d+wToQ52TW54RyEj&5Jjm;n$z*gQb?4E$VV%sE)a 1iKbllQ zS6x@|>^UW_gs2ai4W8X~JKW5@S_?mN5AfejYxD9d`5--YQE=q!e1-99Z3+E5W^b=g zmadM~`2qJ!O4m{kn#N}oJ-0%D`!R>leX4XEBbv-{2f?pT4PqEH%MpEEwNsMvG^lTq z_J4?PTipY^uHDkzV@g>W{%M{m*1z%WYfqLR%1^TfZ0H4?c%|<2sD(HoZa_A~RH(nU z`#xU8(pDtxY>sp(1MdZ^*^xfJG Hs;~J1Zr+) C=PRmsf^BOqYB}e$4<2ByQzr;?pF2P~o zb(tH|I$PFPP0d5p#ghH@>MEoojCxhVeS{ZCyJC}`waDA_Ro3Eh4ChEVJ951`J8wt$ zUt4zyND&hvEx%4ZF_uyH6Z!wjUqfe&3voBIWm11SW_}vwygr z)2MC#xu({(rr?t1<|~oKW K#UJ=?U8j3Y-SH^ z%028{fOeT5OH#OZWzXlD?yIhBgjCiuaHYDne%zf{7&p4QH`qwP1!3e;2x Fq5? z4eV$vW!VCfqA3>Bz6G{mw_58vFV!utne<>EtZRr>NYf~CN55q@5@7{#-`isSGxE`$ z-|Bg9nf%yqbEYxKq<=ajDCaTrb8{TX=c{r$ZvB~5E(D}@2}J`{Rtem}8gMjR=r+$3 zwc%;_myN{okr%z{&4iZ4rt;N^BFe+C>wU2|@^h}QD z=;_D;8%g4=EJpg8;Zw+zAb{ZeEP0vp`VO^&ABrD@OxIjCFA*G*Q&)Fw>c SBFNySzEIaALA-CI>7GW}U)Pk?GV5#?v F-hYZ~yI;7Tm$4_Bm#{**71x*}}n7W;0)`X&Nlwe=Mth z;!5ic{a4#XH^zz9+l(PnxIs4^=?lAEwAHc$L{Nb^yyY2Q<%j^%`U~P?P=WZI 8)5W`el}0t&10hLwM&&Ehz?uYIZ(*6@sJ-bLJbNtoaO81T)RQau+0 zB(JN}38BE~P%nv&7JLg?4H7_F{ghD1> =GT~XfmeYSS>;WQs{tMkKs7H6#ii__A zKm&bzuADRnc1Rvgc*y(P6fK@^r?n6}H)mW$sB*Uh3D kRTy)3<6X0T*}=|L?e8lK2PvS}gnQKL$E69UukCy^fxs|pOy}7e)N9%o z#gH3zm~QSRPZK)feW&q-W6;J*F2zmp<2l7r{Lk$R=!?H4Yx^ZFU 2GwE0_L1B0Hhx?a9F(UMa6t?3~z zi$T}oD8$Bu?ua1`N>5%mOEFcz*CW5A-&t@ULxO)0!Z_13qO1&G%qeatgL(5kCEV!A zzdF=lqdIx^M18Mn*M>T&baCUH+`9OP@b#hWyYmhB=A> `r5EUMt@C=wQ_GEi<0Y9Kb^QEljO c?octiw?QX&QNzEaI@^XZmx+H3{=CG+sok%FDXnyA~BQ&dNg{g_dZziap z8ReFdAUBh51)3i8-!b>{Vr ^7@%lo)t-way42ha=Y#GD-mM8#T zm9ims(q=3P6l28}7=UWLZGbjhFSSKGE1V9qitl-{|7;SGt~1rR=lCjvE4mT&!;Iu_ z!Zd}D%`+H-S85+%tF-}8!J`gG?Uek8`jwTHiEbWv)-sTYwW}xr?(LN=9JP>T$*cQV z-v*)$=HSsRZu(&7insFYqW!||7hPHXBMzq>AI?~LoTr8APx(h!g%!)es!!ruMfiFH zWtxlW43eacCAH4n!B91Vd5+Sxm&`+db|fU4vLh+7fVXedi>X;zZuDmP5DZ`lLkyN1 zjW3ON4zx~R>Z`vmOhBBwcWW`ErueF+Eq5)X$`aENY DWPIo1 z2my~xbLf}$${=l2q1!va!?X|L_LRlb`el R|P?YO~X<#K`D4%K)oO#dhAI8m7*D2g_|6-6Kij?x)9y;jL-QhPWxh@Rg^^ zvDM(I?vPujDK5QPIXQjfv*Xs`e|Do0Lh-yZjg9h+HD_&Fg@6IW;f|;vqrmxJ(14II zr>(l-W!=ZxtT}>~nd^HwdFsWcth#pdr3@BN0++@;A6J~Te`{e(H#dj}x#{wcg%8s~ z ta-t$|Cac79hH#w)(3R(KKMOfu=sG9c06(~G36n*x49{`OQidlN7 zT2A$vMhiTpi)TuAF(icL+K3tAkVi{(pUw9|<&$S`{}T!=1Z=18weU`ju!yaFyd0#4 zcS`}6e7L}Apd1OaK-l6!)&N<{)XDP&`XkyL&(( Wx#|atCMqRN*vNtc$HnVW4J@3E(IqL_QK;3Hb!U26mnI5|AEPJba7~ zyJB~7#rh`SCxKoTKws5^Pgnnl!|;G*>ve+mxkQSqAE9L|CFEDz`( ^ProOnaaK<$p62!fGRQf9n z%f2YN8F~$ICp$xsCi%@hr5vBn@_#0X7yNzv>)ecECF*N>bR!x{H<1OGGf{m=nQTTa zZ%4n^IQjf;-d^FA3yZ&GGS6SHb*_1G;sboK_UY(Sv7n4r&u(Q!HMpdWfRZ-$K;FG- z(e;owoq;L`(O-VIn4Q!1q>g#>U-m7w%XVS2Vd{f+q+Rxd1UOMs_tr>2L-`cr`ODI! zlTO8W-^Q&q2JwrROKwe1N8@y8SHlvu%D+Zbv79U|TF0?)KPEWbow-#!8f({}Y b3A5$tOW6f)V!7c_scohmyf=pn46|trad|z`h7W zlTXJuQdc^2G9_|H9wcZ;$5cge8TL~uZIl?ouI?u4pzMecgm!Y!l7M{%qCcPBD5~Bd zlf%x=eKl|<&`y9MnDNE 7lVybpKGIQ7K{WQ 1G%z?5{CM 0I!e^$R+O6JqFCGuE?t8oZT4o0${@K&Lep$?}e %OV0Yxj0vR<@F8BQ&6hNRWuq+2~qw*3lcZI;FlzPxeg5% zgCtfKk%VgARl2tE652}RvRMjHB{5M e5J_G;u9|hjzRwf0b-_zT+7*^)ta^#+l%=sv|6ScQ-?`;Z%L!PgrC0M+TTb8 zN~U0)Wr=S}ed6o-Q40@pR$OzMn!RG?YHKQI^sLCgR!pO|b<1qOBc^`B!Yn<94b%Hw zcs5`PmzkPVlatb?SCFfhk_hR;;)4>m@^XpUdSf6K@m^xU)TSA>F=)@nk4h~7y5^`+ z$j-RXE{9Wfe}9mFregS=t^9Ng=E#n+UE9@_PV1s^KdS^Qic5r>K0g`F@7$QltX4-o zs? #>q?jC)=b)F))Ry!+;0W>TAq*hrR|X;d4yFiU-Y> zf0e{NdANpaICWcNeiqo`Wmaf4BVi_eL$PEkJyfV=kCdUa+`i9KR?S%WzM=8yexzHb zn>Uz`&z`tcf#@$hUiwwl5QsnN=EBHCz}8kME|$jQq&F2UBuj~_G47g$V{U9D;);6F zP0|#W6o5jvkk9b0R=-`!q{;kMpPBt@m?mPRsbe2* S^aur -jFuwRY$i`DMQ0}m*)T{j(zaqR;3q3`Lu9S5q*NluY*a`yyc;0t zA)yyY^7~2&+jqO_lX#6_MbWqxiJ*6c29Z{`E0xEC&7&*&OQBXGDK3t;gDgNo{jB0P zs;mb`w;!u71K|f_=Ecf)#HB0j>C*&Qo3<1e@tW2W+V=#oDQE%a`VhiaHTn#J?6yTv zK-}v^_ Gso?`>=EEy_9wXa#+GPcg-^2 zJe}Zkl0E&YMBkngZkDUg7Q62QcaBkqBBPM7W83oDMq6v^qct_{L}5GytLfjLu;n<_ z2HhMB|6_>nQv#j6IgkbYnbX@h^***u#5M^6LO&3$)-p4+msxHk^i<(F8}Z<{69ia& zh0U6TaVqe&VK?G8r$01KK&YF?#R1dcmaLM}<_RFU3UNC4q^v1cWU!3pF^iLq3^QGo z0Q0rXG(9T{Xj@)FlwoPqzdzxNO6EhmmaCw+7ZWX1ZE_tr#0@QHyU(Jls$?YEo=mr- z@vg3}_B`egu<>j;TDT-*79o6qla!2%|1FMjrtQ6_C8ueqlV6ZYay51h_;9+fd5L4a z{xEY;h`2vuxPG`f<;s 8Jn6e)gn z3f#A6nDJ@qk!_S`Kl9f8mn~~IepxTo>pWF3181z|=)cIN`RKdF&d$E3)(d%u*8zSC z6<@hc(6%Kof$5*{+_J^4DC;ZDPIz1`w @nemev%R5!4Eh_I1PG)y@9!)7Xu=&yvrkV3Q z@HNK&B-SxB1!NYuX6}6)Yl{d-fwZ|69eCcw@MIaovUt9HPAT)+2f~rXGsv=+6~6AG zRaj=HjEmlgjd%ApGamA$0UcQ+bv_92EikDQy_GgBsK1xvew~5p1nge7w3I3*%^9ZF zl`C}RyCLg(t~As&V=V7-#*5wmU>XrOW*-bE8<&{_Qz!wmYrGa6*@;}~#fb=kkbUi( zaz{uY?5@a*q}LU&CflMCdB#U };LR;u}>eAzPVV&FR$DtVg{v zw+Y5uI4Io7+*O+bqbxwocU(l-f=AADOs=bSB_Wgu`k0_xhMFAMEnuu~7Ry|3$ut?7 zwY%MuILGP)J3GMGQnz+K BfYPttwrqrP3g_rp-bWAJk12Oh7K~~O7 z$n|#Q@ceB?s+=gQ$Fu@|6FQyGMr0G*X?!8-58G?&JWrZU+m?cIx{4{vnD3^90 n1!FDzfvv%f t_CU- z2^&_MBFlxS-C<&k@r>eTNbTLS!n4QU6}ev}ZA*v?hsRDajWCaOKFjM0VktPOh@C1g zWHzF1t<&Y3@Or;Y4oSc5W={3F3(>*~=)$m4_rZXDLji3WG$A`sV_tUj*EITvob;-U z#aw7iEJg~FACDiAOW#V5Xl9}B3*HS1O~L1H8`>@g+Pc1C4iXrJ&I|S=W0rh{E7t1! z`3V}AZDzYyM8kx-`PiaaXcET4O*r&u|2Q6aDT;~KNuUH>Mtbe3$Dujxt!<1Gg{b#T z$DKYFW$so-Dj+z^p^B&D;`lK0Y#R+`Da_l#MSnTA_obN@{)Z|aDOc@J@NX&3K&axWxCQE8WGc}p>Z!= zbZeKPd#hHskwyAOU{-?RVP-#RY47M%_E9d4cES{VI(|b_ 8}_A2KW7hG@i?8AVoRfkll4XVnJq~&L^Q*RM1Q1l=(L7^uy zBWkG6j}2`RmGPK%vXj6 Zl@ti;Q7$&S)Te%I!9(Cv(ltAb9GYs6M1FBxd~;?{HNtGKL@F8N9sLxi=JdQO z!pj((mTIVW{7w974C_0J4Vs?|Zc6 Y-fxnu zctbIkZ%mTwRfPU-2;EseixK7DnnVYLvox&gf*9$Ms0*AYCJ6k zt|3ANdiyOf3vD!8IFIqM%bsQmip%Yn;dLk)@OzIi#ZRMTVrOC~Y1o9!Li#_3X;y|3 z%r8 # zwOsjiEjl9KI1 {Vduc-Z3sW%(_4Fsobz-_Ai1Ec zf{9sC5%A-sG&e6r$=`m|oazI>Ys{7p N7-H*EUSh0A|CW&Fq zEfc|5w9G6_^ig9x+gK2m4Kgc}HW80$Y`*=*SmcVy)7vu+i=>e+Gha dxYMBu&q{2dR|ze+H}3-OXu8dO?@u&w-;hW5>3fzy zZ0^W|ENX|J-pnaUz}&31u~Iw2=dR#3JN0>@7VFBifa5@wqKS!JQs`}X{o9EHmCt$F znsK=b;+J&GVX5ePU32zFE;ycGm(-LW4-w2>U5*|L&Bz_dr?{rumFtZn&MQ0b7xPw- zJ(uVduCJ|&X@)Ox +K6?O+L4$o+4Rb_ z(IsZ*n@tY~WLXs>(y}jYzol=T5en=GlgWex*@E9RT6TxD{2Tox#olCVhf=u7WfEFG z8h2fx(D}};UR2Y=JEl~>f#=qc*A%QU*|fKJyZ`Ikml19O*QizM_`DjxHfx)DE@5T* zKhKBXS4BP$1BnZf5STnKFxE>S0T`&_2LddC$YykHxkA%mO#&{%MsIJmtKC+X-{hh* z&@SU+h4rd0-r8+gO743iLV}L`>wST*2Sb8!C$?I3?NC(Hfs$PDkI~nJp@)Xv*bTwe z)GW@>hG9W?!r8(?QnR~f=jPyoZJF7yw0z{_@e)}*2qs$*%JY(`@05>({EB!QFm>GI z=|`~R3oX4G^J$b;LxYENxZbv+Np>;uA+xl49!(+->?lu3RdtZG2PdN!dC;U5^@!af z^{9#64%n*a zbsgiN&Eh%kM{6r^t}|Sly4vQR7b#gHgK3dH!L0d iyu1G*Ym%Pa7Y-M5iS3*_F0c&f~}54W0wza z{$r?bXk56KmG&W^^!q@iO20K`P~q&1X{a6^S}COt8^y5KUce46`0=JBnVn#uuDAc` zTJ>chzBI0=rt9$>*it+N8NK>Zczx7^lenN)oUpaDzV%AQ%G#qg?BpT*M-gogjt^z9tVp_%E=`A!>>#Soa%b;;zs{k50t4U=(HAM_Rp z)nzRvLH9 MobC^FJT0i=XGN~|e`shIy_MqQ zN>ZT%6bbPfg9Yz@$m$4aNYPcV<)Mz}axrn4xf{5(if=wGw^k_XUMjnoJ9{*OCY!?+ zHzaIYNZ${d5ASC}L)94nWxQ`kmy};oK7KzWa}6p!wsy=k7 3-+3z49?Z5}rtx3h#k+mn|<~t=8)0@>~yGRQk zG7Ig65^#z2nSGcq@oWM n;CtF8-vZVy7J3T&op5>vG$o8MDYqtcFWF8i|v~jR4 zoK@|FM!|ryUIrRUD(~eGryt~C^0A*X3XH|&E^#&pxO99sS3e_eF8H6#L|dI =G{;>)uqqgH3gdzLF<&s}hb&q($mm83c1 z0`U=UYgWbqcD2!>x5qghC#e=lNqjHUCSM*j=9-j^Yxz$;(}`nyiH8dKciTz4lx=^< z&q!yT|D^3_HV|LGw{EImR6SJhU==)L+J{V$YVfQ!oLunqR4j`cVhFRU7D>*QL-l)X z$;jX|%xlUA>m@Ps7Rworr>fh2wx M3cCfy z>ukCP*+RCPN^+RtQd${W&^`NkV0O)}=Z4RH#7@53llrMX>j>$ATAs=DZ1C0%vgh7f z8P qo>^d`ygu9V-3(iDcBeMv6o|g4uc0~6OHS7JBZ)fsu3J>bj99oBC z_}?FFeo8RQg&pB>@DYT>c-bh^g*9S{btvT3KoN(>_t}lEPiklLK~D=f{mnk}i(U-z z@7GEBoQBIE^nBS3#hX4^hk7MrbLw}+Jci6Ow;svW*;%X0j P>v1B;8ZjijgQ t2dm(zk;6r9_FIdSt=916f f|h#tT!zl!=R;?C;VCos%@AT^D#e+zPI5&P{5#gw