|
@@ -0,0 +1,333 @@
|
|
|
|
|
+#include "algorithmprocessdialog.h"
|
|
|
|
|
+#include "ui_algorithmprocessdialog.h"
|
|
|
|
|
+#include <QInputDialog>
|
|
|
|
|
+#include <QMessageBox>
|
|
|
|
|
+#include <QFileDialog>
|
|
|
|
|
+#include <QSpinBox>
|
|
|
|
|
+#include <QDoubleSpinBox>
|
|
|
|
|
+#include <QComboBox>
|
|
|
|
|
+#include <QLabel>
|
|
|
|
|
+#include <QVBoxLayout>
|
|
|
|
|
+#include <QHBoxLayout>
|
|
|
|
|
+#include <QPushButton>
|
|
|
|
|
+#include <QDialog>
|
|
|
|
|
+#include <QJsonObject>
|
|
|
|
|
+#include <QTreeWidget>
|
|
|
|
|
+#include <QTreeWidgetItem>
|
|
|
|
|
+#include <QAbstractItemView>
|
|
|
|
|
+#include <Qt>
|
|
|
|
|
+#include <opencv2/opencv.hpp>
|
|
|
|
|
+#include "imageprocessor.h"
|
|
|
|
|
+#include "algorithmparamfactory.h"
|
|
|
|
|
+#include "algorithmregistry.h"
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+AlgorithmProcessDialog::AlgorithmProcessDialog(QWidget *parent) :
|
|
|
|
|
+ QDialog(parent),
|
|
|
|
|
+ ui(new Ui::AlgorithmProcessDialog),
|
|
|
|
|
+ algorithmProcess(nullptr)
|
|
|
|
|
+{
|
|
|
|
|
+ ui->setupUi(this);
|
|
|
|
|
+
|
|
|
|
|
+ // Connect save and load buttons
|
|
|
|
|
+ connect(ui->saveButton, &QPushButton::clicked, this, &AlgorithmProcessDialog::on_saveButton_clicked);
|
|
|
|
|
+ connect(ui->loadButton, &QPushButton::clicked, this, &AlgorithmProcessDialog::on_loadButton_clicked);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+AlgorithmProcessDialog::~AlgorithmProcessDialog()
|
|
|
|
|
+{
|
|
|
|
|
+ delete ui;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void AlgorithmProcessDialog::setAlgorithmProcess(AlgorithmProcess *process)
|
|
|
|
|
+{
|
|
|
|
|
+ algorithmProcess = process;
|
|
|
|
|
+ updateAlgorithmList();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void AlgorithmProcessDialog::updateAlgorithmList()
|
|
|
|
|
+{
|
|
|
|
|
+ if (!algorithmProcess) return;
|
|
|
|
|
+
|
|
|
|
|
+ ui->algorithmListWidget->clear();
|
|
|
|
|
+ for (const auto& step : algorithmProcess->getSteps()) {
|
|
|
|
|
+ ui->algorithmListWidget->addItem(step.name);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void AlgorithmProcessDialog::on_addButton_clicked()
|
|
|
|
|
+{
|
|
|
|
|
+ if (!algorithmProcess) return;
|
|
|
|
|
+
|
|
|
|
|
+ // Create a dialog for algorithm selection with categories
|
|
|
|
|
+ QDialog dialog(this);
|
|
|
|
|
+ dialog.setWindowTitle("Select Algorithm");
|
|
|
|
|
+ dialog.resize(400, 400);
|
|
|
|
|
+
|
|
|
|
|
+ QVBoxLayout *layout = new QVBoxLayout(&dialog);
|
|
|
|
|
+
|
|
|
|
|
+ // Create a tree widget to display algorithm categories
|
|
|
|
|
+ QTreeWidget *treeWidget = new QTreeWidget(&dialog);
|
|
|
|
|
+ treeWidget->setHeaderLabel("Algorithm Categories");
|
|
|
|
|
+ treeWidget->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
|
|
|
+
|
|
|
|
|
+ // Get all algorithms from AlgorithmRegistry
|
|
|
|
|
+ std::vector<std::string> algorithmNames = AlgorithmRegistry::instance().getAllAlgorithmNames();
|
|
|
|
|
+
|
|
|
|
|
+ // Create a single category for all algorithms
|
|
|
|
|
+ QTreeWidgetItem *categoryItem = new QTreeWidgetItem(treeWidget);
|
|
|
|
|
+ categoryItem->setText(0, "All Algorithms");
|
|
|
|
|
+ categoryItem->setExpanded(true);
|
|
|
|
|
+
|
|
|
|
|
+ // Add algorithms to the category
|
|
|
|
|
+ for (const std::string& name : algorithmNames) {
|
|
|
|
|
+ QTreeWidgetItem *algorithmItem = new QTreeWidgetItem(categoryItem);
|
|
|
|
|
+ algorithmItem->setText(0, QString::fromStdString(name));
|
|
|
|
|
+ algorithmItem->setData(0, Qt::UserRole, QString::fromStdString(name));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ layout->addWidget(treeWidget);
|
|
|
|
|
+
|
|
|
|
|
+ // Add buttons
|
|
|
|
|
+ QHBoxLayout *buttonLayout = new QHBoxLayout();
|
|
|
|
|
+ QPushButton *okButton = new QPushButton("OK", &dialog);
|
|
|
|
|
+ QPushButton *cancelButton = new QPushButton("Cancel", &dialog);
|
|
|
|
|
+
|
|
|
|
|
+ buttonLayout->addStretch();
|
|
|
|
|
+ buttonLayout->addWidget(okButton);
|
|
|
|
|
+ buttonLayout->addWidget(cancelButton);
|
|
|
|
|
+
|
|
|
|
|
+ layout->addLayout(buttonLayout);
|
|
|
|
|
+
|
|
|
|
|
+ // Connect buttons
|
|
|
|
|
+ connect(okButton, &QPushButton::clicked, &dialog, &QDialog::accept);
|
|
|
|
|
+ connect(cancelButton, &QPushButton::clicked, &dialog, &QDialog::reject);
|
|
|
|
|
+
|
|
|
|
|
+ // Execute the dialog
|
|
|
|
|
+ if (dialog.exec() == QDialog::Accepted) {
|
|
|
|
|
+ QTreeWidgetItem *selectedItem = treeWidget->currentItem();
|
|
|
|
|
+ if (selectedItem && selectedItem->parent()) {
|
|
|
|
|
+ // Get algorithm name and type
|
|
|
|
|
+ QString algorithmName = selectedItem->text(0);
|
|
|
|
|
+ QString algorithmType = selectedItem->data(0, Qt::UserRole).toString();
|
|
|
|
|
+
|
|
|
|
|
+ // Create parameters JSON object
|
|
|
|
|
+ QJsonObject params;
|
|
|
|
|
+
|
|
|
|
|
+ // Add algorithm with parameters
|
|
|
|
|
+ algorithmProcess->addStep(algorithmName, params);
|
|
|
|
|
+ updateAlgorithmList();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void AlgorithmProcessDialog::on_removeButton_clicked()
|
|
|
|
|
+{
|
|
|
|
|
+ if (!algorithmProcess) return;
|
|
|
|
|
+
|
|
|
|
|
+ int currentRow = ui->algorithmListWidget->currentRow();
|
|
|
|
|
+ if (currentRow >= 0) {
|
|
|
|
|
+ algorithmProcess->removeStep(currentRow);
|
|
|
|
|
+ updateAlgorithmList();
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void AlgorithmProcessDialog::on_editButton_clicked()
|
|
|
|
|
+{
|
|
|
|
|
+
|
|
|
|
|
+ if (!algorithmProcess) return;
|
|
|
|
|
+
|
|
|
|
|
+ int currentRow = ui->algorithmListWidget->currentRow();
|
|
|
|
|
+ if (currentRow >= 0) {
|
|
|
|
|
+ // Get current algorithm step
|
|
|
|
|
+ QVector<AlgorithmProcess::AlgorithmStep> steps = algorithmProcess->getSteps();
|
|
|
|
|
+ AlgorithmProcess::AlgorithmStep currentStep = steps[currentRow];
|
|
|
|
|
+ QString selectedAlgorithm = currentStep.name;
|
|
|
|
|
+ QJsonObject params = currentStep.params;
|
|
|
|
|
+
|
|
|
|
|
+ // Create parameter dialog
|
|
|
|
|
+ QDialog paramDialog(this);
|
|
|
|
|
+ paramDialog.setWindowTitle("Edit Algorithm Parameters");
|
|
|
|
|
+ paramDialog.resize(400, 300);
|
|
|
|
|
+
|
|
|
|
|
+ QVBoxLayout *paramLayout = new QVBoxLayout(¶mDialog);
|
|
|
|
|
+
|
|
|
|
|
+ // Get algorithm meta information from AlgorithmRegistry
|
|
|
|
|
+ AlgorithmMeta algMeta;
|
|
|
|
|
+ std::shared_ptr<AlgorithmBase> algorithm = AlgorithmRegistry::instance().create(selectedAlgorithm.toStdString());
|
|
|
|
|
+ if (algorithm) {
|
|
|
|
|
+ algMeta = algorithm->getParams();
|
|
|
|
|
+ algMeta.type = selectedAlgorithm;
|
|
|
|
|
+ algMeta.name = selectedAlgorithm;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Create parameter widget using factory
|
|
|
|
|
+ QWidget* paramWidget = AlgorithmParamWidgetFactory::createParamWidget(algMeta, ¶mDialog);
|
|
|
|
|
+ paramLayout->addWidget(paramWidget);
|
|
|
|
|
+
|
|
|
|
|
+ // OK button
|
|
|
|
|
+ QPushButton *okButton = new QPushButton("OK", ¶mDialog);
|
|
|
|
|
+ paramLayout->addWidget(okButton);
|
|
|
|
|
+ connect(okButton, &QPushButton::clicked, ¶mDialog, &QDialog::accept);
|
|
|
|
|
+
|
|
|
|
|
+ if (paramDialog.exec() == QDialog::Accepted) {
|
|
|
|
|
+ // Get parameter values
|
|
|
|
|
+ QMap<QString, QVariant> paramValues = AlgorithmParamWidgetFactory::getParamValues(paramWidget);
|
|
|
|
|
+
|
|
|
|
|
+ // Update params
|
|
|
|
|
+ for (auto it = paramValues.begin(); it != paramValues.end(); ++it) {
|
|
|
|
|
+ QString paramName = it.key();
|
|
|
|
|
+ QVariant paramValue = it.value();
|
|
|
|
|
+
|
|
|
|
|
+ if (paramValue.type() == QVariant::Int) {
|
|
|
|
|
+ params[paramName] = paramValue.toInt();
|
|
|
|
|
+ } else if (paramValue.type() == QVariant::Double) {
|
|
|
|
|
+ params[paramName] = paramValue.toDouble();
|
|
|
|
|
+ } else if (paramValue.type() == QVariant::Bool) {
|
|
|
|
|
+ params[paramName] = paramValue.toBool();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Update algorithm step with new parameters
|
|
|
|
|
+ steps[currentRow].params = params;
|
|
|
|
|
+
|
|
|
|
|
+ // Clear and re-add all steps to update the algorithm process
|
|
|
|
|
+ algorithmProcess->clearSteps();
|
|
|
|
|
+ for (const auto& step : steps) {
|
|
|
|
|
+ algorithmProcess->addStep(step.name, step.params);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ updateAlgorithmList();
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void AlgorithmProcessDialog::on_moveUpButton_clicked()
|
|
|
|
|
+{
|
|
|
|
|
+ if (!algorithmProcess) return;
|
|
|
|
|
+
|
|
|
|
|
+ int currentRow = ui->algorithmListWidget->currentRow();
|
|
|
|
|
+ if (currentRow > 0) {
|
|
|
|
|
+ // Get current steps
|
|
|
|
|
+ QVector<AlgorithmProcess::AlgorithmStep> steps = algorithmProcess->getSteps();
|
|
|
|
|
+
|
|
|
|
|
+ // Swap steps
|
|
|
|
|
+ std::swap(steps[currentRow], steps[currentRow - 1]);
|
|
|
|
|
+
|
|
|
|
|
+ // Clear and re-add all steps
|
|
|
|
|
+ algorithmProcess->clearSteps();
|
|
|
|
|
+ for (const auto& step : steps) {
|
|
|
|
|
+ algorithmProcess->addStep(step.name, step.params);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Update list and select the new position
|
|
|
|
|
+ updateAlgorithmList();
|
|
|
|
|
+ ui->algorithmListWidget->setCurrentRow(currentRow - 1);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void AlgorithmProcessDialog::on_moveDownButton_clicked()
|
|
|
|
|
+{
|
|
|
|
|
+ if (!algorithmProcess) return;
|
|
|
|
|
+
|
|
|
|
|
+ int currentRow = ui->algorithmListWidget->currentRow();
|
|
|
|
|
+ QVector<AlgorithmProcess::AlgorithmStep> steps = algorithmProcess->getSteps();
|
|
|
|
|
+ if (currentRow < steps.size() - 1) {
|
|
|
|
|
+ // Swap steps
|
|
|
|
|
+ std::swap(steps[currentRow], steps[currentRow + 1]);
|
|
|
|
|
+
|
|
|
|
|
+ // Clear and re-add all steps
|
|
|
|
|
+ algorithmProcess->clearSteps();
|
|
|
|
|
+ for (const auto& step : steps) {
|
|
|
|
|
+ algorithmProcess->addStep(step.name, step.params);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Update list and select the new position
|
|
|
|
|
+ updateAlgorithmList();
|
|
|
|
|
+ ui->algorithmListWidget->setCurrentRow(currentRow + 1);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void AlgorithmProcessDialog::on_executeButton_clicked()
|
|
|
|
|
+{
|
|
|
|
|
+ if (!algorithmProcess) return;
|
|
|
|
|
+
|
|
|
|
|
+ // Open file dialog to select image
|
|
|
|
|
+ QString imagePath = QFileDialog::getOpenFileName(
|
|
|
|
|
+ this,
|
|
|
|
|
+ "Select Image",
|
|
|
|
|
+ "",
|
|
|
|
|
+ "Image Files (*.png *.jpg *.bmp *.jpeg)"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ if (!imagePath.isEmpty()) {
|
|
|
|
|
+ // Read image using OpenCV
|
|
|
|
|
+ cv::Mat image = cv::imread(imagePath.toStdString());
|
|
|
|
|
+ if (image.empty()) {
|
|
|
|
|
+ QMessageBox::warning(this, "Error", "Failed to load image!");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Execute algorithm process
|
|
|
|
|
+ cv::Mat result = algorithmProcess->execute(image);
|
|
|
|
|
+
|
|
|
|
|
+ // Save result
|
|
|
|
|
+ QString savePath = QFileDialog::getSaveFileName(
|
|
|
|
|
+ this,
|
|
|
|
|
+ "Save Result",
|
|
|
|
|
+ "",
|
|
|
|
|
+ "Image Files (*.png *.jpg *.bmp *.jpeg)"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ if (!savePath.isEmpty()) {
|
|
|
|
|
+ cv::imwrite(savePath.toStdString(), result);
|
|
|
|
|
+ QMessageBox::information(this, "Success", "Image processed and saved successfully!");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void AlgorithmProcessDialog::on_saveButton_clicked()
|
|
|
|
|
+{
|
|
|
|
|
+ if (!algorithmProcess) return;
|
|
|
|
|
+
|
|
|
|
|
+ // Open file dialog to select save location
|
|
|
|
|
+ QString filePath = QFileDialog::getSaveFileName(
|
|
|
|
|
+ this,
|
|
|
|
|
+ "Save Algorithm Process",
|
|
|
|
|
+ "",
|
|
|
|
|
+ "Algorithm Process Files (*.vm);;All Files (*.*)"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ if (!filePath.isEmpty()) {
|
|
|
|
|
+ // Save algorithm process
|
|
|
|
|
+ if (algorithmProcess->saveToFile(filePath)) {
|
|
|
|
|
+ QMessageBox::information(this, "Success", "Algorithm process saved successfully!");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ QMessageBox::warning(this, "Error", "Failed to save algorithm process!");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void AlgorithmProcessDialog::on_loadButton_clicked()
|
|
|
|
|
+{
|
|
|
|
|
+ if (!algorithmProcess) return;
|
|
|
|
|
+
|
|
|
|
|
+ // Open file dialog to select file to load
|
|
|
|
|
+ QString filePath = QFileDialog::getOpenFileName(
|
|
|
|
|
+ this,
|
|
|
|
|
+ "Load Algorithm Process",
|
|
|
|
|
+ "",
|
|
|
|
|
+ "Algorithm Process Files (*.vm);;All Files (*.*)"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ if (!filePath.isEmpty()) {
|
|
|
|
|
+ // Load algorithm process
|
|
|
|
|
+ if (algorithmProcess->loadFromFile(filePath)) {
|
|
|
|
|
+ updateAlgorithmList();
|
|
|
|
|
+ QMessageBox::information(this, "Success", "Algorithm process loaded successfully!");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ QMessageBox::warning(this, "Error", "Failed to load algorithm process!");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|