├── .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