├── .gitignore ├── CMakeLists.txt ├── CMakePresets.json ├── LICENSE ├── README.md ├── conanfile.txt ├── resources ├── gif │ ├── convert_color.gif │ ├── detect_multiscale.gif │ ├── detect_multiscale_on_original.gif │ └── scale.gif └── images │ ├── images.qrc │ ├── logo.png │ ├── person.jpg │ └── preview.png ├── scripts ├── appimage_deploy.py ├── compile.sh └── setup.sh └── src ├── CustomWidget ├── CheckBoxReadOnly.cpp ├── CheckBoxReadOnly.h ├── DragableTreeOfNodes.cpp ├── DragableTreeOfNodes.h ├── DropGraphicsView.cpp └── DropGraphicsView.h ├── Nodes ├── Basic │ ├── AdditionModel.h │ ├── DivisionModel.h │ ├── MathOperationDataModel.cpp │ ├── MathOperationDataModel.hpp │ ├── MultiplicationModel.hpp │ ├── NumberDisplayDataModel.cpp │ ├── NumberDisplayDataModel.hpp │ ├── NumberSourceDataModel.cpp │ ├── NumberSourceDataModel.hpp │ └── SubtractionModel.h ├── Constants │ ├── PiModel.cpp │ └── PiModel.h ├── Conversor │ ├── MatQt.cpp │ └── MatQt.h ├── Data │ ├── CascadeClassifierData.h │ ├── DataInclude.h │ ├── FileData.h │ ├── ImageData.h │ ├── ImageFormatData.h │ ├── LinesSegmentData.h │ ├── PointData.h │ ├── RectData.h │ ├── RectsData.h │ └── VariantData.h ├── DataOperations │ ├── ScaleRects.cpp │ └── ScaleRects.h ├── Images │ ├── ConvertImageToForm.ui │ ├── ConvertImageToModel.cpp │ ├── ConvertImageToModel.h │ ├── CutImageModel.cpp │ ├── CutImageModel.h │ ├── DrawLinesForm.ui │ ├── DrawLinesModel.cpp │ ├── DrawLinesModel.h │ ├── DrawRectsForm.ui │ ├── DrawRectsModel.cpp │ ├── DrawRectsModel.h │ ├── ImageInfoForm.ui │ ├── ImageInfoModel.cpp │ ├── ImageInfoModel.h │ ├── ImageLoaderModel.cpp │ ├── ImageLoaderModel.hpp │ ├── ImageShowModel.cpp │ ├── ImageShowModel.hpp │ ├── ScaleImageForm.ui │ ├── ScaleImageModel.cpp │ └── ScaleImageModel.h ├── NodesInclude.cpp ├── NodesInclude.h ├── OpenCV │ ├── BlurForm.ui │ ├── BlurModel.cpp │ ├── BlurModel.h │ ├── CannyForm.ui │ ├── CannyModel.cpp │ ├── CannyModel.h │ ├── CascadeClassifierForm.ui │ ├── CascadeClassifierModel.cpp │ ├── CascadeClassifierModel.h │ ├── ColorCVModel.cpp │ ├── ColorCVModel.h │ ├── DetectMultiScaleForm.ui │ ├── DetectMultiScaleModel.cpp │ ├── DetectMultiScaleModel.h │ ├── EqualizeHistModel.cpp │ ├── EqualizeHistModel.h │ ├── FacialDetectorModel.cpp │ ├── FacialDetectorModel.h │ ├── GaussianBlurForm.ui │ ├── GaussianBlurModel.cpp │ ├── GaussianBlurModel.h │ ├── HoughLinesPForm.ui │ ├── HoughLinesPModel.cpp │ ├── HoughLinesPModel.h │ ├── PyrDown.cpp │ ├── PyrDown.h │ ├── PyrUp.cpp │ ├── PyrUp.h │ ├── RectangleForm.ui │ ├── RectangleModel.cpp │ └── RectangleModel.h ├── Variables │ ├── FileFromUrlForm.ui │ ├── FileFromUrlModel.cpp │ ├── FileFromUrlModel.h │ ├── FileVarForm.ui │ ├── FileVarModel.cpp │ ├── FileVarModel.h │ ├── RectForm.ui │ ├── RectModel.cpp │ ├── RectModel.h │ ├── RectVarModel.cpp │ ├── RectVarModel.h │ ├── SizeVarForm.ui │ ├── SizeVarModel.cpp │ └── SizeVarModel.h └── Video │ ├── CameraForm.ui │ ├── CameraModel.cpp │ ├── CameraModel.h │ ├── CaptureModel.cpp │ └── CaptureModel.h ├── Widgets ├── MainWindow.cpp ├── MainWindow.h └── MainWindow.ui └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | 3rdparty/ 2 | .conan*/ 3 | cmake-build*/ 4 | cmake_build*/ 5 | .vscode/ 6 | CMakeUserPresets.json 7 | linuxdeploy* 8 | .idea 9 | .venv -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 6, 3 | "cmakeMinimumRequired": { 4 | "major": 3, 5 | "minor": 26, 6 | "patch": 0 7 | }, 8 | "configurePresets": [ 9 | { 10 | "name": "default-debug", 11 | "hidden": true, 12 | "generator": "Ninja", 13 | "description": "Use this preset for Debug builds", 14 | "cacheVariables": { 15 | "CMAKE_BUILD_TYPE": "Debug", 16 | "CMAKE_TOOLCHAIN_FILE": ".conan/Debug/conan_toolchain.cmake" 17 | } 18 | }, 19 | { 20 | "name": "default-release", 21 | "hidden": true, 22 | "generator": "Ninja", 23 | "description": "Use this preset for Release builds", 24 | "cacheVariables": { 25 | "CMAKE_BUILD_TYPE": "Release", 26 | "CMAKE_TOOLCHAIN_FILE": ".conan/Release/conan_toolchain.cmake" 27 | } 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 PabloPicose 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /conanfile.txt: -------------------------------------------------------------------------------- 1 | [requires] 2 | opencv/4.8.1 3 | 4 | [generators] 5 | CMakeDeps 6 | CMakeToolchain 7 | 8 | [options] 9 | opencv/*:ml=True 10 | opencv/*:dnn=True 11 | opencv/*:objdetect=True 12 | opencv/*:imgproc=True 13 | opencv/*:imgcodecs=True 14 | opencv/*:features2d=True 15 | opencv/*:calib3d=True 16 | opencv/*:highgui=False 17 | opencv/*:videoio=False 18 | opencv/*:gapi=False 19 | opencv/*:with_wayland=False -------------------------------------------------------------------------------- /resources/gif/convert_color.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PabloPicose/ComputerVisionBlueprint/21d38fb844709160cdd51426ea31ee176e462f97/resources/gif/convert_color.gif -------------------------------------------------------------------------------- /resources/gif/detect_multiscale.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PabloPicose/ComputerVisionBlueprint/21d38fb844709160cdd51426ea31ee176e462f97/resources/gif/detect_multiscale.gif -------------------------------------------------------------------------------- /resources/gif/detect_multiscale_on_original.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PabloPicose/ComputerVisionBlueprint/21d38fb844709160cdd51426ea31ee176e462f97/resources/gif/detect_multiscale_on_original.gif -------------------------------------------------------------------------------- /resources/gif/scale.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PabloPicose/ComputerVisionBlueprint/21d38fb844709160cdd51426ea31ee176e462f97/resources/gif/scale.gif -------------------------------------------------------------------------------- /resources/images/images.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | logo.png 4 | 5 | -------------------------------------------------------------------------------- /resources/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PabloPicose/ComputerVisionBlueprint/21d38fb844709160cdd51426ea31ee176e462f97/resources/images/logo.png -------------------------------------------------------------------------------- /resources/images/person.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PabloPicose/ComputerVisionBlueprint/21d38fb844709160cdd51426ea31ee176e462f97/resources/images/person.jpg -------------------------------------------------------------------------------- /resources/images/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PabloPicose/ComputerVisionBlueprint/21d38fb844709160cdd51426ea31ee176e462f97/resources/images/preview.png -------------------------------------------------------------------------------- /scripts/compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Initialize variables 4 | QT_DIR="" 5 | BUILD_TYPE="" 6 | 7 | # Function to print the usage of the script 8 | print_usage() { 9 | echo "Usage: $0 --qt --type " 10 | echo "Example: $0 --qt /opt/Qt5.12.10 --type debug" 11 | } 12 | 13 | # Parse command line arguments 14 | while [ "$#" -gt 0 ]; do 15 | case "$1" in 16 | --qt) 17 | QT_DIR="$2" 18 | shift 2 19 | ;; 20 | --type) 21 | BUILD_TYPE="$2" 22 | if [[ "$BUILD_TYPE" != "debug" && "$BUILD_TYPE" != "release" ]]; then 23 | echo "Error: --type must be 'debug' or 'release'." 24 | print_usage 25 | exit 1 26 | fi 27 | shift 2 28 | ;; 29 | *) 30 | echo "Unknown option: $1" 31 | print_usage 32 | exit 1 33 | ;; 34 | esac 35 | done 36 | 37 | # Check if both arguments were provided 38 | if [ -z "$QT_DIR" ] || [ -z "$BUILD_TYPE" ]; then 39 | echo "Error: Both --qt and --type arguments are required." 40 | print_usage 41 | exit 1 42 | fi 43 | 44 | # Configure and generate the build system 45 | if [ "$BUILD_TYPE" = "debug" ]; then 46 | cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=.conan_debug/conan_toolchain.cmake -B cmake-build-debug -S . -DCMAKE_PREFIX_PATH="$QT_DIR" 47 | cmake --build cmake-build-debug --target all 48 | else 49 | cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=.conan_rel/conan_toolchain.cmake -B cmake-build-release -S . -DCMAKE_PREFIX_PATH="$QT_DIR" 50 | cmake --build cmake-build-release --target all 51 | fi 52 | -------------------------------------------------------------------------------- /scripts/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Source the os-release to get distribution info 4 | source /etc/os-release 5 | 6 | setupConan() { 7 | echo "Setting up Conan..." 8 | # if the command conan --version returns a non-zero status code then install conan via pip install conan==2.11 9 | # Check if the version of conan is 2.11 10 | if ! conan --version | grep -q "2.11"; then 11 | echo "Conan version is not 2.11. Installing Conan..." 12 | pip install conan==2.11 13 | fi 14 | 15 | # check for the conan profile, if the conan profile "ComputerVisionRel" does not exist then create it 16 | conan profile detect -e 17 | } 18 | 19 | # Function to setup dependencies for Ubuntu 20 | setupUbuntuDeps() { 21 | echo "Setting up dependencies for Ubuntu..." 22 | sudo apt install -y libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-sync1 libxcb-xfixes0 libxcb-shape0 libx11-xcb1 python3-venv ninja-build build-essential cmake libxkbcommon-x11-0 libxcb-icccm4 pkg-config git libegl1-mesa libegl1-mesa-dev libpulse-dev fuse 23 | } 24 | 25 | # Main script starts here 26 | # Check if the distribution is Ubuntu 27 | if [ "$ID" = "ubuntu" ]; then 28 | setupUbuntuDeps 29 | else 30 | echo "Dependencies autoinstall is only available in ubuntu. Detected: $PRETTY_NAME" 31 | fi 32 | 33 | # Create a virtual environment on the current directory .venv 34 | python3 -m venv .venv 35 | source .venv/bin/activate 36 | 37 | # Upgrade pip 38 | pip install --upgrade pip 39 | setupConan 40 | # Install conan dependencies 41 | conan install . --output-folder=.conan/Debug --build=missing --settings=build_type=Debug -c tools.system.package_manager:mode=install 42 | conan install . --output-folder=.conan/Release --build=missing --settings=build_type=Release -c tools.system.package_manager:mode=install 43 | 44 | # check if the 3rdparty/nodeeditor directory exists 45 | if [ -d "3rdparty/nodeeditor" ]; then 46 | echo "Nodeeditor already exists. Skipping..." 47 | else 48 | echo "Cloning Nodeeditor..." 49 | # clone inside the 3rdparty directory https://github.com/paceholder/nodeeditor.git 50 | git clone https://github.com/paceholder/nodeeditor.git 3rdparty/nodeeditor 51 | fi 52 | -------------------------------------------------------------------------------- /src/CustomWidget/CheckBoxReadOnly.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/29/24. 3 | // 4 | 5 | #include "CheckBoxReadOnly.h" 6 | #include 7 | 8 | CheckBoxReadOnly::CheckBoxReadOnly(QWidget* parent) : QCheckBox(parent) { 9 | setAttribute(Qt::WA_TransparentForMouseEvents); 10 | setFocusPolicy(Qt::NoFocus); 11 | } 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/CustomWidget/CheckBoxReadOnly.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/29/24. 3 | // 4 | 5 | #ifndef CHECKBOXREADONLY_H 6 | #define CHECKBOXREADONLY_H 7 | 8 | #include 9 | 10 | class CheckBoxReadOnly final: public QCheckBox { 11 | Q_OBJECT 12 | 13 | public: 14 | explicit CheckBoxReadOnly(QWidget* parent = nullptr); 15 | 16 | ~CheckBoxReadOnly() override = default; 17 | }; 18 | 19 | 20 | #endif //CHECKBOXREADONLY_H 21 | -------------------------------------------------------------------------------- /src/CustomWidget/DragableTreeOfNodes.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/11/24. 3 | // 4 | 5 | #include "DragableTreeOfNodes.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | DragableTreeOfNodes::DragableTreeOfNodes(QWidget* parent) : QTreeWidget(parent) { 13 | setDragEnabled(true); 14 | setSelectionMode(QAbstractItemView::SingleSelection); 15 | } 16 | 17 | DragableTreeOfNodes::~DragableTreeOfNodes() = default; 18 | 19 | void DragableTreeOfNodes::fillTreeWidget(const std::shared_ptr& registers) { 20 | const auto mapRegister = registers->registeredModelsCategoryAssociation(); 21 | // print the categories from map 22 | for (auto it = mapRegister.begin(); it != mapRegister.end(); ++it) { 23 | const QString group = it->second; 24 | const QString name = it->first; 25 | m_mapGroupNames[group].append(name); 26 | } 27 | // now sort the names 28 | for (auto it = m_mapGroupNames.begin(); it != m_mapGroupNames.end(); ++it) { 29 | it.value().sort(); 30 | } 31 | for (auto it = m_mapGroupNames.begin(); it != m_mapGroupNames.end(); ++it) { 32 | QTreeWidgetItem* parent = new QTreeWidgetItem(this); 33 | parent->setText(0, it.key()); 34 | for (auto name: it.value()) { 35 | auto child = new QTreeWidgetItem(parent); 36 | child->setText(1, name); 37 | } 38 | } 39 | 40 | // show all the items 41 | expandAll(); 42 | // resize columns to contents 43 | resizeColumnToContents(0); 44 | resizeColumnToContents(1); 45 | } 46 | 47 | void DragableTreeOfNodes::startDrag(Qt::DropActions supportedActions) { 48 | // only the childs nodes with the name filled will be dragged 49 | if (!currentItem() || currentItem()->text(1).isEmpty()) { 50 | return; 51 | } 52 | const QString name = currentItem()->text(1); 53 | QMimeData* mimeData = new QMimeData; 54 | mimeData->setText(name); 55 | // create a drag object 56 | QDrag* drag = new QDrag(this); 57 | drag->setMimeData(mimeData); 58 | // Create a pixmap to display the text being dragged 59 | QPixmap pixmap(100, 30); // Adjust size as needed 60 | pixmap.fill(Qt::white); // Background color 61 | QPainter painter(&pixmap); 62 | painter.setPen(Qt::black); // Text color 63 | painter.drawText(pixmap.rect(), Qt::AlignCenter, name); // Draw the text on the pixmap 64 | drag->setPixmap(pixmap); 65 | 66 | drag->exec(supportedActions); 67 | } 68 | -------------------------------------------------------------------------------- /src/CustomWidget/DragableTreeOfNodes.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/11/24. 3 | // 4 | 5 | #ifndef DRAGABLETREEOFNODES_H 6 | #define DRAGABLETREEOFNODES_H 7 | 8 | #include 9 | 10 | namespace QtNodes { 11 | class NodeDelegateModelRegistry; 12 | } 13 | 14 | class DragableTreeOfNodes final : public QTreeWidget { 15 | Q_OBJECT 16 | 17 | public: 18 | explicit DragableTreeOfNodes(QWidget* parent = nullptr); 19 | 20 | ~DragableTreeOfNodes() override; 21 | 22 | void fillTreeWidget(const std::shared_ptr& registers); 23 | 24 | QMap getMapGroupNames() const { return m_mapGroupNames; } 25 | 26 | protected: 27 | void startDrag(Qt::DropActions supportedActions) override; 28 | private: 29 | QMap m_mapGroupNames; 30 | }; 31 | 32 | 33 | #endif //DRAGABLETREEOFNODES_H 34 | -------------------------------------------------------------------------------- /src/CustomWidget/DropGraphicsView.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/11/24. 3 | // 4 | 5 | #include "DropGraphicsView.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "UndoCommands.hpp" 13 | 14 | DropGraphicsView::DropGraphicsView(QWidget* parent) : QtNodes::GraphicsView(parent) { 15 | setAcceptDrops(true); 16 | } 17 | 18 | void DropGraphicsView::setMapGroupNames(const QMap& mapGroupNames) { 19 | m_mapGroupNames = mapGroupNames; 20 | } 21 | 22 | bool DropGraphicsView::isNameContained(const QString& name) const { 23 | for (auto it = m_mapGroupNames.begin(); it != m_mapGroupNames.end(); ++it) { 24 | if (it.value().contains(name)) { 25 | return true; 26 | } 27 | } 28 | return false; 29 | } 30 | 31 | DropGraphicsView::~DropGraphicsView() { 32 | } 33 | 34 | void DropGraphicsView::placeNodeInScene(const QString& name, const QPoint& mousePos) { 35 | const auto scenePos = mapToScene(mousePos); 36 | m_Nodesscene->undoStack().push(new QtNodes::CreateCommand(m_Nodesscene, name, scenePos)); 37 | } 38 | 39 | void DropGraphicsView::dragEnterEvent(QDragEnterEvent* event) { 40 | if (event->mimeData()->hasText()) { 41 | const QString droppedText = event->mimeData()->text(); 42 | if (isNameContained(droppedText)) { 43 | event->accept(); 44 | } else { 45 | event->ignore(); 46 | } 47 | } else { 48 | event->ignore(); 49 | } 50 | } 51 | 52 | void DropGraphicsView::dropEvent(QDropEvent* event) { 53 | if (event->mimeData()->hasText()) { 54 | // check if the name is contained in the map 55 | const QString droppedText = event->mimeData()->text(); 56 | if (isNameContained(droppedText)) { 57 | placeNodeInScene(droppedText, event->position().toPoint()); 58 | event->acceptProposedAction(); 59 | } else { 60 | event->ignore(); 61 | } 62 | } else { 63 | event->ignore(); 64 | } 65 | } 66 | 67 | void DropGraphicsView::dragMoveEvent(QDragMoveEvent* event) { 68 | if (event->mimeData()->hasText()) { // Or any other condition you want to check 69 | event->acceptProposedAction(); 70 | } else { 71 | event->ignore(); 72 | } 73 | } 74 | 75 | void DropGraphicsView::dragLeaveEvent(QDragLeaveEvent* event) { 76 | event->accept(); 77 | } 78 | -------------------------------------------------------------------------------- /src/CustomWidget/DropGraphicsView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/11/24. 3 | // 4 | 5 | #ifndef DROPGRAPHICSVIEW_H 6 | #define DROPGRAPHICSVIEW_H 7 | 8 | #include 9 | 10 | namespace QtNodes { 11 | class DataFlowGraphicsScene; 12 | } 13 | 14 | class DropGraphicsView final : public QtNodes::GraphicsView { 15 | Q_OBJECT 16 | 17 | public: 18 | explicit DropGraphicsView(QWidget* parent = nullptr); 19 | 20 | void setDataFlowScene(QtNodes::DataFlowGraphicsScene* scene) { m_Nodesscene = scene; } 21 | 22 | void setMapGroupNames(const QMap& mapGroupNames); 23 | 24 | bool isNameContained(const QString& name) const; 25 | 26 | ~DropGraphicsView() override; 27 | 28 | void placeNodeInScene(const QString& name, const QPoint& mousePos); 29 | 30 | protected: 31 | void dragEnterEvent(QDragEnterEvent* event) override; 32 | 33 | void dropEvent(QDropEvent* event) override; 34 | 35 | void dragMoveEvent(QDragMoveEvent* event) override; 36 | 37 | void dragLeaveEvent(QDragLeaveEvent* event) override; 38 | 39 | private: 40 | QtNodes::DataFlowGraphicsScene* m_Nodesscene = nullptr; 41 | 42 | QMap m_mapGroupNames; 43 | }; 44 | 45 | 46 | #endif //DROPGRAPHICSVIEW_H 47 | -------------------------------------------------------------------------------- /src/Nodes/Basic/AdditionModel.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "MathOperationDataModel.hpp" 4 | 5 | class AdditionModel : public MathOperationDataModel 6 | { 7 | public: 8 | ~AdditionModel() override = default; 9 | 10 | public: 11 | QString caption() const override { return QStringLiteral("Addition"); } 12 | 13 | QString name() const override { return QStringLiteral("Addition"); } 14 | 15 | private: 16 | 17 | const QMap> _allowedTypes = { 18 | {QMetaType::Int, {QMetaType::Int, QMetaType::Double}}, 19 | {QMetaType::Double, {QMetaType::Int, QMetaType::Double}}, 20 | {QMetaType::Float, {QMetaType::Int, QMetaType::Double}}, 21 | {QMetaType::QSize, {QMetaType::QSize, QMetaType::Int, QMetaType::Double, QMetaType::Float}}, 22 | }; 23 | 24 | std::shared_ptr compute() const override { 25 | const auto n1 = _number1.lock(); 26 | const auto n2 = _number2.lock(); 27 | if (!n1 || !n2) { 28 | return std::make_shared(); 29 | } 30 | // check if allowed 31 | if (!_allowedTypes.contains(n1->metaType()) || !_allowedTypes[n1->metaType()].contains(n2->metaType())) { 32 | return std::make_shared(); 33 | } 34 | // switch on the type of the dividend 35 | switch (n1->metaType()) { 36 | case QMetaType::Int: { 37 | const int first = n1->variant().toInt(); 38 | // switch on the type of the divisor 39 | switch (n2->metaType()) { 40 | case QMetaType::Int: { 41 | const int second = n2->variant().toInt(); 42 | return std::make_shared(first + second); 43 | } 44 | case QMetaType::Double: { 45 | const double second = n2->variant().toDouble(); 46 | return std::make_shared(first + second); 47 | } 48 | default: 49 | return std::make_shared(); 50 | } 51 | } 52 | case QMetaType::Double: { 53 | const double first = n1->variant().toDouble(); 54 | // switch on the type of the divisor 55 | switch (n2->metaType()) { 56 | case QMetaType::Int: { 57 | const int second = n2->variant().toInt(); 58 | return std::make_shared(first + second); 59 | } 60 | case QMetaType::Double: { 61 | const double second = n2->variant().toDouble(); 62 | return std::make_shared(first + second); 63 | } 64 | default: 65 | return std::make_shared(); 66 | } 67 | } 68 | case QMetaType::Float: { 69 | const float first = n1->variant().toFloat(); 70 | // switch on the type of the divisor 71 | switch (n2->metaType()) { 72 | case QMetaType::Int: { 73 | const int second = n2->variant().toInt(); 74 | return std::make_shared(first + second); 75 | } 76 | case QMetaType::Double: { 77 | const double second = n2->variant().toDouble(); 78 | return std::make_shared(first + second); 79 | } 80 | default: 81 | return std::make_shared(); 82 | } 83 | } 84 | case QMetaType::QSize: { 85 | const QSize first = n1->variant().toSize(); 86 | // switch on the type of the divisor 87 | switch (n2->metaType()) { 88 | case QMetaType::QSize: { 89 | const QSize second = n2->variant().toSize(); 90 | return std::make_shared(first + second); 91 | } 92 | case QMetaType::Int: { 93 | const int second = n2->variant().toInt(); 94 | return std::make_shared(QSize(first.width() + second, first.height() + second)); 95 | } 96 | case QMetaType::Double: { 97 | const double second = n2->variant().toDouble(); 98 | return std::make_shared(QSize(first.width() + second, first.height() + second)); 99 | } 100 | case QMetaType::Float: { 101 | const float second = n2->variant().toFloat(); 102 | return std::make_shared(QSize(first.width() + second, first.height() + second)); 103 | } 104 | default: 105 | qCritical() << "AdditionModel::compute: invalid type"; 106 | return std::make_shared(); 107 | } 108 | } 109 | default: 110 | qCritical() << "AdditionModel::compute: unknown type of dividend"; 111 | return std::make_shared(); 112 | } 113 | } 114 | }; 115 | -------------------------------------------------------------------------------- /src/Nodes/Basic/MathOperationDataModel.cpp: -------------------------------------------------------------------------------- 1 | #include "MathOperationDataModel.hpp" 2 | 3 | 4 | unsigned int MathOperationDataModel::nPorts(QtNodes::PortType portType) const 5 | { 6 | unsigned int result; 7 | 8 | if (portType == QtNodes::PortType::In) 9 | result = 2; 10 | else 11 | result = 1; 12 | 13 | return result; 14 | } 15 | 16 | QtNodes::NodeDataType MathOperationDataModel::dataType(QtNodes::PortType portType, QtNodes::PortIndex) const 17 | { 18 | switch (portType) { 19 | case QtNodes::PortType::In: { 20 | const auto lock1 = _number1.lock(); 21 | if (lock1) { 22 | return lock1->typeIn(); 23 | } else { 24 | return VariantData().type(); 25 | } 26 | const auto lock2 = _number2.lock(); 27 | if (lock2) { 28 | return lock2->typeIn(); 29 | } else { 30 | return VariantData().type(); 31 | } 32 | } 33 | case QtNodes::PortType::Out: { 34 | if (_result) { 35 | return _result->type(); 36 | } else { 37 | return VariantData().type(); 38 | } 39 | } 40 | default: 41 | return VariantData().type(); 42 | } 43 | } 44 | 45 | std::shared_ptr MathOperationDataModel::outData(QtNodes::PortIndex) 46 | { 47 | return _result; 48 | } 49 | 50 | void MathOperationDataModel::setInData(std::shared_ptr const data, QtNodes::PortIndex portIndex) 51 | { 52 | const auto numberData = std::dynamic_pointer_cast(data); 53 | 54 | if (!data) { 55 | Q_EMIT dataInvalidated(0); 56 | } 57 | 58 | if (portIndex == 0) { 59 | _number1 = numberData; 60 | } else { 61 | _number2 = numberData; 62 | } 63 | 64 | _result = compute(); 65 | emit dataUpdated(0); 66 | } 67 | -------------------------------------------------------------------------------- /src/Nodes/Basic/MathOperationDataModel.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Nodes/Data/VariantData.h" 8 | 9 | 10 | /// The model dictates the number of inputs and outputs for the Node. 11 | /// In this example it has no logic. 12 | class MathOperationDataModel : public QtNodes::NodeDelegateModel 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | ~MathOperationDataModel() override = default; 18 | 19 | public: 20 | unsigned int nPorts(QtNodes::PortType portType) const override; 21 | 22 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 23 | 24 | std::shared_ptr outData(QtNodes::PortIndex port) override; 25 | 26 | void setInData(std::shared_ptr data, QtNodes::PortIndex portIndex) override; 27 | 28 | QWidget *embeddedWidget() override { return nullptr; } 29 | 30 | protected: 31 | virtual std::shared_ptr compute() const = 0; 32 | 33 | protected: 34 | std::weak_ptr _number1; 35 | std::weak_ptr _number2; 36 | private: 37 | std::shared_ptr _result; 38 | }; 39 | -------------------------------------------------------------------------------- /src/Nodes/Basic/NumberDisplayDataModel.cpp: -------------------------------------------------------------------------------- 1 | #include "NumberDisplayDataModel.hpp" 2 | 3 | #include 4 | 5 | NumberDisplayDataModel::NumberDisplayDataModel() 6 | : _label{nullptr} 7 | {} 8 | 9 | unsigned int NumberDisplayDataModel::nPorts(PortType portType) const 10 | { 11 | unsigned int result = 1; 12 | 13 | switch (portType) { 14 | case PortType::In: 15 | result = 1; 16 | break; 17 | 18 | case PortType::Out: 19 | result = 0; 20 | 21 | default: 22 | break; 23 | } 24 | 25 | return result; 26 | } 27 | 28 | NodeDataType NumberDisplayDataModel::dataType(PortType, PortIndex) const 29 | { 30 | const auto lockData = _numberData.lock(); 31 | if (lockData) { 32 | return lockData->typeIn(); 33 | } else { 34 | return VariantData().typeIn(); 35 | } 36 | } 37 | 38 | std::shared_ptr NumberDisplayDataModel::outData(PortIndex) 39 | { 40 | std::shared_ptr ptr; 41 | return ptr; 42 | } 43 | 44 | void NumberDisplayDataModel::setInData(std::shared_ptr data, PortIndex portIndex) 45 | { 46 | _numberData = std::dynamic_pointer_cast(data); 47 | const auto lockData = _numberData.lock(); 48 | 49 | if (!_label) 50 | return; 51 | 52 | if (lockData) { 53 | _label->setText(lockData->toString()); 54 | } else { 55 | _label->clear(); 56 | } 57 | 58 | _label->adjustSize(); 59 | } 60 | 61 | QWidget *NumberDisplayDataModel::embeddedWidget() 62 | { 63 | if (!_label) { 64 | _label = new QLabel(); 65 | _label->setMargin(3); 66 | } 67 | 68 | return _label; 69 | } 70 | -------------------------------------------------------------------------------- /src/Nodes/Basic/NumberDisplayDataModel.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | #include "Nodes/Data/VariantData.h" 10 | 11 | using QtNodes::NodeData; 12 | using QtNodes::NodeDataType; 13 | using QtNodes::NodeDelegateModel; 14 | using QtNodes::PortIndex; 15 | using QtNodes::PortType; 16 | 17 | class QLabel; 18 | 19 | /// The model dictates the number of inputs and outputs for the Node. 20 | /// In this example it has no logic. 21 | class NumberDisplayDataModel : public NodeDelegateModel 22 | { 23 | Q_OBJECT 24 | 25 | public: 26 | NumberDisplayDataModel(); 27 | 28 | ~NumberDisplayDataModel() = default; 29 | 30 | public: 31 | QString caption() const override { return QStringLiteral("Result"); } 32 | 33 | bool captionVisible() const override { return false; } 34 | 35 | QString name() const override { return QStringLiteral("Result"); } 36 | 37 | public: 38 | unsigned int nPorts(PortType portType) const override; 39 | 40 | NodeDataType dataType(PortType portType, PortIndex portIndex) const override; 41 | 42 | std::shared_ptr outData(PortIndex port) override; 43 | 44 | void setInData(std::shared_ptr data, PortIndex portIndex) override; 45 | 46 | QWidget *embeddedWidget() override; 47 | 48 | private: 49 | std::weak_ptr _numberData; 50 | 51 | QLabel *_label; 52 | }; 53 | -------------------------------------------------------------------------------- /src/Nodes/Basic/NumberSourceDataModel.cpp: -------------------------------------------------------------------------------- 1 | #include "NumberSourceDataModel.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | NumberSourceDataModel::NumberSourceDataModel() 8 | : m_number(std::make_shared(0)) 9 | , _lineEdit{nullptr} { 10 | } 11 | 12 | QJsonObject NumberSourceDataModel::save() const { 13 | QJsonObject modelJson = NodeDelegateModel::save(); 14 | 15 | modelJson["number"] = QString::number(m_number->variant().toDouble()); 16 | 17 | return modelJson; 18 | } 19 | 20 | void NumberSourceDataModel::load(QJsonObject const& p) { 21 | QJsonValue v = p["number"]; 22 | 23 | if (!v.isUndefined()) { 24 | QString strNum = v.toString(); 25 | 26 | bool ok; 27 | double d = strNum.toDouble(&ok); 28 | if (ok) { 29 | m_number = std::make_shared(d); 30 | 31 | if (_lineEdit) 32 | _lineEdit->setText(strNum); 33 | } 34 | } 35 | } 36 | 37 | unsigned int NumberSourceDataModel::nPorts(PortType portType) const { 38 | unsigned int result = 1; 39 | 40 | switch (portType) { 41 | case PortType::In: 42 | result = 0; 43 | break; 44 | 45 | case PortType::Out: 46 | result = 1; 47 | 48 | default: 49 | break; 50 | } 51 | 52 | return result; 53 | } 54 | 55 | void NumberSourceDataModel::onTextEdited(QString const& str) { 56 | bool ok = false; 57 | // based on the str determine if the number is a double or an int 58 | QVariant number; 59 | if (str.contains('.') || str.contains('e') || str.contains('E')){ 60 | number = str.toDouble(&ok); 61 | } else { 62 | number = str.toInt(&ok); 63 | } 64 | 65 | if (ok) { 66 | m_number = std::make_shared(number); 67 | Q_EMIT dataUpdated(0); 68 | } else { 69 | Q_EMIT dataInvalidated(0); 70 | } 71 | } 72 | 73 | NodeDataType NumberSourceDataModel::dataType(PortType, PortIndex) const { 74 | return m_number->type(); 75 | } 76 | 77 | std::shared_ptr NumberSourceDataModel::outData(PortIndex) { 78 | return m_number; 79 | } 80 | 81 | QWidget* NumberSourceDataModel::embeddedWidget() { 82 | if (!_lineEdit) { 83 | _lineEdit = new QLineEdit(); 84 | 85 | _lineEdit->setValidator(new QDoubleValidator()); 86 | _lineEdit->setMaximumSize(_lineEdit->sizeHint()); 87 | 88 | connect(_lineEdit, &QLineEdit::textChanged, this, &NumberSourceDataModel::onTextEdited); 89 | 90 | _lineEdit->setText(QString::number(m_number->variant().toDouble())); 91 | } 92 | 93 | return _lineEdit; 94 | } 95 | -------------------------------------------------------------------------------- /src/Nodes/Basic/NumberSourceDataModel.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "Nodes/Data/VariantData.h" 5 | 6 | #include 7 | 8 | #include 9 | 10 | class DecimalData; 11 | 12 | using QtNodes::NodeData; 13 | using QtNodes::NodeDataType; 14 | using QtNodes::NodeDelegateModel; 15 | using QtNodes::PortIndex; 16 | using QtNodes::PortType; 17 | 18 | class QLineEdit; 19 | 20 | /// The model dictates the number of inputs and outputs for the Node. 21 | /// In this example it has no logic. 22 | class NumberSourceDataModel : public NodeDelegateModel 23 | { 24 | Q_OBJECT 25 | 26 | public: 27 | NumberSourceDataModel(); 28 | 29 | virtual ~NumberSourceDataModel() {} 30 | 31 | public: 32 | QString caption() const override { return QStringLiteral("Number Source"); } 33 | 34 | QString name() const override { return QStringLiteral("NumberSource"); } 35 | 36 | public: 37 | QJsonObject save() const override; 38 | 39 | void load(QJsonObject const &p) override; 40 | 41 | public: 42 | unsigned int nPorts(PortType portType) const override; 43 | 44 | NodeDataType dataType(PortType portType, PortIndex portIndex) const override; 45 | 46 | std::shared_ptr outData(PortIndex port) override; 47 | 48 | void setInData(std::shared_ptr, PortIndex) override {} 49 | 50 | QWidget *embeddedWidget() override; 51 | 52 | public: 53 | 54 | private Q_SLOTS: 55 | 56 | void onTextEdited(QString const &string); 57 | 58 | private: 59 | std::shared_ptr m_number; 60 | 61 | QLineEdit *_lineEdit; 62 | }; 63 | -------------------------------------------------------------------------------- /src/Nodes/Constants/PiModel.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/27/24. 3 | // 4 | 5 | #include "PiModel.h" 6 | #include 7 | 8 | PiModel::PiModel() { 9 | m_pi = std::make_shared(CV_PI); 10 | } 11 | 12 | QString PiModel::caption() const { 13 | return QStringLiteral("Pi"); 14 | } 15 | 16 | QString PiModel::name() const { 17 | return QStringLiteral("Pi"); 18 | } 19 | 20 | unsigned PiModel::nPorts(QtNodes::PortType portType) const { 21 | if (portType == QtNodes::PortType::In) { 22 | return 0; 23 | } else { 24 | return 1; 25 | } 26 | } 27 | 28 | QtNodes::NodeDataType PiModel::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { 29 | if (portType == QtNodes::PortType::Out) { 30 | return VariantData(0.0).type(); 31 | } else { 32 | return {}; 33 | } 34 | } 35 | 36 | void PiModel::setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) { 37 | } 38 | 39 | std::shared_ptr PiModel::outData(const QtNodes::PortIndex port) { 40 | return m_pi; 41 | } 42 | 43 | QWidget* PiModel::embeddedWidget() { 44 | return nullptr; 45 | } 46 | -------------------------------------------------------------------------------- /src/Nodes/Constants/PiModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/27/24. 3 | // 4 | 5 | #ifndef PIMODEL_H 6 | #define PIMODEL_H 7 | 8 | 9 | #include 10 | #include "Nodes/Data/VariantData.h" 11 | 12 | class PiModel final : public QtNodes::NodeDelegateModel{ 13 | Q_OBJECT 14 | public: 15 | PiModel(); 16 | 17 | QString caption() const override; 18 | 19 | QString name() const override; 20 | 21 | unsigned nPorts(QtNodes::PortType portType) const override; 22 | 23 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 24 | 25 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 26 | 27 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 28 | 29 | QWidget* embeddedWidget() override; 30 | 31 | private: 32 | std::shared_ptr m_pi; 33 | }; 34 | 35 | 36 | 37 | #endif //PIMODEL_H 38 | -------------------------------------------------------------------------------- /src/Nodes/Conversor/MatQt.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/25/24. 3 | // 4 | 5 | #include "MatQt.h" 6 | #include 7 | QImage MatToQImage(const cv::Mat& mat) { 8 | switch (mat.type()) { 9 | // 8-bit, 4 channel 10 | case CV_8UC4: { 11 | const QImage image(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32); 12 | return image.copy(); 13 | } 14 | 15 | // 8-bit, 3 channel 16 | case CV_8UC3: { 17 | const QImage image(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888); 18 | return image.rgbSwapped().copy(); 19 | } 20 | 21 | // 8-bit, 1 channel 22 | case CV_8UC1: { 23 | static QVector sColorTable; 24 | if (sColorTable.isEmpty()) { 25 | for (int i = 0; i < 256; ++i) 26 | sColorTable.push_back(qRgb(i, i, i)); 27 | } 28 | QImage image(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_Indexed8); 29 | image.setColorTable(sColorTable); 30 | return image.copy(); 31 | } 32 | 33 | default: 34 | qWarning("MatToQImage() - cv::Mat image type not handled in switch:"); 35 | break; 36 | } 37 | 38 | return QImage(); 39 | } 40 | 41 | 42 | cv::Mat QImageToMat(const QImage& image) { 43 | cv::Mat mat; 44 | switch (image.format()) { 45 | case QImage::Format_ARGB32: 46 | case QImage::Format_ARGB32_Premultiplied: { 47 | mat = cv::Mat(image.height(), image.width(), CV_8UC4, 48 | const_cast(image.bits()), image.bytesPerLine()); 49 | break; 50 | } 51 | case QImage::Format_RGB32: { 52 | mat = cv::Mat(image.height(), image.width(), CV_8UC4, 53 | const_cast(image.bits()), image.bytesPerLine()); 54 | cv::cvtColor(mat, mat, cv::COLOR_BGRA2BGR); 55 | break; 56 | } 57 | case QImage::Format_RGB888: { 58 | QImage swapped = image.rgbSwapped(); 59 | mat = cv::Mat(swapped.height(), swapped.width(), CV_8UC3, 60 | const_cast(swapped.bits()), swapped.bytesPerLine()); 61 | break; 62 | } 63 | case QImage::Format_Grayscale8: { 64 | mat = cv::Mat(image.height(), image.width(), CV_8UC1, 65 | const_cast(image.bits()), image.bytesPerLine()); 66 | break; 67 | } 68 | // Add other QImage formats if needed. 69 | // QImage::Format_Indexed8 70 | case QImage::Format_Indexed8: { 71 | mat = cv::Mat(image.height(), image.width(), CV_8UC1, 72 | const_cast(image.bits()), image.bytesPerLine()); 73 | break; 74 | } 75 | 76 | default: { 77 | qCritical() << "QImage format not handled in switch:" << image.format(); 78 | // Unsupported format 79 | break; 80 | } 81 | } 82 | return mat; 83 | } 84 | -------------------------------------------------------------------------------- /src/Nodes/Conversor/MatQt.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/25/24. 3 | // 4 | 5 | #ifndef MATQT_H 6 | #define MATQT_H 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | QImage MatToQImage(const cv::Mat& mat); 13 | 14 | //QPixmap MatToQPixmap(const cv::Mat& mat); 15 | 16 | cv::Mat QImageToMat(const QImage& image); 17 | 18 | //cv::Mat QPixmapToMat(const QPixmap& pixmap); 19 | #endif //MATQT_H 20 | -------------------------------------------------------------------------------- /src/Nodes/Data/CascadeClassifierData.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/26/24. 3 | // 4 | 5 | #ifndef CASCADECLASSIFIERDATA_H 6 | #define CASCADECLASSIFIERDATA_H 7 | 8 | #include 9 | #include 10 | 11 | class CascadeClassifierData final : public QtNodes::NodeData { 12 | public: 13 | CascadeClassifierData() { 14 | } 15 | 16 | explicit CascadeClassifierData(const QString& filename) : m_cascadeClassifier( 17 | std::make_shared()) { 18 | m_cascadeClassifier->load(filename.toStdString()); 19 | } 20 | 21 | explicit CascadeClassifierData(const cv::CascadeClassifier& cascadeClassifier) : m_cascadeClassifier( 22 | std::make_shared(cascadeClassifier)) { 23 | } 24 | 25 | 26 | QtNodes::NodeDataType type() const override { 27 | return QtNodes::NodeDataType{"cascadeClassifier", "Cascade Classifier"}; 28 | } 29 | 30 | std::shared_ptr cascadeClassifier() const { 31 | return m_cascadeClassifier; 32 | } 33 | 34 | bool isEmpty() const { 35 | if (m_cascadeClassifier) { 36 | return m_cascadeClassifier->empty(); 37 | } 38 | return true; 39 | } 40 | 41 | private: 42 | std::shared_ptr m_cascadeClassifier; 43 | }; 44 | 45 | #endif //CASCADECLASSIFIERDATA_H 46 | -------------------------------------------------------------------------------- /src/Nodes/Data/DataInclude.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/25/24. 3 | // 4 | 5 | #ifndef DATAINCLUDE_H 6 | #define DATAINCLUDE_H 7 | 8 | #include "Nodes/Data/LinesSegmentData.h" 9 | #include "Nodes/Data/ImageData.h" 10 | #include "Nodes/Data/ImageFormatData.h" 11 | #include "Nodes/Data/FileData.h" 12 | #include "Nodes/Data/RectsData.h" 13 | 14 | #endif //DATAINCLUDE_H 15 | -------------------------------------------------------------------------------- /src/Nodes/Data/FileData.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/1/24. 3 | // 4 | 5 | #ifndef FILEDATA_H 6 | #define FILEDATA_H 7 | 8 | #include 9 | 10 | #include 11 | 12 | class FileData final : public QtNodes::NodeData { 13 | public: 14 | FileData() { 15 | m_file.setAutoRemove(true); 16 | } 17 | 18 | explicit FileData(const QString &filename) { 19 | // if the file exists, load the content into the temp file 20 | if (QFile::exists(filename)) { 21 | m_file.open(); 22 | QFile file(filename); 23 | file.open(QIODevice::ReadOnly); 24 | m_file.write(file.readAll()); 25 | file.close(); 26 | m_file.close(); 27 | } 28 | } 29 | 30 | void setData(const QString &data) { 31 | m_file.setAutoRemove(true); 32 | m_file.open(); 33 | m_file.write(data.toUtf8()); 34 | m_file.close(); 35 | } 36 | 37 | void setData(const QByteArray &data) { 38 | m_file.open(); 39 | m_file.write(data); 40 | m_file.close(); 41 | } 42 | 43 | QtNodes::NodeDataType type() const override { 44 | return QtNodes::NodeDataType{"file", "File"}; 45 | } 46 | 47 | bool exists() const { 48 | return m_file.exists(); 49 | } 50 | 51 | QString fileName() const { 52 | return m_file.fileName(); 53 | } 54 | 55 | private: 56 | QTemporaryFile m_file; 57 | }; 58 | 59 | #endif //FILEDATA_H 60 | -------------------------------------------------------------------------------- /src/Nodes/Data/ImageData.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/28/24. 3 | // 4 | 5 | #ifndef IMAGEDATA_H 6 | #define IMAGEDATA_H 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | class ImageData final : public QtNodes::NodeData { 14 | public: 15 | ImageData() = default; 16 | 17 | explicit ImageData(QImage const &image) : m_image(image) {} 18 | 19 | explicit ImageData(QString const &fileName) : m_image(fileName) {} 20 | 21 | QtNodes::NodeDataType type() const override { 22 | return QtNodes::NodeDataType{"image", "Image"}; 23 | } 24 | 25 | bool isNull() const { return m_image.isNull(); } 26 | 27 | bool isGrayScale() const { return m_image.isGrayscale(); } 28 | 29 | bool hasAlphaChannel() const { return m_image.hasAlphaChannel(); } 30 | 31 | QImage image() const { return m_image; } 32 | 33 | QPixmap pixmap() const { return QPixmap::fromImage(m_image); } 34 | 35 | private: 36 | QImage m_image; 37 | }; 38 | #endif //IMAGEDATA_H 39 | -------------------------------------------------------------------------------- /src/Nodes/Data/ImageFormatData.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/29/24. 3 | // 4 | 5 | #ifndef IMAGEFORMATDATA_H 6 | #define IMAGEFORMATDATA_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | class ImageFormatData final : public QtNodes::NodeData { 14 | public: 15 | ImageFormatData() = default; 16 | 17 | explicit ImageFormatData(const QImage::Format format) : m_format(format) { 18 | } 19 | 20 | explicit ImageFormatData(const QImage& image) : m_format(image.format()) { 21 | } 22 | 23 | QImage::Format format() const { return m_format; } 24 | 25 | QtNodes::NodeDataType type() const override { 26 | return QtNodes::NodeDataType{"imageFormat", "Image Format"}; 27 | } 28 | 29 | static QString formatToString(const QImage::Format format) { 30 | const QMetaObject& metaObject = QImage::staticMetaObject; 31 | const int index = metaObject.indexOfEnumerator("Format"); 32 | const QMetaEnum metaEnum = metaObject.enumerator(index); 33 | return metaEnum.valueToKey(format); 34 | } 35 | 36 | private: 37 | QImage::Format m_format; 38 | }; 39 | #endif //IMAGEFORMATDATA_H 40 | -------------------------------------------------------------------------------- /src/Nodes/Data/LinesSegmentData.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/27/24. 3 | // 4 | 5 | #ifndef LINESSEGMENT_H 6 | #define LINESSEGMENT_H 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | typedef QVector LinesSegment; 15 | 16 | class LinesSegmentData final : public QtNodes::NodeData { 17 | public: 18 | LinesSegmentData() { 19 | } 20 | 21 | explicit LinesSegmentData(const LinesSegment& lines) : m_lines(lines) { 22 | } 23 | 24 | explicit LinesSegmentData(const std::vector& lines) { 25 | for (const auto& line : lines) { 26 | m_lines.push_back(QLine(line[0], line[1], line[2], line[3])); 27 | } 28 | } 29 | 30 | std::vector linesCV() const { 31 | std::vector lines; 32 | for (const auto& line : m_lines) { 33 | lines.push_back(cv::Vec4i(line.x1(), line.y1(), line.x2(), line.y2())); 34 | } 35 | return lines; 36 | } 37 | 38 | LinesSegment lines() { 39 | return m_lines; 40 | } 41 | 42 | LinesSegment lines() const { 43 | return m_lines; 44 | } 45 | 46 | QtNodes::NodeDataType type() const override { 47 | return QtNodes::NodeDataType{"linessegment", "Lines Segment"}; 48 | } 49 | 50 | private: 51 | LinesSegment m_lines; 52 | }; 53 | 54 | 55 | #endif //LINESSEGMENT_H 56 | -------------------------------------------------------------------------------- /src/Nodes/Data/PointData.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/1/24. 3 | // 4 | 5 | #ifndef POINTDATA_H 6 | #define POINTDATA_H 7 | 8 | 9 | #include 10 | #include 11 | 12 | class PointData final : public QtNodes::NodeData { 13 | public: 14 | PointData() { 15 | } 16 | explicit PointData(const QPoint& point) : m_point(point) { 17 | } 18 | 19 | QPoint point() const { 20 | return m_point; 21 | } 22 | 23 | QtNodes::NodeDataType type() const override { 24 | return QtNodes::NodeDataType{"point", "Point"}; 25 | } 26 | private: 27 | QPoint m_point; 28 | }; 29 | 30 | #endif //POINTDATA_H 31 | -------------------------------------------------------------------------------- /src/Nodes/Data/RectData.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/1/24. 3 | // 4 | 5 | #ifndef RECTDATA_H 6 | #define RECTDATA_H 7 | 8 | #include 9 | #include 10 | 11 | class RectData final : public QtNodes::NodeData { 12 | public: 13 | RectData() { 14 | } 15 | explicit RectData(const QRect& rect) : m_rect(rect) { 16 | } 17 | 18 | QRect rect() const { 19 | return m_rect; 20 | } 21 | 22 | QtNodes::NodeDataType type() const override { 23 | return QtNodes::NodeDataType{"rect", "Rect"}; 24 | } 25 | private: 26 | QRect m_rect; 27 | }; 28 | 29 | #endif //RECTDATA_H 30 | -------------------------------------------------------------------------------- /src/Nodes/Data/RectsData.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/1/24. 3 | // 4 | 5 | #ifndef RECTS_H 6 | #define RECTS_H 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | typedef QList Rects; 13 | 14 | class RectsData final : public QtNodes::NodeData { 15 | public: 16 | RectsData() { 17 | } 18 | explicit RectsData(const QRect& rect) : m_rects({rect}) { 19 | } 20 | explicit RectsData(const QList& rects) : m_rects(rects) { 21 | } 22 | 23 | QList rects() { 24 | return m_rects; 25 | } 26 | 27 | QtNodes::NodeDataType type() const override { 28 | return QtNodes::NodeDataType{"rects", "Rects"}; 29 | } 30 | private: 31 | QList m_rects; 32 | }; 33 | 34 | #endif //RECTS_H 35 | -------------------------------------------------------------------------------- /src/Nodes/Data/VariantData.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/29/24. 3 | // 4 | 5 | #ifndef VARIANTDATA_H 6 | #define VARIANTDATA_H 7 | 8 | #include 9 | #include 10 | 11 | class VariantData final : public QtNodes::NodeData { 12 | public: 13 | VariantData() = default; 14 | 15 | explicit VariantData(const QVariant& variant) : m_variant(variant) { 16 | } 17 | 18 | QtNodes::NodeDataType type() const override { 19 | QString typeName = m_variant.typeName(); 20 | // if the typename starts with Q or q, remove it 21 | if (typeName.startsWith('Q') || typeName.startsWith('q')) { 22 | typeName = typeName.mid(1); 23 | } 24 | // the string should have at least 10 characters, if not, fill with spaces 25 | typeName = typeName.rightJustified(10, ' '); 26 | return QtNodes::NodeDataType{ 27 | "variant", 28 | typeName 29 | }; 30 | } 31 | 32 | QtNodes::NodeDataType typeIn() const { 33 | QString typeName = m_variant.typeName(); 34 | if (typeName.startsWith('Q') || typeName.startsWith('q')) { 35 | typeName = typeName.mid(1); 36 | } 37 | typeName = typeName.leftJustified(10, ' '); 38 | return QtNodes::NodeDataType{ 39 | "variant", 40 | typeName 41 | }; 42 | } 43 | 44 | bool isType(QMetaType::Type const type) const { 45 | return m_variant.metaType().id() == type; 46 | } 47 | 48 | QMetaType::Type metaType() const { 49 | return static_cast(m_variant.metaType().id()); 50 | } 51 | 52 | QVariant variant() const { 53 | return m_variant; 54 | } 55 | 56 | bool isValid() const { 57 | return m_variant.isValid(); 58 | } 59 | 60 | QString toString() const { 61 | QString output; 62 | switch (metaType()) { 63 | case QMetaType::QSize: { 64 | const QSize size = m_variant.toSize(); 65 | output = QString("%1x%2").arg(size.width()).arg(size.height()); 66 | break; 67 | } 68 | case QMetaType::Bool: { 69 | output = m_variant.toBool() ? "true" : "false"; 70 | break; 71 | } 72 | default : { 73 | output = m_variant.toString(); 74 | break; 75 | } 76 | } 77 | 78 | return output; 79 | } 80 | 81 | private: 82 | QVariant m_variant; 83 | }; 84 | #endif //VARIANTDATA_H 85 | -------------------------------------------------------------------------------- /src/Nodes/DataOperations/ScaleRects.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/5/24. 3 | // 4 | 5 | #include "ScaleRects.h" 6 | 7 | QString ScaleRects::caption() const { 8 | return QString("Scale Rects"); 9 | } 10 | 11 | QString ScaleRects::name() const { 12 | return QString("Scale Rects"); 13 | } 14 | 15 | unsigned ScaleRects::nPorts(QtNodes::PortType portType) const { 16 | switch (portType) { 17 | case QtNodes::PortType::In: 18 | return 2; 19 | case QtNodes::PortType::Out: 20 | return 1; 21 | default: 22 | return 0; 23 | } 24 | } 25 | 26 | QtNodes::NodeDataType ScaleRects::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { 27 | switch (portType) { 28 | case QtNodes::PortType::In: 29 | switch (portIndex) { 30 | case 0: 31 | return RectsData().type(); 32 | case 1: 33 | return VariantData(QSize()).typeIn(); 34 | default: 35 | return RectsData().type(); 36 | } 37 | case QtNodes::PortType::Out: 38 | return RectsData().type(); 39 | default: 40 | return RectsData().type(); 41 | } 42 | } 43 | 44 | void ScaleRects::setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) { 45 | switch (portIndex) { 46 | case 0: 47 | m_inRectsData = std::dynamic_pointer_cast(nodeData); 48 | break; 49 | case 1: 50 | m_inScaleFactor = std::dynamic_pointer_cast(nodeData); 51 | break; 52 | default: 53 | break; 54 | } 55 | const auto lockRects = m_inRectsData.lock(); 56 | const auto lockScaleFactor = m_inScaleFactor.lock(); 57 | if (lockRects && lockScaleFactor) { 58 | const auto rects = lockRects->rects(); 59 | const auto scaleFactor = lockScaleFactor->variant().toSize(); 60 | QList scaledRects; 61 | for (const auto& rect: rects) { 62 | const QRect result(rect.x() * scaleFactor.width(), rect.y() * scaleFactor.height(), 63 | rect.width() * scaleFactor.width(), rect.height() * scaleFactor.height()); 64 | scaledRects.push_back(result); 65 | } 66 | m_outRectsData = std::make_shared(scaledRects); 67 | } else { 68 | m_outRectsData.reset(); 69 | } 70 | emit dataUpdated(0); 71 | } 72 | 73 | std::shared_ptr ScaleRects::outData(const QtNodes::PortIndex port) { 74 | return m_outRectsData; 75 | } 76 | 77 | QWidget* ScaleRects::embeddedWidget() { 78 | return nullptr; 79 | } 80 | -------------------------------------------------------------------------------- /src/Nodes/DataOperations/ScaleRects.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/5/24. 3 | // 4 | 5 | #ifndef SCALERECTS_H 6 | #define SCALERECTS_H 7 | 8 | #include 9 | #include "Nodes/Data/VariantData.h" 10 | #include "Nodes/Data/RectsData.h" 11 | 12 | class ScaleRects final : public QtNodes::NodeDelegateModel { 13 | Q_OBJECT 14 | public: 15 | QString caption() const override; 16 | 17 | QString name() const override; 18 | 19 | unsigned nPorts(QtNodes::PortType portType) const override; 20 | 21 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 22 | 23 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 24 | 25 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 26 | 27 | QWidget* embeddedWidget() override; 28 | private: 29 | // in 30 | // 0 31 | std::weak_ptr m_inRectsData; 32 | // 1 33 | std::weak_ptr m_inScaleFactor; 34 | // out 35 | // 0 36 | std::shared_ptr m_outRectsData; 37 | }; 38 | 39 | 40 | 41 | #endif //SCALERECTS_H 42 | -------------------------------------------------------------------------------- /src/Nodes/Images/ConvertImageToModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/2/24. 3 | // 4 | 5 | #ifndef CONVERTIMAGETOMODEL_H 6 | #define CONVERTIMAGETOMODEL_H 7 | 8 | #include 9 | #include 10 | 11 | #include "Nodes/Data/ImageData.h" 12 | #include "Nodes/Data/ImageFormatData.h" 13 | 14 | class QComboBox; 15 | 16 | namespace Ui { 17 | class ConvertImageToForm; 18 | } 19 | 20 | class ConvertImageToModel final : public QtNodes::NodeDelegateModel { 21 | Q_OBJECT 22 | 23 | public: 24 | ConvertImageToModel(); 25 | 26 | ~ConvertImageToModel() override; 27 | 28 | QString caption() const override; 29 | 30 | QString name() const override; 31 | 32 | unsigned nPorts(QtNodes::PortType portType) const override; 33 | 34 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 35 | 36 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 37 | 38 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 39 | 40 | QWidget* embeddedWidget() override; 41 | 42 | QJsonObject save() const override; 43 | 44 | void load(QJsonObject const& jsonObj) override; 45 | 46 | private: 47 | static QPair processImage(const QImage& image, QImage::Format format, 48 | QFlags flags); 49 | 50 | void fillComboBoxFormats(QComboBox* comboBox); 51 | 52 | QImage::Format getFormat() const; 53 | 54 | private slots: 55 | void processFinished(); 56 | 57 | void requestProcess(); 58 | 59 | QImage getPixmapToProcess() const; 60 | 61 | void updateFlags(); 62 | 63 | void updateFormat(int index); 64 | 65 | void flagsClicked(); 66 | 67 | private: 68 | QWidget* m_widget = nullptr; 69 | std::unique_ptr m_ui; 70 | QFutureWatcher> m_watcher; 71 | QFlags m_flags; 72 | bool m_processing = false; 73 | // in 74 | // 0 75 | QImage m_lastImageToProcess; 76 | std::weak_ptr m_inImageData; 77 | // 1 78 | QImage::Format m_lastFormatToProcess; 79 | std::weak_ptr m_inImageFormatData; 80 | // out 81 | //0 82 | std::shared_ptr m_outImageData; 83 | //1 84 | QImage::Format m_outImageFormat; 85 | std::shared_ptr m_outImageFormatData; 86 | }; 87 | 88 | 89 | #endif //CONVERTIMAGETOMODEL_H 90 | -------------------------------------------------------------------------------- /src/Nodes/Images/CutImageModel.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/9/24. 3 | // 4 | 5 | #include "CutImageModel.h" 6 | #include "Nodes/Data/VariantData.h" 7 | 8 | QString CutImageModel::caption() const { 9 | return QString("Cut Image"); 10 | } 11 | 12 | QString CutImageModel::name() const { 13 | return QString("Cut Image"); 14 | } 15 | 16 | unsigned CutImageModel::nPorts(QtNodes::PortType portType) const { 17 | switch (portType) { 18 | case QtNodes::PortType::In: 19 | return 2; 20 | case QtNodes::PortType::Out: 21 | return 1; 22 | default: 23 | return 0; 24 | } 25 | } 26 | 27 | QtNodes::NodeDataType CutImageModel::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { 28 | switch (portType) { 29 | case QtNodes::PortType::In: 30 | switch (portIndex) { 31 | case 0: 32 | return ImageData().type(); 33 | case 1: 34 | return RectData().type(); 35 | default: 36 | return VariantData().type(); 37 | } 38 | case QtNodes::PortType::Out: 39 | return ImageData().type(); 40 | default: 41 | return VariantData().type(); 42 | } 43 | } 44 | 45 | void CutImageModel::setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) { 46 | switch (portIndex) { 47 | case 0: 48 | m_inImageData = std::dynamic_pointer_cast(nodeData); 49 | break; 50 | case 1: 51 | m_inRectData = std::dynamic_pointer_cast(nodeData); 52 | break; 53 | } 54 | 55 | if (const auto lock = m_inImageData.lock()) { 56 | if (const auto lockRect = m_inRectData.lock()) { 57 | m_outImageData = std::make_shared(processImage(lock->image(), lockRect->rect())); 58 | } else { 59 | m_outImageData.reset(); 60 | } 61 | } else { 62 | m_outImageData.reset(); 63 | } 64 | emit dataUpdated(0); 65 | } 66 | 67 | std::shared_ptr CutImageModel::outData(const QtNodes::PortIndex port) { 68 | return m_outImageData; 69 | } 70 | 71 | QWidget* CutImageModel::embeddedWidget() { 72 | return nullptr; 73 | } 74 | 75 | QImage CutImageModel::processImage(const QImage& image, const QRect& rect) { 76 | if (rect.isNull()) { 77 | return QImage(); 78 | } 79 | if (rect.isNull()) { 80 | return QImage(); 81 | } 82 | return image.copy(rect); 83 | } 84 | -------------------------------------------------------------------------------- /src/Nodes/Images/CutImageModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/9/24. 3 | // 4 | 5 | #ifndef CUTIMAGEMODEL_H 6 | #define CUTIMAGEMODEL_H 7 | 8 | #include 9 | #include 10 | 11 | #include "Nodes/Data/RectData.h" 12 | #include "Nodes/Data/ImageData.h" 13 | 14 | 15 | class CutImageModel final : public QtNodes::NodeDelegateModel { 16 | Q_OBJECT 17 | 18 | public: 19 | QString caption() const override; 20 | 21 | QString name() const override; 22 | 23 | unsigned nPorts(QtNodes::PortType portType) const override; 24 | 25 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 26 | 27 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 28 | 29 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 30 | 31 | QWidget* embeddedWidget() override; 32 | 33 | private: 34 | static QImage processImage(const QImage& image, const QRect& rect); 35 | 36 | private: 37 | // in 38 | // 0 39 | std::weak_ptr m_inImageData; 40 | // 1 41 | std::weak_ptr m_inRectData; 42 | 43 | // out 44 | // 0 45 | std::shared_ptr m_outImageData; 46 | }; 47 | 48 | 49 | #endif //CUTIMAGEMODEL_H 50 | -------------------------------------------------------------------------------- /src/Nodes/Images/DrawLinesForm.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | DrawLinesForm 4 | 5 | 6 | 7 | 0 8 | 0 9 | 313 10 | 101 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | true 21 | 22 | 23 | QAbstractSpinBox::NoButtons 24 | 25 | 26 | 99999 27 | 28 | 29 | 30 | 31 | 32 | 33 | 1 34 | 35 | 36 | 37 | 38 | 39 | 40 | Time ms: 41 | 42 | 43 | 44 | 45 | 46 | 47 | Line thickness 48 | 49 | 50 | 51 | 52 | 53 | 54 | Line color 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | R 64 | 65 | 66 | 67 | 68 | 69 | 70 | 255 71 | 72 | 73 | 74 | 75 | 76 | 77 | G 78 | 79 | 80 | 81 | 82 | 83 | 84 | 255 85 | 86 | 87 | 88 | 89 | 90 | 91 | B 92 | 93 | 94 | 95 | 96 | 97 | 98 | 255 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /src/Nodes/Images/DrawLinesModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/29/24. 3 | // 4 | 5 | #ifndef DRAWLINESMODEL_H 6 | #define DRAWLINESMODEL_H 7 | 8 | #include 9 | #include 10 | 11 | #include "Nodes/Data/LinesSegmentData.h" 12 | #include "Nodes/Data/ImageData.h" 13 | #include "Nodes/Data/VariantData.h" 14 | 15 | namespace Ui { 16 | class DrawLinesForm; 17 | } 18 | 19 | class DrawLinesModel final : public QtNodes::NodeDelegateModel { 20 | Q_OBJECT 21 | 22 | public: 23 | DrawLinesModel(); 24 | 25 | ~DrawLinesModel() override; 26 | 27 | QString caption() const override; 28 | 29 | QString name() const override; 30 | 31 | unsigned nPorts(QtNodes::PortType portType) const override; 32 | 33 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 34 | 35 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 36 | 37 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 38 | 39 | QWidget* embeddedWidget() override; 40 | 41 | private slots: 42 | void processFinished(); 43 | 44 | void requestProcess(); 45 | 46 | QImage getPixmapToProcess() const; 47 | 48 | private: 49 | static QPair processImage(QImage image, const LinesSegment& linesSegment, 50 | const QColor& color, 51 | int thickness); 52 | 53 | void updateFromInputPort(); 54 | 55 | private: 56 | QWidget* m_widget = nullptr; 57 | QScopedPointer m_ui; 58 | QFutureWatcher> m_watcher; 59 | bool m_processing = false; 60 | 61 | // in 62 | // 0 63 | QImage m_lastPixmapToProcess; 64 | std::weak_ptr m_inImageData; 65 | // 1 66 | std::weak_ptr m_inLinesSegmentData; 67 | // 2 68 | QColor m_lastColor; 69 | std::weak_ptr m_inColor; 70 | // 3 71 | int m_lastThickness = 10; 72 | std::weak_ptr m_inThickness; 73 | 74 | // out 75 | std::shared_ptr m_outImageData; 76 | }; 77 | 78 | 79 | #endif //DRAWLINESMODEL_H 80 | -------------------------------------------------------------------------------- /src/Nodes/Images/DrawRectsForm.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | DrawRectsForm 4 | 5 | 6 | 7 | 0 8 | 0 9 | 315 10 | 101 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | Rect color 21 | 22 | 23 | 24 | 25 | 26 | 27 | Rect thickness 28 | 29 | 30 | 31 | 32 | 33 | 34 | Time ms: 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | R 44 | 45 | 46 | 47 | 48 | 49 | 50 | 255 51 | 52 | 53 | 54 | 55 | 56 | 57 | G 58 | 59 | 60 | 61 | 62 | 63 | 64 | 255 65 | 66 | 67 | 68 | 69 | 70 | 71 | B 72 | 73 | 74 | 75 | 76 | 77 | 78 | 255 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 1 88 | 89 | 90 | 20 91 | 92 | 93 | 94 | 95 | 96 | 97 | true 98 | 99 | 100 | QAbstractSpinBox::NoButtons 101 | 102 | 103 | 99999 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /src/Nodes/Images/DrawRectsModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/1/24. 3 | // 4 | 5 | #ifndef DRAWRECTSMODEL_H 6 | #define DRAWRECTSMODEL_H 7 | 8 | #include 9 | #include 10 | 11 | #include "Nodes/Data/RectsData.h" 12 | #include "Nodes/Data/ImageData.h" 13 | #include "Nodes/Data/VariantData.h" 14 | 15 | namespace Ui { 16 | class DrawRectsForm; 17 | } 18 | 19 | class DrawRectsModel final : public QtNodes::NodeDelegateModel { 20 | Q_OBJECT 21 | 22 | public: 23 | DrawRectsModel(); 24 | 25 | ~DrawRectsModel() override; 26 | 27 | QString caption() const override; 28 | 29 | QString name() const override; 30 | 31 | unsigned nPorts(QtNodes::PortType portType) const override; 32 | 33 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 34 | 35 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 36 | 37 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 38 | 39 | QWidget* embeddedWidget() override; 40 | 41 | private: 42 | static QPair processImage(QImage image, const Rects& rects, const QColor& color, int thickness); 43 | 44 | void updateFromInputPort(); 45 | 46 | QImage getPixmapToProcess() const; 47 | 48 | private slots: 49 | void processFinished(); 50 | 51 | void requestProcess(); 52 | private: 53 | QWidget* m_widget = nullptr; 54 | QScopedPointer m_ui; 55 | QFutureWatcher> m_watcher; 56 | 57 | // in 58 | // 0 59 | QImage m_lastPixmapToProcess; 60 | std::weak_ptr m_inImageData; 61 | // 1 62 | std::weak_ptr m_inRectsData; 63 | // 2 64 | QColor m_color; 65 | std::weak_ptr m_inColor; 66 | // 3 67 | int m_thickness; 68 | std::weak_ptr m_inThickness; 69 | 70 | // out 71 | std::shared_ptr m_outImageData; 72 | }; 73 | 74 | 75 | #endif //DRAWRECTSMODEL_H 76 | -------------------------------------------------------------------------------- /src/Nodes/Images/ImageInfoForm.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ImageInfoForm 4 | 5 | 6 | 7 | 0 8 | 0 9 | 242 10 | 96 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 2 19 | 20 | 21 | 6 22 | 23 | 24 | 25 | 26 | true 27 | 28 | 29 | 30 | 31 | 32 | 33 | Qt::LeftToRight 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | Qt::StrongFocus 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | Is Null 54 | 55 | 56 | 57 | 58 | 59 | 60 | Has Alpha channel 61 | 62 | 63 | 64 | 65 | 66 | 67 | Is Grayscale 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | Format 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | CheckBoxReadOnly 90 | QCheckBox 91 |
CustomWidget/CheckBoxReadOnly.h
92 |
93 |
94 | 95 | 96 |
97 | -------------------------------------------------------------------------------- /src/Nodes/Images/ImageInfoModel.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/29/24. 3 | // 4 | 5 | #include "ImageInfoModel.h" 6 | #include "ui_ImageInfoForm.h" 7 | 8 | ImageInfoModel::ImageInfoModel() { 9 | } 10 | 11 | ImageInfoModel::~ImageInfoModel() { 12 | } 13 | 14 | QString ImageInfoModel::caption() const { 15 | return QString("Image Info"); 16 | } 17 | 18 | QString ImageInfoModel::name() const { 19 | return QString("Image Info"); 20 | } 21 | 22 | unsigned ImageInfoModel::nPorts(QtNodes::PortType portType) const { 23 | switch (portType) { 24 | case QtNodes::PortType::In: 25 | return 1; 26 | case QtNodes::PortType::Out: 27 | return 3; 28 | default: 29 | return 0; 30 | break; 31 | } 32 | } 33 | 34 | QtNodes::NodeDataType ImageInfoModel::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { 35 | switch (portType) { 36 | case QtNodes::PortType::In: 37 | return ImageData().type(); 38 | case QtNodes::PortType::Out: 39 | switch (portIndex) { 40 | case 0: 41 | return ImageData().type(); 42 | case 1: 43 | return ImageFormatData().type(); 44 | case 2: 45 | return VariantData(QSize()).type(); 46 | default: 47 | break; 48 | } 49 | default: 50 | break; 51 | } 52 | return ImageData().type(); 53 | } 54 | 55 | void ImageInfoModel::setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) { 56 | switch (portIndex) { 57 | case 0: { 58 | m_inImageData = std::dynamic_pointer_cast(nodeData); 59 | updateData(); 60 | break; 61 | } 62 | default: 63 | break; 64 | } 65 | } 66 | 67 | std::shared_ptr ImageInfoModel::outData(const QtNodes::PortIndex port) { 68 | switch (port) { 69 | case 0: 70 | return m_outImageData; 71 | case 1: 72 | return m_outFormat; 73 | case 2: 74 | return m_outSize; 75 | default: 76 | return nullptr; 77 | } 78 | } 79 | 80 | QWidget* ImageInfoModel::embeddedWidget() { 81 | if (!m_widget) { 82 | m_ui = std::make_unique(); 83 | m_widget = new QWidget(); 84 | m_ui->setupUi(m_widget); 85 | } 86 | return m_widget; 87 | } 88 | 89 | void ImageInfoModel::invalidateOutData() { 90 | m_outImageData.reset(); 91 | m_outFormat.reset(); 92 | m_outSize.reset(); 93 | } 94 | 95 | void ImageInfoModel::updateData() { 96 | const auto imageLock = m_inImageData.lock(); 97 | if (!imageLock) { 98 | invalidateOutData(); 99 | } else { 100 | m_outImageData = std::make_shared(imageLock->image()); 101 | m_outFormat = std::make_shared(imageLock->image().format()); 102 | m_outSize = std::make_shared(imageLock->image().size()); 103 | if (m_ui) { 104 | m_ui->cb_isNull->setChecked(imageLock->isNull()); 105 | m_ui->cb_isGrayScale->setChecked(imageLock->isGrayScale()); 106 | m_ui->cb_hasAlpha->setChecked(imageLock->hasAlphaChannel()); 107 | m_ui->le_format->setText(formatToString(m_outFormat->format())); 108 | } 109 | } 110 | emit dataUpdated(0); 111 | emit dataUpdated(1); 112 | emit dataUpdated(2); 113 | } 114 | 115 | QString ImageInfoModel::formatToString(QImage::Format const format) { 116 | switch (format) { 117 | case QImage::Format_Invalid: return "Invalid"; 118 | case QImage::Format_Mono: return "Mono"; 119 | case QImage::Format_MonoLSB: return "MonoLSB"; 120 | case QImage::Format_Indexed8: return "Indexed8"; 121 | case QImage::Format_RGB32: return "RGB32"; 122 | case QImage::Format_ARGB32: return "ARGB32"; 123 | case QImage::Format_ARGB32_Premultiplied: return "ARGB32 Premultiplied"; 124 | case QImage::Format_RGB16: return "RGB16"; 125 | case QImage::Format_ARGB8565_Premultiplied: return "ARGB8565 Premultiplied"; 126 | case QImage::Format_RGB666: return "RGB666"; 127 | case QImage::Format_ARGB6666_Premultiplied: return "ARGB6666 Premultiplied"; 128 | case QImage::Format_RGB555: return "RGB555"; 129 | case QImage::Format_ARGB8555_Premultiplied: return "ARGB8555 Premultiplied"; 130 | case QImage::Format_RGB888: return "RGB888"; 131 | case QImage::Format_RGB444: return "RGB444"; 132 | case QImage::Format_ARGB4444_Premultiplied: return "ARGB4444 Premultiplied"; 133 | case QImage::Format_RGBX8888: return "RGBX8888"; 134 | case QImage::Format_RGBA8888: return "RGBA8888"; 135 | case QImage::Format_RGBA8888_Premultiplied: return "RGBA8888 Premultiplied"; 136 | case QImage::Format_BGR30: return "BGR30"; 137 | case QImage::Format_A2BGR30_Premultiplied: return "A2BGR30 Premultiplied"; 138 | case QImage::Format_RGB30: return "RGB30"; 139 | case QImage::Format_A2RGB30_Premultiplied: return "A2RGB30 Premultiplied"; 140 | case QImage::Format_Alpha8: return "Alpha8"; 141 | case QImage::Format_Grayscale8: return "Grayscale8"; 142 | // Include all other formats you need to handle 143 | default: return "Unknown Format"; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/Nodes/Images/ImageInfoModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/29/24. 3 | // 4 | 5 | #ifndef IMAGEINFOMODEL_H 6 | #define IMAGEINFOMODEL_H 7 | 8 | #include 9 | #include "Nodes/Data/ImageData.h" 10 | #include "Nodes/Data/VariantData.h" 11 | #include "Nodes/Data/ImageFormatData.h" 12 | 13 | namespace Ui { 14 | class ImageInfoForm; 15 | } 16 | 17 | class ImageInfoModel final : public QtNodes::NodeDelegateModel { 18 | Q_OBJECT 19 | public: 20 | ImageInfoModel(); 21 | 22 | ~ImageInfoModel() override; 23 | 24 | QString caption() const override; 25 | 26 | QString name() const override; 27 | 28 | unsigned nPorts(QtNodes::PortType portType) const override; 29 | 30 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 31 | 32 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 33 | 34 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 35 | 36 | QWidget* embeddedWidget() override; 37 | 38 | private: 39 | void invalidateOutData(); 40 | 41 | void updateData(); 42 | 43 | static QString formatToString(QImage::Format format); 44 | 45 | private: 46 | std::unique_ptr m_ui; 47 | QWidget* m_widget = nullptr; 48 | 49 | // in 50 | std::weak_ptr m_inImageData; 51 | // out 52 | // 0 53 | std::shared_ptr m_outImageData; 54 | // 1 55 | std::shared_ptr m_outFormat; 56 | // 2 57 | std::shared_ptr m_outSize; 58 | }; 59 | 60 | 61 | 62 | #endif //IMAGEINFOMODEL_H 63 | -------------------------------------------------------------------------------- /src/Nodes/Images/ImageLoaderModel.cpp: -------------------------------------------------------------------------------- 1 | #include "ImageLoaderModel.hpp" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | ImageLoaderModel::ImageLoaderModel() 9 | : _label(new QLabel("Double click to load image")) { 10 | _label->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter); 11 | 12 | QFont f = _label->font(); 13 | f.setBold(true); 14 | f.setItalic(true); 15 | 16 | _label->setFont(f); 17 | 18 | _label->setMinimumSize(200, 200); 19 | //_label->setMaximumSize(500, 300); 20 | 21 | _label->installEventFilter(this); 22 | } 23 | 24 | unsigned int ImageLoaderModel::nPorts(const QtNodes::PortType portType) const { 25 | unsigned int result = 1; 26 | 27 | switch (portType) { 28 | case QtNodes::PortType::In: 29 | result = 0; 30 | break; 31 | 32 | case QtNodes::PortType::Out: 33 | result = 1; 34 | 35 | default: 36 | break; 37 | } 38 | 39 | return result; 40 | } 41 | 42 | QJsonObject ImageLoaderModel::save() const { 43 | QJsonObject modelJson = NodeDelegateModel::save(); 44 | if (m_outImageData && !m_path.isEmpty()) { 45 | modelJson["path"] = m_path; 46 | } 47 | return modelJson; 48 | } 49 | 50 | void ImageLoaderModel::load(QJsonObject const& jsonObj) { 51 | const QJsonValue path = jsonObj["path"]; 52 | if (!path.isUndefined()) { 53 | m_path = path.toString(); 54 | loadImage(); 55 | } 56 | } 57 | 58 | bool ImageLoaderModel::eventFilter(QObject* object, QEvent* event) { 59 | if (object == _label) { 60 | const int w = _label->width(); 61 | const int h = _label->height(); 62 | 63 | if (event->type() == QEvent::MouseButtonPress) { 64 | m_path = QFileDialog::getOpenFileName(nullptr, 65 | tr("Open Image"), 66 | QDir::homePath(), 67 | tr("Image Files (*.png *.jpg *.bmp)")); 68 | if (!m_path.isEmpty()) 69 | loadImage(); 70 | return true; 71 | } else if (event->type() == QEvent::Resize) { 72 | if (m_outImageData && !m_outImageData->isNull()) 73 | _label->setPixmap(m_outImageData->pixmap().scaled(w, h, Qt::KeepAspectRatio)); 74 | } 75 | } 76 | 77 | return false; 78 | } 79 | 80 | void ImageLoaderModel::loadImage() { 81 | if (!m_path.isEmpty()) { 82 | m_outImageData = std::make_shared(m_path); 83 | if (m_outImageData && !m_outImageData->isNull()) { 84 | _label->setPixmap(m_outImageData->pixmap().scaled(_label->width(), _label->height(), Qt::KeepAspectRatio)); 85 | } 86 | } else { 87 | m_outImageData.reset(); 88 | _label->clear(); 89 | } 90 | emit dataUpdated(0); 91 | } 92 | 93 | QtNodes::NodeDataType ImageLoaderModel::dataType(QtNodes::PortType const, QtNodes::PortIndex const) const { 94 | return ImageData().type(); 95 | } 96 | 97 | std::shared_ptr ImageLoaderModel::outData(QtNodes::PortIndex) { 98 | return m_outImageData; 99 | } 100 | -------------------------------------------------------------------------------- /src/Nodes/Images/ImageLoaderModel.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include "Nodes/Data/ImageData.h" 12 | 13 | class ImageLoaderModel final : public QtNodes::NodeDelegateModel 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | ImageLoaderModel(); 19 | 20 | ~ImageLoaderModel() override = default; 21 | 22 | public: 23 | QString caption() const override { return QString("Image source"); } 24 | 25 | QString name() const override { return QString("Image source"); } 26 | 27 | public: 28 | virtual QString modelName() const { return QString("Source Image"); } 29 | 30 | unsigned int nPorts(QtNodes::PortType portType) const override; 31 | 32 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 33 | 34 | std::shared_ptr outData(QtNodes::PortIndex port) override; 35 | 36 | void setInData(std::shared_ptr, QtNodes::PortIndex const portIndex) override {} 37 | 38 | QWidget *embeddedWidget() override { return _label; } 39 | 40 | bool resizable() const override { return true; } 41 | 42 | QJsonObject save() const override; 43 | 44 | void load(QJsonObject const& jsonObj) override; 45 | 46 | protected: 47 | bool eventFilter(QObject *object, QEvent *event) override; 48 | 49 | private: 50 | void loadImage(); 51 | 52 | private: 53 | QLabel *_label; 54 | 55 | QString m_path; 56 | std::shared_ptr m_outImageData; 57 | }; 58 | -------------------------------------------------------------------------------- /src/Nodes/Images/ImageShowModel.cpp: -------------------------------------------------------------------------------- 1 | #include "ImageShowModel.hpp" 2 | 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | ImageShowModel::ImageShowModel() 11 | : _label(new QLabel("Image will appear here")) { 12 | _label->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter); 13 | 14 | QFont f = _label->font(); 15 | f.setBold(true); 16 | f.setItalic(true); 17 | 18 | _label->setFont(f); 19 | 20 | _label->setMinimumSize(200, 200); 21 | 22 | _label->installEventFilter(this); 23 | } 24 | 25 | unsigned int ImageShowModel::nPorts(const QtNodes::PortType portType) const { 26 | unsigned int result = 1; 27 | 28 | switch (portType) { 29 | case QtNodes::PortType::In: 30 | result = 1; 31 | break; 32 | 33 | case QtNodes::PortType::Out: 34 | result = 1; 35 | 36 | default: 37 | break; 38 | } 39 | 40 | return result; 41 | } 42 | 43 | bool ImageShowModel::eventFilter(QObject* object, QEvent* event) { 44 | if (object == _label) { 45 | int w = _label->width(); 46 | int h = _label->height(); 47 | 48 | if (event->type() == QEvent::Resize) { 49 | const auto d = m_outData.lock(); 50 | if (d) { 51 | if (!d->pixmap().isNull()) 52 | _label->setPixmap(d->pixmap().scaled(w, h, Qt::KeepAspectRatio)); 53 | } 54 | } 55 | } 56 | 57 | return false; 58 | } 59 | 60 | QtNodes::NodeDataType ImageShowModel::dataType(QtNodes::PortType const, QtNodes::PortIndex const) const { 61 | return ImageData().type(); 62 | } 63 | 64 | std::shared_ptr ImageShowModel::outData(QtNodes::PortIndex) { 65 | return m_outData.lock(); 66 | } 67 | 68 | void ImageShowModel::setInData(const std::shared_ptr nodeData, QtNodes::PortIndex const) { 69 | m_outData = std::dynamic_pointer_cast(nodeData); 70 | const auto lockData = m_outData.lock(); 71 | 72 | if (lockData) { 73 | 74 | const int w = _label->width(); 75 | const int h = _label->height(); 76 | 77 | if (!lockData->pixmap().isNull()) 78 | _label->setPixmap(lockData->pixmap().scaled(w, h, Qt::KeepAspectRatio)); 79 | } else { 80 | _label->setPixmap(QPixmap()); 81 | } 82 | 83 | Q_EMIT dataUpdated(0); 84 | } 85 | -------------------------------------------------------------------------------- /src/Nodes/Images/ImageShowModel.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | 12 | #include "Nodes/Data/ImageData.h" 13 | 14 | class ImageShowModel final : public QtNodes::NodeDelegateModel 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | ImageShowModel(); 20 | 21 | ~ImageShowModel() override = default; 22 | 23 | public: 24 | QString caption() const override { return QString("Image display"); } 25 | 26 | QString name() const override { return QString("Image display"); } 27 | 28 | public: 29 | virtual QString modelName() const { return QString("Resulting Image"); } 30 | 31 | unsigned int nPorts(QtNodes::PortType portType) const override; 32 | 33 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 34 | 35 | std::shared_ptr outData(QtNodes::PortIndex port) override; 36 | 37 | void setInData(std::shared_ptr nodeData, QtNodes::PortIndex port) override; 38 | 39 | QWidget *embeddedWidget() override { return _label; } 40 | 41 | bool resizable() const override { return true; } 42 | 43 | protected: 44 | bool eventFilter(QObject *object, QEvent *event) override; 45 | 46 | private: 47 | QLabel *_label; 48 | 49 | std::weak_ptr m_outData; 50 | }; 51 | -------------------------------------------------------------------------------- /src/Nodes/Images/ScaleImageForm.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ScaleImageForm 4 | 5 | 6 | 7 | 0 8 | 0 9 | 319 10 | 70 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | 21 | 0 22 | 0 23 | 24 | 25 | 26 | 1 27 | 28 | 29 | 30 | Ignore Aspect Ratio 31 | 32 | 33 | 34 | 35 | Keep Aspect Ratio 36 | 37 | 38 | 39 | 40 | Keep Aspect Ratio by Expanding 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | Aspect Ratio 49 | 50 | 51 | 52 | 53 | 54 | 55 | Time ms: 56 | 57 | 58 | 59 | 60 | 61 | 62 | true 63 | 64 | 65 | QAbstractSpinBox::NoButtons 66 | 67 | 68 | 99999 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /src/Nodes/Images/ScaleImageModel.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/5/24. 3 | // 4 | 5 | #include "ScaleImageModel.h" 6 | #include "ui_ScaleImageForm.h" 7 | #include 8 | #include 9 | 10 | ScaleImageModel::ScaleImageModel() { 11 | } 12 | 13 | ScaleImageModel::~ScaleImageModel() { 14 | } 15 | 16 | QString ScaleImageModel::caption() const { 17 | return QString("Scale Image"); 18 | } 19 | 20 | QString ScaleImageModel::name() const { 21 | return QString("Scale Image"); 22 | } 23 | 24 | unsigned ScaleImageModel::nPorts(QtNodes::PortType portType) const { 25 | switch (portType) { 26 | case QtNodes::PortType::In: 27 | return 2; 28 | case QtNodes::PortType::Out: 29 | return 1; 30 | default: 31 | return 0; 32 | } 33 | } 34 | 35 | QtNodes::NodeDataType ScaleImageModel::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { 36 | switch (portType) { 37 | case QtNodes::PortType::In: 38 | switch (portIndex) { 39 | case 0: 40 | return ImageData().type(); 41 | case 1: 42 | return VariantData(QSize()).typeIn(); 43 | default: 44 | return ImageData().type(); 45 | } 46 | case QtNodes::PortType::Out: 47 | return ImageData().type(); 48 | default: 49 | return ImageData().type(); 50 | } 51 | } 52 | 53 | void ScaleImageModel::setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) { 54 | switch (portIndex) { 55 | case 0: 56 | m_inImageData = std::dynamic_pointer_cast(nodeData); 57 | break; 58 | case 1: 59 | m_inScaleFactor = std::dynamic_pointer_cast(nodeData); 60 | break; 61 | default: 62 | break; 63 | } 64 | requestProcess(); 65 | } 66 | 67 | std::shared_ptr ScaleImageModel::outData(const QtNodes::PortIndex port) { 68 | return m_outImageData; 69 | } 70 | 71 | QWidget* ScaleImageModel::embeddedWidget() { 72 | if (!m_widget) { 73 | m_ui.reset(new Ui::ScaleImageForm); 74 | m_widget = new QWidget(); 75 | m_ui->setupUi(m_widget); 76 | // connect combobox cb_aspectRatio to requestProcess 77 | connect(m_ui->cb_aspectRatio, QOverload::of(&QComboBox::currentIndexChanged), this, &ScaleImageModel::requestProcess); 78 | } 79 | return m_widget; 80 | } 81 | 82 | QPair ScaleImageModel::processImage(const QImage& image, const QSize& scaleFactor, Qt::AspectRatioMode mode) { 83 | QElapsedTimer timer; 84 | timer.start(); 85 | const auto scaledImage = image.scaled(scaleFactor, mode); 86 | return {scaledImage, static_cast(timer.elapsed())}; 87 | } 88 | 89 | void ScaleImageModel::requestProcess() { 90 | const auto lockImage = m_inImageData.lock(); 91 | const auto lockScaleFactor = m_inScaleFactor.lock(); 92 | if (lockImage && lockScaleFactor) { 93 | const auto image = lockImage->image(); 94 | const auto scaleFactor = lockScaleFactor->variant().toSize(); 95 | if (image.isNull() || scaleFactor.isEmpty()) { 96 | m_outImageData.reset(); 97 | return; 98 | } 99 | // get aspect ratio mode from the current index of the combobox 100 | const auto mode = static_cast(m_ui->cb_aspectRatio->currentIndex()); 101 | const auto [fst, snd] = processImage(image, scaleFactor, mode); 102 | m_outImageData = std::make_shared(fst); 103 | if (m_ui) { 104 | m_ui->sb_time->setValue(snd); 105 | } 106 | } else { 107 | m_outImageData.reset(); 108 | } 109 | emit dataUpdated(0); 110 | } 111 | -------------------------------------------------------------------------------- /src/Nodes/Images/ScaleImageModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/5/24. 3 | // 4 | 5 | #ifndef SCALEIMAGEMODEL_H 6 | #define SCALEIMAGEMODEL_H 7 | 8 | 9 | #include 10 | #include "Nodes/Data/ImageData.h" 11 | #include "Nodes/Data/VariantData.h" 12 | 13 | namespace Ui { 14 | class ScaleImageForm; 15 | } 16 | 17 | class ScaleImageModel final : public QtNodes::NodeDelegateModel { 18 | Q_OBJECT 19 | 20 | public: 21 | ScaleImageModel(); 22 | 23 | ~ScaleImageModel() override; 24 | 25 | QString caption() const override; 26 | 27 | QString name() const override; 28 | 29 | unsigned nPorts(QtNodes::PortType portType) const override; 30 | 31 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 32 | 33 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 34 | 35 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 36 | 37 | QWidget* embeddedWidget() override; 38 | private: 39 | static QPair processImage(const QImage& image, const QSize& scaleFactor, Qt::AspectRatioMode mode); 40 | 41 | void requestProcess(); 42 | private: 43 | QWidget* m_widget = nullptr; 44 | QScopedPointer m_ui; 45 | 46 | // in 47 | // 0 48 | std::weak_ptr m_inImageData; 49 | // 1 50 | std::weak_ptr m_inScaleFactor; 51 | // out 52 | // 0 53 | std::shared_ptr m_outImageData; 54 | }; 55 | 56 | 57 | #endif //SCALEIMAGEMODEL_H 58 | -------------------------------------------------------------------------------- /src/Nodes/NodesInclude.cpp: -------------------------------------------------------------------------------- 1 | #include "NodesInclude.h" 2 | 3 | -------------------------------------------------------------------------------- /src/Nodes/NodesInclude.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/24/24. 3 | // 4 | 5 | #ifndef NODESINCLUDE_H 6 | #define NODESINCLUDE_H 7 | 8 | #include 9 | 10 | #include "Nodes/Constants/PiModel.h" 11 | 12 | #include "Nodes/Basic/AdditionModel.h" 13 | #include "Nodes/Basic/DivisionModel.h" 14 | #include "Nodes/Basic/MathOperationDataModel.hpp" 15 | #include "Nodes/Basic/MultiplicationModel.hpp" 16 | #include "Nodes/Basic/NumberDisplayDataModel.hpp" 17 | #include "Nodes/Basic/NumberSourceDataModel.hpp" 18 | #include "Nodes/Basic/SubtractionModel.h" 19 | 20 | #include "Nodes/Images/ImageLoaderModel.hpp" 21 | #include "Nodes/Images/ImageShowModel.hpp" 22 | #include "Nodes/Images/ImageInfoModel.h" 23 | #include "Nodes/Images/DrawLinesModel.h" 24 | #include "Nodes/Images/DrawRectsModel.h" 25 | #include "Nodes/Images/ConvertImageToModel.h" 26 | #include "Nodes/Images/ScaleImageModel.h" 27 | #include "Nodes/Images/CutImageModel.h" 28 | // Variables 29 | #include "Nodes/Variables/SizeVarModel.h" 30 | #include "Nodes/Variables/FileVarModel.h" 31 | #include "Nodes/Variables/FileFromUrlModel.h" 32 | #include "Nodes/Variables/RectVarModel.h" 33 | #include "Nodes/Variables/RectModel.h" 34 | 35 | // DataOperations 36 | #include "Nodes/DataOperations/ScaleRects.h" 37 | 38 | // opencv 39 | #include "Nodes/OpenCV/ColorCVModel.h" 40 | #include "Nodes/OpenCV/BlurModel.h" 41 | #include "Nodes/OpenCV/CannyModel.h" 42 | #include "Nodes/OpenCV/GaussianBlurModel.h" 43 | #include "Nodes/OpenCV/HoughLinesPModel.h" 44 | #include "Nodes/OpenCV/CascadeClassifierModel.h" 45 | #include "Nodes/OpenCV/EqualizeHistModel.h" 46 | #include "Nodes/OpenCV/DetectMultiScaleModel.h" 47 | #include "Nodes/OpenCV/PyrDown.h" 48 | 49 | // video 50 | #include "Nodes/Video/CameraModel.h" 51 | #include "Nodes/Video/CaptureModel.h" 52 | 53 | // data 54 | #include "Nodes/Data/DataInclude.h" 55 | 56 | // Conversor 57 | #include "Nodes/Conversor/MatQt.h" 58 | 59 | 60 | #endif //NODESINCLUDE_H 61 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/BlurForm.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | BlurForm 4 | 5 | 6 | 7 | 0 8 | 0 9 | 182 10 | 114 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Width 23 | 24 | 25 | 26 | 27 | 28 | 29 | 0 30 | 31 | 32 | 999999999 33 | 34 | 35 | 36 | 37 | 38 | 39 | Height 40 | 41 | 42 | 43 | 44 | 45 | 46 | 0 47 | 48 | 49 | 999999999 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | Width should be > 0 59 | 60 | 61 | 62 | 63 | 64 | 65 | Height should be > 0 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/BlurModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/24/24. 3 | // 4 | 5 | #ifndef BLURMODEL_H 6 | #define BLURMODEL_H 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | #include "Nodes/Data/ImageData.h" 13 | #include "Nodes/Data/VariantData.h" 14 | 15 | 16 | namespace Ui { 17 | class BlurForm; 18 | } 19 | 20 | class BlurModel final : public QtNodes::NodeDelegateModel { 21 | Q_OBJECT 22 | 23 | public: 24 | BlurModel(); 25 | 26 | ~BlurModel() override; 27 | 28 | QString caption() const override; 29 | 30 | QString name() const override; 31 | 32 | unsigned nPorts(QtNodes::PortType portType) const override; 33 | 34 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 35 | 36 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 37 | 38 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 39 | 40 | QWidget* embeddedWidget() override; 41 | 42 | private: 43 | static QImage processImage(const QSize& size, const QImage& image); 44 | 45 | QImage getImageToProcess() const; 46 | 47 | private slots: 48 | void processFinished(); 49 | 50 | void requestProcess(); 51 | 52 | private: 53 | QWidget* m_widget = nullptr; 54 | Ui::BlurForm* m_ui = nullptr; 55 | 56 | std::weak_ptr m_inImageData; 57 | std::shared_ptr m_outImageData; 58 | 59 | QImage m_lastImageToProcess; 60 | 61 | QFutureWatcher m_watcher; 62 | }; 63 | 64 | 65 | #endif //BLURMODEL_H 66 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/CannyForm.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | CannyForm 4 | 5 | 6 | 7 | 0 8 | 0 9 | 248 10 | 120 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | Threshold 21 | 22 | 23 | 24 | 25 | 26 | 27 | 1.000000000000000 28 | 29 | 30 | 99999.000000000000000 31 | 32 | 33 | 34 | 35 | 36 | 37 | Threshold 2 38 | 39 | 40 | 41 | 42 | 43 | 44 | 0.000000000000000 45 | 46 | 47 | 99999.000000000000000 48 | 49 | 50 | 51 | 52 | 53 | 54 | Aperture size (odd [3,7]) 55 | 56 | 57 | 58 | 59 | 60 | 61 | 3 62 | 63 | 64 | 7 65 | 66 | 67 | 2 68 | 69 | 70 | 71 | 72 | 73 | 74 | L2 gradient 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/CannyModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/25/24. 3 | // 4 | 5 | #ifndef CANNYMODEL_H 6 | #define CANNYMODEL_H 7 | 8 | #include 9 | #include 10 | #include "Nodes/Data/ImageData.h" 11 | #include "Nodes/Data/VariantData.h" 12 | 13 | 14 | namespace Ui { 15 | class CannyForm; 16 | } 17 | 18 | class CannyModel final : public QtNodes::NodeDelegateModel { 19 | Q_OBJECT 20 | 21 | public: 22 | CannyModel(); 23 | 24 | ~CannyModel() override; 25 | 26 | QString caption() const override; 27 | 28 | QString name() const override; 29 | 30 | unsigned nPorts(QtNodes::PortType portType) const override; 31 | 32 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 33 | 34 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 35 | 36 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 37 | 38 | QWidget* embeddedWidget() override; 39 | 40 | QImage getImageToProcess() const; 41 | 42 | private: 43 | static QImage processImage(const QImage& image, double lowThreshold, double highThreshold, 44 | int apertureSize, bool useL2Gradient); 45 | 46 | private slots: 47 | void processFinished(); 48 | 49 | void requestProcess(); 50 | 51 | private: 52 | QWidget* m_widget = nullptr; 53 | Ui::CannyForm* m_ui = nullptr; 54 | // in 55 | // 0 56 | std::weak_ptr m_inImageData; 57 | // 1 58 | double m_lowThreshold = 0.0; 59 | // 2 60 | double m_highThreshold = 0.0; 61 | // 3 62 | int m_apertureSize = 3; 63 | // 4 64 | bool m_useL2Gradient = false; 65 | 66 | // out 67 | std::shared_ptr m_outImageData; 68 | QImage m_lastImageToProcess; 69 | 70 | QFutureWatcher m_watcher; 71 | }; 72 | 73 | 74 | #endif //CANNYMODEL_H 75 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/CascadeClassifierForm.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | CascadeClassifierForm 4 | 5 | 6 | 7 | 0 8 | 0 9 | 94 10 | 33 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | Loaded 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | CheckBoxReadOnly 36 | QCheckBox 37 |
CustomWidget/CheckBoxReadOnly.h
38 |
39 |
40 | 41 | 42 |
43 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/CascadeClassifierModel.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/1/24. 3 | // 4 | 5 | #include "CascadeClassifierModel.h" 6 | #include "ui_CascadeClassifierForm.h" 7 | 8 | CascadeClassifier::CascadeClassifier() { 9 | } 10 | 11 | CascadeClassifier::~CascadeClassifier() { 12 | } 13 | 14 | QString CascadeClassifier::caption() const { 15 | return QString("Cascade Classifier"); 16 | } 17 | 18 | QString CascadeClassifier::name() const { 19 | return QString("Cascade Classifier"); 20 | } 21 | 22 | unsigned CascadeClassifier::nPorts(QtNodes::PortType portType) const { 23 | switch (portType) { 24 | case QtNodes::PortType::In: 25 | return 1; 26 | case QtNodes::PortType::Out: 27 | return 1; 28 | default: 29 | return 0; 30 | } 31 | } 32 | 33 | QtNodes::NodeDataType CascadeClassifier::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { 34 | switch (portType) { 35 | case QtNodes::PortType::In: 36 | return FileData().type(); 37 | case QtNodes::PortType::Out: 38 | return CascadeClassifierData().type(); 39 | default: 40 | return FileData().type(); 41 | } 42 | } 43 | 44 | void CascadeClassifier::setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) { 45 | switch (portIndex) { 46 | case 0: { 47 | m_inFileData = std::dynamic_pointer_cast(nodeData); 48 | const auto lockData = m_inFileData.lock(); 49 | if (lockData) { 50 | const auto path = lockData->fileName(); 51 | try { 52 | cv::CascadeClassifier cascadeClassifier; 53 | cascadeClassifier.load(path.toStdString()); 54 | m_outFileData = std::make_shared(cascadeClassifier); 55 | if (m_ui) { 56 | const bool isLoaded = !m_outFileData->isEmpty(); 57 | m_ui->cb_loaded->setChecked(isLoaded); 58 | } 59 | } catch (cv::Exception& e) { 60 | qWarning() << e.what(); 61 | m_outFileData.reset(); 62 | if (m_ui) { 63 | m_ui->cb_loaded->setChecked(false); 64 | } 65 | } 66 | } else { 67 | m_outFileData.reset(); 68 | if (m_ui) { 69 | m_ui->cb_loaded->setChecked(false); 70 | } 71 | } 72 | emit dataUpdated(0); 73 | } 74 | break; 75 | default: 76 | break; 77 | } 78 | } 79 | 80 | std::shared_ptr CascadeClassifier::outData(const QtNodes::PortIndex port) { 81 | switch (port) { 82 | case 0: 83 | return m_outFileData; 84 | default: 85 | return nullptr; 86 | } 87 | } 88 | 89 | QWidget* CascadeClassifier::embeddedWidget() { 90 | if (!m_widget) { 91 | m_widget = new QWidget(); 92 | m_ui = std::make_unique(); 93 | m_ui->setupUi(m_widget); 94 | } 95 | return m_widget; 96 | } 97 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/CascadeClassifierModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/1/24. 3 | // 4 | 5 | #ifndef CASCADECLASSIFIER_H 6 | #define CASCADECLASSIFIER_H 7 | 8 | 9 | #include 10 | #include "Nodes/Data/FileData.h" 11 | #include "Nodes/Data/CascadeClassifierData.h" 12 | 13 | namespace Ui { 14 | class CascadeClassifierForm; 15 | } 16 | 17 | class CascadeClassifier final : public QtNodes::NodeDelegateModel { 18 | Q_OBJECT 19 | 20 | public: 21 | CascadeClassifier(); 22 | 23 | ~CascadeClassifier() override; 24 | 25 | QString caption() const override; 26 | 27 | QString name() const override; 28 | 29 | unsigned nPorts(QtNodes::PortType portType) const override; 30 | 31 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 32 | 33 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 34 | 35 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 36 | 37 | QWidget* embeddedWidget() override; 38 | 39 | private: 40 | std::unique_ptr m_ui; 41 | QWidget* m_widget = nullptr; 42 | 43 | std::weak_ptr m_inFileData; 44 | 45 | std::shared_ptr m_outFileData; 46 | }; 47 | 48 | 49 | #endif //CASCADECLASSIFIER_H 50 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/ColorCVModel.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/24/24. 3 | // 4 | 5 | #include "ColorCVModel.h" 6 | #include 7 | 8 | #include "Nodes/Data/ImageData.h" 9 | #include "Nodes/Conversor/MatQt.h" 10 | 11 | ColorCVModel::ColorCVModel() { 12 | } 13 | 14 | ColorCVModel::~ColorCVModel() { 15 | delete m_comboBox; 16 | m_comboBox = nullptr; 17 | } 18 | 19 | QString ColorCVModel::caption() const { 20 | return "Color OpenCV"; 21 | } 22 | 23 | QString ColorCVModel::name() const { 24 | return "Color OpenCV"; 25 | } 26 | 27 | unsigned ColorCVModel::nPorts(QtNodes::PortType portType) const { 28 | unsigned result = 1; 29 | 30 | switch (portType) { 31 | case QtNodes::PortType::In: 32 | result = 1; 33 | break; 34 | 35 | case QtNodes::PortType::Out: 36 | result = 1; 37 | break; 38 | 39 | default: 40 | break; 41 | } 42 | return result; 43 | } 44 | 45 | QtNodes::NodeDataType ColorCVModel::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { 46 | return ImageData().type(); 47 | } 48 | 49 | void ColorCVModel::setInData(std::shared_ptr const nodeData, const QtNodes::PortIndex portIndex) { 50 | m_inImageData = std::dynamic_pointer_cast(nodeData); 51 | const auto lockData = m_inImageData.lock(); 52 | if (lockData) { 53 | const auto image = lockData->image(); 54 | m_outImageData = std::make_shared(processImage(image, m_comboBox->currentData().toInt())); 55 | } else { 56 | m_outImageData.reset(); 57 | } 58 | Q_EMIT dataUpdated(0); 59 | } 60 | 61 | std::shared_ptr ColorCVModel::outData(const QtNodes::PortIndex port) { 62 | return m_outImageData; 63 | } 64 | 65 | QWidget* ColorCVModel::embeddedWidget() { 66 | if (!m_comboBox) { 67 | m_comboBox = new QComboBox(); 68 | m_comboBox->addItem("BGR to GRAY", cv::COLOR_BGR2GRAY); 69 | m_comboBox->addItem("GRAY to BGR", cv::COLOR_GRAY2BGR); 70 | m_comboBox->setMaximumSize(m_comboBox->sizeHint()); 71 | cv::COLOR_RGB2GRAY; 72 | 73 | connect(m_comboBox, QOverload::of(&QComboBox::currentIndexChanged), 74 | [=](int) { 75 | Q_EMIT dataUpdated(0); 76 | }); 77 | } 78 | return m_comboBox; 79 | } 80 | 81 | QImage ColorCVModel::processImage(QImage image, const int code) { 82 | if (image.isNull()) { 83 | return QImage(); 84 | } 85 | const auto mat = QImageToMat(image); 86 | cv::Mat out; 87 | cv::cvtColor(mat, out, code); 88 | 89 | return MatToQImage(out); 90 | } 91 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/ColorCVModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/24/24. 3 | // 4 | 5 | #ifndef COLORCV_H 6 | #define COLORCV_H 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "Nodes/Data/ImageData.h" 13 | 14 | class ColorCVModel final : public QtNodes::NodeDelegateModel { 15 | Q_OBJECT 16 | public: 17 | ColorCVModel(); 18 | 19 | ~ColorCVModel() override; 20 | 21 | QString caption() const override; 22 | 23 | QString name() const override; 24 | 25 | unsigned nPorts(QtNodes::PortType portType) const override; 26 | 27 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 28 | 29 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 30 | 31 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 32 | 33 | QWidget* embeddedWidget() override; 34 | 35 | private: 36 | static QImage processImage(QImage image, int code); 37 | 38 | private: 39 | std::weak_ptr m_inImageData; 40 | std::shared_ptr m_outImageData; 41 | QComboBox* m_comboBox = nullptr; 42 | }; 43 | 44 | 45 | 46 | #endif //COLORCV_H 47 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/DetectMultiScaleForm.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | DetectMultiScaleForm 4 | 5 | 6 | 7 | 0 8 | 0 9 | 338 10 | 161 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | 1.100000000000000 21 | 22 | 23 | 24 | 25 | 26 | 27 | 3 28 | 29 | 30 | 31 | 32 | 33 | 34 | Max size 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | W 44 | 45 | 46 | 47 | 48 | 49 | 50 | 999999999 51 | 52 | 53 | 54 | 55 | 56 | 57 | H 58 | 59 | 60 | 61 | 62 | 63 | 64 | 999999999 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | Min neighbors 74 | 75 | 76 | 77 | 78 | 79 | 80 | Scale factor 81 | 82 | 83 | 84 | 85 | 86 | 87 | Min size 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | W 97 | 98 | 99 | 100 | 101 | 102 | 103 | 999999999 104 | 105 | 106 | 107 | 108 | 109 | 110 | H 111 | 112 | 113 | 114 | 115 | 116 | 117 | 999999999 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | Time ms: 127 | 128 | 129 | 130 | 131 | 132 | 133 | true 134 | 135 | 136 | 999999999 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/DetectMultiScaleModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/1/24. 3 | // 4 | 5 | #ifndef DETECTMULTISCALEMODEL_H 6 | #define DETECTMULTISCALEMODEL_H 7 | 8 | #include 9 | #include "Nodes/Data/FileData.h" 10 | #include "Nodes/Data/CascadeClassifierData.h" 11 | #include "Nodes/Data/VariantData.h" 12 | #include "Nodes/Data/ImageData.h" 13 | #include "Nodes/Data/RectsData.h" 14 | 15 | #include 16 | 17 | namespace Ui { 18 | class DetectMultiScaleForm; 19 | } 20 | 21 | class DetectMultiScaleModel final : public QtNodes::NodeDelegateModel { 22 | Q_OBJECT 23 | 24 | public: 25 | DetectMultiScaleModel(); 26 | 27 | ~DetectMultiScaleModel() override; 28 | 29 | QString caption() const override; 30 | 31 | QString name() const override; 32 | 33 | unsigned nPorts(QtNodes::PortType portType) const override; 34 | 35 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 36 | 37 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 38 | 39 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 40 | 41 | QWidget* embeddedWidget() override; 42 | 43 | QString portCaption(QtNodes::PortType, QtNodes::PortIndex) const override; 44 | 45 | private slots: 46 | void processFinished(); 47 | 48 | private: 49 | static QPair, quint64> processMultiScale(const QImage& image, cv::CascadeClassifier cc, 50 | double scaleFactor, int minNeighbors, int flags = 0, 51 | const QSize& minSize = QSize(), 52 | const QSize& maxSize = QSize()); 53 | 54 | void requestProcess(); 55 | 56 | void updateInData(); 57 | 58 | QImage getLatestImageToProcess() const; 59 | 60 | private: 61 | QWidget* m_widget = nullptr; 62 | std::unique_ptr m_ui; 63 | QFutureWatcher, quint64>> m_watcher; 64 | bool m_processing = false; 65 | 66 | // in 67 | // 0 68 | QImage m_lastImageToProcess; 69 | std::weak_ptr m_inImageData; 70 | // 1 71 | std::weak_ptr m_inFileData; 72 | // 2 73 | double m_inScaleFactor = 1.1; 74 | std::weak_ptr m_inScaleFactorData; 75 | // 3 76 | int m_inMinNeighbors = 3; 77 | std::weak_ptr m_inMinNeighborsData; 78 | // 4 79 | QSize m_inMinSize = QSize(0,0); 80 | std::weak_ptr m_inMinSizeData; 81 | // 5 82 | QSize m_inMaxSize = QSize(0,0); 83 | std::weak_ptr m_inMaxSizeData; 84 | 85 | // out 86 | std::shared_ptr m_outImageData; 87 | }; 88 | 89 | 90 | #endif //DETECTMULTISCALEMODEL_H 91 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/EqualizeHistModel.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/1/24. 3 | // 4 | 5 | #include "EqualizeHistModel.h" 6 | 7 | #include "Nodes/Conversor/MatQt.h" 8 | #include 9 | #include 10 | 11 | EqualizeHistModel::EqualizeHistModel() { 12 | connect(&m_watcher, &QFutureWatcher>::finished, this, &EqualizeHistModel::processFinished); 13 | } 14 | 15 | EqualizeHistModel::~EqualizeHistModel() { 16 | } 17 | 18 | QString EqualizeHistModel::caption() const { 19 | return "Equalize Hist"; 20 | } 21 | 22 | QString EqualizeHistModel::name() const { 23 | return "Equalize Hist"; 24 | } 25 | 26 | unsigned EqualizeHistModel::nPorts(QtNodes::PortType portType) const { 27 | return 1; 28 | } 29 | 30 | QtNodes::NodeDataType EqualizeHistModel::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { 31 | return ImageData().type(); 32 | } 33 | 34 | void EqualizeHistModel::setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) { 35 | switch (portIndex) { 36 | case 0: 37 | m_inImageData = std::dynamic_pointer_cast(nodeData); 38 | if (m_inImageData.expired()) { 39 | m_outImageData.reset(); 40 | emit dataUpdated(0); 41 | return; 42 | } 43 | m_lastImageToProcess = m_inImageData.lock()->image(); 44 | requestProcess(); 45 | break; 46 | default: 47 | break; 48 | } 49 | } 50 | 51 | std::shared_ptr EqualizeHistModel::outData(const QtNodes::PortIndex port) { 52 | return m_outImageData; 53 | } 54 | 55 | QWidget* EqualizeHistModel::embeddedWidget() { 56 | if (!m_widget) { 57 | m_widget = new QLabel("Time: 0 ms "); 58 | } 59 | return m_widget; 60 | } 61 | 62 | QString EqualizeHistModel::portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { 63 | switch (portType) { 64 | case QtNodes::PortType::In: 65 | return QStringLiteral("Image 8-bit"); 66 | default: 67 | break; 68 | } 69 | return NodeDelegateModel::portCaption(portType, portIndex); 70 | } 71 | 72 | bool EqualizeHistModel::portCaptionVisible(QtNodes::PortType port, QtNodes::PortIndex port_index) const { 73 | switch (port) { 74 | case QtNodes::PortType::In: 75 | return true; 76 | default: 77 | return NodeDelegateModel::portCaptionVisible(port, port_index); 78 | break; 79 | } 80 | } 81 | 82 | void EqualizeHistModel::processFinished() { 83 | const auto [image, time] = m_watcher.result(); 84 | if (!m_inImageData.expired()) { 85 | m_outImageData = std::make_shared(image); 86 | m_widget->setText(QString("Time: %1 ms").arg(time)); 87 | emit dataUpdated(0); 88 | } 89 | m_widget->adjustSize(); 90 | m_processing = false; 91 | requestProcess(); 92 | } 93 | 94 | void EqualizeHistModel::requestProcess() { 95 | if (m_processing) 96 | return; 97 | if (m_lastImageToProcess.isNull()) 98 | return; 99 | if (m_inImageData.expired()) 100 | return; 101 | m_processing = true; 102 | 103 | const auto future = QtConcurrent::run(equializeHist, m_lastImageToProcess); 104 | m_lastImageToProcess = QImage(); 105 | m_watcher.setFuture(future); 106 | } 107 | 108 | QPair EqualizeHistModel::equializeHist(const QImage& image) { 109 | QElapsedTimer timer; 110 | timer.start(); 111 | const cv::Mat mat = QImageToMat(image); 112 | QImage result; 113 | try { 114 | cv::Mat dst; 115 | cv::equalizeHist(mat, dst); 116 | result = MatToQImage(dst); 117 | } catch (cv::Exception& e) { 118 | qDebug() << e.what(); 119 | } 120 | return qMakePair(result, timer.elapsed()); 121 | } 122 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/EqualizeHistModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/1/24. 3 | // 4 | 5 | #ifndef EQUIALIZEHIST_H 6 | #define EQUIALIZEHIST_H 7 | 8 | 9 | #include 10 | #include "Nodes/Data/ImageData.h" 11 | 12 | #include 13 | 14 | class QLabel; 15 | 16 | class EqualizeHistModel final : public QtNodes::NodeDelegateModel { 17 | Q_OBJECT 18 | 19 | public: 20 | EqualizeHistModel(); 21 | 22 | ~EqualizeHistModel() override; 23 | 24 | QString caption() const override; 25 | 26 | QString name() const override; 27 | 28 | unsigned nPorts(QtNodes::PortType portType) const override; 29 | 30 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 31 | 32 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 33 | 34 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 35 | 36 | QWidget* embeddedWidget() override; 37 | 38 | QString portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 39 | 40 | bool portCaptionVisible(QtNodes::PortType, QtNodes::PortIndex) const override; 41 | 42 | private slots: 43 | void processFinished(); 44 | 45 | void requestProcess(); 46 | private: 47 | static QPair equializeHist(const QImage& image); 48 | 49 | private: 50 | QLabel* m_widget = nullptr; 51 | QImage m_lastImageToProcess; 52 | std::weak_ptr m_inImageData; 53 | 54 | std::shared_ptr m_outImageData; 55 | 56 | QFutureWatcher> m_watcher; 57 | bool m_processing = false; 58 | }; 59 | 60 | 61 | #endif //EQUIALIZEHIST_H 62 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/FacialDetectorModel.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/26/24. 3 | // 4 | 5 | #include "FacialDetectorModel.h" 6 | 7 | #include 8 | 9 | 10 | FacialDetectorModel::FacialDetectorModel() { 11 | cv::CascadeClassifier faceCascade; 12 | cv::Mat image; 13 | std::vector faces; 14 | faceCascade.detectMultiScale(image, faces, 1.2, 5, 0, cv::Size(30, 30)); 15 | 16 | cv::GaussianBlur(image, image, cv::Size(3, 3), 0, 0); 17 | cv::dilate(image, image, cv::Mat(), cv::Point(-1, -1), 2, 1, 1); 18 | cv::HoughLinesP(image, image, 1, CV_PI / 180, 50, 50, 10); 19 | } 20 | 21 | FacialDetectorModel::~FacialDetectorModel() { 22 | } 23 | 24 | QString FacialDetectorModel::caption() const { 25 | } 26 | 27 | QString FacialDetectorModel::name() const { 28 | } 29 | 30 | unsigned FacialDetectorModel::nPorts(QtNodes::PortType portType) const { 31 | } 32 | 33 | QtNodes::NodeDataType FacialDetectorModel::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { 34 | } 35 | 36 | void FacialDetectorModel::setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) { 37 | } 38 | 39 | std::shared_ptr FacialDetectorModel::outData(const QtNodes::PortIndex port) { 40 | } 41 | 42 | QWidget* FacialDetectorModel::embeddedWidget() { 43 | } 44 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/FacialDetectorModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/26/24. 3 | // 4 | 5 | #ifndef FACIALDETECTORMODEL_H 6 | #define FACIALDETECTORMODEL_H 7 | 8 | #include 9 | 10 | class FacialDetectorModel final : public QtNodes::NodeDelegateModel{ 11 | Q_OBJECT 12 | public: 13 | FacialDetectorModel(); 14 | 15 | ~FacialDetectorModel() override; 16 | 17 | QString caption() const override; 18 | 19 | QString name() const override; 20 | 21 | unsigned nPorts(QtNodes::PortType portType) const override; 22 | 23 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 24 | 25 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 26 | 27 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 28 | 29 | QWidget* embeddedWidget() override; 30 | }; 31 | 32 | 33 | 34 | #endif //FACIALDETECTORMODEL_H 35 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/GaussianBlurForm.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | GaussianBlurForm 4 | 5 | 6 | 7 | 0 8 | 0 9 | 172 10 | 280 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | Size 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | w 29 | 30 | 31 | 32 | 33 | 34 | 35 | 1 36 | 37 | 38 | 999999999 39 | 40 | 41 | 2 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | h 53 | 54 | 55 | 56 | 57 | 58 | 59 | 1 60 | 61 | 62 | 999999999 63 | 64 | 65 | 2 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | Sigma 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | x 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | y 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | Border 117 | 118 | 119 | 120 | 121 | 122 | 123 | false 124 | 125 | 126 | 3 127 | 128 | 129 | 130 | Constant 131 | 132 | 133 | 134 | 135 | Replicate 136 | 137 | 138 | 139 | 140 | Reflect 141 | 142 | 143 | 144 | 145 | Reflect 101 146 | 147 | 148 | 149 | 150 | Transparent 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | Time ms: 163 | 164 | 165 | 166 | 167 | 168 | 169 | true 170 | 171 | 172 | QAbstractSpinBox::NoButtons 173 | 174 | 175 | 999999999 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/GaussianBlurModel.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/26/24. 3 | // 4 | #include 5 | #include 6 | 7 | #include "GaussianBlurModel.h" 8 | #include "Nodes/Data/DataInclude.h" 9 | #include "ui_GaussianBlurForm.h" 10 | 11 | #include "Nodes/Conversor/MatQt.h" 12 | 13 | #include 14 | 15 | GaussianBlurModel::GaussianBlurModel() { 16 | connect(&m_watcher, &QFutureWatcher>::finished, this, 17 | &GaussianBlurModel::processFinished); 18 | } 19 | 20 | GaussianBlurModel::~GaussianBlurModel() { 21 | } 22 | 23 | QString GaussianBlurModel::caption() const { 24 | return "Gaussian Blur"; 25 | } 26 | 27 | QString GaussianBlurModel::name() const { 28 | return "Gaussian Blur"; 29 | } 30 | 31 | unsigned GaussianBlurModel::nPorts(QtNodes::PortType portType) const { 32 | return 1; 33 | } 34 | 35 | QtNodes::NodeDataType GaussianBlurModel::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { 36 | return ImageData().type(); 37 | } 38 | 39 | void GaussianBlurModel::setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) { 40 | switch (portIndex) { 41 | case 0: { 42 | m_inImageData = std::dynamic_pointer_cast(nodeData); 43 | const auto lock = m_inImageData.lock(); 44 | if (lock) { 45 | m_lastImageToProcess = getImageToProcess(); 46 | } else { 47 | m_outImageData.reset(); 48 | m_lastImageToProcess = QImage(); 49 | emit dataUpdated(0); 50 | } 51 | break; 52 | } 53 | default: 54 | break; 55 | } 56 | requestProcess(); 57 | } 58 | 59 | std::shared_ptr GaussianBlurModel::outData(const QtNodes::PortIndex port) { 60 | return m_outImageData; 61 | } 62 | 63 | QWidget* GaussianBlurModel::embeddedWidget() { 64 | if (!m_widget) { 65 | m_ui = std::make_unique(); 66 | m_widget = new QWidget(); 67 | m_ui->setupUi(m_widget); 68 | // width and height should be odd and positive 69 | connect(m_ui->sb_size_w, QOverload::of(&QSpinBox::valueChanged), this, [this](int value) { 70 | if (value % 2 == 0) { 71 | m_ui->sb_size_w->setValue(value + 1); 72 | return; 73 | } 74 | m_lastImageToProcess = getImageToProcess(); 75 | requestProcess(); 76 | }); 77 | connect(m_ui->sb_size_h, QOverload::of(&QSpinBox::valueChanged), this, [this](int value) { 78 | if (value % 2 == 0) { 79 | m_ui->sb_size_h->setValue(value + 1); 80 | return; 81 | } 82 | m_lastImageToProcess = getImageToProcess(); 83 | requestProcess(); 84 | }); 85 | connect(m_ui->sigmaXSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), this, [this]() { 86 | m_lastImageToProcess = getImageToProcess(); 87 | requestProcess(); 88 | }); 89 | connect(m_ui->sigmaYSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), this, [this]() { 90 | m_lastImageToProcess = getImageToProcess(); 91 | requestProcess(); 92 | }); 93 | } 94 | return m_widget; 95 | } 96 | 97 | void GaussianBlurModel::processFinished() { 98 | const auto tuple = m_watcher.result(); 99 | if (m_inImageData.expired()) { 100 | m_outImageData.reset(); 101 | } else { 102 | m_outImageData = std::make_shared(std::get<0>(tuple)); 103 | } 104 | const quint64 time = std::get<1>(tuple); 105 | m_ui->sb_time->setValue(time); 106 | Q_EMIT dataUpdated(0); 107 | requestProcess(); 108 | } 109 | 110 | void GaussianBlurModel::requestProcess() { 111 | if (m_watcher.isRunning()) { 112 | return; 113 | } 114 | if (m_lastImageToProcess.isNull()) { 115 | return; 116 | } 117 | const auto future = QtConcurrent::run(processImage, m_lastImageToProcess, QSize(m_ui->sb_size_w->value(), 118 | m_ui->sb_size_h->value()), 119 | m_ui->sigmaXSpinBox->value(), m_ui->sigmaYSpinBox->value()); 120 | m_lastImageToProcess = QImage(); 121 | m_watcher.setFuture(future); 122 | } 123 | 124 | std::tuple GaussianBlurModel::processImage(const QImage image, const QSize& size, 125 | const double sigmaX, 126 | const double sigmaY) { 127 | QElapsedTimer timer; 128 | timer.start(); 129 | const cv::Mat src = QImageToMat(image); 130 | cv::Mat dst; 131 | try { 132 | cv::GaussianBlur(src, dst, cv::Size(size.width(), size.height()), sigmaX, sigmaY); 133 | } catch (cv::Exception& e) { 134 | qDebug() << e.what(); 135 | return std::make_tuple(QImage(), timer.elapsed()); 136 | } 137 | const QImage result = MatToQImage(dst); 138 | return std::make_tuple(result, timer.elapsed()); 139 | } 140 | 141 | QImage GaussianBlurModel::getImageToProcess() const { 142 | const auto lock = m_inImageData.lock(); 143 | if (!lock) { 144 | return QImage(); 145 | } 146 | return lock->image(); 147 | } 148 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/GaussianBlurModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/26/24. 3 | // 4 | 5 | #ifndef GAUSSIANBLURMODEL_H 6 | #define GAUSSIANBLURMODEL_H 7 | 8 | #include 9 | #include 10 | #include "Nodes/Data/ImageData.h" 11 | 12 | namespace Ui { 13 | class GaussianBlurForm; 14 | } 15 | 16 | 17 | class GaussianBlurModel final : public QtNodes::NodeDelegateModel { 18 | Q_OBJECT 19 | 20 | public: 21 | GaussianBlurModel(); 22 | 23 | ~GaussianBlurModel() override; 24 | 25 | QString caption() const override; 26 | 27 | QString name() const override; 28 | 29 | unsigned nPorts(QtNodes::PortType portType) const override; 30 | 31 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 32 | 33 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 34 | 35 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 36 | 37 | QWidget* embeddedWidget() override; 38 | 39 | private slots: 40 | void processFinished(); 41 | 42 | void requestProcess(); 43 | 44 | private: 45 | static std::tuple processImage(QImage image, const QSize& size, double sigmaX, double sigmaY); 46 | 47 | QImage getImageToProcess() const; 48 | 49 | private: 50 | std::unique_ptr m_ui; 51 | QWidget* m_widget = nullptr; 52 | 53 | std::weak_ptr m_inImageData; 54 | std::shared_ptr m_outImageData; 55 | 56 | QImage m_lastImageToProcess; 57 | QFutureWatcher> m_watcher; 58 | }; 59 | 60 | 61 | #endif //GAUSSIANBLURMODEL_H 62 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/HoughLinesPForm.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | HoughLinesPForm 4 | 5 | 6 | 7 | 0 8 | 0 9 | 281 10 | 177 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 9 19 | 20 | 21 | 1 22 | 23 | 24 | 25 | 26 | 27 | 0 28 | 0 29 | 30 | 31 | 32 | 80 33 | 34 | 35 | 999999999 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 0 51 | 0 52 | 53 | 54 | 55 | Threshold 56 | 57 | 58 | 59 | 60 | 61 | 62 | Theta 63 | 64 | 65 | 66 | 67 | 68 | 69 | Rho 70 | 71 | 72 | 73 | 74 | 75 | 76 | Time ms: 77 | 78 | 79 | 80 | 81 | 82 | 83 | Max line gap 84 | 85 | 86 | 87 | 88 | 89 | 90 | 15 91 | 92 | 93 | 1.000000000000000 94 | 95 | 96 | 97 | 98 | 99 | 100 | true 101 | 102 | 103 | QAbstractSpinBox::NoButtons 104 | 105 | 106 | 999999999 107 | 108 | 109 | 110 | 111 | 112 | 113 | 14 114 | 115 | 116 | 0.000000000000000 117 | 118 | 119 | 9999999999999.000000000000000 120 | 121 | 122 | 30.000000000000000 123 | 124 | 125 | 126 | 127 | 128 | 129 | Min line length 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 15 144 | 145 | 146 | 9.000000000000000 147 | 148 | 149 | 0.010000000000000 150 | 151 | 152 | 0.017453000000000 153 | 154 | 155 | 156 | 157 | 158 | 159 | 14 160 | 161 | 162 | 9999999999.000000000000000 163 | 164 | 165 | 10.000000000000000 166 | 167 | 168 | 169 | 170 | 171 | 172 | Qt::RightToLeft 173 | 174 | 175 | Running 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/HoughLinesPModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/27/24. 3 | // 4 | 5 | #ifndef HOUGHLINESP_H 6 | #define HOUGHLINESP_H 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | #include "Nodes/Data/LinesSegmentData.h" 13 | #include "Nodes/Data/ImageData.h" 14 | #include "Nodes/Data/VariantData.h" 15 | 16 | namespace Ui { 17 | class HoughLinesPForm; 18 | } 19 | 20 | 21 | class HoughLinesPModel final : public QtNodes::NodeDelegateModel { 22 | Q_OBJECT 23 | 24 | public: 25 | HoughLinesPModel(); 26 | 27 | ~HoughLinesPModel() override; 28 | 29 | QString caption() const override; 30 | 31 | QString name() const override; 32 | 33 | unsigned nPorts(QtNodes::PortType portType) const override; 34 | 35 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 36 | 37 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 38 | 39 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 40 | 41 | QWidget* embeddedWidget() override; 42 | 43 | private slots: 44 | void processFinished(); 45 | 46 | void requestProcess(); 47 | 48 | private: 49 | static std::tuple processImage(QImage image, double rho, double theta, 50 | int threshold, 51 | double minLineLength, double maxLineGap); 52 | 53 | QImage getPixmapToProcess(); 54 | 55 | private: 56 | std::unique_ptr m_ui; 57 | QWidget* m_widget = nullptr; 58 | 59 | 60 | QImage m_lastPixmapToProcess; 61 | QFutureWatcher> m_watcher; 62 | std::shared_ptr m_outLinesData; 63 | 64 | std::weak_ptr m_inPixmapData; 65 | double m_rho = 1; 66 | double m_theta = CV_PI / 180; 67 | int m_threshold = 50; 68 | double m_minLineLength = 50; 69 | double m_maxLineGap = 10; 70 | }; 71 | 72 | 73 | #endif //HOUGHLINESP_H 74 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/PyrDown.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/11/24. 3 | // 4 | 5 | #include "PyrDown.h" 6 | #include 7 | #include 8 | #include 9 | #include "Nodes/Conversor/MatQt.h" 10 | #include 11 | 12 | PyrDown::PyrDown() { 13 | connect(&m_watcher, &QFutureWatcher>::finished, this, &PyrDown::processFinished); 14 | } 15 | 16 | PyrDown::~PyrDown() { 17 | } 18 | 19 | QString PyrDown::caption() const { 20 | return QStringLiteral("Pyr Down"); 21 | } 22 | 23 | QString PyrDown::name() const { 24 | return QStringLiteral("Pyr Down"); 25 | } 26 | 27 | unsigned PyrDown::nPorts(QtNodes::PortType portType) const { 28 | switch (portType) { 29 | case QtNodes::PortType::In: 30 | return 2; 31 | case QtNodes::PortType::Out: 32 | return 1; 33 | default: 34 | return 0; 35 | } 36 | } 37 | 38 | QtNodes::NodeDataType PyrDown::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { 39 | switch (portType) { 40 | case QtNodes::PortType::In: 41 | if (portIndex == 0) { 42 | return ImageData().type(); 43 | } else { 44 | return VariantData(QSize()).typeIn(); 45 | } 46 | case QtNodes::PortType::Out: 47 | return ImageData().type(); 48 | default: 49 | return ImageData().type(); 50 | } 51 | } 52 | 53 | void PyrDown::setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) { 54 | switch (portIndex) { 55 | case 0: 56 | m_inImageData = std::dynamic_pointer_cast(nodeData); 57 | if (m_inImageData.expired()) { 58 | m_outImageData.reset(); 59 | m_spinBox->setValue(0); 60 | } 61 | break; 62 | case 1: 63 | m_inSizeData = std::dynamic_pointer_cast(nodeData); 64 | 65 | break; 66 | default: 67 | qCritical() << "Wrong port index"; 68 | } 69 | if (const auto lock = m_inImageData.lock()) { 70 | m_lastImageToProcess = lock->image(); 71 | } 72 | requestProcess(); 73 | } 74 | 75 | std::shared_ptr PyrDown::outData(const QtNodes::PortIndex port) { 76 | return m_outImageData; 77 | } 78 | 79 | QWidget* PyrDown::embeddedWidget() { 80 | if (!m_widget) { 81 | // Create inside the widget a horizontal layout with a label "Time ms:" and a spin box 82 | m_widget = new QWidget(); 83 | auto verticalLayout = new QHBoxLayout(m_widget); 84 | auto label = new QLabel("Time ms:", m_widget); 85 | verticalLayout->addWidget(label); 86 | m_spinBox = new QSpinBox(m_widget); 87 | m_spinBox->setRange(0, 999999999); 88 | m_spinBox->setReadOnly(true); 89 | m_spinBox->setButtonSymbols(QAbstractSpinBox::NoButtons); 90 | verticalLayout->addWidget(m_spinBox); 91 | } 92 | return m_widget; 93 | } 94 | 95 | bool PyrDown::portCaptionVisible(QtNodes::PortType port, QtNodes::PortIndex port_index) const { 96 | return true; 97 | } 98 | 99 | QString PyrDown::portCaption(QtNodes::PortType port, QtNodes::PortIndex port_index) const { 100 | switch (port) { 101 | case QtNodes::PortType::In: 102 | if (port_index == 0) { 103 | return QStringLiteral("Image"); 104 | } else { 105 | return QStringLiteral("[OPT]Scale factor (Size)"); 106 | } 107 | case QtNodes::PortType::Out: 108 | return QStringLiteral("Image"); 109 | default: 110 | return QStringLiteral("Image"); 111 | } 112 | } 113 | 114 | QPair PyrDown::processImage(const QImage& image, const QSize& size) { 115 | QElapsedTimer timer; 116 | timer.start(); 117 | const cv::Mat src = QImageToMat(image); 118 | QImage result; 119 | try { 120 | cv::Mat dst; 121 | if (size.isEmpty()) { 122 | cv::pyrDown(src, dst); 123 | } else { 124 | const cv::Size cvSize(src.cols / size.width(), src.rows / size.height()); 125 | cv::pyrDown(src, dst, cvSize); 126 | } 127 | result = MatToQImage(dst); 128 | } catch (cv::Exception& e) { 129 | const QString error = QString("PyrDown::processImage cv::Exception: %1").arg(e.what()); 130 | qCritical() << error; 131 | } 132 | return {static_cast(timer.elapsed()), result}; 133 | } 134 | 135 | void PyrDown::requestProcess() { 136 | if (m_processing) { 137 | return; 138 | } 139 | const auto lockImage = m_inImageData.lock(); 140 | const auto lockSize = m_inSizeData.lock(); 141 | if (!lockImage || m_lastImageToProcess.isNull()) { 142 | return; 143 | } 144 | const QSize size = lockSize ? lockSize->variant().toSize() : QSize(); 145 | m_processing = true; 146 | const auto future = QtConcurrent::run(processImage, m_lastImageToProcess, size); 147 | m_lastImageToProcess = QImage(); 148 | m_watcher.setFuture(future); 149 | } 150 | 151 | void PyrDown::processFinished() { 152 | m_processing = false; 153 | const auto [time, image] = m_watcher.result(); 154 | m_spinBox->setValue(static_cast(time)); 155 | m_outImageData = std::make_shared(image); 156 | emit dataUpdated(0); 157 | } 158 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/PyrDown.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/11/24. 3 | // 4 | 5 | #ifndef PYRDOWN_H 6 | #define PYRDOWN_H 7 | 8 | 9 | #include 10 | #include 11 | #include "Nodes/Data/ImageData.h" 12 | #include "Nodes/Data/VariantData.h" 13 | 14 | class QSpinBox; 15 | 16 | class PyrDown final : public QtNodes::NodeDelegateModel { 17 | Q_OBJECT 18 | 19 | public: 20 | PyrDown(); 21 | 22 | ~PyrDown() override; 23 | 24 | QString caption() const override; 25 | 26 | QString name() const override; 27 | 28 | unsigned nPorts(QtNodes::PortType portType) const override; 29 | 30 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 31 | 32 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 33 | 34 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 35 | 36 | QWidget* embeddedWidget() override; 37 | 38 | bool portCaptionVisible(QtNodes::PortType, QtNodes::PortIndex) const override; 39 | 40 | QString portCaption(QtNodes::PortType, QtNodes::PortIndex) const override; 41 | 42 | private: 43 | static QPair processImage(const QImage& image, const QSize& size); 44 | 45 | private slots: 46 | void requestProcess(); 47 | 48 | void processFinished(); 49 | 50 | private: 51 | QWidget* m_widget = nullptr; 52 | QSpinBox* m_spinBox = nullptr; 53 | // in 54 | // 0 55 | std::weak_ptr m_inImageData; 56 | QImage m_lastImageToProcess; 57 | // 1 58 | std::weak_ptr m_inSizeData; 59 | // out 60 | std::shared_ptr m_outImageData; 61 | QFutureWatcher> m_watcher; 62 | bool m_processing = false; 63 | }; 64 | 65 | 66 | #endif //PYRDOWN_H 67 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/PyrUp.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/11/24. 3 | // 4 | 5 | #include "PyrUp.h" 6 | #include 7 | #include 8 | #include 9 | #include "Nodes/Conversor/MatQt.h" 10 | #include 11 | 12 | PyrUp::PyrUp() { 13 | connect(&m_watcher, &QFutureWatcher>::finished, this, &PyrUp::processFinished); 14 | } 15 | 16 | PyrUp::~PyrUp() { 17 | } 18 | 19 | QString PyrUp::caption() const { 20 | return QStringLiteral("Pyr Up"); 21 | } 22 | 23 | QString PyrUp::name() const { 24 | return QStringLiteral("Pyr Up"); 25 | } 26 | 27 | unsigned PyrUp::nPorts(QtNodes::PortType portType) const { 28 | switch (portType) { 29 | case QtNodes::PortType::In: 30 | return 2; 31 | case QtNodes::PortType::Out: 32 | return 1; 33 | default: 34 | return 0; 35 | } 36 | } 37 | 38 | QtNodes::NodeDataType PyrUp::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { 39 | switch (portType) { 40 | case QtNodes::PortType::In: 41 | if (portIndex == 0) { 42 | return ImageData().type(); 43 | } else { 44 | return VariantData(QSize()).typeIn(); 45 | } 46 | case QtNodes::PortType::Out: 47 | return ImageData().type(); 48 | default: 49 | return ImageData().type(); 50 | } 51 | } 52 | 53 | void PyrUp::setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) { 54 | switch (portIndex) { 55 | case 0: 56 | m_inImageData = std::dynamic_pointer_cast(nodeData); 57 | if (m_inImageData.expired()) { 58 | m_outImageData.reset(); 59 | m_spinBox->setValue(0); 60 | } 61 | break; 62 | case 1: 63 | m_inSizeData = std::dynamic_pointer_cast(nodeData); 64 | 65 | break; 66 | default: 67 | qCritical() << "Wrong port index"; 68 | } 69 | if (const auto lock = m_inImageData.lock()) { 70 | m_lastImageToProcess = lock->image(); 71 | } 72 | requestProcess(); 73 | } 74 | 75 | std::shared_ptr PyrUp::outData(const QtNodes::PortIndex port) { 76 | return m_outImageData; 77 | } 78 | 79 | QWidget* PyrUp::embeddedWidget() { 80 | if (!m_widget) { 81 | // Create inside the widget a horizontal layout with a label "Time ms:" and a spin box 82 | m_widget = new QWidget(); 83 | auto verticalLayout = new QHBoxLayout(m_widget); 84 | auto label = new QLabel("Time ms:", m_widget); 85 | verticalLayout->addWidget(label); 86 | m_spinBox = new QSpinBox(m_widget); 87 | m_spinBox->setRange(0, 999999999); 88 | m_spinBox->setReadOnly(true); 89 | m_spinBox->setButtonSymbols(QAbstractSpinBox::NoButtons); 90 | verticalLayout->addWidget(m_spinBox); 91 | } 92 | return m_widget; 93 | } 94 | 95 | bool PyrUp::portCaptionVisible(QtNodes::PortType port, QtNodes::PortIndex port_index) const { 96 | return true; 97 | } 98 | 99 | QString PyrUp::portCaption(QtNodes::PortType port, QtNodes::PortIndex port_index) const { 100 | switch (port) { 101 | case QtNodes::PortType::In: 102 | if (port_index == 0) { 103 | return QStringLiteral("Image"); 104 | } else { 105 | return QStringLiteral("[OPT]Scale factor (Size)"); 106 | } 107 | case QtNodes::PortType::Out: 108 | return QStringLiteral("Image"); 109 | default: 110 | return QStringLiteral("Image"); 111 | } 112 | } 113 | 114 | QPair PyrUp::processImage(const QImage& image, const QSize& size) { 115 | QElapsedTimer timer; 116 | timer.start(); 117 | const cv::Mat src = QImageToMat(image); 118 | QImage result; 119 | try { 120 | cv::Mat dst; 121 | if (size.isEmpty()) { 122 | cv::pyrUp(src, dst); 123 | } else { 124 | const cv::Size cvSize(src.cols / size.width(), src.rows / size.height()); 125 | cv::pyrUp(src, dst, cvSize); 126 | } 127 | result = MatToQImage(dst); 128 | } catch (cv::Exception& e) { 129 | const QString error = QString("PyrDown::processImage cv::Exception: %1").arg(e.what()); 130 | qCritical() << error; 131 | } 132 | return {static_cast(timer.elapsed()), result}; 133 | } 134 | 135 | void PyrUp::requestProcess() { 136 | if (m_processing) { 137 | return; 138 | } 139 | const auto lockImage = m_inImageData.lock(); 140 | const auto lockSize = m_inSizeData.lock(); 141 | if (!lockImage || m_lastImageToProcess.isNull()) { 142 | return; 143 | } 144 | const QSize size = lockSize ? lockSize->variant().toSize() : QSize(); 145 | m_processing = true; 146 | const auto future = QtConcurrent::run(processImage, m_lastImageToProcess, size); 147 | m_lastImageToProcess = QImage(); 148 | m_watcher.setFuture(future); 149 | } 150 | 151 | void PyrUp::processFinished() { 152 | m_processing = false; 153 | const auto [time, image] = m_watcher.result(); 154 | m_spinBox->setValue(static_cast(time)); 155 | m_outImageData = std::make_shared(image); 156 | emit dataUpdated(0); 157 | } 158 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/PyrUp.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/11/24. 3 | // 4 | 5 | #ifndef PYRUP_H 6 | #define PYRUP_H 7 | 8 | 9 | #include 10 | #include 11 | #include "Nodes/Data/ImageData.h" 12 | #include "Nodes/Data/VariantData.h" 13 | 14 | class QSpinBox; 15 | 16 | class PyrUp final : public QtNodes::NodeDelegateModel { 17 | Q_OBJECT 18 | 19 | public: 20 | PyrUp(); 21 | 22 | ~PyrUp() override; 23 | 24 | QString caption() const override; 25 | 26 | QString name() const override; 27 | 28 | unsigned nPorts(QtNodes::PortType portType) const override; 29 | 30 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 31 | 32 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 33 | 34 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 35 | 36 | QWidget* embeddedWidget() override; 37 | 38 | bool portCaptionVisible(QtNodes::PortType, QtNodes::PortIndex) const override; 39 | 40 | QString portCaption(QtNodes::PortType, QtNodes::PortIndex) const override; 41 | 42 | private: 43 | static QPair processImage(const QImage& image, const QSize& size); 44 | 45 | private slots: 46 | void requestProcess(); 47 | 48 | void processFinished(); 49 | 50 | private: 51 | QWidget* m_widget = nullptr; 52 | QSpinBox* m_spinBox = nullptr; 53 | // in 54 | // 0 55 | std::weak_ptr m_inImageData; 56 | QImage m_lastImageToProcess; 57 | // 1 58 | std::weak_ptr m_inSizeData; 59 | // out 60 | std::shared_ptr m_outImageData; 61 | QFutureWatcher> m_watcher; 62 | bool m_processing = false; 63 | }; 64 | 65 | 66 | #endif //PYRUP_H 67 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/RectangleForm.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | RectangleForm 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | RectangleModel 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/RectangleModel.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/26/24. 3 | // 4 | 5 | // You may need to build the project (run Qt uic code generator) to get "ui_RectangleModel.h" resolved 6 | 7 | #include "RectangleModel.h" 8 | #include "ui_RectangleForm.h" 9 | 10 | 11 | RectangleModel::RectangleModel() { 12 | } 13 | 14 | RectangleModel::~RectangleModel() { 15 | } 16 | 17 | QString RectangleModel::caption() const { 18 | return QStringLiteral("Rectangle"); 19 | } 20 | 21 | QString RectangleModel::name() const { 22 | return QStringLiteral("Rectangle"); 23 | } 24 | 25 | unsigned RectangleModel::nPorts(QtNodes::PortType portType) const { 26 | } 27 | 28 | QtNodes::NodeDataType RectangleModel::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { 29 | } 30 | 31 | void RectangleModel::setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) { 32 | } 33 | 34 | std::shared_ptr RectangleModel::outData(const QtNodes::PortIndex port) { 35 | } 36 | 37 | QWidget* RectangleModel::embeddedWidget() { 38 | } 39 | -------------------------------------------------------------------------------- /src/Nodes/OpenCV/RectangleModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/26/24. 3 | // 4 | 5 | #ifndef RECTANGLEMODEL_H 6 | #define RECTANGLEMODEL_H 7 | 8 | #include 9 | 10 | QT_BEGIN_NAMESPACE 11 | 12 | namespace Ui { 13 | class RectangleForm; 14 | } 15 | 16 | QT_END_NAMESPACE 17 | 18 | class RectangleModel : public QtNodes::NodeDelegateModel { 19 | Q_OBJECT 20 | 21 | public: 22 | explicit RectangleModel(); 23 | 24 | ~RectangleModel() override; 25 | 26 | QString caption() const override; 27 | 28 | QString name() const override; 29 | 30 | unsigned nPorts(QtNodes::PortType portType) const override; 31 | 32 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 33 | 34 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 35 | 36 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 37 | 38 | QWidget* embeddedWidget() override; 39 | 40 | private: 41 | Ui::RectangleForm* ui = nullptr; 42 | }; 43 | 44 | 45 | #endif //RECTANGLEMODEL_H 46 | -------------------------------------------------------------------------------- /src/Nodes/Variables/FileFromUrlForm.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | FileFromUrlForm 4 | 5 | 6 | 7 | 0 8 | 0 9 | 610 10 | 128 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | Url 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | Qt::Horizontal 33 | 34 | 35 | 36 | 40 37 | 20 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | false 46 | 47 | 48 | Request 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | Progress 58 | 59 | 60 | 61 | 62 | 63 | 64 | 0 65 | 66 | 67 | 68 | 69 | 70 | 71 | File status 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | Empty 81 | 82 | 83 | true 84 | 85 | 86 | true 87 | 88 | 89 | 90 | 91 | 92 | 93 | Error 94 | 95 | 96 | true 97 | 98 | 99 | 100 | 101 | 102 | 103 | Loaded 104 | 105 | 106 | true 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | CheckBoxReadOnly 117 | QCheckBox 118 |
CustomWidget/CheckBoxReadOnly.h
119 |
120 |
121 | 122 | 123 |
124 | -------------------------------------------------------------------------------- /src/Nodes/Variables/FileFromUrlModel.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/11/24. 3 | // 4 | 5 | #include "FileFromUrlModel.h" 6 | #include "ui_FileFromUrlForm.h" 7 | 8 | FileFromUrlModel::FileFromUrlModel() { 9 | m_networkManager = new QNetworkAccessManager(this); 10 | } 11 | 12 | FileFromUrlModel::~FileFromUrlModel() { 13 | } 14 | 15 | QString FileFromUrlModel::caption() const { 16 | return QString("File From URL"); 17 | } 18 | 19 | QString FileFromUrlModel::name() const { 20 | return QString("File From URL"); 21 | } 22 | 23 | unsigned FileFromUrlModel::nPorts(QtNodes::PortType portType) const { 24 | switch (portType) { 25 | case QtNodes::PortType::In: 26 | return 0; 27 | case QtNodes::PortType::Out: 28 | return 1; 29 | default: 30 | return 0; 31 | } 32 | } 33 | 34 | QtNodes::NodeDataType FileFromUrlModel::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { 35 | switch (portType) { 36 | case QtNodes::PortType::Out: 37 | return FileData().type(); 38 | default: 39 | return FileData().type(); 40 | } 41 | } 42 | 43 | void FileFromUrlModel::setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) { 44 | } 45 | 46 | std::shared_ptr FileFromUrlModel::outData(const QtNodes::PortIndex port) { 47 | return m_outFileData; 48 | } 49 | 50 | QWidget* FileFromUrlModel::embeddedWidget() { 51 | if (m_widget == nullptr) { 52 | m_widget = new QWidget(); 53 | m_ui.reset(new Ui::FileFromUrlForm); 54 | m_ui->setupUi(m_widget); 55 | connect(m_ui->le_url, &QLineEdit::textEdited, this, &FileFromUrlModel::onTextEdited); 56 | connect(m_ui->pb_request, &QPushButton::clicked, this, &FileFromUrlModel::onStartRequest); 57 | } 58 | return m_widget; 59 | } 60 | 61 | void FileFromUrlModel::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { 62 | // update the progressBar 63 | if (m_ui) { 64 | m_ui->progressBar->setMaximum(bytesTotal); 65 | m_ui->progressBar->setValue(bytesReceived); 66 | } 67 | } 68 | 69 | void FileFromUrlModel::onError(QNetworkReply::NetworkError code) { 70 | m_reply->deleteLater(); 71 | if (m_ui) { 72 | m_ui->pb_request->setEnabled(true); 73 | m_ui->cb_error->setChecked(true); 74 | // reset the progressBar 75 | m_ui->progressBar->setValue(0); 76 | } 77 | } 78 | 79 | void FileFromUrlModel::onRequestFinished() { 80 | m_reply->deleteLater(); 81 | if (m_ui) { 82 | m_ui->pb_request->setEnabled(true); 83 | } 84 | if (m_reply->error() == QNetworkReply::NoError) { 85 | // create a FileData with the downloaded file 86 | m_outFileData = std::make_shared(); 87 | m_outFileData->setData(m_reply->readAll()); 88 | if (m_ui) { 89 | m_ui->cb_loaded->setChecked(true); 90 | } 91 | } else { 92 | m_outFileData.reset(); 93 | m_ui->cb_error->setChecked(true); 94 | } 95 | 96 | emit dataUpdated(0); 97 | } 98 | 99 | void FileFromUrlModel::onTextEdited(const QString& text) { 100 | m_url = QUrl(text); 101 | if (m_ui) { 102 | m_ui->pb_request->setEnabled(m_url.isValid()); 103 | } 104 | } 105 | 106 | void FileFromUrlModel::onStartRequest() { 107 | if (m_url.isValid()) { 108 | if (m_ui) { 109 | m_ui->pb_request->setEnabled(false); 110 | m_ui->progressBar->setValue(0); 111 | m_ui->cb_empty->setChecked(true); 112 | } 113 | // start the request 114 | const QNetworkRequest request(m_url); 115 | m_reply = m_networkManager->get(request); 116 | connect(m_reply, &QNetworkReply::downloadProgress, this, &FileFromUrlModel::onDownloadProgress); 117 | connect(m_reply, &QNetworkReply::errorOccurred, this, &FileFromUrlModel::onError); 118 | connect(m_reply, &QNetworkReply::finished, this, &FileFromUrlModel::onRequestFinished); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/Nodes/Variables/FileFromUrlModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/11/24. 3 | // 4 | 5 | #ifndef FILEFROMURL_H 6 | #define FILEFROMURL_H 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | #include 14 | #include 15 | #include "Nodes/Data/FileData.h" 16 | 17 | namespace Ui { 18 | class FileFromUrlForm; 19 | } 20 | 21 | class FileFromUrlModel final : public QtNodes::NodeDelegateModel { 22 | Q_OBJECT 23 | 24 | public: 25 | FileFromUrlModel(); 26 | 27 | ~FileFromUrlModel() override; 28 | 29 | QString caption() const override; 30 | 31 | QString name() const override; 32 | 33 | unsigned nPorts(QtNodes::PortType portType) const override; 34 | 35 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 36 | 37 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 38 | 39 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 40 | 41 | QWidget* embeddedWidget() override; 42 | 43 | private slots: 44 | 45 | void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); 46 | 47 | void onError(QNetworkReply::NetworkError code); 48 | 49 | void onRequestFinished(); 50 | 51 | void onTextEdited(const QString& text); 52 | 53 | void onStartRequest(); 54 | 55 | private: 56 | QNetworkAccessManager* m_networkManager = nullptr; 57 | QWidget* m_widget = nullptr; 58 | QNetworkReply* m_reply = nullptr; 59 | QScopedPointer m_ui; 60 | 61 | QUrl m_url; 62 | 63 | // out 64 | //1 65 | std::shared_ptr m_outFileData; 66 | }; 67 | 68 | 69 | #endif //FILEFROMURL_H 70 | -------------------------------------------------------------------------------- /src/Nodes/Variables/FileVarForm.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | FileVarForm 4 | 5 | 6 | 7 | 0 8 | 0 9 | 266 10 | 82 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | Path: 24 | 25 | 26 | 27 | 28 | 29 | 30 | Exist 31 | 32 | 33 | 34 | 35 | 36 | 37 | ... 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | Name 52 | 53 | 54 | 55 | 56 | 57 | 58 | true 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | CheckBoxReadOnly 67 | QCheckBox 68 |
CustomWidget/CheckBoxReadOnly.h
69 |
70 |
71 | 72 | 73 |
74 | -------------------------------------------------------------------------------- /src/Nodes/Variables/FileVarModel.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/1/24. 3 | // 4 | 5 | #include "FileVarModel.h" 6 | #include "ui_FileVarForm.h" 7 | #include 8 | 9 | FileVarModel::FileVarModel() { 10 | } 11 | 12 | FileVarModel::~FileVarModel() { 13 | } 14 | 15 | QString FileVarModel::caption() const { 16 | return "File"; 17 | } 18 | 19 | QString FileVarModel::name() const { 20 | return "File"; 21 | } 22 | 23 | unsigned FileVarModel::nPorts(QtNodes::PortType portType) const { 24 | switch (portType) { 25 | case QtNodes::PortType::In: 26 | return 0; 27 | case QtNodes::PortType::Out: 28 | return 1; 29 | default: 30 | return 0; 31 | } 32 | } 33 | 34 | QtNodes::NodeDataType FileVarModel::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { 35 | switch (portType) { 36 | case QtNodes::PortType::In: 37 | return FileData().type(); 38 | case QtNodes::PortType::Out: 39 | return FileData().type(); 40 | default: 41 | return FileData().type(); 42 | } 43 | } 44 | 45 | void FileVarModel::setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) { 46 | } 47 | 48 | std::shared_ptr FileVarModel::outData(const QtNodes::PortIndex port) { 49 | return m_outFileData; 50 | } 51 | 52 | QWidget* FileVarModel::embeddedWidget() { 53 | if (!m_widget) { 54 | m_widget = new QWidget(); 55 | m_ui = std::make_unique(); 56 | m_ui->setupUi(m_widget); 57 | connect(m_ui->tb_find, &QToolButton::clicked, this, &FileVarModel::onBrowseButtonClicked); 58 | connect(m_ui->le_path, &QLineEdit::textChanged, this, &FileVarModel::onTextChanged); 59 | } 60 | return m_widget; 61 | } 62 | 63 | QJsonObject FileVarModel::save() const { 64 | QJsonObject modelJson = NodeDelegateModel::save(); 65 | modelJson["path"] = m_ui->le_path->text(); 66 | return modelJson; 67 | } 68 | 69 | void FileVarModel::load(QJsonObject const& jsonObj) { 70 | const QJsonValue path = jsonObj["path"]; 71 | if (!path.isUndefined()) { 72 | onTextChanged(path.toString()); 73 | } 74 | } 75 | 76 | void FileVarModel::onBrowseButtonClicked() { 77 | // open file dialog from the home directory 78 | const QString fileName = QFileDialog::getOpenFileName(nullptr, tr("Open File"), QDir::homePath()); 79 | if (!fileName.isEmpty()) { 80 | onTextChanged(fileName); 81 | } 82 | } 83 | 84 | void FileVarModel::onTextChanged(const QString& text) { 85 | QSignalBlocker blocker(m_ui->le_path); 86 | m_ui->le_path->setText(text); 87 | const QFileInfo file(text); 88 | const bool exists = file.exists(); 89 | m_ui->cb_exist->setChecked(exists); 90 | m_ui->le_path->adjustSize(); 91 | if (exists) { 92 | m_ui->le_name->setText(file.fileName()); 93 | m_outFileData = std::make_shared(text); 94 | } else { 95 | m_outFileData.reset(); 96 | } 97 | emit dataUpdated(0); 98 | } 99 | -------------------------------------------------------------------------------- /src/Nodes/Variables/FileVarModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/1/24. 3 | // 4 | 5 | #ifndef FILEVARMODEL_H 6 | #define FILEVARMODEL_H 7 | 8 | #include 9 | #include "Nodes/Data/FileData.h" 10 | #include "Nodes/Data/CascadeClassifierData.h" 11 | 12 | namespace Ui { 13 | class FileVarForm; 14 | } 15 | 16 | 17 | class FileVarModel final : public QtNodes::NodeDelegateModel { 18 | Q_OBJECT 19 | 20 | public: 21 | FileVarModel(); 22 | 23 | ~FileVarModel() override; 24 | 25 | QString caption() const override; 26 | 27 | QString name() const override; 28 | 29 | unsigned nPorts(QtNodes::PortType portType) const override; 30 | 31 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 32 | 33 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 34 | 35 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 36 | 37 | QWidget* embeddedWidget() override; 38 | 39 | QJsonObject save() const override; 40 | 41 | void load(QJsonObject const& jsonObj) override; 42 | 43 | private slots: 44 | void onBrowseButtonClicked(); 45 | 46 | void onTextChanged(const QString& text); 47 | 48 | private: 49 | std::unique_ptr m_ui; 50 | QWidget* m_widget = nullptr; 51 | 52 | // out 53 | std::shared_ptr m_outFileData; 54 | }; 55 | 56 | 57 | #endif //FILEVARMODEL_H 58 | -------------------------------------------------------------------------------- /src/Nodes/Variables/RectForm.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | RectForm 4 | 5 | 6 | 7 | 0 8 | 0 9 | 307 10 | 105 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | Size 21 | 22 | 23 | 24 | 25 | 26 | 27 | Top left 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | W 37 | 38 | 39 | 40 | 41 | 42 | 43 | 999999999 44 | 45 | 46 | 47 | 48 | 49 | 50 | H 51 | 52 | 53 | 54 | 55 | 56 | 57 | 999999999 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | X: 69 | 70 | 71 | 72 | 73 | 74 | 75 | -999999999 76 | 77 | 78 | 999999999 79 | 80 | 81 | 82 | 83 | 84 | 85 | Y: 86 | 87 | 88 | 89 | 90 | 91 | 92 | -999999999 93 | 94 | 95 | 999999999 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | Center 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | X: 114 | 115 | 116 | 117 | 118 | 119 | 120 | true 121 | 122 | 123 | QAbstractSpinBox::NoButtons 124 | 125 | 126 | -999999999 127 | 128 | 129 | 999999999 130 | 131 | 132 | 133 | 134 | 135 | 136 | Y: 137 | 138 | 139 | 140 | 141 | 142 | 143 | true 144 | 145 | 146 | QAbstractSpinBox::NoButtons 147 | 148 | 149 | -999999999 150 | 151 | 152 | 999999999 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /src/Nodes/Variables/RectModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/9/24. 3 | // 4 | 5 | #ifndef RECTMODEL_H 6 | #define RECTMODEL_H 7 | 8 | 9 | #include 10 | #include 11 | #include "Nodes/Data/RectData.h" 12 | #include "Nodes/Data/PointData.h" 13 | #include "Nodes/Data/VariantData.h" 14 | 15 | namespace Ui { 16 | class RectForm; 17 | } 18 | 19 | class RectModel final : public QtNodes::NodeDelegateModel { 20 | Q_OBJECT 21 | 22 | public: 23 | RectModel(); 24 | 25 | ~RectModel() override; 26 | 27 | QString caption() const override; 28 | 29 | QString name() const override; 30 | 31 | unsigned nPorts(QtNodes::PortType portType) const override; 32 | 33 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 34 | 35 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 36 | 37 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 38 | 39 | QWidget* embeddedWidget() override; 40 | 41 | bool portCaptionVisible(QtNodes::PortType, QtNodes::PortIndex) const override; 42 | 43 | QString portCaption(QtNodes::PortType, QtNodes::PortIndex) const override; 44 | 45 | private slots: 46 | void updateRectFromUI(); 47 | 48 | void updateCenter(); 49 | 50 | private: 51 | QWidget* m_widget = nullptr; 52 | std::unique_ptr m_ui; 53 | // in 54 | // 0 55 | std::weak_ptr m_inRectData; 56 | //out 57 | // 0 58 | QRect m_outRect; 59 | std::shared_ptr m_outRectsData; 60 | // 1 61 | std::shared_ptr m_outCenterData; 62 | 63 | }; 64 | 65 | 66 | #endif //RECTMODEL_H 67 | -------------------------------------------------------------------------------- /src/Nodes/Variables/RectVarModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/1/24. 3 | // 4 | 5 | #ifndef RECTVARMODEL_H 6 | #define RECTVARMODEL_H 7 | 8 | 9 | #include 10 | #include 11 | #include "Nodes/Data/RectsData.h" 12 | #include "Nodes/Data/RectData.h" 13 | #include "Nodes/Data/PointData.h" 14 | #include "Nodes/Data/VariantData.h" 15 | 16 | 17 | class RectVarModel final : public QtNodes::NodeDelegateModel { 18 | Q_OBJECT 19 | 20 | public: 21 | RectVarModel(); 22 | 23 | ~RectVarModel() override; 24 | 25 | QString caption() const override; 26 | 27 | QString name() const override; 28 | 29 | unsigned nPorts(QtNodes::PortType portType) const override; 30 | 31 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 32 | 33 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 34 | 35 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 36 | 37 | QWidget* embeddedWidget() override; 38 | 39 | QString portCaption(QtNodes::PortType, QtNodes::PortIndex) const override; 40 | 41 | bool portCaptionVisible(QtNodes::PortType, QtNodes::PortIndex) const override { return true; } 42 | 43 | //QJsonObject save() const override; 44 | 45 | //void load(QJsonObject const& jsonObj) override; 46 | 47 | QtNodes::ConnectionPolicy portConnectionPolicy(QtNodes::PortType, QtNodes::PortIndex) const override; 48 | 49 | 50 | private slots: 51 | void updateRect(); 52 | 53 | void inputConnectionDeleted(QtNodes::ConnectionId const&) override; 54 | 55 | void inputConnectionCreated(QtNodes::ConnectionId const&) override; 56 | 57 | private: 58 | QWidget* m_widget = nullptr; 59 | 60 | // in 61 | QMap> m_inVRectsDataMap; 62 | QMap> m_inRectDataMap; 63 | //std::weak_ptr m_inRectsData; 64 | 65 | // out 66 | //0 67 | std::shared_ptr m_outRectsData; 68 | QList> m_outRectsDataList; 69 | }; 70 | 71 | 72 | #endif //RECTVARMODEL_H 73 | -------------------------------------------------------------------------------- /src/Nodes/Variables/SizeVarForm.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | SizeVarForm 4 | 5 | 6 | 7 | 0 8 | 0 9 | 157 10 | 70 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | Width 21 | 22 | 23 | 24 | 25 | 26 | 27 | 999999999 28 | 29 | 30 | 31 | 32 | 33 | 34 | Height 35 | 36 | 37 | 38 | 39 | 40 | 41 | 999999999 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/Nodes/Variables/SizeVarModel.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/29/24. 3 | // 4 | 5 | #include "SizeVarModel.h" 6 | #include "ui_SizeVarForm.h" 7 | 8 | SizeVarModel::SizeVarModel() { 9 | } 10 | 11 | SizeVarModel::~SizeVarModel() { 12 | } 13 | 14 | QString SizeVarModel::caption() const { 15 | return QString("Size"); 16 | } 17 | 18 | QString SizeVarModel::name() const { 19 | return QString("Size"); 20 | } 21 | 22 | unsigned SizeVarModel::nPorts(QtNodes::PortType portType) const { 23 | switch (portType) { 24 | case QtNodes::PortType::In: 25 | return 1; 26 | case QtNodes::PortType::Out: 27 | return 3; 28 | default: 29 | return 0; 30 | } 31 | } 32 | 33 | QtNodes::NodeDataType SizeVarModel::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { 34 | switch (portType) { 35 | case QtNodes::PortType::In: 36 | return VariantData().typeIn(); 37 | case QtNodes::PortType::Out: 38 | switch (portIndex) { 39 | case 0: 40 | return VariantData(QSize()).type(); 41 | case 1: 42 | return VariantData(0).type(); 43 | case 2: 44 | return VariantData(0).type(); 45 | default: 46 | break; 47 | } 48 | default: 49 | return VariantData().type(); 50 | } 51 | } 52 | 53 | void SizeVarModel::setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) { 54 | m_inSizeData = std::dynamic_pointer_cast(nodeData); 55 | const auto lockSize = m_inSizeData.lock(); 56 | if (lockSize && lockSize->metaType() == QMetaType::QSize){ 57 | setOutSize(lockSize->variant().toSize()); 58 | // disable the spinboxes 59 | m_ui->sb_width->setEnabled(false); 60 | m_ui->sb_height->setEnabled(false); 61 | } else { 62 | setOutSize(m_outSize); 63 | // enable the spinboxes 64 | m_ui->sb_width->setEnabled(true); 65 | m_ui->sb_height->setEnabled(true); 66 | } 67 | } 68 | 69 | std::shared_ptr SizeVarModel::outData(const QtNodes::PortIndex port) { 70 | switch (port) { 71 | case 0: 72 | return m_outSizeData; 73 | case 1: 74 | return m_outWidthData; 75 | case 2: 76 | return m_outHeightData; 77 | default: 78 | return nullptr; 79 | } 80 | } 81 | 82 | QWidget* SizeVarModel::embeddedWidget() { 83 | if (!m_widget) { 84 | m_ui = std::make_unique(); 85 | m_widget = new QWidget(); 86 | m_ui->setupUi(m_widget); 87 | // sb_width and sb_height are QSpinBox 88 | connect(m_ui->sb_width, QOverload::of(&QSpinBox::valueChanged), [this](int value) { 89 | setOutSize(QSize(value, m_outSize.height())); 90 | }); 91 | connect(m_ui->sb_height, QOverload::of(&QSpinBox::valueChanged), [this](int value) { 92 | setOutSize(QSize(m_outSize.width(), value)); 93 | }); 94 | setOutSize(QSize(0, 0)); 95 | } 96 | return m_widget; 97 | } 98 | 99 | QJsonObject SizeVarModel::save() const { 100 | QJsonObject modelJson = NodeDelegateModel::save(); 101 | if (m_inSizeData.expired() && m_ui) { 102 | modelJson["width"] = m_ui->sb_width->value(); 103 | modelJson["height"] = m_ui->sb_height->value(); 104 | } 105 | return modelJson; 106 | } 107 | 108 | void SizeVarModel::load(QJsonObject const& jsonObj) { 109 | if (m_inSizeData.expired() && m_ui) { 110 | setOutSize(QSize(jsonObj["width"].toInt(), jsonObj["height"].toInt())); 111 | } 112 | } 113 | 114 | void SizeVarModel::setOutSize(const QSize& size) { 115 | // updates the size from incoming data 116 | m_outSize = size; 117 | m_outSizeData = std::make_shared(m_outSize); 118 | m_outWidthData = std::make_shared(m_outSize.width()); 119 | m_outHeightData = std::make_shared(m_outSize.height()); 120 | // block signals to avoid infinite loop 121 | QSignalBlocker blocker(m_ui->sb_width); 122 | QSignalBlocker blocker2(m_ui->sb_height); 123 | m_ui->sb_width->setValue(m_outSize.width()); 124 | m_ui->sb_height->setValue(m_outSize.height()); 125 | 126 | emit dataUpdated(0); 127 | emit dataUpdated(1); 128 | emit dataUpdated(2); 129 | } 130 | -------------------------------------------------------------------------------- /src/Nodes/Variables/SizeVarModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/29/24. 3 | // 4 | 5 | #ifndef SIZEVARMODEL_H 6 | #define SIZEVARMODEL_H 7 | 8 | #include 9 | #include "Nodes/Data/VariantData.h" 10 | 11 | namespace Ui { 12 | class SizeVarForm; 13 | } 14 | 15 | class SizeVarModel final : public QtNodes::NodeDelegateModel { 16 | Q_OBJECT 17 | public: 18 | SizeVarModel(); 19 | 20 | ~SizeVarModel() override; 21 | 22 | QString caption() const override; 23 | 24 | QString name() const override; 25 | 26 | unsigned nPorts(QtNodes::PortType portType) const override; 27 | 28 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 29 | 30 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 31 | 32 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 33 | 34 | QWidget* embeddedWidget() override; 35 | 36 | QJsonObject save() const override; 37 | 38 | void load(QJsonObject const& jsonObj) override; 39 | 40 | private: 41 | void setOutSize(const QSize& size); 42 | 43 | private: 44 | std::unique_ptr m_ui; 45 | QWidget* m_widget = nullptr; 46 | 47 | // in 48 | std::weak_ptr m_inSizeData; 49 | // out 50 | // 0 51 | QSize m_outSize; 52 | std::shared_ptr m_outSizeData; 53 | // 1 54 | std::shared_ptr m_outWidthData; 55 | // 2 56 | std::shared_ptr m_outHeightData; 57 | }; 58 | 59 | 60 | 61 | #endif //SIZEVARMODEL_H 62 | -------------------------------------------------------------------------------- /src/Nodes/Video/CameraForm.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | CameraForm 4 | 5 | 6 | 7 | 0 8 | 0 9 | 225 10 | 70 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Device: 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 0 31 | 0 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | Qt::RightToLeft 42 | 43 | 44 | Available frames 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | CheckBoxReadOnly 53 | QCheckBox 54 |
CustomWidget/CheckBoxReadOnly.h
55 |
56 |
57 | 58 | 59 |
60 | -------------------------------------------------------------------------------- /src/Nodes/Video/CameraModel.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/9/24. 3 | // 4 | 5 | #include "CameraModel.h" 6 | #include "ui_CameraForm.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | CameraModel::CameraModel() { 17 | m_captureSession.reset(new QMediaCaptureSession); 18 | m_videoSink.reset(new QVideoSink); 19 | connect(m_videoSink.data(), &QVideoSink::videoFrameChanged, this, &CameraModel::onFrameAvailable); 20 | setCamera(QMediaDevices::defaultVideoInput()); 21 | } 22 | 23 | CameraModel::~CameraModel() { 24 | } 25 | 26 | QString CameraModel::caption() const { 27 | return QString("Camera"); 28 | } 29 | 30 | QString CameraModel::name() const { 31 | return QString("Camera"); 32 | } 33 | 34 | unsigned CameraModel::nPorts(QtNodes::PortType portType) const { 35 | switch (portType) { 36 | case QtNodes::PortType::In: 37 | return 0; 38 | case QtNodes::PortType::Out: 39 | return 1; 40 | default: 41 | return 0; 42 | } 43 | } 44 | 45 | QtNodes::NodeDataType CameraModel::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { 46 | switch (portType) { 47 | case QtNodes::PortType::In: 48 | return ImageData().type(); 49 | case QtNodes::PortType::Out: 50 | return ImageData().type(); 51 | default: 52 | return ImageData().type(); 53 | } 54 | } 55 | 56 | void CameraModel::setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) { 57 | } 58 | 59 | std::shared_ptr CameraModel::outData(const QtNodes::PortIndex port) { 60 | return m_outImageData; 61 | } 62 | 63 | QWidget* CameraModel::embeddedWidget() { 64 | if (!m_widget) { 65 | m_ui.reset(new Ui::CameraForm); 66 | m_widget = new QWidget(); 67 | m_ui->setupUi(m_widget); 68 | // cb_devices QComboBox 69 | connect(m_ui->cb_devices, QOverload::of(&QComboBox::currentIndexChanged), this, 70 | &CameraModel::onDeviceChanged); 71 | updateCameras(); 72 | } 73 | return m_widget; 74 | } 75 | 76 | 77 | void CameraModel::onDeviceChanged(const int index) { 78 | const QList devices = QMediaDevices::videoInputs(); 79 | if (index < devices.size()) { 80 | setCamera(devices[index]); 81 | } 82 | } 83 | 84 | void CameraModel::updateCameras() { 85 | if (m_ui) { 86 | m_ui->cb_devices->clear(); 87 | const QList devices = QMediaDevices::videoInputs(); 88 | for (const QCameraDevice& device: devices) { 89 | m_ui->cb_devices->addItem(device.description()); 90 | } 91 | } 92 | } 93 | 94 | void CameraModel::setCamera(const QCameraDevice& device) { 95 | m_camera.reset(new QCamera(device)); 96 | m_captureSession->setCamera(m_camera.data()); 97 | 98 | m_captureSession->setVideoSink(m_videoSink.data()); 99 | 100 | m_camera->start(); 101 | } 102 | 103 | void CameraModel::onFrameAvailable(const QVideoFrame& frame) { 104 | QVideoFrame copy(frame); 105 | if (copy.map(QVideoFrame::ReadOnly)) { 106 | const QImage image = copy.toImage(); 107 | m_outImageData = std::make_shared(image); 108 | emit dataUpdated(0); 109 | // update ui label with image 110 | if (m_ui) { 111 | m_ui->cb_takingFrame->setChecked(true); 112 | } 113 | } 114 | else { 115 | m_outImageData.reset(); 116 | emit dataUpdated(0); 117 | if (m_ui) { 118 | m_ui->cb_takingFrame->setChecked(false); 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/Nodes/Video/CameraModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/9/24. 3 | // 4 | 5 | #ifndef CAMERAMODEL_H 6 | #define CAMERAMODEL_H 7 | 8 | 9 | #include 10 | #include 11 | 12 | #include "Nodes/Data/ImageData.h" 13 | 14 | namespace Ui { 15 | class CameraForm; 16 | } 17 | 18 | class QLabel; 19 | class QCamera; 20 | class QComboBox; 21 | class QVideoFrame; 22 | class QMediaCaptureSession; 23 | class QVideoSink; 24 | class QCameraDevice; 25 | 26 | class CameraModel final : public QtNodes::NodeDelegateModel { 27 | Q_OBJECT 28 | 29 | public: 30 | CameraModel(); 31 | 32 | ~CameraModel() override; 33 | 34 | QString caption() const override; 35 | 36 | QString name() const override; 37 | 38 | unsigned nPorts(QtNodes::PortType portType) const override; 39 | 40 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 41 | 42 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 43 | 44 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 45 | 46 | QWidget* embeddedWidget() override; 47 | 48 | bool resizable() const override { return true; } 49 | 50 | 51 | private slots: 52 | void onDeviceChanged(int index); 53 | 54 | void updateCameras(); 55 | 56 | void setCamera(const QCameraDevice& device); 57 | 58 | void onFrameAvailable(const QVideoFrame& frame); 59 | 60 | private: 61 | QWidget* m_widget = nullptr; 62 | QScopedPointer m_ui; 63 | 64 | QScopedPointer m_camera; 65 | QScopedPointer m_captureSession; 66 | QScopedPointer m_videoSink; 67 | 68 | // out 69 | std::shared_ptr m_outImageData; 70 | }; 71 | 72 | 73 | #endif //CAMERAMODEL_H 74 | -------------------------------------------------------------------------------- /src/Nodes/Video/CaptureModel.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/9/24. 3 | // 4 | 5 | #include "CaptureModel.h" 6 | 7 | #include 8 | 9 | QString CaptureModel::caption() const { 10 | return QString("Capture"); 11 | } 12 | 13 | QString CaptureModel::name() const { 14 | return QString("Capture"); 15 | } 16 | 17 | unsigned CaptureModel::nPorts(QtNodes::PortType portType) const { 18 | switch (portType) { 19 | case QtNodes::PortType::In: 20 | return 1; 21 | case QtNodes::PortType::Out: 22 | return 1; 23 | default: 24 | return 0; 25 | } 26 | } 27 | 28 | QtNodes::NodeDataType CaptureModel::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { 29 | return ImageData().type(); 30 | } 31 | 32 | void CaptureModel::setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) { 33 | switch (portIndex) { 34 | case 0: 35 | m_inImageData = std::dynamic_pointer_cast(nodeData); 36 | break; 37 | } 38 | } 39 | 40 | std::shared_ptr CaptureModel::outData(const QtNodes::PortIndex port) { 41 | return m_outImageData; 42 | } 43 | 44 | QWidget* CaptureModel::embeddedWidget() { 45 | if (!m_button) { 46 | m_button = new QPushButton("Capture"); 47 | connect(m_button, &QPushButton::clicked, this, &CaptureModel::captureClicked); 48 | } 49 | return m_button; 50 | } 51 | 52 | void CaptureModel::captureClicked() { 53 | if (const auto lock = m_inImageData.lock()) { 54 | m_outImageData = std::make_shared(lock->image()); 55 | } else { 56 | m_outImageData.reset(); 57 | } 58 | emit dataUpdated(0); 59 | } 60 | -------------------------------------------------------------------------------- /src/Nodes/Video/CaptureModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 3/9/24. 3 | // 4 | 5 | #ifndef CAPTUREMODEL_H 6 | #define CAPTUREMODEL_H 7 | 8 | #include 9 | #include 10 | 11 | #include "Nodes/Data/ImageData.h" 12 | 13 | class QPushButton; 14 | 15 | class CaptureModel final : public QtNodes::NodeDelegateModel { 16 | Q_OBJECT 17 | 18 | public: 19 | QString caption() const override; 20 | 21 | QString name() const override; 22 | 23 | unsigned nPorts(QtNodes::PortType portType) const override; 24 | 25 | QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; 26 | 27 | void setInData(std::shared_ptr nodeData, const QtNodes::PortIndex portIndex) override; 28 | 29 | std::shared_ptr outData(const QtNodes::PortIndex port) override; 30 | 31 | QWidget* embeddedWidget() override; 32 | 33 | private slots: 34 | void captureClicked(); 35 | 36 | private: 37 | QPushButton* m_button = nullptr; 38 | // in 39 | // 0 40 | std::weak_ptr m_inImageData; 41 | // out 42 | // 0 43 | std::shared_ptr m_outImageData; 44 | }; 45 | 46 | 47 | #endif //CAPTUREMODEL_H 48 | -------------------------------------------------------------------------------- /src/Widgets/MainWindow.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/24/24. 3 | // 4 | 5 | // You may need to build the project (run Qt uic code generator) to get "ui_MainWindow.h" resolved 6 | 7 | #include "MainWindow.h" 8 | #include "ui_MainWindow.h" 9 | #include 10 | 11 | #include 12 | #include 13 | #include "Nodes/NodesInclude.h" 14 | #include "UndoCommands.hpp" 15 | 16 | #include 17 | 18 | 19 | MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow) { 20 | ui->setupUi(this); 21 | const auto registers = registerDataModels(); 22 | ui->tw_nodes->fillTreeWidget(registers); 23 | 24 | m_model = new QtNodes::DataFlowGraphModel(registers); 25 | m_scene = new QtNodes::DataFlowGraphicsScene(*m_model); 26 | m_model->setParent(m_scene); 27 | 28 | ui->nodes_graphicsView->setMapGroupNames(ui->tw_nodes->getMapGroupNames()); 29 | ui->nodes_graphicsView->setDataFlowScene(m_scene); 30 | ui->nodes_graphicsView->setScene(m_scene); 31 | 32 | connect(ui->actionSave, &QAction::triggered, this, &MainWindow::onActionSaveTriggered); 33 | connect(ui->actionLoad, &QAction::triggered, this, &MainWindow::onActionLoadTriggered); 34 | 35 | //setMouseTracking(true); 36 | //placeNodeInScene("NumberSource", QPointF(881,455));/ 37 | } 38 | 39 | MainWindow::~MainWindow() { 40 | delete ui; 41 | } 42 | 43 | void MainWindow::mouseMoveEvent(QMouseEvent* event) { 44 | QMainWindow::mouseMoveEvent(event); 45 | // print the mouse position 46 | // qDebug() << event->pos(); 47 | } 48 | 49 | void MainWindow::onActionSaveTriggered() { 50 | m_scene->save(); 51 | } 52 | 53 | void MainWindow::onActionLoadTriggered() { 54 | m_scene->load(); 55 | } 56 | 57 | std::shared_ptr MainWindow::registerDataModels() { 58 | auto ret = std::make_shared(); 59 | ret->registerModel("Constants"); 60 | 61 | ret->registerModel("Sources"); 62 | 63 | ret->registerModel("Displays"); 64 | 65 | ret->registerModel("Operators"); 66 | ret->registerModel("Operators"); 67 | ret->registerModel("Operators"); 68 | ret->registerModel("Operators"); 69 | 70 | ret->registerModel("Images"); 71 | ret->registerModel("Images"); 72 | ret->registerModel("Images"); 73 | ret->registerModel("Images"); 74 | ret->registerModel("Images"); 75 | ret->registerModel("Images"); 76 | ret->registerModel("Images"); 77 | ret->registerModel("Images"); 78 | 79 | ret->registerModel("OpenCV"); 80 | ret->registerModel("OpenCV"); 81 | ret->registerModel("OpenCV"); 82 | ret->registerModel("OpenCV"); 83 | ret->registerModel("OpenCV"); 84 | ret->registerModel("OpenCV"); 85 | ret->registerModel("OpenCV"); 86 | 87 | ret->registerModel("CascadeClassifier"); 88 | ret->registerModel("CascadeClassifier"); 89 | 90 | ret->registerModel("Variables"); 91 | ret->registerModel("Variables"); 92 | ret->registerModel("Variables"); 93 | ret->registerModel("Variables"); 94 | ret->registerModel("Variables"); 95 | 96 | ret->registerModel("Video"); 97 | ret->registerModel("Video"); 98 | 99 | ret->registerModel("Data Operations"); 100 | 101 | return ret; 102 | } 103 | -------------------------------------------------------------------------------- /src/Widgets/MainWindow.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by pablo on 2/24/24. 3 | // 4 | 5 | #ifndef MAINWINDOW_H 6 | #define MAINWINDOW_H 7 | 8 | #include 9 | #include 10 | 11 | namespace QtNodes { 12 | class DataFlowGraphicsScene; 13 | class DataFlowGraphModel; 14 | class NodeDelegateModelRegistry; 15 | class UndoStack; 16 | } 17 | 18 | QT_BEGIN_NAMESPACE 19 | 20 | namespace Ui { 21 | class MainWindow; 22 | } 23 | 24 | QT_END_NAMESPACE 25 | 26 | class MainWindow final : public QMainWindow { 27 | Q_OBJECT 28 | 29 | public: 30 | explicit MainWindow(QWidget* parent = nullptr); 31 | 32 | ~MainWindow() override; 33 | 34 | protected: 35 | void mouseMoveEvent(QMouseEvent* event) override; 36 | 37 | private slots: 38 | void onActionSaveTriggered(); 39 | 40 | void onActionLoadTriggered(); 41 | 42 | private: 43 | std::shared_ptr registerDataModels(); 44 | 45 | private: 46 | Ui::MainWindow* ui; 47 | QtNodes::DataFlowGraphModel* m_model = nullptr; 48 | QtNodes::DataFlowGraphicsScene* m_scene = nullptr; 49 | 50 | QMap m_mapGroupNames; 51 | }; 52 | 53 | 54 | #endif //MAINWINDOW_H 55 | -------------------------------------------------------------------------------- /src/Widgets/MainWindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1119 10 | 746 11 | 12 | 13 | 14 | Computer Vision Blueprint 15 | 16 | 17 | 18 | 19 | 20 | 21 | Qt::Horizontal 22 | 23 | 24 | 25 | Nodes 26 | 27 | 28 | 29 | 30 | 31 | 32 | Category 33 | 34 | 35 | 36 | 37 | Name 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 70 48 | 0 49 | 50 | 51 | 52 | Scene 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 0 68 | 0 69 | 1119 70 | 20 71 | 72 | 73 | 74 | 75 | File 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | Save 86 | 87 | 88 | 89 | 90 | Load 91 | 92 | 93 | 94 | 95 | 96 | DragableTreeOfNodes 97 | QTreeWidget 98 |
CustomWidget/DragableTreeOfNodes.h
99 |
100 | 101 | DropGraphicsView 102 | QGraphicsView 103 |
CustomWidget/DropGraphicsView.h
104 |
105 |
106 | 107 | 108 |
109 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include "Widgets/MainWindow.h" 5 | 6 | static void setStyle() { 7 | QtNodes::ConnectionStyle::setConnectionStyle( 8 | R"( 9 | { 10 | "ConnectionStyle": { 11 | "ConstructionColor": "gray", 12 | "NormalColor": "black", 13 | "SelectedColor": "gray", 14 | "SelectedHaloColor": "deepskyblue", 15 | "HoveredColor": "deepskyblue", 16 | 17 | "LineWidth": 3.0, 18 | "ConstructionLineWidth": 2.0, 19 | "PointDiameter": 10.0, 20 | 21 | "UseDataDefinedColors": true 22 | } 23 | } 24 | )"); 25 | } 26 | 27 | int main(int argc, char* argv[]) { 28 | QApplication a(argc, argv); 29 | a.setWindowIcon(QIcon(":/images/logo.png")); 30 | setStyle(); 31 | 32 | MainWindow w; 33 | w.show(); 34 | 35 | 36 | return a.exec(); 37 | } 38 | --------------------------------------------------------------------------------