From fc9d6fdc2e150088d44b315da7c5834bc591dbb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Mon, 18 Oct 2021 12:05:55 +0200 Subject: [PATCH 01/57] add initial gui project --- depthai_demo.py | 4 ++ gui/.gitignore | 73 ++++++++++++++++++++++++++ gui/README.md | 28 ++++++++++ gui/__init__.py | 0 gui/depthai_demo.pyproject | 3 ++ gui/main.py | 30 +++++++++++ gui/view.qml | 103 +++++++++++++++++++++++++++++++++++++ requirements.txt | 1 + 8 files changed, 242 insertions(+) create mode 100644 gui/.gitignore create mode 100644 gui/README.md create mode 100644 gui/__init__.py create mode 100644 gui/depthai_demo.pyproject create mode 100644 gui/main.py create mode 100644 gui/view.qml diff --git a/depthai_demo.py b/depthai_demo.py index 2c08e2596..7c2d9a2b5 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -14,6 +14,10 @@ from depthai_sdk import FPSHandler, loadModule, getDeviceInfo, downloadYTVideo, Previews from depthai_sdk.managers import NNetManager, PreviewManager, PipelineManager, EncodingManager, BlobManager +from gui.main import DemoQtGui + +DemoQtGui() + DISP_CONF_MIN = int(os.getenv("DISP_CONF_MIN", 0)) DISP_CONF_MAX = int(os.getenv("DISP_CONF_MAX", 255)) SIGMA_MIN = int(os.getenv("SIGMA_MIN", 0)) diff --git a/gui/.gitignore b/gui/.gitignore new file mode 100644 index 000000000..fab7372d7 --- /dev/null +++ b/gui/.gitignore @@ -0,0 +1,73 @@ +# This file is used to ignore files which are generated +# ---------------------------------------------------------------------------- + +*~ +*.autosave +*.a +*.core +*.moc +*.o +*.obj +*.orig +*.rej +*.so +*.so.* +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +!core/ +tags +.DS_Store +.directory +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp +Thumbs.db +*.res +*.rc +/.qmake.cache +/.qmake.stash + +# qtcreator generated files +*.pro.user* + +# xemacs temporary files +*.flc + +# Vim temporary files +.*.swp + +# Visual Studio generated files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* + +# MinGW generated files +*.Debug +*.Release + +# Python byte code +*.pyc + +# Binaries +# -------- +*.dll +*.exe + diff --git a/gui/README.md b/gui/README.md new file mode 100644 index 000000000..72d3789b3 --- /dev/null +++ b/gui/README.md @@ -0,0 +1,28 @@ +# DepthAI Demo GUI + + +## Local development + +> :warning: Instructions tested on Mac but should be similar in other OSes. Feel free to extend this section if it's different in your scenario :warning: + +First, download QT Everywhere 6.2.0 from [this link](https://download.qt.io/archive/qt/6.2/6.2.0/single/qt-everywhere-src-6.2.0.tar.xz.mirrorlist) (on Windows, use [this link](https://download.qt.io/archive/qt/6.2/6.2.0/single/qt-everywhere-src-6.2.0.zip.mirrorlist)) + +Next, extract the package and cd into it. Now, run the following commands: + +``` +# to prepare qt everywhere repository +$ ./configure -prefix $PWD/qtbase +# to compile the qt, may take a while (on my MacBook Air it tool 4hrs) +$ cmake --build . +``` + +Now, download the [QT Creator](https://www.qt.io/product/development-tools). After downloading and installing this tool: +- open Preferences +- go to Kits > Qt Versions +- Click "Add" +- point to the qt everywnere directory and `qtbase/bin/qmake` +- Go to Kits +- Edit both of the kits by clicking on them, scrolling down to Qt Version and selecting the qt-everywhere version we just added +- Restart QT Creator + +Now, the setup is ready and the Designer tool can be used too \ No newline at end of file diff --git a/gui/__init__.py b/gui/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/gui/depthai_demo.pyproject b/gui/depthai_demo.pyproject new file mode 100644 index 000000000..e6f087cce --- /dev/null +++ b/gui/depthai_demo.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["main.py", "view.qml"] +} diff --git a/gui/main.py b/gui/main.py new file mode 100644 index 000000000..b73651b7b --- /dev/null +++ b/gui/main.py @@ -0,0 +1,30 @@ +# This Python file uses the following encoding: utf-8 +import sys +from pathlib import Path + +from PySide6.QtCore import QStringListModel, QUrl +from PySide6.QtQuick import QQuickView +from PySide6.QtWidgets import QApplication + + +class DemoQtGui: + def __init__(self): + self.app = QApplication() + self.view = QQuickView() + self.view.setResizeMode(QQuickView.SizeRootObjectToView) + self.my_model = QStringListModel() + self.my_model.setStringList(["test1", "test2"]) + self.view.setInitialProperties({"myModel": self.my_model}) + self.qml_file = Path(__file__).parent / "view.qml" + self.view.setSource(QUrl.fromLocalFile(self.qml_file.resolve())) + if self.view.status() == QQuickView.Error: + sys.exit(-1) + self.view.show() + self.app.exec() + del self.view + + def show_splash(self): + pass + +if __name__ == "__main__": + DemoQtGui() diff --git a/gui/view.qml b/gui/view.qml new file mode 100644 index 000000000..5590fd1f8 --- /dev/null +++ b/gui/view.qml @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of Qt for Python. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.12 +import QtQuick.Controls 2.12 + +Page { + width: 640 + height: 480 + required property var myModel + + header: Label { + color: "#15af15" + text: qsTr("Where do people use Qt?") + font.pointSize: 17 + font.bold: true + font.family: "Arial" + renderType: Text.NativeRendering + horizontalAlignment: Text.AlignHCenter + padding: 10 + } + Rectangle { + id: root + width: parent.width + height: parent.height + + Image { + id: image + fillMode: Image.PreserveAspectFit + anchors.centerIn: root + source: "./logo.png" + opacity: 0.5 + + } + + ListView { + id: view + anchors.fill: root + anchors.margins: 25 + model: myModel + delegate: Text { + anchors.leftMargin: 50 + font.pointSize: 15 + horizontalAlignment: Text.AlignHCenter + text: display + } + } + } + NumberAnimation { + id: anim + running: true + target: view + property: "contentY" + duration: 500 + } +} diff --git a/requirements.txt b/requirements.txt index fca990d9c..2f0a656ff 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ argcomplete==1.12.1 -e ./depthai_sdk --extra-index-url https://artifacts.luxonis.com/artifactory/luxonis-python-snapshot-local/ depthai==2.10.0.0.dev+7a0749a61597c086c5fd6e579618ae33accec8df +PySide6==6.2.0 \ No newline at end of file From c763f6e3ead41f18f57e8f1179935c609d263956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Mon, 18 Oct 2021 12:06:10 +0200 Subject: [PATCH 02/57] fix typo --- gui/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/README.md b/gui/README.md index 72d3789b3..476798548 100644 --- a/gui/README.md +++ b/gui/README.md @@ -12,7 +12,7 @@ Next, extract the package and cd into it. Now, run the following commands: ``` # to prepare qt everywhere repository $ ./configure -prefix $PWD/qtbase -# to compile the qt, may take a while (on my MacBook Air it tool 4hrs) +# to compile the qt, may take a while (on my MacBook Air it took 4hrs) $ cmake --build . ``` From acc479693870c8b7b1c822a921f8b477eb59e54f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Wed, 20 Oct 2021 12:46:27 +0200 Subject: [PATCH 03/57] working prototype --- gui/main.py | 52 ++-- gui/view.qml | 812 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 811 insertions(+), 53 deletions(-) diff --git a/gui/main.py b/gui/main.py index b73651b7b..7451b2710 100644 --- a/gui/main.py +++ b/gui/main.py @@ -2,29 +2,43 @@ import sys from pathlib import Path -from PySide6.QtCore import QStringListModel, QUrl -from PySide6.QtQuick import QQuickView -from PySide6.QtWidgets import QApplication +from PySide6.QtCore import QObject, Slot +from PySide6.QtGui import QGuiApplication +from PySide6.QtQml import QQmlApplicationEngine, QmlElement +from PySide6.QtQuickControls2 import QQuickStyle + +# To be used on the @QmlElement decorator +# (QML_IMPORT_MINOR_VERSION is optional) +QML_IMPORT_NAME = "dai.gui" +QML_IMPORT_MAJOR_VERSION = 1 + + +@QmlElement +class Bridge(QObject): + @Slot(bool) + def toggleSubpixel(self, state): + print("STATE: {}".format(state)) + + @Slot(int) + def setDisparityConfidenceThreshold(self, value): + print("setting new threshold: {}".format(value)) class DemoQtGui: - def __init__(self): - self.app = QApplication() - self.view = QQuickView() - self.view.setResizeMode(QQuickView.SizeRootObjectToView) - self.my_model = QStringListModel() - self.my_model.setStringList(["test1", "test2"]) - self.view.setInitialProperties({"myModel": self.my_model}) + def __init__(self, device): + self.app = QGuiApplication() + self.engine = QQmlApplicationEngine() self.qml_file = Path(__file__).parent / "view.qml" - self.view.setSource(QUrl.fromLocalFile(self.qml_file.resolve())) - if self.view.status() == QQuickView.Error: + with self.qml_file.open('rb') as f: + additional = b"import dai.gui 1.0\n" + self.engine.loadData(additional + f.read()) + if not self.engine.rootObjects(): sys.exit(-1) - self.view.show() - self.app.exec() - del self.view - - def show_splash(self): - pass + sys.exit(self.app.exec()) if __name__ == "__main__": - DemoQtGui() + # pm = PipelineManager() + # pm.createColorCam(xout=True) + # with dai.Device(pm.pipeline) as device: + # DemoQtGui(device) + DemoQtGui(None) diff --git a/gui/view.qml b/gui/view.qml index 5590fd1f8..f13e89144 100644 --- a/gui/view.qml +++ b/gui/view.qml @@ -48,56 +48,800 @@ ** ****************************************************************************/ -import QtQuick 2.12 -import QtQuick.Controls 2.12 +import QtQuick 2.0 +import QtQuick.Layouts 1.11 +import QtQuick.Controls 2.1 +import QtQuick.Window 2.1 +import QtQuick.Controls.Material 2.1 -Page { +ApplicationWindow { width: 640 - height: 480 - required property var myModel - - header: Label { - color: "#15af15" - text: qsTr("Where do people use Qt?") - font.pointSize: 17 - font.bold: true - font.family: "Arial" - renderType: Text.NativeRendering - horizontalAlignment: Text.AlignHCenter - padding: 10 + height: 640 + Material.theme: Material.Dark + Material.accent: Material.Red + visible: true + + Bridge { + id: bridge } + Rectangle { id: root + x: 0 + y: 0 width: parent.width - height: parent.height - - Image { - id: image - fillMode: Image.PreserveAspectFit - anchors.centerIn: root - source: "./logo.png" - opacity: 0.5 - - } - + height: 640 + color: "#000000" + enabled: true + ListView { id: view anchors.fill: root anchors.margins: 25 - model: myModel + anchors.bottomMargin: 320 delegate: Text { anchors.leftMargin: 50 font.pointSize: 15 horizontalAlignment: Text.AlignHCenter text: display } + + ComboBox { + id: comboBox + x: 0 + y: 110 + width: 195 + height: 25 + } + + Slider { + id: slider + x: 359 + y: 102 + width: 200 + height: 25 + snapMode: RangeSlider.NoSnap + stepSize: 1 + from: 0 + to: 255 + value: 240 + onValueChanged: { + bridge.setDisparityConfidenceThreshold(value) + } + } + + Text { + id: text2 + x: 0 + y: 71 + width: 195 + height: 25 + color: "#ffffff" + text: qsTr("Median filtering") + font.pixelSize: 18 + font.styleName: "Regular" + font.weight: Font.Medium + font.family: "Courier" + } + + Switch { + id: switch1 + x: 0 + y: 187 + text: qsTr("Left Right Check") + transformOrigin: Item.Center + font.preferShaping: false + font.kerning: false + font.family: "Courier" + autoExclusive: true + } + + Switch { + id: switch2 + x: 0 + y: 233 + text: qsTr("Extended Disparity") + autoExclusive: true + font.kerning: false + font.family: "Courier" + font.preferShaping: false + transformOrigin: Item.Center + onToggled: { + bridge.toggleSubpixel(switch2.checked) + } + } + + Switch { + id: switch3 + x: 0 + y: 141 + text: qsTr("Subpixel") + autoExclusive: true + font.kerning: false + transformOrigin: Item.Center + font.preferShaping: false + font.family: "Courier" + } + + Text { + id: text3 + x: 359 + y: 71 + width: 200 + height: 25 + color: "#ffffff" + text: qsTr("Confidence Threshold") + font.pixelSize: 18 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.weight: Font.Medium + font.family: "Courier" + } + + Slider { + id: slider1 + x: 360 + y: 172 + width: 200 + height: 25 + stepSize: 1 + snapMode: RangeSlider.NoSnap + value: 240 + to: 255 + } + + Text { + id: text4 + x: 339 + y: 102 + width: 14 + height: 25 + color: "#ffffff" + text: qsTr("0") + font.pixelSize: 12 + } + + Text { + id: text5 + x: 566 + y: 102 + width: 17 + height: 25 + color: "#ffffff" + text: qsTr("255") + font.pixelSize: 12 + } + + Text { + id: text6 + x: 359 + y: 141 + width: 200 + height: 25 + color: "#ffffff" + text: qsTr("Bilateral Sigma") + font.pixelSize: 18 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.weight: Font.Medium + font.family: "Courier" + } + + Text { + id: text7 + x: 338 + y: 172 + width: 17 + height: 25 + color: "#ffffff" + text: qsTr("0") + font.pixelSize: 12 + } + + Text { + id: text8 + x: 566 + y: 175 + width: 17 + height: 20 + color: "#ffffff" + text: qsTr("255") + font.pixelSize: 12 + rotation: 0 + } + + Text { + id: text9 + x: 359 + y: 209 + width: 200 + height: 25 + color: "#ffffff" + text: qsTr("Depth Range") + font.pixelSize: 18 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.weight: Font.Medium + font.family: "Courier" + } + + RangeSlider { + id: rangeSlider + x: 362 + y: 233 + width: 198 + height: 27 + snapMode: RangeSlider.NoSnap + stepSize: 1 + to: 10000 + focusPolicy: Qt.StrongFocus + second.value: 10000 + first.value: 0 + } + + Text { + id: text1 + x: 79 + y: 0 + width: 433 + height: 30 + color: "#ffffff" + text: qsTr("Depth Properties") + font.pixelSize: 26 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.family: "Courier" + } + + Text { + id: text32 + x: 566 + y: 237 + width: 17 + height: 20 + color: "#ffffff" + text: qsTr("10m") + font.pixelSize: 12 + rotation: 0 + } + + Text { + id: text33 + x: 338 + y: 237 + width: 17 + height: 20 + color: "#ffffff" + text: qsTr("0m") + font.pixelSize: 12 + rotation: 0 + } + + + } + + ListView { + id: listView + x: 25 + y: 348 + width: 590 + height: 284 + + Text { + id: text10 + x: 79 + y: 8 + width: 433 + height: 30 + color: "#ffffff" + text: qsTr("Camera Properties") + font.pixelSize: 26 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.family: "Courier" + } + + TextField { + id: textField + x: 85 + y: 80 + width: 106 + height: 25 + text: "" + placeholderText: "ISO" + font.family: "Courier" + } + + Text { + id: text11 + x: 0 + y: 44 + width: 197 + height: 30 + color: "#ffffff" + text: qsTr("Color") + font.pixelSize: 26 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.family: "Courier" + } + + Text { + id: text12 + x: 385 + y: 44 + width: 197 + height: 30 + color: "#ffffff" + text: qsTr("Right") + font.pixelSize: 26 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.family: "Courier" + } + + Text { + id: text13 + x: 203 + y: 44 + width: 181 + height: 30 + color: "#ffffff" + text: qsTr("Left") + font.pixelSize: 26 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.family: "Courier" + } + + Text { + id: text14 + x: -6 + y: 80 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("ISO") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + TextField { + id: textField1 + x: 85 + y: 111 + width: 106 + height: 25 + text: "" + placeholderText: qsTr("Exposure") + } + + Text { + id: text15 + x: -6 + y: 111 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Exposure") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider2 + x: 85 + y: 142 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + } + + Text { + id: text16 + x: -6 + y: 142 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Saturation") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider3 + x: 85 + y: 173 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + } + + Text { + id: text17 + x: -6 + y: 173 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Contrast") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider4 + x: 85 + y: 204 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + } + + Text { + id: text18 + x: -6 + y: 204 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Brightness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider5 + x: 85 + y: 235 + width: 106 + height: 25 + stepSize: 1 + to: 4 + from: 0 + value: 0 + } + + Text { + id: text19 + x: -6 + y: 235 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Sharpness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Text { + id: text20 + x: 393 + y: 80 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("ISO") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + TextField { + id: textField2 + x: 484 + y: 80 + width: 106 + height: 25 + text: "" + placeholderText: "ISO" + font.family: "Courier" + } + + TextField { + id: textField3 + x: 484 + y: 111 + width: 106 + height: 25 + text: "" + font.family: "Courier" + placeholderText: qsTr("Exposure") + } + + Text { + id: text21 + x: 393 + y: 111 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Exposure") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider6 + x: 484 + y: 142 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + } + + Text { + id: text22 + x: 393 + y: 142 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Saturation") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider7 + x: 484 + y: 173 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + } + + Text { + id: text23 + x: 393 + y: 173 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Contrast") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider8 + x: 484 + y: 204 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + } + + Text { + id: text24 + x: 393 + y: 204 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Brightness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider9 + x: 484 + y: 235 + width: 106 + height: 25 + stepSize: 1 + to: 4 + from: 0 + value: 0 + } + + Text { + id: text25 + x: 393 + y: 235 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Sharpness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Text { + id: text26 + x: 197 + y: 80 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("ISO") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + TextField { + id: textField4 + x: 288 + y: 80 + width: 106 + height: 25 + text: "" + placeholderText: "ISO" + font.family: "Courier" + } + + TextField { + id: textField5 + x: 288 + y: 111 + width: 106 + height: 25 + text: "" + placeholderText: qsTr("Exposure") + } + + Text { + id: text27 + x: 197 + y: 111 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Exposure") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider10 + x: 288 + y: 142 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + } + + Text { + id: text28 + x: 197 + y: 142 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Saturation") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider11 + x: 288 + y: 173 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + } + + Text { + id: text29 + x: 197 + y: 173 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Contrast") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider12 + x: 288 + y: 204 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + } + + Text { + id: text30 + x: 197 + y: 204 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Brightness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider13 + x: 288 + y: 235 + width: 106 + height: 25 + stepSize: 1 + to: 4 + from: 0 + value: 0 + } + + Text { + id: text31 + x: 197 + y: 235 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Sharpness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } } - } - NumberAnimation { - id: anim - running: true - target: view - property: "contentY" - duration: 500 } } From 49ac5b3b30d274909b7dfef8c505b363f87ce075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Wed, 20 Oct 2021 14:32:52 +0200 Subject: [PATCH 04/57] split into multiple views --- gui/README.md | 10 +- gui/depthai_demo.pyproject | 2 +- gui/main.py | 6 +- gui/view.qml | 847 --------------------------------- gui/views/CameraProperties.qml | 537 +++++++++++++++++++++ gui/views/DepthProperties.qml | 257 ++++++++++ gui/views/root.qml | 88 ++++ 7 files changed, 893 insertions(+), 854 deletions(-) delete mode 100644 gui/view.qml create mode 100644 gui/views/CameraProperties.qml create mode 100644 gui/views/DepthProperties.qml create mode 100644 gui/views/root.qml diff --git a/gui/README.md b/gui/README.md index 476798548..d5ce0c897 100644 --- a/gui/README.md +++ b/gui/README.md @@ -17,12 +17,18 @@ $ cmake --build . ``` Now, download the [QT Creator](https://www.qt.io/product/development-tools). After downloading and installing this tool: -- open Preferences -- go to Kits > Qt Versions +- go to Preferences > Kits > Qt Versions - Click "Add" - point to the qt everywnere directory and `qtbase/bin/qmake` - Go to Kits - Edit both of the kits by clicking on them, scrolling down to Qt Version and selecting the qt-everywhere version we just added - Restart QT Creator +- go to Preferences > Qt Quick +- Click "Qt Quick Designer" +- Under "QML Emulation Layer" select second option - "Use QML emulation layer that is built...", leaving the default path +- Close Preferences +- Open .qml file and click "Design" +- A build process should start automatically. It may throw a warning that the build process is not responding, ignore +- Restart QT Creator Now, the setup is ready and the Designer tool can be used too \ No newline at end of file diff --git a/gui/depthai_demo.pyproject b/gui/depthai_demo.pyproject index e6f087cce..dc9962291 100644 --- a/gui/depthai_demo.pyproject +++ b/gui/depthai_demo.pyproject @@ -1,3 +1,3 @@ { - "files": ["main.py", "view.qml"] + "files": ["main.py", "views/DepthProperties.qml", "views/root.qml", "views/CameraProperties.qml"] } diff --git a/gui/main.py b/gui/main.py index 7451b2710..20a333487 100644 --- a/gui/main.py +++ b/gui/main.py @@ -28,10 +28,8 @@ class DemoQtGui: def __init__(self, device): self.app = QGuiApplication() self.engine = QQmlApplicationEngine() - self.qml_file = Path(__file__).parent / "view.qml" - with self.qml_file.open('rb') as f: - additional = b"import dai.gui 1.0\n" - self.engine.loadData(additional + f.read()) + self.qml_file = Path(__file__).parent / "views" / "root.qml" + self.engine.load(self.qml_file) if not self.engine.rootObjects(): sys.exit(-1) sys.exit(self.app.exec()) diff --git a/gui/view.qml b/gui/view.qml deleted file mode 100644 index f13e89144..000000000 --- a/gui/view.qml +++ /dev/null @@ -1,847 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of Qt for Python. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.0 -import QtQuick.Layouts 1.11 -import QtQuick.Controls 2.1 -import QtQuick.Window 2.1 -import QtQuick.Controls.Material 2.1 - -ApplicationWindow { - width: 640 - height: 640 - Material.theme: Material.Dark - Material.accent: Material.Red - visible: true - - Bridge { - id: bridge - } - - Rectangle { - id: root - x: 0 - y: 0 - width: parent.width - height: 640 - color: "#000000" - enabled: true - - ListView { - id: view - anchors.fill: root - anchors.margins: 25 - anchors.bottomMargin: 320 - delegate: Text { - anchors.leftMargin: 50 - font.pointSize: 15 - horizontalAlignment: Text.AlignHCenter - text: display - } - - ComboBox { - id: comboBox - x: 0 - y: 110 - width: 195 - height: 25 - } - - Slider { - id: slider - x: 359 - y: 102 - width: 200 - height: 25 - snapMode: RangeSlider.NoSnap - stepSize: 1 - from: 0 - to: 255 - value: 240 - onValueChanged: { - bridge.setDisparityConfidenceThreshold(value) - } - } - - Text { - id: text2 - x: 0 - y: 71 - width: 195 - height: 25 - color: "#ffffff" - text: qsTr("Median filtering") - font.pixelSize: 18 - font.styleName: "Regular" - font.weight: Font.Medium - font.family: "Courier" - } - - Switch { - id: switch1 - x: 0 - y: 187 - text: qsTr("Left Right Check") - transformOrigin: Item.Center - font.preferShaping: false - font.kerning: false - font.family: "Courier" - autoExclusive: true - } - - Switch { - id: switch2 - x: 0 - y: 233 - text: qsTr("Extended Disparity") - autoExclusive: true - font.kerning: false - font.family: "Courier" - font.preferShaping: false - transformOrigin: Item.Center - onToggled: { - bridge.toggleSubpixel(switch2.checked) - } - } - - Switch { - id: switch3 - x: 0 - y: 141 - text: qsTr("Subpixel") - autoExclusive: true - font.kerning: false - transformOrigin: Item.Center - font.preferShaping: false - font.family: "Courier" - } - - Text { - id: text3 - x: 359 - y: 71 - width: 200 - height: 25 - color: "#ffffff" - text: qsTr("Confidence Threshold") - font.pixelSize: 18 - horizontalAlignment: Text.AlignHCenter - font.styleName: "Regular" - font.weight: Font.Medium - font.family: "Courier" - } - - Slider { - id: slider1 - x: 360 - y: 172 - width: 200 - height: 25 - stepSize: 1 - snapMode: RangeSlider.NoSnap - value: 240 - to: 255 - } - - Text { - id: text4 - x: 339 - y: 102 - width: 14 - height: 25 - color: "#ffffff" - text: qsTr("0") - font.pixelSize: 12 - } - - Text { - id: text5 - x: 566 - y: 102 - width: 17 - height: 25 - color: "#ffffff" - text: qsTr("255") - font.pixelSize: 12 - } - - Text { - id: text6 - x: 359 - y: 141 - width: 200 - height: 25 - color: "#ffffff" - text: qsTr("Bilateral Sigma") - font.pixelSize: 18 - horizontalAlignment: Text.AlignHCenter - font.styleName: "Regular" - font.weight: Font.Medium - font.family: "Courier" - } - - Text { - id: text7 - x: 338 - y: 172 - width: 17 - height: 25 - color: "#ffffff" - text: qsTr("0") - font.pixelSize: 12 - } - - Text { - id: text8 - x: 566 - y: 175 - width: 17 - height: 20 - color: "#ffffff" - text: qsTr("255") - font.pixelSize: 12 - rotation: 0 - } - - Text { - id: text9 - x: 359 - y: 209 - width: 200 - height: 25 - color: "#ffffff" - text: qsTr("Depth Range") - font.pixelSize: 18 - horizontalAlignment: Text.AlignHCenter - font.styleName: "Regular" - font.weight: Font.Medium - font.family: "Courier" - } - - RangeSlider { - id: rangeSlider - x: 362 - y: 233 - width: 198 - height: 27 - snapMode: RangeSlider.NoSnap - stepSize: 1 - to: 10000 - focusPolicy: Qt.StrongFocus - second.value: 10000 - first.value: 0 - } - - Text { - id: text1 - x: 79 - y: 0 - width: 433 - height: 30 - color: "#ffffff" - text: qsTr("Depth Properties") - font.pixelSize: 26 - horizontalAlignment: Text.AlignHCenter - font.styleName: "Regular" - font.family: "Courier" - } - - Text { - id: text32 - x: 566 - y: 237 - width: 17 - height: 20 - color: "#ffffff" - text: qsTr("10m") - font.pixelSize: 12 - rotation: 0 - } - - Text { - id: text33 - x: 338 - y: 237 - width: 17 - height: 20 - color: "#ffffff" - text: qsTr("0m") - font.pixelSize: 12 - rotation: 0 - } - - - } - - ListView { - id: listView - x: 25 - y: 348 - width: 590 - height: 284 - - Text { - id: text10 - x: 79 - y: 8 - width: 433 - height: 30 - color: "#ffffff" - text: qsTr("Camera Properties") - font.pixelSize: 26 - horizontalAlignment: Text.AlignHCenter - font.styleName: "Regular" - font.family: "Courier" - } - - TextField { - id: textField - x: 85 - y: 80 - width: 106 - height: 25 - text: "" - placeholderText: "ISO" - font.family: "Courier" - } - - Text { - id: text11 - x: 0 - y: 44 - width: 197 - height: 30 - color: "#ffffff" - text: qsTr("Color") - font.pixelSize: 26 - horizontalAlignment: Text.AlignHCenter - font.styleName: "Regular" - font.family: "Courier" - } - - Text { - id: text12 - x: 385 - y: 44 - width: 197 - height: 30 - color: "#ffffff" - text: qsTr("Right") - font.pixelSize: 26 - horizontalAlignment: Text.AlignHCenter - font.styleName: "Regular" - font.family: "Courier" - } - - Text { - id: text13 - x: 203 - y: 44 - width: 181 - height: 30 - color: "#ffffff" - text: qsTr("Left") - font.pixelSize: 26 - horizontalAlignment: Text.AlignHCenter - font.styleName: "Regular" - font.family: "Courier" - } - - Text { - id: text14 - x: -6 - y: 80 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("ISO") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - TextField { - id: textField1 - x: 85 - y: 111 - width: 106 - height: 25 - text: "" - placeholderText: qsTr("Exposure") - } - - Text { - id: text15 - x: -6 - y: 111 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Exposure") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider2 - x: 85 - y: 142 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - } - - Text { - id: text16 - x: -6 - y: 142 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Saturation") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider3 - x: 85 - y: 173 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - } - - Text { - id: text17 - x: -6 - y: 173 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Contrast") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider4 - x: 85 - y: 204 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - } - - Text { - id: text18 - x: -6 - y: 204 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Brightness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider5 - x: 85 - y: 235 - width: 106 - height: 25 - stepSize: 1 - to: 4 - from: 0 - value: 0 - } - - Text { - id: text19 - x: -6 - y: 235 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Sharpness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Text { - id: text20 - x: 393 - y: 80 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("ISO") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - TextField { - id: textField2 - x: 484 - y: 80 - width: 106 - height: 25 - text: "" - placeholderText: "ISO" - font.family: "Courier" - } - - TextField { - id: textField3 - x: 484 - y: 111 - width: 106 - height: 25 - text: "" - font.family: "Courier" - placeholderText: qsTr("Exposure") - } - - Text { - id: text21 - x: 393 - y: 111 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Exposure") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider6 - x: 484 - y: 142 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - } - - Text { - id: text22 - x: 393 - y: 142 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Saturation") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider7 - x: 484 - y: 173 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - } - - Text { - id: text23 - x: 393 - y: 173 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Contrast") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider8 - x: 484 - y: 204 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - } - - Text { - id: text24 - x: 393 - y: 204 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Brightness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider9 - x: 484 - y: 235 - width: 106 - height: 25 - stepSize: 1 - to: 4 - from: 0 - value: 0 - } - - Text { - id: text25 - x: 393 - y: 235 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Sharpness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Text { - id: text26 - x: 197 - y: 80 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("ISO") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - TextField { - id: textField4 - x: 288 - y: 80 - width: 106 - height: 25 - text: "" - placeholderText: "ISO" - font.family: "Courier" - } - - TextField { - id: textField5 - x: 288 - y: 111 - width: 106 - height: 25 - text: "" - placeholderText: qsTr("Exposure") - } - - Text { - id: text27 - x: 197 - y: 111 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Exposure") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider10 - x: 288 - y: 142 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - } - - Text { - id: text28 - x: 197 - y: 142 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Saturation") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider11 - x: 288 - y: 173 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - } - - Text { - id: text29 - x: 197 - y: 173 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Contrast") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider12 - x: 288 - y: 204 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - } - - Text { - id: text30 - x: 197 - y: 204 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Brightness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider13 - x: 288 - y: 235 - width: 106 - height: 25 - stepSize: 1 - to: 4 - from: 0 - value: 0 - } - - Text { - id: text31 - x: 197 - y: 235 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Sharpness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - } - } -} diff --git a/gui/views/CameraProperties.qml b/gui/views/CameraProperties.qml new file mode 100644 index 000000000..a443cbab4 --- /dev/null +++ b/gui/views/CameraProperties.qml @@ -0,0 +1,537 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.11 +import QtQuick.Controls 2.1 +import QtQuick.Window 2.1 +import QtQuick.Controls.Material 2.1 + +ListView { + id: listView + + Rectangle { + id: backgroundRect1 + color: "black" + width: parent.width + height: parent.height + + Text { + id: text10 + x: 79 + y: 8 + width: 433 + height: 30 + color: "#ffffff" + text: qsTr("Camera Properties") + font.pixelSize: 26 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.family: "Courier" + } + + TextField { + id: textField + x: 85 + y: 80 + width: 106 + height: 25 + text: "" + placeholderText: "ISO" + font.family: "Courier" + } + + Text { + id: text11 + x: 0 + y: 44 + width: 197 + height: 30 + color: "#ffffff" + text: qsTr("Color") + font.pixelSize: 26 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.family: "Courier" + } + + Text { + id: text12 + x: 385 + y: 44 + width: 197 + height: 30 + color: "#ffffff" + text: qsTr("Right") + font.pixelSize: 26 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.family: "Courier" + } + + Text { + id: text13 + x: 203 + y: 44 + width: 181 + height: 30 + color: "#ffffff" + text: qsTr("Left") + font.pixelSize: 26 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.family: "Courier" + } + + Text { + id: text14 + x: -6 + y: 80 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("ISO") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + TextField { + id: textField1 + x: 85 + y: 111 + width: 106 + height: 25 + text: "" + placeholderText: qsTr("Exposure") + } + + Text { + id: text15 + x: -6 + y: 111 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Exposure") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider2 + x: 85 + y: 142 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + } + + Text { + id: text16 + x: -6 + y: 142 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Saturation") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider3 + x: 85 + y: 173 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + } + + Text { + id: text17 + x: -6 + y: 173 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Contrast") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider4 + x: 85 + y: 204 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + } + + Text { + id: text18 + x: -6 + y: 204 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Brightness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider5 + x: 85 + y: 235 + width: 106 + height: 25 + stepSize: 1 + to: 4 + from: 0 + value: 0 + } + + Text { + id: text19 + x: -6 + y: 235 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Sharpness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Text { + id: text20 + x: 393 + y: 80 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("ISO") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + TextField { + id: textField2 + x: 484 + y: 80 + width: 106 + height: 25 + text: "" + placeholderText: "ISO" + font.family: "Courier" + } + + TextField { + id: textField3 + x: 484 + y: 111 + width: 106 + height: 25 + text: "" + font.family: "Courier" + placeholderText: qsTr("Exposure") + } + + Text { + id: text21 + x: 393 + y: 111 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Exposure") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider6 + x: 484 + y: 142 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + } + + Text { + id: text22 + x: 393 + y: 142 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Saturation") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider7 + x: 484 + y: 173 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + } + + Text { + id: text23 + x: 393 + y: 173 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Contrast") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider8 + x: 484 + y: 204 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + } + + Text { + id: text24 + x: 393 + y: 204 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Brightness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider9 + x: 484 + y: 235 + width: 106 + height: 25 + stepSize: 1 + to: 4 + from: 0 + value: 0 + } + + Text { + id: text25 + x: 393 + y: 235 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Sharpness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Text { + id: text26 + x: 197 + y: 80 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("ISO") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + TextField { + id: textField4 + x: 288 + y: 80 + width: 106 + height: 25 + text: "" + placeholderText: "ISO" + font.family: "Courier" + } + + TextField { + id: textField5 + x: 288 + y: 111 + width: 106 + height: 25 + text: "" + placeholderText: qsTr("Exposure") + } + + Text { + id: text27 + x: 197 + y: 111 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Exposure") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider10 + x: 288 + y: 142 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + } + + Text { + id: text28 + x: 197 + y: 142 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Saturation") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider11 + x: 288 + y: 173 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + } + + Text { + id: text29 + x: 197 + y: 173 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Contrast") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider12 + x: 288 + y: 204 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + } + + Text { + id: text30 + x: 197 + y: 204 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Brightness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider13 + x: 288 + y: 235 + width: 106 + height: 25 + stepSize: 1 + to: 4 + from: 0 + value: 0 + } + + Text { + id: text31 + x: 197 + y: 235 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Sharpness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + } +} +/*##^## +Designer { + D{i:0;autoSize:true;height:480;width:640} +} +##^##*/ diff --git a/gui/views/DepthProperties.qml b/gui/views/DepthProperties.qml new file mode 100644 index 000000000..d77651b4c --- /dev/null +++ b/gui/views/DepthProperties.qml @@ -0,0 +1,257 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.11 +import QtQuick.Controls 2.1 +import QtQuick.Window 2.1 +import QtQuick.Controls.Material 2.1 + +ListView { + id: view + anchors.fill: root + anchors.margins: 25 + anchors.bottomMargin: 320 + delegate: Text { + anchors.leftMargin: 50 + font.pointSize: 15 + horizontalAlignment: Text.AlignHCenter + text: display + } + + Rectangle { + id: backgroundRect1 + color: "black" + width: parent.width + height: parent.height + + ComboBox { + id: comboBox + x: 0 + y: 110 + width: 195 + height: 25 + } + + Slider { + id: slider + x: 359 + y: 102 + width: 200 + height: 25 + snapMode: RangeSlider.NoSnap + stepSize: 1 + from: 0 + to: 255 + value: 240 + onValueChanged: { + bridge.setDisparityConfidenceThreshold(value) + } + } + + Text { + id: text2 + x: 0 + y: 71 + width: 195 + height: 25 + color: "#ffffff" + text: qsTr("Median filtering") + font.pixelSize: 18 + font.styleName: "Regular" + font.weight: Font.Medium + font.family: "Courier" + } + + Switch { + id: switch1 + x: 0 + y: 187 + text: qsTr("Left Right Check") + transformOrigin: Item.Center + font.preferShaping: false + font.kerning: false + font.family: "Courier" + autoExclusive: true + } + + Switch { + id: switch2 + x: 0 + y: 233 + text: qsTr("Extended Disparity") + autoExclusive: true + font.kerning: false + font.family: "Courier" + font.preferShaping: false + transformOrigin: Item.Center + onToggled: { + bridge.toggleSubpixel(switch2.checked) + } + } + + Switch { + id: switch3 + x: 0 + y: 141 + text: qsTr("Subpixel") + autoExclusive: true + font.kerning: false + transformOrigin: Item.Center + font.preferShaping: false + font.family: "Courier" + } + + Text { + id: text3 + x: 359 + y: 71 + width: 200 + height: 25 + color: "#ffffff" + text: qsTr("Confidence Threshold") + font.pixelSize: 18 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.weight: Font.Medium + font.family: "Courier" + } + + Slider { + id: slider1 + x: 360 + y: 172 + width: 200 + height: 25 + stepSize: 1 + snapMode: RangeSlider.NoSnap + value: 240 + to: 255 + } + + Text { + id: text4 + x: 339 + y: 102 + width: 14 + height: 25 + color: "#ffffff" + text: qsTr("0") + font.pixelSize: 12 + } + + Text { + id: text5 + x: 566 + y: 102 + width: 17 + height: 25 + color: "#ffffff" + text: qsTr("255") + font.pixelSize: 12 + } + + Text { + id: text6 + x: 359 + y: 141 + width: 200 + height: 25 + color: "#ffffff" + text: qsTr("Bilateral Sigma") + font.pixelSize: 18 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.weight: Font.Medium + font.family: "Courier" + } + + Text { + id: text7 + x: 338 + y: 172 + width: 17 + height: 25 + color: "#ffffff" + text: qsTr("0") + font.pixelSize: 12 + } + + Text { + id: text8 + x: 566 + y: 175 + width: 17 + height: 20 + color: "#ffffff" + text: qsTr("255") + font.pixelSize: 12 + rotation: 0 + } + + Text { + id: text9 + x: 359 + y: 209 + width: 200 + height: 25 + color: "#ffffff" + text: qsTr("Depth Range") + font.pixelSize: 18 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.weight: Font.Medium + font.family: "Courier" + } + + RangeSlider { + id: rangeSlider + x: 362 + y: 233 + width: 198 + height: 27 + snapMode: RangeSlider.NoSnap + stepSize: 1 + to: 10000 + focusPolicy: Qt.StrongFocus + second.value: 10000 + first.value: 0 + } + + Text { + id: text1 + x: 79 + y: 0 + width: 433 + height: 30 + color: "#ffffff" + text: qsTr("Depth Properties") + font.pixelSize: 26 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.family: "Courier" + } + + Text { + id: text32 + x: 566 + y: 237 + width: 17 + height: 20 + color: "#ffffff" + text: qsTr("10m") + font.pixelSize: 12 + rotation: 0 + } + + Text { + id: text33 + x: 338 + y: 237 + width: 17 + height: 20 + color: "#ffffff" + text: qsTr("0m") + font.pixelSize: 12 + rotation: 0 + } + + } +} \ No newline at end of file diff --git a/gui/views/root.qml b/gui/views/root.qml new file mode 100644 index 000000000..d4a6d93e1 --- /dev/null +++ b/gui/views/root.qml @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of Qt for Python. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Layouts 1.11 +import QtQuick.Controls 2.1 +import QtQuick.Window 2.1 +import QtQuick.Controls.Material 2.1 + +import dai.gui 1.0 + +ApplicationWindow { + width: 640 + height: 640 + Material.theme: Material.Dark + Material.accent: Material.Red + visible: true + + Bridge { + id: bridge + } + + Rectangle { + id: root + x: 0 + y: 0 + width: parent.width + height: 640 + color: "#000000" + enabled: true + + DepthProperties {} + + CameraProperties { + x: 25 + y: 348 + width: 590 + height: 284 + } + } +} From f5a927334da1fdb68af93afdec849b7b9876dd21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Thu, 21 Oct 2021 13:51:15 +0200 Subject: [PATCH 05/57] update --- gui/main.py | 117 +++- gui/views/CameraProperties.qml | 1102 +++++++++++++++++--------------- gui/views/DepthProperties.qml | 40 +- gui/views/root.qml | 13 +- 4 files changed, 732 insertions(+), 540 deletions(-) diff --git a/gui/main.py b/gui/main.py index 20a333487..e3ed18a03 100644 --- a/gui/main.py +++ b/gui/main.py @@ -1,11 +1,12 @@ # This Python file uses the following encoding: utf-8 import sys +import threading from pathlib import Path - -from PySide6.QtCore import QObject, Slot +import time +from PySide6.QtCore import QObject, Slot, Signal from PySide6.QtGui import QGuiApplication from PySide6.QtQml import QQmlApplicationEngine, QmlElement -from PySide6.QtQuickControls2 import QQuickStyle +import depthai as dai # To be used on the @QmlElement decorator # (QML_IMPORT_MINOR_VERSION is optional) @@ -14,29 +15,115 @@ @QmlElement -class Bridge(QObject): +class DepthBridge(QObject): + onUpdate = Signal() + @Slot(bool) def toggleSubpixel(self, state): - print("STATE: {}".format(state)) + print("Sub: {}".format(state)) + + @Slot(bool) + def toggleExtendedDisparity(self, state): + print("Ext: {}".format(state)) + + @Slot(bool) + def toggleLeftRightCheck(self, state): + print("Lrc: {}".format(state)) @Slot(int) def setDisparityConfidenceThreshold(self, value): - print("setting new threshold: {}".format(value)) + print("Dct: {}".format(value)) + + @Slot(int) + def setBilateralSigma(self, value): + print("Bls: {}".format(value)) + + @Slot(int) + def setBilateralSigma(self, value): + print("Sig: {}".format(value)) + + @Slot(int, int) + def setDepthRange(self, valFrom, valTo): + print("Rng: {} - {}".format(valFrom, valTo)) + + @Slot(str) + def setMedianFilter(self, state): + print("Med: {}".format(state)) + + +class BaseCamBridge(QObject): + @Slot(int) + def setIso(self, value): + print("ISO: {}".format(value)) + + @Slot(int) + def setExposure(self, value): + print("Exposure: {}".format(value)) + + @Slot(int) + def setContrast(self, value): + print("Contrast: {}".format(value)) + + @Slot(int) + def setBrightness(self, value): + print("Brightness: {}".format(value)) + + @Slot(int) + def setSaturation(self, value): + print("Saturation: {}".format(value)) + + @Slot(int) + def setSharpness(self, value): + print("Sharpness: {}".format(value)) + + +@QmlElement +class ColorCamBridge(BaseCamBridge): + onUpdate = Signal() + + +@QmlElement +class LeftCamBridge(BaseCamBridge): + onUpdate = Signal() + + +@QmlElement +class RightCamBridge(BaseCamBridge): + onUpdate = Signal() + + +class StoppableThread(threading.Thread): + """Thread class with a stop() method. The thread itself has to check + regularly for the stopped() condition.""" + + def __init__(self, *args, **kwargs): + super(StoppableThread, self).__init__(*args, **kwargs) + self._stop_event = threading.Event() + + def stop(self): + self._stop_event.set() + + def stopped(self): + return self._stop_event.is_set() class DemoQtGui: - def __init__(self, device): + def __init__(self): self.app = QGuiApplication() self.engine = QQmlApplicationEngine() - self.qml_file = Path(__file__).parent / "views" / "root.qml" - self.engine.load(self.qml_file) + + def setData(self, name, value): + self.engine.rootContext().setContextProperty(name, value) + + def startGui(self): + self.engine.load(Path(__file__).parent / "views" / "root.qml") if not self.engine.rootObjects(): - sys.exit(-1) + raise RuntimeError("Unable to start GUI - no root objects!") sys.exit(self.app.exec()) + if __name__ == "__main__": - # pm = PipelineManager() - # pm.createColorCam(xout=True) - # with dai.Device(pm.pipeline) as device: - # DemoQtGui(device) - DemoQtGui(None) + medianChoices = list(filter(lambda name: name.startswith('KERNEL_') or name.startswith('MEDIAN_'), vars(dai.MedianFilter).keys()))[::-1] + gui = DemoQtGui() + gui.setData("medianChoices", medianChoices) + gui.startGui() diff --git a/gui/views/CameraProperties.qml b/gui/views/CameraProperties.qml index a443cbab4..7ca93d47a 100644 --- a/gui/views/CameraProperties.qml +++ b/gui/views/CameraProperties.qml @@ -13,521 +13,593 @@ ListView { width: parent.width height: parent.height - Text { - id: text10 - x: 79 - y: 8 - width: 433 - height: 30 - color: "#ffffff" - text: qsTr("Camera Properties") - font.pixelSize: 26 - horizontalAlignment: Text.AlignHCenter - font.styleName: "Regular" - font.family: "Courier" - } - - TextField { - id: textField - x: 85 - y: 80 - width: 106 - height: 25 - text: "" - placeholderText: "ISO" - font.family: "Courier" - } - - Text { - id: text11 - x: 0 - y: 44 - width: 197 - height: 30 - color: "#ffffff" - text: qsTr("Color") - font.pixelSize: 26 - horizontalAlignment: Text.AlignHCenter - font.styleName: "Regular" - font.family: "Courier" - } - - Text { - id: text12 - x: 385 - y: 44 - width: 197 - height: 30 - color: "#ffffff" - text: qsTr("Right") - font.pixelSize: 26 - horizontalAlignment: Text.AlignHCenter - font.styleName: "Regular" - font.family: "Courier" - } - - Text { - id: text13 - x: 203 - y: 44 - width: 181 - height: 30 - color: "#ffffff" - text: qsTr("Left") - font.pixelSize: 26 - horizontalAlignment: Text.AlignHCenter - font.styleName: "Regular" - font.family: "Courier" - } - - Text { - id: text14 - x: -6 - y: 80 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("ISO") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - TextField { - id: textField1 - x: 85 - y: 111 - width: 106 - height: 25 - text: "" - placeholderText: qsTr("Exposure") - } - - Text { - id: text15 - x: -6 - y: 111 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Exposure") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider2 - x: 85 - y: 142 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - } - - Text { - id: text16 - x: -6 - y: 142 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Saturation") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider3 - x: 85 - y: 173 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - } - - Text { - id: text17 - x: -6 - y: 173 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Contrast") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider4 - x: 85 - y: 204 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - } - - Text { - id: text18 - x: -6 - y: 204 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Brightness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider5 - x: 85 - y: 235 - width: 106 - height: 25 - stepSize: 1 - to: 4 - from: 0 - value: 0 - } - - Text { - id: text19 - x: -6 - y: 235 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Sharpness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Text { - id: text20 - x: 393 - y: 80 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("ISO") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - TextField { - id: textField2 - x: 484 - y: 80 - width: 106 - height: 25 - text: "" - placeholderText: "ISO" - font.family: "Courier" - } - - TextField { - id: textField3 - x: 484 - y: 111 - width: 106 - height: 25 - text: "" - font.family: "Courier" - placeholderText: qsTr("Exposure") - } - - Text { - id: text21 - x: 393 - y: 111 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Exposure") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider6 - x: 484 - y: 142 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - } - - Text { - id: text22 - x: 393 - y: 142 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Saturation") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider7 - x: 484 - y: 173 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - } - - Text { - id: text23 - x: 393 - y: 173 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Contrast") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider8 - x: 484 - y: 204 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - } - - Text { - id: text24 - x: 393 - y: 204 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Brightness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider9 - x: 484 - y: 235 - width: 106 - height: 25 - stepSize: 1 - to: 4 - from: 0 - value: 0 - } - - Text { - id: text25 - x: 393 - y: 235 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Sharpness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Text { - id: text26 - x: 197 - y: 80 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("ISO") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - TextField { - id: textField4 - x: 288 - y: 80 - width: 106 - height: 25 - text: "" - placeholderText: "ISO" - font.family: "Courier" - } - - TextField { - id: textField5 - x: 288 - y: 111 - width: 106 - height: 25 - text: "" - placeholderText: qsTr("Exposure") - } - - Text { - id: text27 - x: 197 - y: 111 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Exposure") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider10 - x: 288 - y: 142 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - } - - Text { - id: text28 - x: 197 - y: 142 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Saturation") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider11 - x: 288 - y: 173 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - } - - Text { - id: text29 - x: 197 - y: 173 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Contrast") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider12 - x: 288 - y: 204 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - } - - Text { - id: text30 - x: 197 - y: 204 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Brightness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider13 - x: 288 - y: 235 - width: 106 - height: 25 - stepSize: 1 - to: 4 - from: 0 - value: 0 - } - - Text { - id: text31 - x: 197 - y: 235 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Sharpness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Text { + id: text10 + x: 79 + y: 8 + width: 433 + height: 30 + color: "#ffffff" + text: qsTr("Camera Properties") + font.pixelSize: 26 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.family: "Courier" + } + + Text { + id: text11 + x: 0 + y: 44 + width: 197 + height: 30 + color: "#ffffff" + text: qsTr("Color") + font.pixelSize: 26 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.family: "Courier" + } + + Text { + id: text12 + x: 385 + y: 44 + width: 197 + height: 30 + color: "#ffffff" + text: qsTr("Right") + font.pixelSize: 26 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.family: "Courier" + } + + Text { + id: text13 + x: 203 + y: 44 + width: 181 + height: 30 + color: "#ffffff" + text: qsTr("Left") + font.pixelSize: 26 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.family: "Courier" + } + + TextField { + id: textField + x: 85 + y: 80 + width: 106 + height: 25 + text: "" + bottomPadding: 5 + validator: IntValidator {} + placeholderText: "ISO" + font.family: "Courier" + onEditingFinished: { + colorCamBridge.setIso(text) + } + } + + Text { + id: text14 + x: -6 + y: 80 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("ISO") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + TextField { + id: textField1 + x: 85 + y: 111 + width: 106 + height: 25 + text: "" + bottomPadding: 5 + font.family: "Courier" + placeholderText: qsTr("Exposure") + validator: IntValidator {} + onEditingFinished: { + colorCamBridge.setExposure(text) + } + } + + + Text { + id: text15 + x: -6 + y: 111 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Exposure") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider2 + x: 85 + y: 142 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + colorCamBridge.setSaturation(value) + } + } + + Text { + id: text16 + x: -6 + y: 142 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Saturation") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider3 + x: 85 + y: 173 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + colorCamBridge.setContrast(value) + } + } + + Text { + id: text17 + x: -6 + y: 173 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Contrast") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider4 + x: 85 + y: 204 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + colorCamBridge.setBrightness(value) + } + } + + Text { + id: text18 + x: -6 + y: 204 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Brightness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider5 + x: 85 + y: 235 + width: 106 + height: 25 + stepSize: 1 + to: 4 + from: 0 + value: 0 + onValueChanged: { + colorCamBridge.setSharpness(value) + } + } + + Text { + id: text19 + x: -6 + y: 235 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Sharpness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Text { + id: text20 + x: 393 + y: 80 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("ISO") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + TextField { + id: textField2 + x: 484 + y: 80 + width: 106 + height: 25 + color: "#ddffffff" + text: "" + bottomPadding: 5 + validator: IntValidator {} + placeholderText: "ISO" + font.family: "Courier" + onEditingFinished: { + rightCamBridge.setIso(text) + } + } + + TextField { + id: textField3 + x: 484 + y: 111 + width: 106 + height: 25 + color: "#ddffffff" + text: "" + bottomPadding: 5 + font.family: "Courier" + placeholderText: qsTr("Exposure") + validator: IntValidator {} + onEditingFinished: { + rightCamBridge.setExposure(text) + } + } + + Text { + id: text21 + x: 393 + y: 111 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Exposure") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider6 + x: 484 + y: 142 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + rightCamBridge.setSaturation(value) + } + } + + Text { + id: text22 + x: 393 + y: 142 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Saturation") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider7 + x: 484 + y: 173 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + rightCamBridge.setContrast(value) + } + } + + Text { + id: text23 + x: 393 + y: 173 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Contrast") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider8 + x: 484 + y: 204 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + rightCamBridge.setBrightness(value) + } + } + + Text { + id: text24 + x: 393 + y: 204 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Brightness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider9 + x: 484 + y: 235 + width: 106 + height: 25 + stepSize: 1 + to: 4 + from: 0 + value: 0 + onValueChanged: { + rightCamBridge.setSharpness(value) + } + } + + Text { + id: text25 + x: 393 + y: 235 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Sharpness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Text { + id: text26 + x: 197 + y: 80 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("ISO") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + TextField { + id: textField4 + x: 288 + y: 80 + width: 106 + height: 25 + color: "#ddffffff" + text: "" + bottomPadding: 5 + placeholderText: "ISO" + font.family: "Courier" + validator: IntValidator {} + onEditingFinished: { + leftCamBridge.setIso(text) + } + } + + TextField { + id: textField5 + x: 288 + y: 111 + width: 106 + height: 25 + color: "#ddffffff" + text: "" + bottomPadding: 5 + placeholderText: qsTr("Exposure") + validator: IntValidator {} + onEditingFinished: { + leftCamBridge.setExposure(text) + } + } + + Text { + id: text27 + x: 197 + y: 111 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Exposure") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider10 + x: 288 + y: 142 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + leftCamBridge.setSaturation(value) + } + } + + Text { + id: text28 + x: 197 + y: 142 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Saturation") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider11 + x: 288 + y: 173 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + leftCamBridge.setContrast(value) + } + } + + Text { + id: text29 + x: 197 + y: 173 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Contrast") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider12 + x: 288 + y: 204 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + leftCamBridge.setBrightness(value) + } + } + + Text { + id: text30 + x: 197 + y: 204 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Brightness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider13 + x: 288 + y: 235 + width: 106 + height: 25 + stepSize: 1 + to: 4 + from: 0 + value: 0 + onValueChanged: { + leftCamBridge.setSharpness(value) + } + } + + Text { + id: text31 + x: 197 + y: 235 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Sharpness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } } } /*##^## diff --git a/gui/views/DepthProperties.qml b/gui/views/DepthProperties.qml index d77651b4c..e22102e28 100644 --- a/gui/views/DepthProperties.qml +++ b/gui/views/DepthProperties.qml @@ -25,9 +25,13 @@ ListView { ComboBox { id: comboBox x: 0 - y: 110 + y: 102 width: 195 - height: 25 + height: 33 + model: medianChoices + onActivated: function(index) { + depthBridge.setMedianFilter(model[index]) + } } Slider { @@ -42,7 +46,7 @@ ListView { to: 255 value: 240 onValueChanged: { - bridge.setDisparityConfidenceThreshold(value) + depthBridge.setDisparityConfidenceThreshold(value) } } @@ -69,7 +73,10 @@ ListView { font.preferShaping: false font.kerning: false font.family: "Courier" - autoExclusive: true + autoExclusive: false + onToggled: { + depthBridge.toggleLeftRightCheck(switch1.checked) + } } Switch { @@ -77,13 +84,13 @@ ListView { x: 0 y: 233 text: qsTr("Extended Disparity") - autoExclusive: true + autoExclusive: false font.kerning: false font.family: "Courier" font.preferShaping: false transformOrigin: Item.Center onToggled: { - bridge.toggleSubpixel(switch2.checked) + depthBridge.toggleExtendedDisparity(switch2.checked) } } @@ -92,11 +99,14 @@ ListView { x: 0 y: 141 text: qsTr("Subpixel") - autoExclusive: true + autoExclusive: false font.kerning: false transformOrigin: Item.Center font.preferShaping: false font.family: "Courier" + onToggled: { + depthBridge.toggleSubpixel(switch3.checked) + } } Text { @@ -124,6 +134,9 @@ ListView { snapMode: RangeSlider.NoSnap value: 240 to: 255 + onValueChanged: { + depthBridge.setBilateralSigma(value) + } } Text { @@ -213,6 +226,12 @@ ListView { focusPolicy: Qt.StrongFocus second.value: 10000 first.value: 0 + first.onMoved: { + depthBridge.setDepthRange(first.value, second.value) + } + second.onMoved: { + depthBridge.setDepthRange(first.value, second.value) + } } Text { @@ -254,4 +273,9 @@ ListView { } } -} \ No newline at end of file +} +/*##^## +Designer { + D{i:0;autoSize:true;height:480;width:640} +} +##^##*/ diff --git a/gui/views/root.qml b/gui/views/root.qml index d4a6d93e1..565e0944c 100644 --- a/gui/views/root.qml +++ b/gui/views/root.qml @@ -63,8 +63,17 @@ ApplicationWindow { Material.accent: Material.Red visible: true - Bridge { - id: bridge + DepthBridge { + id: depthBridge + } + ColorCamBridge { + id: colorCamBridge + } + LeftCamBridge { + id: leftCamBridge + } + RightCamBridge { + id: rightCamBridge } Rectangle { From bc5b0204038c04b9e53e38b0c60f23c376c9b397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Thu, 21 Oct 2021 13:52:28 +0200 Subject: [PATCH 06/57] Update README.md --- gui/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gui/README.md b/gui/README.md index d5ce0c897..37fb35b0d 100644 --- a/gui/README.md +++ b/gui/README.md @@ -19,7 +19,7 @@ $ cmake --build . Now, download the [QT Creator](https://www.qt.io/product/development-tools). After downloading and installing this tool: - go to Preferences > Kits > Qt Versions - Click "Add" -- point to the qt everywnere directory and `qtbase/bin/qmake` +- point to the qt everywhere directory and `qtbase/bin/qmake` - Go to Kits - Edit both of the kits by clicking on them, scrolling down to Qt Version and selecting the qt-everywhere version we just added - Restart QT Creator @@ -31,4 +31,4 @@ Now, download the [QT Creator](https://www.qt.io/product/development-tools). Aft - A build process should start automatically. It may throw a warning that the build process is not responding, ignore - Restart QT Creator -Now, the setup is ready and the Designer tool can be used too \ No newline at end of file +Now, the setup is ready and the Designer tool can be used too From 65f420bc9eb2637ddf3b0cff262b60ad15f57968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Fri, 22 Oct 2021 14:15:50 +0200 Subject: [PATCH 07/57] Adjust GUI for image --- depthai_demo.py | 776 ++++++++++-------- .../depthai_sdk/managers/preview_manager.py | 10 +- gui/main.py | 66 +- gui/views/CameraPreview.qml | 16 + gui/views/DepthProperties.qml | 3 - gui/views/root.qml | 24 +- 6 files changed, 495 insertions(+), 400 deletions(-) create mode 100644 gui/views/CameraPreview.qml diff --git a/depthai_demo.py b/depthai_demo.py index 7c2d9a2b5..932fd27f0 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -1,13 +1,13 @@ #!/usr/bin/env python3 import os +import threading +from contextlib import ExitStack from itertools import cycle from pathlib import Path import cv2 import depthai as dai import platform -import numpy as np - from depthai_helpers.arg_manager import parseArgs from depthai_helpers.config_manager import ConfigManager, DEPTHAI_ZOO, DEPTHAI_VIDEOS from depthai_helpers.version_check import checkRequirementsVersion @@ -16,88 +16,19 @@ from gui.main import DemoQtGui -DemoQtGui() - -DISP_CONF_MIN = int(os.getenv("DISP_CONF_MIN", 0)) -DISP_CONF_MAX = int(os.getenv("DISP_CONF_MAX", 255)) -SIGMA_MIN = int(os.getenv("SIGMA_MIN", 0)) -SIGMA_MAX = int(os.getenv("SIGMA_MAX", 250)) -LRCT_MIN = int(os.getenv("LRCT_MIN", 0)) -LRCT_MAX = int(os.getenv("LRCT_MAX", 10)) - print('Using depthai module from: ', dai.__file__) print('Depthai version installed: ', dai.__version__) if platform.machine() not in ['armv6l', 'aarch64']: checkRequirementsVersion() -conf = ConfigManager(parseArgs()) -conf.linuxCheckApplyUsbRules() -if not conf.useCamera: - if str(conf.args.video).startswith('https'): - conf.args.video = downloadYTVideo(conf.args.video, DEPTHAI_VIDEOS) +confManager = ConfigManager(parseArgs()) +confManager.linuxCheckApplyUsbRules() +if not confManager.useCamera: + if str(confManager.args.video).startswith('https'): + confManager.args.video = downloadYTVideo(confManager.args.video, DEPTHAI_VIDEOS) print("Youtube video downloaded.") - if not Path(conf.args.video).exists(): - raise ValueError("Path {} does not exists!".format(conf.args.video)) - -callbacks = loadModule(conf.args.callback) -rgbRes = conf.getRgbResolution() -monoRes = conf.getMonoResolution() - - -if conf.args.reportFile: - reportFileP = Path(conf.args.reportFile).with_suffix('.csv') - reportFileP.parent.mkdir(parents=True, exist_ok=True) - reportFile = open(conf.args.reportFile, 'a') - - -def printSysInfo(info): - m = 1024 * 1024 # MiB - if not conf.args.reportFile: - if "memory" in conf.args.report: - print(f"Drr used / total - {info.ddrMemoryUsage.used / m:.2f} / {info.ddrMemoryUsage.total / m:.2f} MiB") - print(f"Cmx used / total - {info.cmxMemoryUsage.used / m:.2f} / {info.cmxMemoryUsage.total / m:.2f} MiB") - print(f"LeonCss heap used / total - {info.leonCssMemoryUsage.used / m:.2f} / {info.leonCssMemoryUsage.total / m:.2f} MiB") - print(f"LeonMss heap used / total - {info.leonMssMemoryUsage.used / m:.2f} / {info.leonMssMemoryUsage.total / m:.2f} MiB") - if "temp" in conf.args.report: - t = info.chipTemperature - print(f"Chip temperature - average: {t.average:.2f}, css: {t.css:.2f}, mss: {t.mss:.2f}, upa0: {t.upa:.2f}, upa1: {t.dss:.2f}") - if "cpu" in conf.args.report: - print(f"Cpu usage - Leon OS: {info.leonCssCpuUsage.average * 100:.2f}%, Leon RT: {info.leonMssCpuUsage.average * 100:.2f} %") - print("----------------------------------------") - else: - data = {} - if "memory" in conf.args.report: - data = { - **data, - "ddrUsed": info.ddrMemoryUsage.used, - "ddrTotal": info.ddrMemoryUsage.total, - "cmxUsed": info.cmxMemoryUsage.used, - "cmxTotal": info.cmxMemoryUsage.total, - "leonCssUsed": info.leonCssMemoryUsage.used, - "leonCssTotal": info.leonCssMemoryUsage.total, - "leonMssUsed": info.leonMssMemoryUsage.used, - "leonMssTotal": info.leonMssMemoryUsage.total, - } - if "temp" in conf.args.report: - data = { - **data, - "tempAvg": info.chipTemperature.average, - "tempCss": info.chipTemperature.css, - "tempMss": info.chipTemperature.mss, - "tempUpa0": info.chipTemperature.upa, - "tempUpa1": info.chipTemperature.dss, - } - if "cpu" in conf.args.report: - data = { - **data, - "cpuCssAvg": info.leonCssCpuUsage.average, - "cpuMssAvg": info.leonMssCpuUsage.average, - } - - if reportFile.tell() == 0: - print(','.join(data.keys()), file=reportFile) - callbacks.onReport(data) - print(','.join(map(str, data.values())), file=reportFile) + if not Path(confManager.args.video).exists(): + raise ValueError("Path {} does not exists!".format(confManager.args.video)) class Trackbars: @@ -117,307 +48,448 @@ def fn(value): Trackbars.instances[name] = {**Trackbars.instances.get(name, {}), window: defaultVal} cv2.setTrackbarPos(name, window, defaultVal) -deviceInfo = getDeviceInfo(conf.args.deviceId) -openvinoVersion = None -if conf.args.openvinoVersion: - openvinoVersion = getattr(dai.OpenVINO.Version, 'VERSION_' + conf.args.openvinoVersion) -pm = PipelineManager(openvinoVersion) - -if conf.args.xlinkChunkSize is not None: - pm.setXlinkChunkSize(conf.args.xlinkChunkSize) - -if conf.useNN: - blobManager = BlobManager( - zooDir=DEPTHAI_ZOO, - zooName=conf.getModelName(), - ) - nnManager = NNetManager(inputSize=conf.inputSize) - - if conf.getModelDir() is not None: - configPath = conf.getModelDir() / Path(conf.getModelName()).with_suffix(f".json") - nnManager.readConfig(configPath) - - nnManager.countLabel(conf.getCountLabel(nnManager)) - pm.setNnManager(nnManager) - -# Pipeline is defined, now we can connect to the device -with dai.Device(pm.pipeline.getOpenVINOVersion(), deviceInfo, usb2Mode=conf.args.usbSpeed == "usb2") as device: - if deviceInfo.desc.protocol == dai.XLinkProtocol.X_LINK_USB_VSC: - print("USB Connection speed: {}".format(device.getUsbSpeed())) - conf.adjustParamsToDevice(device) - conf.adjustPreviewToOptions() - if conf.lowBandwidth: - pm.enableLowBandwidth() - cap = cv2.VideoCapture(conf.args.video) if not conf.useCamera else None - fps = FPSHandler() if conf.useCamera else FPSHandler(cap) - - if conf.useCamera or conf.args.sync: - pv = PreviewManager(display=conf.args.show, nnSource=conf.getModelSource(), colorMap=conf.getColorMap(), - dispMultiplier=conf.dispMultiplier, mouseTracker=True, lowBandwidth=conf.lowBandwidth, - scale=conf.args.scale, sync=conf.args.sync, fpsHandler=fps) - - if conf.leftCameraEnabled: - pm.createLeftCam(monoRes, conf.args.monoFps, orientation=conf.args.cameraOrientation.get(Previews.left.name), - xout=Previews.left.name in conf.args.show and (conf.getModelSource() != "left" or not conf.args.sync) - ) - if conf.rightCameraEnabled: - pm.createRightCam(monoRes, conf.args.monoFps, orientation=conf.args.cameraOrientation.get(Previews.right.name), - xout=Previews.right.name in conf.args.show and (conf.getModelSource() != "right" or not conf.args.sync) - ) - if conf.rgbCameraEnabled: - pm.createColorCam(nnManager.inputSize if conf.useNN else conf.previewSize, rgbRes, conf.args.rgbFps, orientation=conf.args.cameraOrientation.get(Previews.color.name), - fullFov=not conf.args.disableFullFovNn, xout=Previews.color.name in conf.args.show and (conf.getModelSource() != "color" or not conf.args.sync) - ) - - if conf.useDepth: - pm.createDepth( - conf.args.disparityConfidenceThreshold, - conf.getMedianFilter(), - conf.args.sigma, - conf.args.stereoLrCheck, - conf.args.lrcThreshold, - conf.args.extendedDisparity, - conf.args.subpixel, - useDepth=Previews.depth.name in conf.args.show or Previews.depthRaw.name in conf.args.show , - useDisparity=Previews.disparity.name in conf.args.show or Previews.disparityColor.name in conf.args.show, - useRectifiedLeft=Previews.rectifiedLeft.name in conf.args.show and (conf.getModelSource() != "rectifiedLeft" or not conf.args.sync), - useRectifiedRight=Previews.rectifiedRight.name in conf.args.show and (conf.getModelSource() != "rectifiedRight" or not conf.args.sync), + +noop = lambda *a, **k: None + + +class Demo: + DISP_CONF_MIN = int(os.getenv("DISP_CONF_MIN", 0)) + DISP_CONF_MAX = int(os.getenv("DISP_CONF_MAX", 255)) + SIGMA_MIN = int(os.getenv("SIGMA_MIN", 0)) + SIGMA_MAX = int(os.getenv("SIGMA_MAX", 250)) + LRCT_MIN = int(os.getenv("LRCT_MIN", 0)) + LRCT_MAX = int(os.getenv("LRCT_MAX", 10)) + + def run_all(self): + self.setup() + self.run() + + def __init__(self, conf: ConfigManager, displayFrames=True, onNewFrame = noop, onShowFrame = noop, onNn = noop, onReport = noop, onSetup = noop, onTeardown = noop, onIter = noop, shouldRun = lambda inst: True): + self._stack = ExitStack() + self._conf = conf + self._rgbRes = conf.getRgbResolution() + self._monoRes = conf.getMonoResolution() + self._deviceInfo = getDeviceInfo(conf.args.deviceId) + self._openvinoVersion = None + if conf.args.openvinoVersion: + self._openvinoVersion = getattr(dai.OpenVINO.Version, 'VERSION_' + conf.args.openvinoVersion) + self._displayFrames = displayFrames + + self.onNewFrame = onNewFrame + self.onShowFrame = onShowFrame + self.onNn = onNn + self.onReport = onReport + self.onSetup = onSetup + self.onTeardown = onTeardown + self.onIter = onIter + self.shouldRun = shouldRun + + def setup(self): + if self._conf.args.reportFile: + reportFileP = Path(self._conf.args.reportFile).with_suffix('.csv') + reportFileP.parent.mkdir(parents=True, exist_ok=True) + self._reportFile = self._stack.enter_context(reportFileP.open('a')) + self._pm = PipelineManager(self._openvinoVersion) + + if self._conf.args.xlinkChunkSize is not None: + self._pm.setXlinkChunkSize(self._conf.args.xlinkChunkSize) + + if self._conf.useNN: + self._blobManager = BlobManager( + zooDir=DEPTHAI_ZOO, + zooName=self._conf.getModelName(), ) + self._nnManager = NNetManager(inputSize=self._conf.inputSize) - encManager = None - if len(conf.args.encode) > 1: - encManager = EncodingManager(conf.args.encode, conf.args.encodeOutput) - encManager.createEncoders(pm) - - if len(conf.args.report) > 0: - pm.createSystemLogger() - - if conf.useNN: - nn = nnManager.createNN( - pipeline=pm.pipeline, nodes=pm.nodes, source=conf.getModelSource(), - blobPath=blobManager.getBlob(shaves=conf.shaves, openvinoVersion=nnManager.openvinoVersion), - useDepth=conf.useDepth, minDepth=conf.args.minDepth, maxDepth=conf.args.maxDepth, - sbbScaleFactor=conf.args.sbbScaleFactor, fullFov=not conf.args.disableFullFovNn, - flipDetection=conf.getModelSource() in ("rectifiedLeft", "rectifiedRight") and not conf.args.stereoLrCheck, - ) + if self._conf.getModelDir() is not None: + configPath = self._conf.getModelDir() / Path(self._conf.getModelName()).with_suffix(f".json") + self._nnManager.readConfig(configPath) - pm.addNn( - nn=nn, sync=conf.args.sync, xoutNnInput=Previews.nnInput.name in conf.args.show, - useDepth=conf.useDepth, xoutSbb=conf.args.spatialBoundingBox and conf.useDepth + self._nnManager.countLabel(self._conf.getCountLabel(self._nnManager)) + self._pm.setNnManager(self._nnManager) + + self._device = self._stack.enter_context( + dai.Device(self._pm.pipeline.getOpenVINOVersion(), self._deviceInfo, usb2Mode=self._conf.args.usbSpeed == "usb2") ) + if self._deviceInfo.desc.protocol == dai.XLinkProtocol.X_LINK_USB_VSC: + print("USB Connection speed: {}".format(self._device.getUsbSpeed())) + self._conf.adjustParamsToDevice(self._device) + self._conf.adjustPreviewToOptions() + if self._conf.lowBandwidth: + self._pm.enableLowBandwidth() + self._cap = cv2.VideoCapture(self._conf.args.video) if not self._conf.useCamera else None + self._fps = FPSHandler() if self._conf.useCamera else FPSHandler(self._cap) + + if self._conf.useCamera or self._conf.args.sync: + self._pv = PreviewManager(display=self._conf.args.show, nnSource=self._conf.getModelSource(), colorMap=self._conf.getColorMap(), + dispMultiplier=self._conf.dispMultiplier, mouseTracker=True, lowBandwidth=self._conf.lowBandwidth, + scale=self._conf.args.scale, sync=self._conf.args.sync, fpsHandler=self._fps, createWindows=self._displayFrames) + + if self._conf.leftCameraEnabled: + self._pm.createLeftCam(self._monoRes, self._conf.args.monoFps, + orientation=self._conf.args.cameraOrientation.get(Previews.left.name), + xout=Previews.left.name in self._conf.args.show and (self._conf.getModelSource() != "left" or not self._conf.args.sync)) + if self._conf.rightCameraEnabled: + self._pm.createRightCam(self._monoRes, self._conf.args.monoFps, + orientation=self._conf.args.cameraOrientation.get(Previews.right.name), + xout=Previews.right.name in self._conf.args.show and (self._conf.getModelSource() != "right" or not self._conf.args.sync)) + if self._conf.rgbCameraEnabled: + self._pm.createColorCam(self._nnManager.inputSize if self._conf.useNN else self._conf.previewSize, self._rgbRes, self._conf.args.rgbFps, + orientation=self._conf.args.cameraOrientation.get(Previews.color.name), + fullFov=not self._conf.args.disableFullFovNn, + xout=Previews.color.name in self._conf.args.show and (self._conf.getModelSource() != "color" or not self._conf.args.sync)) + + if self._conf.useDepth: + self._pm.createDepth( + self._conf.args.disparityConfidenceThreshold, + self._conf.getMedianFilter(), + self._conf.args.sigma, + self._conf.args.stereoLrCheck, + self._conf.args.lrcThreshold, + self._conf.args.extendedDisparity, + self._conf.args.subpixel, + useDepth=Previews.depth.name in self._conf.args.show or Previews.depthRaw.name in self._conf.args.show, + useDisparity=Previews.disparity.name in self._conf.args.show or Previews.disparityColor.name in self._conf.args.show, + useRectifiedLeft=Previews.rectifiedLeft.name in self._conf.args.show and ( + self._conf.getModelSource() != "rectifiedLeft" or not self._conf.args.sync), + useRectifiedRight=Previews.rectifiedRight.name in self._conf.args.show and ( + self._conf.getModelSource() != "rectifiedRight" or not self._conf.args.sync), + ) + + self._encManager = None + if len(self._conf.args.encode) > 1: + self._encManager = EncodingManager(self._conf.args.encode, self._conf.args.encodeOutput) + self._encManager.createEncoders(self._pm) + + if len(self._conf.args.report) > 0: + self._pm.createSystemLogger() + + if self._conf.useNN: + self._nn = self._nnManager.createNN( + pipeline=self._pm.pipeline, nodes=self._pm.nodes, source=self._conf.getModelSource(), + blobPath=self._blobManager.getBlob(shaves=self._conf.shaves, openvinoVersion=self._nnManager.openvinoVersion), + useDepth=self._conf.useDepth, minDepth=self._conf.args.minDepth, maxDepth=self._conf.args.maxDepth, + sbbScaleFactor=self._conf.args.sbbScaleFactor, fullFov=not self._conf.args.disableFullFovNn, + flipDetection=self._conf.getModelSource() in ( + "rectifiedLeft", "rectifiedRight") and not self._conf.args.stereoLrCheck, + ) - # Start pipeline - device.startPipeline(pm.pipeline) - pm.createDefaultQueues(device) - if conf.useNN: - nnManager.createQueues(device) - - sbbOut = device.getOutputQueue("sbb", maxSize=1, blocking=False) if conf.useNN and conf.args.spatialBoundingBox else None - logOut = device.getOutputQueue("systemLogger", maxSize=30, blocking=False) if len(conf.args.report) > 0 else None - - medianFilters = cycle([item for name, item in vars(dai.MedianFilter).items() if name.startswith('KERNEL_') or name.startswith('MEDIAN_')]) - for medFilter in medianFilters: - # move the cycle to the current median filter - if medFilter == pm._depthConfig.getMedianFilter(): - break - - if conf.useCamera: - def createQueueCallback(queueName): - if queueName in [Previews.disparityColor.name, Previews.disparity.name, Previews.depth.name, Previews.depthRaw.name]: - Trackbars.createTrackbar('Disparity confidence', queueName, DISP_CONF_MIN, DISP_CONF_MAX, conf.args.disparityConfidenceThreshold, - lambda value: pm.updateDepthConfig(device, dct=value)) - if queueName in [Previews.depthRaw.name, Previews.depth.name]: - Trackbars.createTrackbar('Bilateral sigma', queueName, SIGMA_MIN, SIGMA_MAX, conf.args.sigma, - lambda value: pm.updateDepthConfig(device, sigma=value)) - if conf.args.stereoLrCheck: - Trackbars.createTrackbar('LR-check threshold', queueName, LRCT_MIN, LRCT_MAX, conf.args.lrcThreshold, - lambda value: pm.updateDepthConfig(device, lrcThreshold=value)) - - cameras = device.getConnectedCameras() - if dai.CameraBoardSocket.LEFT in cameras and dai.CameraBoardSocket.RIGHT in cameras: - pv.collectCalibData(device) - - cameraConfig = { - "exposure": conf.args.cameraExposure, - "sensitivity": conf.args.cameraSensitivity, - "saturation": conf.args.cameraSaturation, - "contrast": conf.args.cameraContrast, - "brightness": conf.args.cameraBrightness, - "sharpness": conf.args.cameraSharpness - } - def updateCameraConfigs(): - if conf.leftCameraEnabled: - pm.updateLeftCamConfig(device, **cameraConfig) - if conf.rightCameraEnabled: - pm.updateRightCamConfig(device, **cameraConfig) - if conf.rgbCameraEnabled: - pm.updateColorCamConfig(device, **cameraConfig) - - if any(cameraConfig.values()): - updateCameraConfigs() - - pv.createQueues(device, createQueueCallback) - if encManager is not None: - encManager.createDefaultQueues(device) - elif conf.args.sync: - hostOut = device.getOutputQueue(Previews.nnInput.name, maxSize=1, blocking=False) - - seqNum = 0 - hostFrame = None - nnData = [] - sbbRois = [] - callbacks.onSetup(**locals()) - - try: - while True: - fps.nextIter() - callbacks.onIter(**locals()) - if conf.useCamera: - pv.prepareFrames(callback=callbacks.onNewFrame) - if encManager is not None: - encManager.parseQueues() - - if sbbOut is not None: - sbb = sbbOut.tryGet() - if sbb is not None: - sbbRois = sbb.getConfigData() - depthFrames = [pv.get(Previews.depthRaw.name), pv.get(Previews.depth.name)] - for depthFrame in depthFrames: - if depthFrame is None: - continue - - for roiData in sbbRois: - roi = roiData.roi.denormalize(depthFrame.shape[1], depthFrame.shape[0]) - topLeft = roi.topLeft() - bottomRight = roi.bottomRight() - # Display SBB on the disparity map - cv2.rectangle(depthFrame, (int(topLeft.x), int(topLeft.y)), (int(bottomRight.x), int(bottomRight.y)), nnManager._bboxColors[0], 2) - else: - readCorrectly, rawHostFrame = cap.read() - if not readCorrectly: - break - - nnManager.sendInputFrame(rawHostFrame, seqNum) - seqNum += 1 - - if not conf.args.sync: - hostFrame = rawHostFrame - fps.tick('host') - - if conf.useNN: - inNn = nnManager.outputQueue.tryGet() - if inNn is not None: - callbacks.onNn(inNn) - if not conf.useCamera and conf.args.sync: - hostFrame = Previews.nnInput.value(hostOut.get()) - nnData = nnManager.decode(inNn) - fps.tick('nn') - - if conf.useCamera: - if conf.useNN: - nnManager.draw(pv, nnData) - - def showFramesCallback(frame, name): - fps.drawFps(frame, name) - h, w = frame.shape[:2] - if name in [Previews.disparityColor.name, Previews.disparity.name, Previews.depth.name, Previews.depthRaw.name]: - text = "Median filter: {} [M]".format(pm._depthConfig.getMedianFilter().name.lstrip("KERNEL_").lstrip("MEDIAN_")) - cv2.putText(frame, text, (10, h - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, 0, 4) - cv2.putText(frame, text, (10, h - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, 255, 1) - elif conf.args.cameraControlls and name in [Previews.color.name, Previews.left.name, Previews.right.name]: - text = "Exposure: {} T [+] [-] G".format(cameraConfig["exposure"] if cameraConfig["exposure"] is not None else "auto") - label_width = cv2.getTextSize(text, cv2.FONT_HERSHEY_TRIPLEX, 0.5, 4)[0][0] - cv2.putText(frame, text, (w - label_width, h - 110), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (0, 0, 0), 4) - cv2.putText(frame, text, (w - label_width, h - 110), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255, 255, 255), 1) - text = "Sensitivity: {} Y [+] [-] H".format(cameraConfig["sensitivity"] if cameraConfig["sensitivity"] is not None else "auto") - label_width = cv2.getTextSize(text, cv2.FONT_HERSHEY_TRIPLEX, 0.5, 4)[0][0] - cv2.putText(frame, text, (w - label_width, h - 90), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (0, 0, 0), 4) - cv2.putText(frame, text, (w - label_width, h - 90), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255, 255, 255), 1) - text = "Saturation: {} U [+] [-] J".format(cameraConfig["saturation"] if cameraConfig["saturation"] is not None else "auto") - label_width = cv2.getTextSize(text, cv2.FONT_HERSHEY_TRIPLEX, 0.5, 4)[0][0] - cv2.putText(frame, text, (w - label_width, h - 70), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (0, 0, 0), 4) - cv2.putText(frame, text, (w - label_width, h - 70), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255, 255, 255), 1) - text = "Contrast: {} I [+] [-] K".format(cameraConfig["contrast"] if cameraConfig["contrast"] is not None else "auto") - label_width = cv2.getTextSize(text, cv2.FONT_HERSHEY_TRIPLEX, 0.5, 4)[0][0] - cv2.putText(frame, text, (w - label_width, h - 50), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (0, 0, 0), 4) - cv2.putText(frame, text, (w - label_width, h - 50), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255, 255, 255), 1) - text = "Brightness: {} O [+] [-] L".format(cameraConfig["brightness"] if cameraConfig["brightness"] is not None else "auto") - label_width = cv2.getTextSize(text, cv2.FONT_HERSHEY_TRIPLEX, 0.5, 4)[0][0] - cv2.putText(frame, text, (w - label_width, h - 30), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (0, 0, 0), 4) - cv2.putText(frame, text, (w - label_width, h - 30), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255, 255, 255), 1) - text = "Sharpness: {} P [+] [-] ;".format(cameraConfig["sharpness"] if cameraConfig["sharpness"] is not None else "auto") - label_width = cv2.getTextSize(text, cv2.FONT_HERSHEY_TRIPLEX, 0.5, 4)[0][0] - cv2.putText(frame, text, (w - label_width, h - 10), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (0, 0, 0), 4) - cv2.putText(frame, text, (w - label_width, h - 10), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255, 255, 255), 1) - returnFrame = callbacks.onShowFrame(frame, name) - return returnFrame if returnFrame is not None else frame - pv.showFrames(callback=showFramesCallback) - elif hostFrame is not None: - debugHostFrame = hostFrame.copy() - if conf.useNN: - nnManager.draw(debugHostFrame, nnData) - fps.drawFps(debugHostFrame, "host") + self._pm.addNn( + nn=self._nn, sync=self._conf.args.sync, xoutNnInput=Previews.nnInput.name in self._conf.args.show, + useDepth=self._conf.useDepth, xoutSbb=self._conf.args.spatialBoundingBox and self._conf.useDepth + ) + + def run(self): + self._device.startPipeline(self._pm.pipeline) + self._pm.createDefaultQueues(self._device) + if self._conf.useNN: + self._nnManager.createQueues(self._device) + + self._sbbOut = self._device.getOutputQueue("sbb", maxSize=1, blocking=False) if self._conf.useNN and self._conf.args.spatialBoundingBox else None + self._logOut = self._device.getOutputQueue("systemLogger", maxSize=30, blocking=False) if len(self._conf.args.report) > 0 else None + + self._medianFilters = cycle([item for name, item in vars(dai.MedianFilter).items() if name.startswith('KERNEL_') or name.startswith('MEDIAN_')]) + for medFilter in self._medianFilters: + # move the cycle to the current median filter + if medFilter == self._pm._depthConfig.getMedianFilter(): + break + + if self._conf.useCamera: + cameras = self._device.getConnectedCameras() + if dai.CameraBoardSocket.LEFT in cameras and dai.CameraBoardSocket.RIGHT in cameras: + self._pv.collectCalibData(self._device) + + self._cameraConfig = { + "exposure": self._conf.args.cameraExposure, + "sensitivity": self._conf.args.cameraSensitivity, + "saturation": self._conf.args.cameraSaturation, + "contrast": self._conf.args.cameraContrast, + "brightness": self._conf.args.cameraBrightness, + "sharpness": self._conf.args.cameraSharpness + } + + if any(self._cameraConfig.values()): + self._updateCameraConfigs() + + self._pv.createQueues(self._device, self._createQueueCallback) + if self._encManager is not None: + self._encManager.createDefaultQueues(self._device) + elif self._conf.args.sync: + self._hostOut = self._device.getOutputQueue(Previews.nnInput.name, maxSize=1, blocking=False) + + self._seqNum = 0 + self._hostFrame = None + self._nnData = [] + self._sbbRois = [] + self.onSetup(self) + + try: + while self.shouldRun(self): + self._fps.nextIter() + self.onIter(self) + self.loop() + except StopIteration: + pass + finally: + if self._conf.useCamera and self._encManager is not None: + self._encManager.close() + self._stack.close() + + self._fps.printStatus() + self.onTeardown(self) + + + def loop(self): + if self._conf.useCamera: + self._pv.prepareFrames(callback=self.onNewFrame) + if self._encManager is not None: + self._encManager.parseQueues() + + if self._sbbOut is not None: + sbb = self._sbbOut.tryGet() + if sbb is not None: + self._sbbRois = sbb.getConfigData() + depthFrames = [self._pv.get(Previews.depthRaw.name), self._pv.get(Previews.depth.name)] + for depthFrame in depthFrames: + if depthFrame is None: + continue + + for roiData in self._sbbRois: + roi = roiData.roi.denormalize(depthFrame.shape[1], depthFrame.shape[0]) + topLeft = roi.topLeft() + bottomRight = roi.bottomRight() + # Display SBB on the disparity map + cv2.rectangle(depthFrame, (int(topLeft.x), int(topLeft.y)), (int(bottomRight.x), int(bottomRight.y)), self._nnManager._bboxColors[0], 2) + else: + readCorrectly, rawHostFrame = self._cap.read() + if not readCorrectly: + raise StopIteration() + + self._nnManager.sendInputFrame(rawHostFrame, self._seqNum) + self._seqNum += 1 + + if not self._conf.args.sync: + self._hostFrame = rawHostFrame + self._fps.tick('host') + + if self._conf.useNN: + inNn = self._nnManager.outputQueue.tryGet() + if inNn is not None: + self.onNn(inNn) + if not self._conf.useCamera and self._conf.args.sync: + self._hostFrame = Previews.nnInput.value(self._hostOut.get()) + self._nnData = self._nnManager.decode(inNn) + self._fps.tick('nn') + + if self._conf.useCamera: + if self._conf.useNN: + self._nnManager.draw(self._pv, self._nnData) + self._pv.showFrames(callback=self._showFramesCallback) + elif self._hostFrame is not None: + debugHostFrame = self._hostFrame.copy() + if self._conf.useNN: + self._nnManager.draw(debugHostFrame, self._nnData) + self._fps.drawFps(debugHostFrame, "host") + if self._displayFrames: cv2.imshow("host", debugHostFrame) - if logOut: - logs = logOut.tryGetAll() - for log in logs: - printSysInfo(log) + if self._logOut: + logs = self._logOut.tryGetAll() + for log in logs: + self._printSysInfo(log) + if self._displayFrames: key = cv2.waitKey(1) if key == ord('q'): - break + raise StopIteration() elif key == ord('m'): - nextFilter = next(medianFilters) - pm.updateDepthConfig(device, median=nextFilter) + nextFilter = next(self._medianFilters) + self._pm.updateDepthConfig(self._device, median=nextFilter) - if conf.args.cameraControlls: + if self._conf.args.cameraControlls: update = True if key == ord('t'): - cameraConfig["exposure"] = 10000 if cameraConfig["exposure"] is None else 500 if cameraConfig["exposure"] == 1 else min(cameraConfig["exposure"] + 500, 33000) - if cameraConfig["sensitivity"] is None: - cameraConfig["sensitivity"] = 800 + self._cameraConfig["exposure"] = 10000 if self._cameraConfig["exposure"] is None else 500 if self._cameraConfig["exposure"] == 1 else min(self._cameraConfig["exposure"] + 500, 33000) + if self._cameraConfig["sensitivity"] is None: + self._cameraConfig["sensitivity"] = 800 elif key == ord('g'): - cameraConfig["exposure"] = 10000 if cameraConfig["exposure"] is None else max(cameraConfig["exposure"] - 500, 1) - if cameraConfig["sensitivity"] is None: - cameraConfig["sensitivity"] = 800 + self._cameraConfig["exposure"] = 10000 if self._cameraConfig["exposure"] is None else max(self._cameraConfig["exposure"] - 500, 1) + if self._cameraConfig["sensitivity"] is None: + self._cameraConfig["sensitivity"] = 800 elif key == ord('y'): - cameraConfig["sensitivity"] = 800 if cameraConfig["sensitivity"] is None else min(cameraConfig["sensitivity"] + 50, 1600) - if cameraConfig["exposure"] is None: - cameraConfig["exposure"] = 10000 + self._cameraConfig["sensitivity"] = 800 if self._cameraConfig["sensitivity"] is None else min(self._cameraConfig["sensitivity"] + 50, 1600) + if self._cameraConfig["exposure"] is None: + self._cameraConfig["exposure"] = 10000 elif key == ord('h'): - cameraConfig["sensitivity"] = 800 if cameraConfig["sensitivity"] is None else max(cameraConfig["sensitivity"] - 50, 100) - if cameraConfig["exposure"] is None: - cameraConfig["exposure"] = 10000 + self._cameraConfig["sensitivity"] = 800 if self._cameraConfig["sensitivity"] is None else max(self._cameraConfig["sensitivity"] - 50, 100) + if self._cameraConfig["exposure"] is None: + self._cameraConfig["exposure"] = 10000 elif key == ord('u'): - cameraConfig["saturation"] = 0 if cameraConfig["saturation"] is None else min(cameraConfig["saturation"] + 1, 10) + self._cameraConfig["saturation"] = 0 if self._cameraConfig["saturation"] is None else min(self._cameraConfig["saturation"] + 1, 10) elif key == ord('j'): - cameraConfig["saturation"] = 0 if cameraConfig["saturation"] is None else max(cameraConfig["saturation"] - 1, -10) + self._cameraConfig["saturation"] = 0 if self._cameraConfig["saturation"] is None else max(self._cameraConfig["saturation"] - 1, -10) elif key == ord('i'): - cameraConfig["contrast"] = 0 if cameraConfig["contrast"] is None else min(cameraConfig["contrast"] + 1, 10) + self._cameraConfig["contrast"] = 0 if self._cameraConfig["contrast"] is None else min(self._cameraConfig["contrast"] + 1, 10) elif key == ord('k'): - cameraConfig["contrast"] = 0 if cameraConfig["contrast"] is None else max(cameraConfig["contrast"] - 1, -10) + self._cameraConfig["contrast"] = 0 if self._cameraConfig["contrast"] is None else max(self._cameraConfig["contrast"] - 1, -10) elif key == ord('o'): - cameraConfig["brightness"] = 0 if cameraConfig["brightness"] is None else min(cameraConfig["brightness"] + 1, 10) + self._cameraConfig["brightness"] = 0 if self._cameraConfig["brightness"] is None else min(self._cameraConfig["brightness"] + 1, 10) elif key == ord('l'): - cameraConfig["brightness"] = 0 if cameraConfig["brightness"] is None else max(cameraConfig["brightness"] - 1, -10) + self._cameraConfig["brightness"] = 0 if self._cameraConfig["brightness"] is None else max(self._cameraConfig["brightness"] - 1, -10) elif key == ord('p'): - cameraConfig["sharpness"] = 0 if cameraConfig["sharpness"] is None else min(cameraConfig["sharpness"] + 1, 4) + self._cameraConfig["sharpness"] = 0 if self._cameraConfig["sharpness"] is None else min(self._cameraConfig["sharpness"] + 1, 4) elif key == ord(';'): - cameraConfig["sharpness"] = 0 if cameraConfig["sharpness"] is None else max(cameraConfig["sharpness"] - 1, 0) + self._cameraConfig["sharpness"] = 0 if self._cameraConfig["sharpness"] is None else max(self._cameraConfig["sharpness"] - 1, 0) else: update = False if update: - updateCameraConfigs() - - finally: - if conf.useCamera and encManager is not None: - encManager.close() - -if conf.args.reportFile: - reportFile.close() - -fps.printStatus() -callbacks.onTeardown(**locals()) \ No newline at end of file + self._updateCameraConfigs() + + def _createQueueCallback(self, queueName): + if queueName in [Previews.disparityColor.name, Previews.disparity.name, Previews.depth.name, Previews.depthRaw.name]: + Trackbars.createTrackbar('Disparity confidence', queueName, self.DISP_CONF_MIN, self.DISP_CONF_MAX, self._conf.args.disparityConfidenceThreshold, + lambda value: self._pm.updateDepthConfig(self._device, dct=value)) + if queueName in [Previews.depthRaw.name, Previews.depth.name]: + Trackbars.createTrackbar('Bilateral sigma', queueName, self.SIGMA_MIN, self.SIGMA_MAX, self._conf.args.sigma, + lambda value: self._pm.updateDepthConfig(self._device, sigma=value)) + if self._conf.args.stereoLrCheck: + Trackbars.createTrackbar('LR-check threshold', queueName, self.LRCT_MIN, self.LRCT_MAX, self._conf.args.lrcThreshold, + lambda value: self._pm.updateDepthConfig(self._device, lrcThreshold=value)) + + def _updateCameraConfigs(self): + if self._conf.leftCameraEnabled: + self._pm.updateLeftCamConfig(self._device, **self._cameraConfig) + if self._conf.rightCameraEnabled: + self._pm.updateRightCamConfig(self._device, **self._cameraConfig) + if self._conf.rgbCameraEnabled: + self._pm.updateColorCamConfig(self._device, **self._cameraConfig) + + def _showFramesCallback(self, frame, name): + self._fps.drawFps(frame, name) + h, w = frame.shape[:2] + if name in [Previews.disparityColor.name, Previews.disparity.name, Previews.depth.name, Previews.depthRaw.name]: + text = "Median filter: {} [M]".format(self._pm._depthConfig.getMedianFilter().name.lstrip("KERNEL_").lstrip("MEDIAN_")) + cv2.putText(frame, text, (10, h - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, 0, 4) + cv2.putText(frame, text, (10, h - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, 255, 1) + elif self._conf.args.cameraControlls and name in [Previews.color.name, Previews.left.name, Previews.right.name]: + text = "Exposure: {} T [+] [-] G".format(self._cameraConfig["exposure"] if self._cameraConfig["exposure"] is not None else "auto") + label_width = cv2.getTextSize(text, cv2.FONT_HERSHEY_TRIPLEX, 0.5, 4)[0][0] + cv2.putText(frame, text, (w - label_width, h - 110), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (0, 0, 0), 4) + cv2.putText(frame, text, (w - label_width, h - 110), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255, 255, 255), 1) + text = "Sensitivity: {} Y [+] [-] H".format(self._cameraConfig["sensitivity"] if self._cameraConfig["sensitivity"] is not None else "auto") + label_width = cv2.getTextSize(text, cv2.FONT_HERSHEY_TRIPLEX, 0.5, 4)[0][0] + cv2.putText(frame, text, (w - label_width, h - 90), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (0, 0, 0), 4) + cv2.putText(frame, text, (w - label_width, h - 90), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255, 255, 255), 1) + text = "Saturation: {} U [+] [-] J".format(self._cameraConfig["saturation"] if self._cameraConfig["saturation"] is not None else "auto") + label_width = cv2.getTextSize(text, cv2.FONT_HERSHEY_TRIPLEX, 0.5, 4)[0][0] + cv2.putText(frame, text, (w - label_width, h - 70), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (0, 0, 0), 4) + cv2.putText(frame, text, (w - label_width, h - 70), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255, 255, 255), 1) + text = "Contrast: {} I [+] [-] K".format(self._cameraConfig["contrast"] if self._cameraConfig["contrast"] is not None else "auto") + label_width = cv2.getTextSize(text, cv2.FONT_HERSHEY_TRIPLEX, 0.5, 4)[0][0] + cv2.putText(frame, text, (w - label_width, h - 50), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (0, 0, 0), 4) + cv2.putText(frame, text, (w - label_width, h - 50), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255, 255, 255), 1) + text = "Brightness: {} O [+] [-] L".format(self._cameraConfig["brightness"] if self._cameraConfig["brightness"] is not None else "auto") + label_width = cv2.getTextSize(text, cv2.FONT_HERSHEY_TRIPLEX, 0.5, 4)[0][0] + cv2.putText(frame, text, (w - label_width, h - 30), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (0, 0, 0), 4) + cv2.putText(frame, text, (w - label_width, h - 30), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255, 255, 255), 1) + text = "Sharpness: {} P [+] [-] ;".format(self._cameraConfig["sharpness"] if self._cameraConfig["sharpness"] is not None else "auto") + label_width = cv2.getTextSize(text, cv2.FONT_HERSHEY_TRIPLEX, 0.5, 4)[0][0] + cv2.putText(frame, text, (w - label_width, h - 10), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (0, 0, 0), 4) + cv2.putText(frame, text, (w - label_width, h - 10), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255, 255, 255), 1) + returnFrame = self.onShowFrame(frame, name) + return returnFrame if returnFrame is not None else frame + + + def _printSysInfo(self, info): + m = 1024 * 1024 # MiB + if not self._conf.args.reportFile: + if "memory" in self._conf.args.report: + print(f"Drr used / total - {info.ddrMemoryUsage.used / m:.2f} / {info.ddrMemoryUsage.total / m:.2f} MiB") + print(f"Cmx used / total - {info.cmxMemoryUsage.used / m:.2f} / {info.cmxMemoryUsage.total / m:.2f} MiB") + print(f"LeonCss heap used / total - {info.leonCssMemoryUsage.used / m:.2f} / {info.leonCssMemoryUsage.total / m:.2f} MiB") + print(f"LeonMss heap used / total - {info.leonMssMemoryUsage.used / m:.2f} / {info.leonMssMemoryUsage.total / m:.2f} MiB") + if "temp" in self._conf.args.report: + t = info.chipTemperature + print(f"Chip temperature - average: {t.average:.2f}, css: {t.css:.2f}, mss: {t.mss:.2f}, upa0: {t.upa:.2f}, upa1: {t.dss:.2f}") + if "cpu" in self._conf.args.report: + print(f"Cpu usage - Leon OS: {info.leonCssCpuUsage.average * 100:.2f}%, Leon RT: {info.leonMssCpuUsage.average * 100:.2f} %") + print("----------------------------------------") + else: + data = {} + if "memory" in self._conf.args.report: + data = { + **data, + "ddrUsed": info.ddrMemoryUsage.used, + "ddrTotal": info.ddrMemoryUsage.total, + "cmxUsed": info.cmxMemoryUsage.used, + "cmxTotal": info.cmxMemoryUsage.total, + "leonCssUsed": info.leonCssMemoryUsage.used, + "leonCssTotal": info.leonCssMemoryUsage.total, + "leonMssUsed": info.leonMssMemoryUsage.used, + "leonMssTotal": info.leonMssMemoryUsage.total, + } + if "temp" in self._conf.args.report: + data = { + **data, + "tempAvg": info.chipTemperature.average, + "tempCss": info.chipTemperature.css, + "tempMss": info.chipTemperature.mss, + "tempUpa0": info.chipTemperature.upa, + "tempUpa1": info.chipTemperature.dss, + } + if "cpu" in self._conf.args.report: + data = { + **data, + "cpuCssAvg": info.leonCssCpuUsage.average, + "cpuMssAvg": info.leonMssCpuUsage.average, + } + + if self._reportFile.tell() == 0: + print(','.join(data.keys()), file=self._reportFile) + self.onReport(data) + print(','.join(map(str, data.values())), file=self._reportFile) + + +class App(DemoQtGui): + def __init__(self): + super().__init__() + self._demoInstance = Demo(confManager, displayFrames=False, onNewFrame=self.demoOnNewFrame, onShowFrame=self.demoOnShowFrame, onNn=self.demoOnNn, onReport=self.demoOnReport, onSetup=self.demoOnSetup, onTeardown=self.demoOnTeardown, onIter=self.demoOnIter, shouldRun=self.demoShouldRun) + + def demoOnNewFrame(self, frame, source): + pass + + def demoOnShowFrame(self, frame, source): + pass + + def demoOnNn(self, nn_packet): + pass + + def demoOnReport(self, report): + pass + + def demoOnSetup(self, instance): + medianChoices = list(filter(lambda name: name.startswith('KERNEL_') or name.startswith('MEDIAN_'), vars(dai.MedianFilter).keys()))[::-1] + self.setData("medianChoices", medianChoices) + + def demoOnTeardown(self, instance): + pass + + def demoOnIter(self, instance): + pass + + def demoShouldRun(self, instance): + return True + + def start(self): + self._t = threading.Thread(target=self._demoInstance.run_all) + self._t.start() + self.startGui() + + def guiOnDepthConfigUpdate(self, median=None): + self._demoInstance._pm.updateDepthConfig(self._demoInstance._device, median=median) + + +if __name__ == "__main__": + App().start() \ No newline at end of file diff --git a/depthai_sdk/src/depthai_sdk/managers/preview_manager.py b/depthai_sdk/src/depthai_sdk/managers/preview_manager.py index 89a9da46e..5e6337e85 100644 --- a/depthai_sdk/src/depthai_sdk/managers/preview_manager.py +++ b/depthai_sdk/src/depthai_sdk/managers/preview_manager.py @@ -13,7 +13,7 @@ class PreviewManager: #: dict: Contains name -> frame mapping that can be used to modify specific frames directly frames = {} - def __init__(self, display=[], nnSource=None, colorMap=cv2.COLORMAP_JET, dispMultiplier=255/96, mouseTracker=False, lowBandwidth=False, scale=None, sync=False, fpsHandler=None): + def __init__(self, display=[], nnSource=None, colorMap=cv2.COLORMAP_JET, dispMultiplier=255/96, mouseTracker=False, lowBandwidth=False, scale=None, sync=False, fpsHandler=None, createWindows=True): """ Args: display (list, Optional): List of :obj:`depthai_sdk.Previews` objects representing the streams to display @@ -25,6 +25,7 @@ def __init__(self, display=[], nnSource=None, colorMap=cv2.COLORMAP_JET, dispMul lowBandwidth (bool, Optional): If set to :code:`True`, will decode the received frames assuming they were encoded with MJPEG encoding scale (dict, Optional): Allows to scale down frames before preview. Useful when previewing e.g. 4K frames dispMultiplier (float, Optional): Value used for depth <-> disparity calculations + createWindows (bool, Optional): If True, will create preview windows using OpenCV (enabled by default) """ self.sync = sync self.nnSource = nnSource @@ -35,6 +36,7 @@ def __init__(self, display=[], nnSource=None, colorMap=cv2.COLORMAP_JET, dispMul self._fpsHandler = fpsHandler self._mouseTracker = MouseClickTracker() if mouseTracker else None self._display = display + self._createWindows = createWindows self._rawFrames = {} def collectCalibData(self, device): @@ -70,7 +72,8 @@ def createQueues(self, device, callback=None): """ self.outputQueues = [] for name in self._display: - cv2.namedWindow(name) + if self._createWindows: + cv2.namedWindow(name) if callable(callback): callback(name) if self._mouseTracker is not None: @@ -158,7 +161,8 @@ def showFrames(self, callback=None): newFrame = callback(frame, name) if newFrame is not None: frame = newFrame - cv2.imshow(name, frame) + if self._createWindows: + cv2.imshow(name, frame) def has(self, name): """ diff --git a/gui/main.py b/gui/main.py index e3ed18a03..4d28b9c2f 100644 --- a/gui/main.py +++ b/gui/main.py @@ -14,10 +14,32 @@ QML_IMPORT_MAJOR_VERSION = 1 +class DemoQtGui: + instance = None + + def __init__(self): + self.app = QGuiApplication() + self.engine = QQmlApplicationEngine() + self.setInstance() + + def setInstance(self): + DemoQtGui.instance = self + + def setData(self, name, value): + self.engine.rootContext().setContextProperty(name, value) + + def startGui(self): + self.engine.load(Path(__file__).parent / "views" / "root.qml") + if not self.engine.rootObjects(): + raise RuntimeError("Unable to start GUI - no root objects!") + sys.exit(self.app.exec()) + + def guiOnDepthConfigUpdate(self, median=None): + pass + + @QmlElement class DepthBridge(QObject): - onUpdate = Signal() - @Slot(bool) def toggleSubpixel(self, state): print("Sub: {}".format(state)) @@ -48,7 +70,9 @@ def setDepthRange(self, valFrom, valTo): @Slot(str) def setMedianFilter(self, state): - print("Med: {}".format(state)) + value = getattr(dai.MedianFilter, state) + DemoQtGui.instance.guiOnDepthConfigUpdate(median=value) + print("Med: {}".format(value)) class BaseCamBridge(QObject): @@ -79,47 +103,17 @@ def setSharpness(self, value): @QmlElement class ColorCamBridge(BaseCamBridge): - onUpdate = Signal() + pass @QmlElement class LeftCamBridge(BaseCamBridge): - onUpdate = Signal() + pass @QmlElement class RightCamBridge(BaseCamBridge): - onUpdate = Signal() - - -class StoppableThread(threading.Thread): - """Thread class with a stop() method. The thread itself has to check - regularly for the stopped() condition.""" - - def __init__(self, *args, **kwargs): - super(StoppableThread, self).__init__(*args, **kwargs) - self._stop_event = threading.Event() - - def stop(self): - self._stop_event.set() - - def stopped(self): - return self._stop_event.is_set() - - -class DemoQtGui: - def __init__(self): - self.app = QGuiApplication() - self.engine = QQmlApplicationEngine() - - def setData(self, name, value): - self.engine.rootContext().setContextProperty(name, value) - - def startGui(self): - self.engine.load(Path(__file__).parent / "views" / "root.qml") - if not self.engine.rootObjects(): - raise RuntimeError("Unable to start GUI - no root objects!") - sys.exit(self.app.exec()) + pass if __name__ == "__main__": diff --git a/gui/views/CameraPreview.qml b/gui/views/CameraPreview.qml new file mode 100644 index 000000000..047673001 --- /dev/null +++ b/gui/views/CameraPreview.qml @@ -0,0 +1,16 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.11 +import QtQuick.Controls 2.1 +import QtQuick.Window 2.1 +import QtQuick.Controls.Material 2.1 + +ListView { + id: cameraPreview + + Rectangle { + id: cameraPreviewRect + color: "black" + width: parent.width + height: parent.height + } +} \ No newline at end of file diff --git a/gui/views/DepthProperties.qml b/gui/views/DepthProperties.qml index e22102e28..1479e0841 100644 --- a/gui/views/DepthProperties.qml +++ b/gui/views/DepthProperties.qml @@ -6,9 +6,6 @@ import QtQuick.Controls.Material 2.1 ListView { id: view - anchors.fill: root - anchors.margins: 25 - anchors.bottomMargin: 320 delegate: Text { anchors.leftMargin: 50 font.pointSize: 15 diff --git a/gui/views/root.qml b/gui/views/root.qml index 565e0944c..2a0ce0a74 100644 --- a/gui/views/root.qml +++ b/gui/views/root.qml @@ -57,7 +57,7 @@ import QtQuick.Controls.Material 2.1 import dai.gui 1.0 ApplicationWindow { - width: 640 + width: 1200 height: 640 Material.theme: Material.Dark Material.accent: Material.Red @@ -81,17 +81,29 @@ ApplicationWindow { x: 0 y: 0 width: parent.width - height: 640 + height: parent.height color: "#000000" enabled: true - DepthProperties {} + CameraPreview { + x: 0 + y: 0 + width: 610 + height: parent.height + } + + DepthProperties { + x: 610 + y: 0 + width: 590 + height: 340 + } CameraProperties { - x: 25 - y: 348 + x: 610 + y: 340 width: 590 - height: 284 + height: 300 } } } From b01cce0624d0f91204a6f11e36e573217c5f8b3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Fri, 22 Oct 2021 17:31:45 +0200 Subject: [PATCH 08/57] working preview --- depthai_demo.py | 36 ++++++++++++++++++++++++++-- gui/depthai_demo.pyproject | 2 +- gui/main.py | 48 +++++++++++++++++++++++++++++++++++-- gui/views/CameraPreview.qml | 31 ++++++++++++++++++++++-- gui/views/root.qml | 11 +++++---- 5 files changed, 117 insertions(+), 11 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 932fd27f0..35e7478dd 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -1,13 +1,20 @@ #!/usr/bin/env python3 import os +import queue import threading +import time from contextlib import ExitStack from itertools import cycle from pathlib import Path +from queue import Queue + import cv2 import depthai as dai import platform +import numpy as np +from PySide6.QtGui import QImage + from depthai_helpers.arg_manager import parseArgs from depthai_helpers.config_manager import ConfigManager, DEPTHAI_ZOO, DEPTHAI_VIDEOS from depthai_helpers.version_check import checkRequirementsVersion @@ -452,6 +459,19 @@ def _printSysInfo(self, info): print(','.join(map(str, data.values())), file=self._reportFile) +def create_blank(width, height, rgb_color=(0, 0, 0)): + """Create new image(numpy array) filled with certain color in RGB""" + # Create black blank image + image = np.zeros((height, width, 3), np.uint8) + + # Since OpenCV uses BGR, convert the color first + color = tuple(reversed(rgb_color)) + # Fill image with color + image[:] = color + + return image + + class App(DemoQtGui): def __init__(self): super().__init__() @@ -461,7 +481,14 @@ def demoOnNewFrame(self, frame, source): pass def demoOnShowFrame(self, frame, source): - pass + if source == self.selectedPreview: + try: + if self.writer is not None: + scaledFrame = cv2.resize(frame, (560, 560)) + img = QImage(scaledFrame.data, 560, 560, 3 * 560, QImage.Format_BGR888) + self.writer.updatePreviewSignal.emit(img) + except queue.Full: + pass def demoOnNn(self, nn_packet): pass @@ -471,7 +498,9 @@ def demoOnReport(self, report): def demoOnSetup(self, instance): medianChoices = list(filter(lambda name: name.startswith('KERNEL_') or name.startswith('MEDIAN_'), vars(dai.MedianFilter).keys()))[::-1] - self.setData("medianChoices", medianChoices) + self.writer.setDataSignal.emit(["medianChoices", medianChoices]) + self.writer.setDataSignal.emit(["previewChoices", confManager.args.show]) + self.selectedPreview = confManager.args.show[0] def demoOnTeardown(self, instance): pass @@ -490,6 +519,9 @@ def start(self): def guiOnDepthConfigUpdate(self, median=None): self._demoInstance._pm.updateDepthConfig(self._demoInstance._device, median=median) + def guiOnPreviewChangeSelected(self, selected): + self.selectedPreview = selected + if __name__ == "__main__": App().start() \ No newline at end of file diff --git a/gui/depthai_demo.pyproject b/gui/depthai_demo.pyproject index dc9962291..5689a8318 100644 --- a/gui/depthai_demo.pyproject +++ b/gui/depthai_demo.pyproject @@ -1,3 +1,3 @@ { - "files": ["main.py", "views/DepthProperties.qml", "views/root.qml", "views/CameraProperties.qml"] + "files": ["main.py", "views/DepthProperties.qml", "views/root.qml", "views/CameraProperties.qml", "views/CameraPreview.qml"] } diff --git a/gui/main.py b/gui/main.py index 4d28b9c2f..2319934ff 100644 --- a/gui/main.py +++ b/gui/main.py @@ -3,19 +3,49 @@ import threading from pathlib import Path import time + +import numpy as np from PySide6.QtCore import QObject, Slot, Signal -from PySide6.QtGui import QGuiApplication +from PySide6.QtGui import QGuiApplication, QImage from PySide6.QtQml import QQmlApplicationEngine, QmlElement import depthai as dai # To be used on the @QmlElement decorator # (QML_IMPORT_MINOR_VERSION is optional) +from PySide6.QtQuick import QQuickPaintedItem + QML_IMPORT_NAME = "dai.gui" QML_IMPORT_MAJOR_VERSION = 1 +class Singleton(type(QQuickPaintedItem)): + _instances = {} + def __call__(cls, *args, **kwargs): + if cls not in cls._instances: + cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) + return cls._instances[cls] + + +@QmlElement +class ImageWriter(QQuickPaintedItem, metaclass=Singleton): + updatePreviewSignal = Signal(QImage) + setDataSignal = Signal(list) + frame = QImage() + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.setRenderTarget(QQuickPaintedItem.FramebufferObject) + + def paint(self, painter): + painter.drawImage(0, 0, self.frame) + + def update_frame(self, image): + self.frame = image + self.update() + class DemoQtGui: instance = None + writer = None def __init__(self): self.app = QGuiApplication() @@ -25,18 +55,32 @@ def __init__(self): def setInstance(self): DemoQtGui.instance = self - def setData(self, name, value): + @Slot(list) + def setData(self, data): + name, value = data self.engine.rootContext().setContextProperty(name, value) + @Slot(QImage) + def updatePreview(self, data): + self.writer.update_frame(data) + def startGui(self): self.engine.load(Path(__file__).parent / "views" / "root.qml") if not self.engine.rootObjects(): raise RuntimeError("Unable to start GUI - no root objects!") + self.writer = ImageWriter() + self.writer.updatePreviewSignal.connect(self.updatePreview) + self.writer.setDataSignal.connect(self.setData) sys.exit(self.app.exec()) def guiOnDepthConfigUpdate(self, median=None): pass +@QmlElement +class PreviewBridge(QObject): + @Slot(str) + def changeSelected(self, state): + DemoQtGui.instance.guiOnPreviewChangeSelected(state) @QmlElement class DepthBridge(QObject): diff --git a/gui/views/CameraPreview.qml b/gui/views/CameraPreview.qml index 047673001..cfc27de1f 100644 --- a/gui/views/CameraPreview.qml +++ b/gui/views/CameraPreview.qml @@ -4,6 +4,8 @@ import QtQuick.Controls 2.1 import QtQuick.Window 2.1 import QtQuick.Controls.Material 2.1 +import dai.gui 1.0 + ListView { id: cameraPreview @@ -11,6 +13,31 @@ ListView { id: cameraPreviewRect color: "black" width: parent.width - height: parent.height + height: 640 + + ComboBox { + id: comboBoxImage + x: 210 + y: 5 + width: 200 + height: 30 + model: previewChoices + onActivated: function(index) { + previewBridge.changeSelected(model[index]) + } + } + + ImageWriter { + id: imageWriter + x: 40 + y: 40 + width: 560 + height: 560 + } } -} \ No newline at end of file +} +/*##^## +Designer { + D{i:0;autoSize:true;height:480;width:640} +} +##^##*/ diff --git a/gui/views/root.qml b/gui/views/root.qml index 2a0ce0a74..6135c22d2 100644 --- a/gui/views/root.qml +++ b/gui/views/root.qml @@ -57,7 +57,7 @@ import QtQuick.Controls.Material 2.1 import dai.gui 1.0 ApplicationWindow { - width: 1200 + width: 1270 height: 640 Material.theme: Material.Dark Material.accent: Material.Red @@ -75,6 +75,9 @@ ApplicationWindow { RightCamBridge { id: rightCamBridge } + PreviewBridge { + id: previewBridge + } Rectangle { id: root @@ -88,19 +91,19 @@ ApplicationWindow { CameraPreview { x: 0 y: 0 - width: 610 + width: 640 height: parent.height } DepthProperties { - x: 610 + x: 640 y: 0 width: 590 height: 340 } CameraProperties { - x: 610 + x: 640 y: 340 width: 590 height: 300 From 4d3b4a93805639fa645d368b47bbe09a0bc9b77d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Fri, 22 Oct 2021 18:31:54 +0200 Subject: [PATCH 09/57] Add parameters and sliders handling --- depthai_demo.py | 113 ++++++++++++++---------------- depthai_helpers/config_manager.py | 10 +-- gui/main.py | 36 +++++----- gui/views/CameraProperties.qml | 12 ++-- gui/views/DepthProperties.qml | 98 ++++++++++++++++++++------ 5 files changed, 159 insertions(+), 110 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 35e7478dd..9df94a586 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -2,27 +2,20 @@ import os import queue import threading -import time from contextlib import ExitStack from itertools import cycle from pathlib import Path -from queue import Queue import cv2 import depthai as dai import platform -import numpy as np -from PySide6.QtGui import QImage - from depthai_helpers.arg_manager import parseArgs from depthai_helpers.config_manager import ConfigManager, DEPTHAI_ZOO, DEPTHAI_VIDEOS from depthai_helpers.version_check import checkRequirementsVersion from depthai_sdk import FPSHandler, loadModule, getDeviceInfo, downloadYTVideo, Previews from depthai_sdk.managers import NNetManager, PreviewManager, PipelineManager, EncodingManager, BlobManager -from gui.main import DemoQtGui - print('Using depthai module from: ', dai.__file__) print('Depthai version installed: ', dai.__version__) if platform.machine() not in ['armv6l', 'aarch64']: @@ -458,70 +451,70 @@ def _printSysInfo(self, info): self.onReport(data) print(','.join(map(str, data.values())), file=self._reportFile) +if __name__ == "__main__": + from gui.main import DemoQtGui + from PySide6.QtGui import QImage -def create_blank(width, height, rgb_color=(0, 0, 0)): - """Create new image(numpy array) filled with certain color in RGB""" - # Create black blank image - image = np.zeros((height, width, 3), np.uint8) - - # Since OpenCV uses BGR, convert the color first - color = tuple(reversed(rgb_color)) - # Fill image with color - image[:] = color - - return image - - -class App(DemoQtGui): - def __init__(self): - super().__init__() - self._demoInstance = Demo(confManager, displayFrames=False, onNewFrame=self.demoOnNewFrame, onShowFrame=self.demoOnShowFrame, onNn=self.demoOnNn, onReport=self.demoOnReport, onSetup=self.demoOnSetup, onTeardown=self.demoOnTeardown, onIter=self.demoOnIter, shouldRun=self.demoShouldRun) - - def demoOnNewFrame(self, frame, source): - pass + class App(DemoQtGui): + def __init__(self): + super().__init__() + self._demoInstance = Demo(confManager, displayFrames=False, onNewFrame=self.demoOnNewFrame, onShowFrame=self.demoOnShowFrame, onNn=self.demoOnNn, onReport=self.demoOnReport, onSetup=self.demoOnSetup, onTeardown=self.demoOnTeardown, onIter=self.demoOnIter, shouldRun=self.demoShouldRun) - def demoOnShowFrame(self, frame, source): - if source == self.selectedPreview: - try: - if self.writer is not None: - scaledFrame = cv2.resize(frame, (560, 560)) - img = QImage(scaledFrame.data, 560, 560, 3 * 560, QImage.Format_BGR888) - self.writer.updatePreviewSignal.emit(img) - except queue.Full: - pass + def demoOnNewFrame(self, frame, source): + pass - def demoOnNn(self, nn_packet): - pass + def demoOnShowFrame(self, frame, source): + if source == self.selectedPreview: + try: + if self.writer is not None: + scaledFrame = cv2.resize(frame, (560, 560)) + if len(frame.shape) == 3: + img = QImage(scaledFrame.data, 560, 560, frame.shape[2] * 560, QImage.Format_BGR888) + else: + img = QImage(scaledFrame.data, 560, 560, 560, QImage.Format_Grayscale8) + self.writer.updatePreviewSignal.emit(img) + except queue.Full: + pass + + def demoOnNn(self, nn_packet): + pass - def demoOnReport(self, report): - pass + def demoOnReport(self, report): + pass - def demoOnSetup(self, instance): - medianChoices = list(filter(lambda name: name.startswith('KERNEL_') or name.startswith('MEDIAN_'), vars(dai.MedianFilter).keys()))[::-1] - self.writer.setDataSignal.emit(["medianChoices", medianChoices]) - self.writer.setDataSignal.emit(["previewChoices", confManager.args.show]) - self.selectedPreview = confManager.args.show[0] + def demoOnSetup(self, instance): + medianChoices = list(filter(lambda name: name.startswith('KERNEL_') or name.startswith('MEDIAN_'), vars(dai.MedianFilter).keys()))[::-1] + self.writer.setDataSignal.emit(["medianChoices", medianChoices]) + self.writer.setDataSignal.emit(["previewChoices", confManager.args.show]) + self.selectedPreview = confManager.args.show[0] - def demoOnTeardown(self, instance): - pass + def demoOnTeardown(self, instance): + pass - def demoOnIter(self, instance): - pass + def demoOnIter(self, instance): + pass - def demoShouldRun(self, instance): - return True + def demoShouldRun(self, instance): + return True - def start(self): - self._t = threading.Thread(target=self._demoInstance.run_all) - self._t.start() - self.startGui() + def start(self): + self._t = threading.Thread(target=self._demoInstance.run_all) + self._t.start() + self.startGui() - def guiOnDepthConfigUpdate(self, median=None): - self._demoInstance._pm.updateDepthConfig(self._demoInstance._device, median=median) + def guiOnDepthConfigUpdate(self, median=None, dct=None, sigma=None, lrcThreshold=None): + self._demoInstance._pm.updateDepthConfig(self._demoInstance._device, median=median, dct=dct, sigma=sigma, lrcThreshold=lrcThreshold) - def guiOnPreviewChangeSelected(self, selected): - self.selectedPreview = selected + def guiOnCameraConfigUpdate(self, name, exposure=None, sensitivity=None, saturation=None, contrast=None, brightness=None, sharpness=None): + if name == "color": + fun = self._demoInstance._pm.updateColorCamConfig + elif name == "left": + fun = self._demoInstance._pm.updateLeftCamConfig + else: + fun = self._demoInstance._pm.updateRightCamConfig + fun(self._demoInstance._device, exposure, sensitivity, saturation, contrast, brightness, sharpness) + def guiOnPreviewChangeSelected(self, selected): + self.selectedPreview = selected -if __name__ == "__main__": App().start() \ No newline at end of file diff --git a/depthai_helpers/config_manager.py b/depthai_helpers/config_manager.py index 036e9b4ed..5f4ac6eae 100644 --- a/depthai_helpers/config_manager.py +++ b/depthai_helpers/config_manager.py @@ -127,21 +127,21 @@ def adjustPreviewToOptions(self): if len(self.args.show) != 0: return - if self.args.camera == "color" and Previews.color.name not in self.args.show: + if Previews.color.name not in self.args.show: self.args.show.append(Previews.color.name) if self.useDepth: if self.lowBandwidth and Previews.disparityColor.name not in self.args.show: self.args.show.append(Previews.disparityColor.name) elif not self.lowBandwidth and Previews.depth.name not in self.args.show: self.args.show.append(Previews.depth.name) - if self.args.camera == "left" and Previews.rectifiedLeft.name not in self.args.show: + if Previews.rectifiedLeft.name not in self.args.show: self.args.show.append(Previews.rectifiedLeft.name) - if self.args.camera == "right" and Previews.rectifiedRight.name not in self.args.show: + if Previews.rectifiedRight.name not in self.args.show: self.args.show.append(Previews.rectifiedRight.name) else: - if self.args.camera == "left" and Previews.left.name not in self.args.show: + if Previews.left.name not in self.args.show: self.args.show.append(Previews.left.name) - if self.args.camera == "right" and Previews.right.name not in self.args.show: + if Previews.right.name not in self.args.show: self.args.show.append(Previews.right.name) def adjustParamsToDevice(self, device): diff --git a/gui/main.py b/gui/main.py index 2319934ff..36b9743cf 100644 --- a/gui/main.py +++ b/gui/main.py @@ -73,7 +73,7 @@ def startGui(self): self.writer.setDataSignal.connect(self.setData) sys.exit(self.app.exec()) - def guiOnDepthConfigUpdate(self, median=None): + def guiOnDepthConfigUpdate(self, median=None, dct=None, sigma=None, lrcThreshold=None): pass @QmlElement @@ -98,15 +98,15 @@ def toggleLeftRightCheck(self, state): @Slot(int) def setDisparityConfidenceThreshold(self, value): - print("Dct: {}".format(value)) + DemoQtGui.instance.guiOnDepthConfigUpdate(dct=value) @Slot(int) - def setBilateralSigma(self, value): - print("Bls: {}".format(value)) + def setLrcThreshold(self, value): + DemoQtGui.instance.guiOnDepthConfigUpdate(lrcThreshold=value) @Slot(int) def setBilateralSigma(self, value): - print("Sig: {}".format(value)) + DemoQtGui.instance.guiOnDepthConfigUpdate(sigma=value) @Slot(int, int) def setDepthRange(self, valFrom, valTo): @@ -116,48 +116,46 @@ def setDepthRange(self, valFrom, valTo): def setMedianFilter(self, state): value = getattr(dai.MedianFilter, state) DemoQtGui.instance.guiOnDepthConfigUpdate(median=value) - print("Med: {}".format(value)) class BaseCamBridge(QObject): - @Slot(int) - def setIso(self, value): - print("ISO: {}".format(value)) + name = "base" - @Slot(int) - def setExposure(self, value): - print("Exposure: {}".format(value)) + @Slot(int, int) + def setIsoExposure(self, iso, exposure): + if iso > 0 and exposure > 0: + DemoQtGui.instance.guiOnCameraConfigUpdate(self.name, sensitivity=iso, exposure=exposure) @Slot(int) def setContrast(self, value): - print("Contrast: {}".format(value)) + DemoQtGui.instance.guiOnCameraConfigUpdate(self.name, contrast=value) @Slot(int) def setBrightness(self, value): - print("Brightness: {}".format(value)) + DemoQtGui.instance.guiOnCameraConfigUpdate(self.name, brightness=value) @Slot(int) def setSaturation(self, value): - print("Saturation: {}".format(value)) + DemoQtGui.instance.guiOnCameraConfigUpdate(self.name, saturation=value) @Slot(int) def setSharpness(self, value): - print("Sharpness: {}".format(value)) + DemoQtGui.instance.guiOnCameraConfigUpdate(self.name, sharpness=value) @QmlElement class ColorCamBridge(BaseCamBridge): - pass + name = "color" @QmlElement class LeftCamBridge(BaseCamBridge): - pass + name = "left" @QmlElement class RightCamBridge(BaseCamBridge): - pass + name = "right" if __name__ == "__main__": diff --git a/gui/views/CameraProperties.qml b/gui/views/CameraProperties.qml index 7ca93d47a..a9269029a 100644 --- a/gui/views/CameraProperties.qml +++ b/gui/views/CameraProperties.qml @@ -81,7 +81,7 @@ ListView { placeholderText: "ISO" font.family: "Courier" onEditingFinished: { - colorCamBridge.setIso(text) + colorCamBridge.setIsoExposure(text, textField1.text) } } @@ -111,7 +111,7 @@ ListView { placeholderText: qsTr("Exposure") validator: IntValidator {} onEditingFinished: { - colorCamBridge.setExposure(text) + colorCamBridge.setIsoExposure(textField.text, text) } } @@ -273,7 +273,7 @@ ListView { placeholderText: "ISO" font.family: "Courier" onEditingFinished: { - rightCamBridge.setIso(text) + rightCamBridge.setIsoExposure(text, textField3.text) } } @@ -290,7 +290,7 @@ ListView { placeholderText: qsTr("Exposure") validator: IntValidator {} onEditingFinished: { - rightCamBridge.setExposure(text) + rightCamBridge.setIsoExposure(textField2.text, text) } } @@ -451,7 +451,7 @@ ListView { font.family: "Courier" validator: IntValidator {} onEditingFinished: { - leftCamBridge.setIso(text) + leftCamBridge.setIsoExposure(text, textField5.text) } } @@ -467,7 +467,7 @@ ListView { placeholderText: qsTr("Exposure") validator: IntValidator {} onEditingFinished: { - leftCamBridge.setExposure(text) + leftCamBridge.setIsoExposure(textField4.text, text) } } diff --git a/gui/views/DepthProperties.qml b/gui/views/DepthProperties.qml index 1479e0841..a4319f1e9 100644 --- a/gui/views/DepthProperties.qml +++ b/gui/views/DepthProperties.qml @@ -33,8 +33,8 @@ ListView { Slider { id: slider - x: 359 - y: 102 + x: 360 + y: 89 width: 200 height: 25 snapMode: RangeSlider.NoSnap @@ -66,6 +66,7 @@ ListView { x: 0 y: 187 text: qsTr("Left Right Check") + enabled: false transformOrigin: Item.Center font.preferShaping: false font.kerning: false @@ -81,6 +82,7 @@ ListView { x: 0 y: 233 text: qsTr("Extended Disparity") + enabled: false autoExclusive: false font.kerning: false font.family: "Courier" @@ -96,6 +98,7 @@ ListView { x: 0 y: 141 text: qsTr("Subpixel") + enabled: false autoExclusive: false font.kerning: false transformOrigin: Item.Center @@ -123,13 +126,13 @@ ListView { Slider { id: slider1 - x: 360 - y: 172 + x: 362 + y: 133 width: 200 height: 25 stepSize: 1 snapMode: RangeSlider.NoSnap - value: 240 + value: 0 to: 255 onValueChanged: { depthBridge.setBilateralSigma(value) @@ -138,8 +141,8 @@ ListView { Text { id: text4 - x: 339 - y: 102 + x: 340 + y: 89 width: 14 height: 25 color: "#ffffff" @@ -150,7 +153,7 @@ ListView { Text { id: text5 x: 566 - y: 102 + y: 89 width: 17 height: 25 color: "#ffffff" @@ -160,8 +163,8 @@ ListView { Text { id: text6 - x: 359 - y: 141 + x: 360 + y: 115 width: 200 height: 25 color: "#ffffff" @@ -175,8 +178,8 @@ ListView { Text { id: text7 - x: 338 - y: 172 + x: 337 + y: 133 width: 17 height: 25 color: "#ffffff" @@ -187,7 +190,7 @@ ListView { Text { id: text8 x: 566 - y: 175 + y: 136 width: 17 height: 20 color: "#ffffff" @@ -198,8 +201,8 @@ ListView { Text { id: text9 - x: 359 - y: 209 + x: 362 + y: 158 width: 200 height: 25 color: "#ffffff" @@ -213,10 +216,11 @@ ListView { RangeSlider { id: rangeSlider - x: 362 - y: 233 + x: 364 + y: 181 width: 198 height: 27 + enabled: false snapMode: RangeSlider.NoSnap stepSize: 1 to: 10000 @@ -248,7 +252,7 @@ ListView { Text { id: text32 x: 566 - y: 237 + y: 185 width: 17 height: 20 color: "#ffffff" @@ -259,8 +263,8 @@ ListView { Text { id: text33 - x: 338 - y: 237 + x: 337 + y: 185 width: 17 height: 20 color: "#ffffff" @@ -269,6 +273,60 @@ ListView { rotation: 0 } + Text { + id: text10 + x: 360 + y: 214 + width: 200 + height: 25 + color: "#ffffff" + text: qsTr("LRC Threshold") + font.pixelSize: 18 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.weight: Font.Medium + font.family: "Courier" + } + + Slider { + id: lrcSlider + x: 361 + y: 233 + width: 198 + height: 27 + stepSize: 1 + to: 10 + value: 10 + from: 0 + onValueChanged: { + depthBridge.setLrcThreshold(value) + } + } + + Text { + id: text34 + x: 566 + y: 233 + width: 17 + height: 20 + color: "#ffffff" + text: qsTr("10") + font.pixelSize: 12 + rotation: 0 + } + + Text { + id: text35 + x: 337 + y: 233 + width: 17 + height: 20 + color: "#ffffff" + text: qsTr("0") + font.pixelSize: 12 + rotation: 0 + } + } } /*##^## From c31e26916dd9a26d5ba9789e0676d63d531b00e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Fri, 22 Oct 2021 18:38:20 +0200 Subject: [PATCH 10/57] optimize imports --- gui/main.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/gui/main.py b/gui/main.py index 36b9743cf..b351f46f1 100644 --- a/gui/main.py +++ b/gui/main.py @@ -1,10 +1,6 @@ # This Python file uses the following encoding: utf-8 import sys -import threading from pathlib import Path -import time - -import numpy as np from PySide6.QtCore import QObject, Slot, Signal from PySide6.QtGui import QGuiApplication, QImage from PySide6.QtQml import QQmlApplicationEngine, QmlElement From 9d006655e1595f7a77bd30e6be9037465b1827a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Fri, 22 Oct 2021 18:48:39 +0200 Subject: [PATCH 11/57] improve thread exitting --- depthai_demo.py | 13 +++++++++++-- gui/main.py | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 9df94a586..9a822eb56 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -458,6 +458,7 @@ def _printSysInfo(self, info): class App(DemoQtGui): def __init__(self): super().__init__() + self.running = False self._demoInstance = Demo(confManager, displayFrames=False, onNewFrame=self.demoOnNewFrame, onShowFrame=self.demoOnShowFrame, onNn=self.demoOnNn, onReport=self.demoOnReport, onSetup=self.demoOnSetup, onTeardown=self.demoOnTeardown, onIter=self.demoOnIter, shouldRun=self.demoShouldRun) def demoOnNewFrame(self, frame, source): @@ -495,12 +496,20 @@ def demoOnIter(self, instance): pass def demoShouldRun(self, instance): - return True + return self.running def start(self): + self.running = True self._t = threading.Thread(target=self._demoInstance.run_all) self._t.start() - self.startGui() + exit_code = self.startGui() + self.running = False + try: + self._t.join(2) # try exiting gracefully + except: + self._demoInstance._stack.close() + self._t.join() + raise SystemExit(exit_code) def guiOnDepthConfigUpdate(self, median=None, dct=None, sigma=None, lrcThreshold=None): self._demoInstance._pm.updateDepthConfig(self._demoInstance._device, median=median, dct=dct, sigma=sigma, lrcThreshold=lrcThreshold) diff --git a/gui/main.py b/gui/main.py index b351f46f1..8b910426e 100644 --- a/gui/main.py +++ b/gui/main.py @@ -67,7 +67,7 @@ def startGui(self): self.writer = ImageWriter() self.writer.updatePreviewSignal.connect(self.updatePreview) self.writer.setDataSignal.connect(self.setData) - sys.exit(self.app.exec()) + return self.app.exec() def guiOnDepthConfigUpdate(self, median=None, dct=None, sigma=None, lrcThreshold=None): pass From 181410705d664aa2ba6d981625b717587ccbd1a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Mon, 25 Oct 2021 12:47:20 +0200 Subject: [PATCH 12/57] adjust setMouseCallback --- depthai_sdk/src/depthai_sdk/managers/preview_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depthai_sdk/src/depthai_sdk/managers/preview_manager.py b/depthai_sdk/src/depthai_sdk/managers/preview_manager.py index 5e6337e85..19fbf8f5b 100644 --- a/depthai_sdk/src/depthai_sdk/managers/preview_manager.py +++ b/depthai_sdk/src/depthai_sdk/managers/preview_manager.py @@ -76,7 +76,7 @@ def createQueues(self, device, callback=None): cv2.namedWindow(name) if callable(callback): callback(name) - if self._mouseTracker is not None: + if self._createWindows and self._mouseTracker is not None: cv2.setMouseCallback(name, self._mouseTracker.selectPoint(name)) if name not in (Previews.disparityColor.name, Previews.depth.name): # generated on host self.outputQueues.append(device.getOutputQueue(name=name, maxSize=1, blocking=False)) From ad1b8abdf556a7c5b2442b5e4f013594c035245f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Mon, 25 Oct 2021 12:49:12 +0200 Subject: [PATCH 13/57] adjust createTrackbar --- depthai_demo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depthai_demo.py b/depthai_demo.py index 9a822eb56..b16f7215a 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -348,7 +348,7 @@ def loop(self): self._updateCameraConfigs() def _createQueueCallback(self, queueName): - if queueName in [Previews.disparityColor.name, Previews.disparity.name, Previews.depth.name, Previews.depthRaw.name]: + if self._displayFrames and queueName in [Previews.disparityColor.name, Previews.disparity.name, Previews.depth.name, Previews.depthRaw.name]: Trackbars.createTrackbar('Disparity confidence', queueName, self.DISP_CONF_MIN, self.DISP_CONF_MAX, self._conf.args.disparityConfidenceThreshold, lambda value: self._pm.updateDepthConfig(self._device, dct=value)) if queueName in [Previews.depthRaw.name, Previews.depth.name]: From 3f8f9294a3ebceacb7a4a2d544a5dc48c5093f8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Wed, 27 Oct 2021 10:29:07 +0200 Subject: [PATCH 14/57] add Tabs --- depthai_demo.py | 26 +- depthai_sdk/src/depthai_sdk/utils.py | 18 + gui/main.py | 9 + gui/views/CameraProperties.qml | 1040 +++++++++++++------------- gui/views/root.qml | 45 +- 5 files changed, 613 insertions(+), 525 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index b16f7215a..d1d15fa08 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -13,7 +13,7 @@ from depthai_helpers.arg_manager import parseArgs from depthai_helpers.config_manager import ConfigManager, DEPTHAI_ZOO, DEPTHAI_VIDEOS from depthai_helpers.version_check import checkRequirementsVersion -from depthai_sdk import FPSHandler, loadModule, getDeviceInfo, downloadYTVideo, Previews +from depthai_sdk import FPSHandler, loadModule, getDeviceInfo, downloadYTVideo, Previews, resizeLetterbox from depthai_sdk.managers import NNetManager, PreviewManager, PipelineManager, EncodingManager, BlobManager print('Using depthai module from: ', dai.__file__) @@ -459,6 +459,7 @@ class App(DemoQtGui): def __init__(self): super().__init__() self.running = False + self.restartRequired = False self._demoInstance = Demo(confManager, displayFrames=False, onNewFrame=self.demoOnNewFrame, onShowFrame=self.demoOnShowFrame, onNn=self.demoOnNn, onReport=self.demoOnReport, onSetup=self.demoOnSetup, onTeardown=self.demoOnTeardown, onIter=self.demoOnIter, shouldRun=self.demoShouldRun) def demoOnNewFrame(self, frame, source): @@ -468,7 +469,7 @@ def demoOnShowFrame(self, frame, source): if source == self.selectedPreview: try: if self.writer is not None: - scaledFrame = cv2.resize(frame, (560, 560)) + scaledFrame = resizeLetterbox(frame, (560, 560)) if len(frame.shape) == 3: img = QImage(scaledFrame.data, 560, 560, frame.shape[2] * 560, QImage.Format_BGR888) else: @@ -498,6 +499,10 @@ def demoOnIter(self, instance): def demoShouldRun(self, instance): return self.running + def updateArg(self, arg_name, arg_value): + setattr(confManager.args, arg_name, arg_value) + self.restartRequired = True + def start(self): self.running = True self._t = threading.Thread(target=self._demoInstance.run_all) @@ -511,6 +516,7 @@ def start(self): self._t.join() raise SystemExit(exit_code) + def guiOnDepthConfigUpdate(self, median=None, dct=None, sigma=None, lrcThreshold=None): self._demoInstance._pm.updateDepthConfig(self._demoInstance._device, median=median, dct=dct, sigma=sigma, lrcThreshold=lrcThreshold) @@ -523,6 +529,22 @@ def guiOnCameraConfigUpdate(self, name, exposure=None, sensitivity=None, saturat fun = self._demoInstance._pm.updateRightCamConfig fun(self._demoInstance._device, exposure, sensitivity, saturation, contrast, brightness, sharpness) + def guiOnDepthSetupUpdate(self, depthFrom=None, depthTo=None, subpixel=None, lrc=None, extended=None): + if depthFrom is not None: + self.updateArg("minDepth", subpixel) + if depthTo is not None: + self.updateArg("maxDepth", depthTo) + if subpixel is not None: + self.updateArg("subpixel", subpixel) + if extended is not None: + self.updateArg("extendedDisparity", subpixel) + if lrc is not None: + self.updateArg("stereoLrCheck", subpixel) + + + def guiOnCameraSetupUpdate(self, name): + pass + def guiOnPreviewChangeSelected(self, selected): self.selectedPreview = selected diff --git a/depthai_sdk/src/depthai_sdk/utils.py b/depthai_sdk/src/depthai_sdk/utils.py index 0a2322f5f..bf4f0694d 100644 --- a/depthai_sdk/src/depthai_sdk/utils.py +++ b/depthai_sdk/src/depthai_sdk/utils.py @@ -244,3 +244,21 @@ def cropToAspectRatio(frame, size): newH = (currentRatio/newRatio) * h crop = int((h - newH) / 2) return frame[crop:h-crop, :] + + +def resizeLetterbox(frame, size): + """ + Transforms the frame to meet the desired size, preserving the aspect ratio and adding black borders (letterboxing) + Args: + frame (numpy.ndarray): Source frame that will be resized + size (tuple): Desired frame size (width, heigth) + """ + border_v = 0 + border_h = 0 + if (size[1] / size[0]) >= (frame.shape[0] / frame.shape[1]): + border_v = int((((size[1] / size[0]) * frame.shape[1]) - frame.shape[0]) / 2) + else: + border_h = int((((size[0] / size[1]) * frame.shape[0]) - frame.shape[1]) / 2) + frame = cv2.copyMakeBorder(frame, border_v, border_v, border_h, border_h, cv2.BORDER_CONSTANT, 0) + return cv2.resize(frame, size) + diff --git a/gui/main.py b/gui/main.py index 8b910426e..64f8a75d6 100644 --- a/gui/main.py +++ b/gui/main.py @@ -72,12 +72,21 @@ def startGui(self): def guiOnDepthConfigUpdate(self, median=None, dct=None, sigma=None, lrcThreshold=None): pass + +@QmlElement +class AppBridge(QObject): + @Slot() + def applyAndRestart(self): + print("RESTART") + + @QmlElement class PreviewBridge(QObject): @Slot(str) def changeSelected(self, state): DemoQtGui.instance.guiOnPreviewChangeSelected(state) + @QmlElement class DepthBridge(QObject): @Slot(bool) diff --git a/gui/views/CameraProperties.qml b/gui/views/CameraProperties.qml index a9269029a..95046cc34 100644 --- a/gui/views/CameraProperties.qml +++ b/gui/views/CameraProperties.qml @@ -27,578 +27,590 @@ ListView { font.family: "Courier" } - Text { - id: text11 - x: 0 - y: 44 - width: 197 - height: 30 - color: "#ffffff" - text: qsTr("Color") - font.pixelSize: 26 - horizontalAlignment: Text.AlignHCenter - font.styleName: "Regular" - font.family: "Courier" - } + Rectangle { + id: colorCamRect + + Text { + id: text11 + x: 0 + y: 44 + width: 197 + height: 30 + color: "#ffffff" + text: qsTr("Color") + font.pixelSize: 26 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.family: "Courier" + } - Text { - id: text12 - x: 385 - y: 44 - width: 197 - height: 30 - color: "#ffffff" - text: qsTr("Right") - font.pixelSize: 26 - horizontalAlignment: Text.AlignHCenter - font.styleName: "Regular" - font.family: "Courier" - } + TextField { + id: textField + x: 85 + y: 80 + width: 106 + height: 25 + text: "" + bottomPadding: 5 + validator: IntValidator {} + placeholderText: "ISO" + font.family: "Courier" + onEditingFinished: { + colorCamBridge.setIsoExposure(text, textField1.text) + } + } - Text { - id: text13 - x: 203 - y: 44 - width: 181 - height: 30 - color: "#ffffff" - text: qsTr("Left") - font.pixelSize: 26 - horizontalAlignment: Text.AlignHCenter - font.styleName: "Regular" - font.family: "Courier" - } + Text { + id: text14 + x: -6 + y: 80 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("ISO") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } - TextField { - id: textField - x: 85 - y: 80 - width: 106 - height: 25 - text: "" - bottomPadding: 5 - validator: IntValidator {} - placeholderText: "ISO" - font.family: "Courier" - onEditingFinished: { - colorCamBridge.setIsoExposure(text, textField1.text) + TextField { + id: textField1 + x: 85 + y: 111 + width: 106 + height: 25 + text: "" + bottomPadding: 5 + font.family: "Courier" + placeholderText: qsTr("Exposure") + validator: IntValidator {} + onEditingFinished: { + colorCamBridge.setIsoExposure(textField.text, text) + } } - } - Text { - id: text14 - x: -6 - y: 80 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("ISO") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - TextField { - id: textField1 - x: 85 - y: 111 - width: 106 - height: 25 - text: "" - bottomPadding: 5 - font.family: "Courier" - placeholderText: qsTr("Exposure") - validator: IntValidator {} - onEditingFinished: { - colorCamBridge.setIsoExposure(textField.text, text) + + Text { + id: text15 + x: -6 + y: 111 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Exposure") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" } - } + Slider { + id: slider2 + x: 85 + y: 142 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + colorCamBridge.setSaturation(value) + } + } - Text { - id: text15 - x: -6 - y: 111 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Exposure") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Text { + id: text16 + x: -6 + y: 142 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Saturation") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } - Slider { - id: slider2 - x: 85 - y: 142 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - onValueChanged: { - colorCamBridge.setSaturation(value) + Slider { + id: slider3 + x: 85 + y: 173 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + colorCamBridge.setContrast(value) + } } - } - Text { - id: text16 - x: -6 - y: 142 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Saturation") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Text { + id: text17 + x: -6 + y: 173 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Contrast") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } - Slider { - id: slider3 - x: 85 - y: 173 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - onValueChanged: { - colorCamBridge.setContrast(value) + Slider { + id: slider4 + x: 85 + y: 204 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + colorCamBridge.setBrightness(value) + } } - } - Text { - id: text17 - x: -6 - y: 173 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Contrast") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Text { + id: text18 + x: -6 + y: 204 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Brightness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } - Slider { - id: slider4 - x: 85 - y: 204 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - onValueChanged: { - colorCamBridge.setBrightness(value) + Slider { + id: slider5 + x: 85 + y: 235 + width: 106 + height: 25 + stepSize: 1 + to: 4 + from: 0 + value: 0 + onValueChanged: { + colorCamBridge.setSharpness(value) + } } - } - Text { - id: text18 - x: -6 - y: 204 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Brightness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Text { + id: text19 + x: -6 + y: 235 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Sharpness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } - Slider { - id: slider5 - x: 85 - y: 235 - width: 106 - height: 25 - stepSize: 1 - to: 4 - from: 0 - value: 0 - onValueChanged: { - colorCamBridge.setSharpness(value) + Text { + id: text20 + x: 393 + y: 80 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("ISO") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" } } - Text { - id: text19 - x: -6 - y: 235 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Sharpness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Rectangle { + id: leftCamRect + + Text { + id: text13 + x: 203 + y: 44 + width: 181 + height: 30 + color: "#ffffff" + text: qsTr("Left") + font.pixelSize: 26 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.family: "Courier" + } - Text { - id: text20 - x: 393 - y: 80 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("ISO") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Text { + id: text26 + x: 197 + y: 80 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("ISO") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } - TextField { - id: textField2 - x: 484 - y: 80 - width: 106 - height: 25 - color: "#ddffffff" - text: "" - bottomPadding: 5 - validator: IntValidator {} - placeholderText: "ISO" - font.family: "Courier" - onEditingFinished: { - rightCamBridge.setIsoExposure(text, textField3.text) + TextField { + id: textField4 + x: 288 + y: 80 + width: 106 + height: 25 + color: "#ddffffff" + text: "" + bottomPadding: 5 + placeholderText: "ISO" + font.family: "Courier" + validator: IntValidator {} + onEditingFinished: { + leftCamBridge.setIsoExposure(text, textField5.text) + } } - } - TextField { - id: textField3 - x: 484 - y: 111 - width: 106 - height: 25 - color: "#ddffffff" - text: "" - bottomPadding: 5 - font.family: "Courier" - placeholderText: qsTr("Exposure") - validator: IntValidator {} - onEditingFinished: { - rightCamBridge.setIsoExposure(textField2.text, text) + TextField { + id: textField5 + x: 288 + y: 111 + width: 106 + height: 25 + color: "#ddffffff" + text: "" + bottomPadding: 5 + placeholderText: qsTr("Exposure") + validator: IntValidator {} + onEditingFinished: { + leftCamBridge.setIsoExposure(textField4.text, text) + } } - } - Text { - id: text21 - x: 393 - y: 111 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Exposure") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Text { + id: text27 + x: 197 + y: 111 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Exposure") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } - Slider { - id: slider6 - x: 484 - y: 142 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - onValueChanged: { - rightCamBridge.setSaturation(value) + Slider { + id: slider10 + x: 288 + y: 142 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + leftCamBridge.setSaturation(value) + } } - } - Text { - id: text22 - x: 393 - y: 142 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Saturation") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Text { + id: text28 + x: 197 + y: 142 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Saturation") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } - Slider { - id: slider7 - x: 484 - y: 173 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - onValueChanged: { - rightCamBridge.setContrast(value) + Slider { + id: slider11 + x: 288 + y: 173 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + leftCamBridge.setContrast(value) + } } - } - Text { - id: text23 - x: 393 - y: 173 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Contrast") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Text { + id: text29 + x: 197 + y: 173 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Contrast") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } - Slider { - id: slider8 - x: 484 - y: 204 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - onValueChanged: { - rightCamBridge.setBrightness(value) + Slider { + id: slider12 + x: 288 + y: 204 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + leftCamBridge.setBrightness(value) + } } - } - Text { - id: text24 - x: 393 - y: 204 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Brightness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Text { + id: text30 + x: 197 + y: 204 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Brightness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } - Slider { - id: slider9 - x: 484 - y: 235 - width: 106 - height: 25 - stepSize: 1 - to: 4 - from: 0 - value: 0 - onValueChanged: { - rightCamBridge.setSharpness(value) + Slider { + id: slider13 + x: 288 + y: 235 + width: 106 + height: 25 + stepSize: 1 + to: 4 + from: 0 + value: 0 + onValueChanged: { + leftCamBridge.setSharpness(value) + } } - } - Text { - id: text25 - x: 393 - y: 235 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Sharpness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" + Text { + id: text31 + x: 197 + y: 235 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Sharpness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } } - Text { - id: text26 - x: 197 - y: 80 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("ISO") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Rectangle { + id: rightCamRect + + Text { + id: text12 + x: 385 + y: 44 + width: 197 + height: 30 + color: "#ffffff" + text: qsTr("Right") + font.pixelSize: 26 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.family: "Courier" + } - TextField { - id: textField4 - x: 288 - y: 80 - width: 106 - height: 25 - color: "#ddffffff" - text: "" - bottomPadding: 5 - placeholderText: "ISO" - font.family: "Courier" - validator: IntValidator {} - onEditingFinished: { - leftCamBridge.setIsoExposure(text, textField5.text) + TextField { + id: textField2 + x: 484 + y: 80 + width: 106 + height: 25 + color: "#ddffffff" + text: "" + bottomPadding: 5 + validator: IntValidator {} + placeholderText: "ISO" + font.family: "Courier" + onEditingFinished: { + rightCamBridge.setIsoExposure(text, textField3.text) + } } - } - TextField { - id: textField5 - x: 288 - y: 111 - width: 106 - height: 25 - color: "#ddffffff" - text: "" - bottomPadding: 5 - placeholderText: qsTr("Exposure") - validator: IntValidator {} - onEditingFinished: { - leftCamBridge.setIsoExposure(textField4.text, text) + TextField { + id: textField3 + x: 484 + y: 111 + width: 106 + height: 25 + color: "#ddffffff" + text: "" + bottomPadding: 5 + font.family: "Courier" + placeholderText: qsTr("Exposure") + validator: IntValidator {} + onEditingFinished: { + rightCamBridge.setIsoExposure(textField2.text, text) + } } - } - Text { - id: text27 - x: 197 - y: 111 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Exposure") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Text { + id: text21 + x: 393 + y: 111 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Exposure") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } - Slider { - id: slider10 - x: 288 - y: 142 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - onValueChanged: { - leftCamBridge.setSaturation(value) + Slider { + id: slider6 + x: 484 + y: 142 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + rightCamBridge.setSaturation(value) + } } - } - Text { - id: text28 - x: 197 - y: 142 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Saturation") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Text { + id: text22 + x: 393 + y: 142 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Saturation") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } - Slider { - id: slider11 - x: 288 - y: 173 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - onValueChanged: { - leftCamBridge.setContrast(value) + Slider { + id: slider7 + x: 484 + y: 173 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + rightCamBridge.setContrast(value) + } } - } - Text { - id: text29 - x: 197 - y: 173 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Contrast") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Text { + id: text23 + x: 393 + y: 173 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Contrast") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } - Slider { - id: slider12 - x: 288 - y: 204 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - onValueChanged: { - leftCamBridge.setBrightness(value) + Slider { + id: slider8 + x: 484 + y: 204 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + rightCamBridge.setBrightness(value) + } } - } - Text { - id: text30 - x: 197 - y: 204 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Brightness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Text { + id: text24 + x: 393 + y: 204 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Brightness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } - Slider { - id: slider13 - x: 288 - y: 235 - width: 106 - height: 25 - stepSize: 1 - to: 4 - from: 0 - value: 0 - onValueChanged: { - leftCamBridge.setSharpness(value) + Slider { + id: slider9 + x: 484 + y: 235 + width: 106 + height: 25 + stepSize: 1 + to: 4 + from: 0 + value: 0 + onValueChanged: { + rightCamBridge.setSharpness(value) + } } - } - Text { - id: text31 - x: 197 - y: 235 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Sharpness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" + Text { + id: text25 + x: 393 + y: 235 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Sharpness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } } } } diff --git a/gui/views/root.qml b/gui/views/root.qml index 6135c22d2..eefd7f8be 100644 --- a/gui/views/root.qml +++ b/gui/views/root.qml @@ -63,6 +63,10 @@ ApplicationWindow { Material.accent: Material.Red visible: true + AppBridge { + id: appBridge + } + DepthBridge { id: depthBridge } @@ -95,18 +99,41 @@ ApplicationWindow { height: parent.height } - DepthProperties { + TabBar { + id: bar + x: 640 + y: 0 + height: 50 + width: 590 + + TabButton { + text: "Depth" + } + TabButton { + text: "Camera" + } + } + + StackLayout { x: 640 - y: 0 - width: 590 - height: 340 + y: 70 + width: 630 + currentIndex: bar.currentIndex + Item { + DepthProperties {} + } + Item { + CameraProperties {} + } } - CameraProperties { - x: 640 - y: 340 - width: 590 - height: 300 + Button { + x: 667 + y: 540 + height: 60 + width: 563 + text: "Apply and Restart" + onClicked: appBridge.applyAndRestart() } } } From ad5e19bcc949074bea1863e712d9a33e798971d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Wed, 27 Oct 2021 13:00:58 +0200 Subject: [PATCH 15/57] Add restart first attempt --- depthai_demo.py | 143 ++++++++++++++++++++++------------ gui/main.py | 21 ++--- gui/views/DepthProperties.qml | 4 - gui/views/root.qml | 1 + 4 files changed, 103 insertions(+), 66 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index d1d15fa08..1e5b9893b 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -2,6 +2,7 @@ import os import queue import threading +import time from contextlib import ExitStack from itertools import cycle from pathlib import Path @@ -64,7 +65,7 @@ def run_all(self): self.setup() self.run() - def __init__(self, conf: ConfigManager, displayFrames=True, onNewFrame = noop, onShowFrame = noop, onNn = noop, onReport = noop, onSetup = noop, onTeardown = noop, onIter = noop, shouldRun = lambda inst: True): + def __init__(self, conf: ConfigManager, displayFrames=True, onNewFrame = noop, onShowFrame = noop, onNn = noop, onReport = noop, onSetup = noop, onTeardown = noop, onIter = noop, shouldRun = lambda: True): self._stack = ExitStack() self._conf = conf self._rgbRes = conf.getRgbResolution() @@ -83,6 +84,25 @@ def __init__(self, conf: ConfigManager, displayFrames=True, onNewFrame = noop, o self.onTeardown = onTeardown self.onIter = onIter self.shouldRun = shouldRun + + def setCallbacks(self, onNewFrame=None, onShowFrame=None, onNn=None, onReport=None, onSetup=None, onTeardown=None, onIter=None, shouldRun=None): + if onNewFrame is not None: + self.onNewFrame = onNewFrame + if onShowFrame is not None: + self.onShowFrame = onShowFrame + if onNn is not None: + self.onNn = onNn + if onReport is not None: + self.onReport = onReport + if onSetup is not None: + self.onSetup = onSetup + if onTeardown is not None: + self.onTeardown = onTeardown + if onIter is not None: + self.onIter = onIter + if shouldRun is not None: + self.shouldRun = shouldRun + def setup(self): if self._conf.args.reportFile: @@ -180,7 +200,9 @@ def setup(self): ) def run(self): + print("STARTING_PIPELINE") self._device.startPipeline(self._pm.pipeline) + print("STARTED_PIPELINE") self._pm.createDefaultQueues(self._device) if self._conf.useNN: self._nnManager.createQueues(self._device) @@ -224,7 +246,7 @@ def run(self): self.onSetup(self) try: - while self.shouldRun(self): + while self.shouldRun(): self._fps.nextIter() self.onIter(self) self.loop() @@ -451,71 +473,96 @@ def _printSysInfo(self, info): self.onReport(data) print(','.join(map(str, data.values())), file=self._reportFile) + + if __name__ == "__main__": from gui.main import DemoQtGui from PySide6.QtGui import QImage - class App(DemoQtGui): - def __init__(self): - super().__init__() + from PySide6.QtCore import QRunnable, Slot, QThreadPool, QObject, Signal + + + class WorkerSignals(QObject): + updatePreviewSignal = Signal(QImage) + setDataSignal = Signal(list) + + class Worker(QRunnable): + def __init__(self, instance, selectedPreview=None): + super(Worker, self).__init__() self.running = False - self.restartRequired = False - self._demoInstance = Demo(confManager, displayFrames=False, onNewFrame=self.demoOnNewFrame, onShowFrame=self.demoOnShowFrame, onNn=self.demoOnNn, onReport=self.demoOnReport, onSetup=self.demoOnSetup, onTeardown=self.demoOnTeardown, onIter=self.demoOnIter, shouldRun=self.demoShouldRun) + self.selectedPreview = selectedPreview + self.instance = instance + self.signals = WorkerSignals() - def demoOnNewFrame(self, frame, source): - pass + @Slot() + def run(self): + self.running = True + self.instance.setCallbacks(shouldRun=self.shouldRun, onShowFrame=self.onShowFrame, onSetup=self.onSetup) + self.instance.run_all() - def demoOnShowFrame(self, frame, source): - if source == self.selectedPreview: - try: - if self.writer is not None: - scaledFrame = resizeLetterbox(frame, (560, 560)) - if len(frame.shape) == 3: - img = QImage(scaledFrame.data, 560, 560, frame.shape[2] * 560, QImage.Format_BGR888) - else: - img = QImage(scaledFrame.data, 560, 560, 560, QImage.Format_Grayscale8) - self.writer.updatePreviewSignal.emit(img) - except queue.Full: - pass - - def demoOnNn(self, nn_packet): - pass + def shouldRun(self): + return self.running - def demoOnReport(self, report): - pass + def onShowFrame(self, frame, source): + if source == self.selectedPreview: + scaledFrame = resizeLetterbox(frame, (560, 560)) + if len(frame.shape) == 3: + img = QImage(scaledFrame.data, 560, 560, frame.shape[2] * 560, QImage.Format_BGR888) + else: + img = QImage(scaledFrame.data, 560, 560, 560, QImage.Format_Grayscale8) + self.signals.updatePreviewSignal.emit(img) - def demoOnSetup(self, instance): + def onSetup(self, instance): medianChoices = list(filter(lambda name: name.startswith('KERNEL_') or name.startswith('MEDIAN_'), vars(dai.MedianFilter).keys()))[::-1] - self.writer.setDataSignal.emit(["medianChoices", medianChoices]) - self.writer.setDataSignal.emit(["previewChoices", confManager.args.show]) + self.signals.setDataSignal.emit(["medianChoices", medianChoices]) + self.signals.setDataSignal.emit(["previewChoices", confManager.args.show]) self.selectedPreview = confManager.args.show[0] + self.signals.setDataSignal.emit(["restartRequired", False]) - def demoOnTeardown(self, instance): - pass - def demoOnIter(self, instance): - pass - - def demoShouldRun(self, instance): - return self.running + class App(DemoQtGui): + def __init__(self): + super().__init__() + self.running = False + self.dataInitialized = False + self.appInitialized = False + self.threadpool = QThreadPool() + self._demoInstance = Demo(confManager, displayFrames=False) def updateArg(self, arg_name, arg_value): setattr(confManager.args, arg_name, arg_value) - self.restartRequired = True + self.worker.signals.setDataSignal.emit(["restartRequired", True]) def start(self): self.running = True - self._t = threading.Thread(target=self._demoInstance.run_all) - self._t.start() - exit_code = self.startGui() - self.running = False - try: - self._t.join(2) # try exiting gracefully - except: - self._demoInstance._stack.close() - self._t.join() - raise SystemExit(exit_code) + self.worker = Worker(self._demoInstance) + self.worker.signals.updatePreviewSignal.connect(self.updatePreview) + self.worker.signals.setDataSignal.connect(self.setData) + self.threadpool.start(self.worker) + if not self.appInitialized: + self.appInitialized = True + exit_code = self.startGui() + raise SystemExit(exit_code) + + def stop(self): + self.worker.running = False + self.threadpool.waitForDone(100) + previous_device = self._demoInstance._deviceInfo + self._demoInstance._stack.close() + del self._demoInstance._device + del self._demoInstance + start = time.time() + while time.time() - start < 10: + if previous_device.getMxId() in list(map(lambda info: info.getMxId(), dai.Device.getAllAvailableDevices())): + self._demoInstance = Demo(confManager, displayFrames=False) + break + else: + raise RuntimeError("Device not available again after 10 seconds!") + + def restartDemo(self): + self.stop() + self.start() def guiOnDepthConfigUpdate(self, median=None, dct=None, sigma=None, lrcThreshold=None): self._demoInstance._pm.updateDepthConfig(self._demoInstance._device, median=median, dct=dct, sigma=sigma, lrcThreshold=lrcThreshold) @@ -546,6 +593,6 @@ def guiOnCameraSetupUpdate(self, name): pass def guiOnPreviewChangeSelected(self, selected): - self.selectedPreview = selected + self.worker.selectedPreview = selected App().start() \ No newline at end of file diff --git a/gui/main.py b/gui/main.py index 64f8a75d6..50859116f 100644 --- a/gui/main.py +++ b/gui/main.py @@ -23,12 +23,10 @@ def __call__(cls, *args, **kwargs): @QmlElement class ImageWriter(QQuickPaintedItem, metaclass=Singleton): - updatePreviewSignal = Signal(QImage) - setDataSignal = Signal(list) frame = QImage() - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def __init__(self): + super().__init__() self.setRenderTarget(QQuickPaintedItem.FramebufferObject) def paint(self, painter): @@ -65,19 +63,14 @@ def startGui(self): if not self.engine.rootObjects(): raise RuntimeError("Unable to start GUI - no root objects!") self.writer = ImageWriter() - self.writer.updatePreviewSignal.connect(self.updatePreview) - self.writer.setDataSignal.connect(self.setData) return self.app.exec() - def guiOnDepthConfigUpdate(self, median=None, dct=None, sigma=None, lrcThreshold=None): - pass - @QmlElement class AppBridge(QObject): @Slot() def applyAndRestart(self): - print("RESTART") + DemoQtGui.instance.restartDemo() @QmlElement @@ -91,15 +84,15 @@ def changeSelected(self, state): class DepthBridge(QObject): @Slot(bool) def toggleSubpixel(self, state): - print("Sub: {}".format(state)) + DemoQtGui.instance.guiOnDepthSetupUpdate(subpixel=state) @Slot(bool) def toggleExtendedDisparity(self, state): - print("Ext: {}".format(state)) + DemoQtGui.instance.guiOnDepthSetupUpdate(extended=state) @Slot(bool) def toggleLeftRightCheck(self, state): - print("Lrc: {}".format(state)) + DemoQtGui.instance.guiOnDepthSetupUpdate(lrc=state) @Slot(int) def setDisparityConfidenceThreshold(self, value): @@ -115,7 +108,7 @@ def setBilateralSigma(self, value): @Slot(int, int) def setDepthRange(self, valFrom, valTo): - print("Rng: {} - {}".format(valFrom, valTo)) + DemoQtGui.instance.guiOnDepthSetupUpdate(depthFrom=valFrom, depthTo=valTo) @Slot(str) def setMedianFilter(self, state): diff --git a/gui/views/DepthProperties.qml b/gui/views/DepthProperties.qml index a4319f1e9..deb0d7bbc 100644 --- a/gui/views/DepthProperties.qml +++ b/gui/views/DepthProperties.qml @@ -66,7 +66,6 @@ ListView { x: 0 y: 187 text: qsTr("Left Right Check") - enabled: false transformOrigin: Item.Center font.preferShaping: false font.kerning: false @@ -82,7 +81,6 @@ ListView { x: 0 y: 233 text: qsTr("Extended Disparity") - enabled: false autoExclusive: false font.kerning: false font.family: "Courier" @@ -98,7 +96,6 @@ ListView { x: 0 y: 141 text: qsTr("Subpixel") - enabled: false autoExclusive: false font.kerning: false transformOrigin: Item.Center @@ -220,7 +217,6 @@ ListView { y: 181 width: 198 height: 27 - enabled: false snapMode: RangeSlider.NoSnap stepSize: 1 to: 10000 diff --git a/gui/views/root.qml b/gui/views/root.qml index eefd7f8be..958edd373 100644 --- a/gui/views/root.qml +++ b/gui/views/root.qml @@ -130,6 +130,7 @@ ApplicationWindow { Button { x: 667 y: 540 + enabled: restartRequired height: 60 width: 563 text: "Apply and Restart" From cd4d200d9fe152c942d086132a0c46063bd66096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Thu, 28 Oct 2021 16:18:45 +0200 Subject: [PATCH 16/57] Add AI options --- depthai_demo.py | 47 +- depthai_helpers/config_manager.py | 10 +- gui/depthai_demo.pyproject | 3 +- gui/main.py | 52 ++ gui/views/AIProperties.qml | 346 ++++++++++ gui/views/CameraProperties.qml | 1067 +++++++++++++++++------------ gui/views/DepthProperties.qml | 2 +- gui/views/root.qml | 10 + 8 files changed, 1079 insertions(+), 458 deletions(-) create mode 100644 gui/views/AIProperties.qml diff --git a/depthai_demo.py b/depthai_demo.py index 1e5b9893b..88a5ce7f2 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -497,6 +497,7 @@ def __init__(self, instance, selectedPreview=None): @Slot() def run(self): self.running = True + self.signals.setDataSignal.emit(["restartRequired", False]) self.instance.setCallbacks(shouldRun=self.shouldRun, onShowFrame=self.onShowFrame, onSetup=self.onSetup) self.instance.run_all() @@ -515,9 +516,13 @@ def onShowFrame(self, frame, source): def onSetup(self, instance): medianChoices = list(filter(lambda name: name.startswith('KERNEL_') or name.startswith('MEDIAN_'), vars(dai.MedianFilter).keys()))[::-1] self.signals.setDataSignal.emit(["medianChoices", medianChoices]) + colorChoices = list(filter(lambda name: name[0].isupper(), vars(dai.ColorCameraProperties.SensorResolution).keys())) + self.signals.setDataSignal.emit(["colorResolutionChoices", colorChoices]) + monoChoices = list(filter(lambda name: name[0].isupper(), vars(dai.MonoCameraProperties.SensorResolution).keys())) + self.signals.setDataSignal.emit(["monoResolutionChoices", monoChoices]) self.signals.setDataSignal.emit(["previewChoices", confManager.args.show]) self.selectedPreview = confManager.args.show[0] - self.signals.setDataSignal.emit(["restartRequired", False]) + self.signals.setDataSignal.emit(["availableModels", confManager.getAvailableZooModels()]) class App(DemoQtGui): @@ -542,6 +547,7 @@ def start(self): if not self.appInitialized: self.appInitialized = True exit_code = self.startGui() + self.stop() raise SystemExit(exit_code) def stop(self): @@ -578,19 +584,48 @@ def guiOnCameraConfigUpdate(self, name, exposure=None, sensitivity=None, saturat def guiOnDepthSetupUpdate(self, depthFrom=None, depthTo=None, subpixel=None, lrc=None, extended=None): if depthFrom is not None: - self.updateArg("minDepth", subpixel) + self.updateArg("minDepth", depthFrom) if depthTo is not None: self.updateArg("maxDepth", depthTo) if subpixel is not None: self.updateArg("subpixel", subpixel) if extended is not None: - self.updateArg("extendedDisparity", subpixel) + self.updateArg("extendedDisparity", extended) if lrc is not None: - self.updateArg("stereoLrCheck", subpixel) + self.updateArg("stereoLrCheck", lrc) + def guiOnCameraSetupUpdate(self, name, fps=None, resolution=None): + if fps is not None: + if name == "color": + self.updateArg("rgbFps", fps) + else: + self.updateArg("monoFps", fps) + if resolution is not None: + if name == "color": + self.updateArg("rgbResolution", resolution) + else: + self.updateArg("monoResolution", resolution) + + def guiOnAiSetupUpdate(self, cnn=None, shave=None, source=None, fullFov=None, sync=None, sbb=None, sbbFactor=None, ov=None, countLabel=None): + if cnn is not None: + self.updateArg("cnnModel", cnn) + if shave is not None: + self.updateArg("shaves", shave) + if source is not None: + self.updateArg("camera", source) + if fullFov is not None: + self.updateArg("disableFullFovNn", not fullFov) + if sync is not None: + self.updateArg("sync", sync) + if sbb is not None: + self.updateArg("spatialBoundingBox", sbb) + if sbbFactor is not None: + self.updateArg("sbbScaleFactor", sbbFactor) + if ov is not None: + self.updateArg("openvinoVersion", ov) + if countLabel is not None: + self.updateArg("countLabel", countLabel) - def guiOnCameraSetupUpdate(self, name): - pass def guiOnPreviewChangeSelected(self, selected): self.worker.selectedPreview = selected diff --git a/depthai_helpers/config_manager.py b/depthai_helpers/config_manager.py index 5f4ac6eae..79fd7af6f 100644 --- a/depthai_helpers/config_manager.py +++ b/depthai_helpers/config_manager.py @@ -84,6 +84,15 @@ def getModelDir(self): if self.args.cnnModel is not None and (DEPTHAI_ZOO / self.args.cnnModel).exists(): return DEPTHAI_ZOO / self.args.cnnModel + def getAvailableZooModels(self): + def verify(path: Path): + return path.parent.name == path.stem + + def convert(path: Path): + return path.stem + + return list(map(convert, filter(verify, DEPTHAI_ZOO.rglob("**/*.json")))) + def getColorMap(self): return getattr(cv2, "COLORMAP_{}".format(self.args.colorMap)) @@ -180,7 +189,6 @@ def adjustParamsToDevice(self, device): else: self.args.bandwidth = "high" - def linuxCheckApplyUsbRules(self): if platform.system() == 'Linux': ret = subprocess.call(['grep', '-irn', 'ATTRS{idVendor}=="03e7"', '/etc/udev/rules.d'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) diff --git a/gui/depthai_demo.pyproject b/gui/depthai_demo.pyproject index 5689a8318..9a9a4d494 100644 --- a/gui/depthai_demo.pyproject +++ b/gui/depthai_demo.pyproject @@ -1,3 +1,4 @@ { - "files": ["main.py", "views/DepthProperties.qml", "views/root.qml", "views/CameraProperties.qml", "views/CameraPreview.qml"] + "files": ["main.py", "views/DepthProperties.qml", "views/root.qml", "views/CameraProperties.qml", + "views/CameraPreview.qml", "views/AIProperties.qml"] } diff --git a/gui/main.py b/gui/main.py index 50859116f..6fa9c2859 100644 --- a/gui/main.py +++ b/gui/main.py @@ -73,6 +73,46 @@ def applyAndRestart(self): DemoQtGui.instance.restartDemo() +@QmlElement +class AIBridge(QObject): + @Slot(str) + def setCnnModel(self, name): + DemoQtGui.instance.guiOnAiSetupUpdate(cnn=name) + + @Slot(int) + def setShaves(self, value): + DemoQtGui.instance.guiOnAiSetupUpdate(shave=value) + + @Slot(str) + def setModelSource(self, value): + DemoQtGui.instance.guiOnAiSetupUpdate(source=value) + + @Slot(bool) + def setFullFov(self, value): + DemoQtGui.instance.guiOnAiSetupUpdate(fullFov=value) + + @Slot(bool) + def setSyncNN(self, value): + DemoQtGui.instance.guiOnAiSetupUpdate(sync=value) + + @Slot(bool) + def setSbb(self, value): + DemoQtGui.instance.guiOnAiSetupUpdate(sbb=value) + + @Slot(float) + def setSbbFactor(self, value): + DemoQtGui.instance.guiOnAiSetupUpdate(sbbFactor=value) + + @Slot(str) + def setOvVersion(self, state): + value = getattr(dai.OpenVINO, state) + DemoQtGui.instance.guiOnAiSetupUpdate(ov=value) + + @Slot(str) + def setCountLabel(self, state): + DemoQtGui.instance.guiOnAiSetupUpdate(countLabel=state) + + @QmlElement class PreviewBridge(QObject): @Slot(str) @@ -140,6 +180,18 @@ def setSaturation(self, value): def setSharpness(self, value): DemoQtGui.instance.guiOnCameraConfigUpdate(self.name, sharpness=value) + @Slot(int) + def setFps(self, value): + DemoQtGui.instance.guiOnCameraSetupUpdate(self.name, fps=value) + + @Slot(str) + def setResolution(self, state): + if self.name == "color": + value = getattr(dai.ColorCameraProperties.SensorResolution, state) + else: + value = getattr(dai.MonoCameraProperties.SensorResolution, state) + DemoQtGui.instance.guiOnCameraSetupUpdate(self.name, resolution=value) + @QmlElement class ColorCamBridge(BaseCamBridge): diff --git a/gui/views/AIProperties.qml b/gui/views/AIProperties.qml new file mode 100644 index 000000000..7f5a9daf0 --- /dev/null +++ b/gui/views/AIProperties.qml @@ -0,0 +1,346 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.11 +import QtQuick.Controls 2.1 +import QtQuick.Window 2.1 +import QtQuick.Controls.Material 2.1 + +ListView { + id: aiProperties + + Rectangle { + id: backgroundRectAI + color: "black" + z: 0 + width: parent.width + height: parent.height + + Text { + id: textAI + x: 79 + y: 8 + width: 433 + height: 30 + color: "#ffffff" + text: qsTr("AI Properties") + font.pixelSize: 26 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.family: "Courier" + } + + Rectangle { + id: aiRect + + Text { + id: text33 + x: 90 + y: 56 + width: 124 + height: 33 + color: "#ffffff" + text: qsTr("CNN model") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.weight: Font.Bold + font.family: "Courier" + } + + ComboBox { + id: comboBoxModels + x: 220 + y: 56 + width: 282 + height: 33 + model: modelChoices + onActivated: function(index) { + aiBridge.setCnnModel(model[index]) + } + } + + Text { + id: text34 + x: 90 + y: 134 + width: 124 + height: 33 + color: "#ffffff" + text: qsTr("Model source") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + font.weight: Font.Bold + } + + ComboBox { + id: comboBox1 + x: 220 + y: 134 + width: 141 + height: 33 + model: modelSourceChoices + onActivated: function(index) { + aiBridge.setModelSource(model[index]) + } + } + + Text { + id: text36 + x: 90 + y: 95 + width: 124 + height: 33 + color: "#ffffff" + text: qsTr("SHAVEs") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + font.weight: Font.Bold + } + + Text { + id: text35 + x: 196 + y: 101 + width: 18 + height: 20 + color: "#ffffff" + text: qsTr("0") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + rotation: 0 + } + + Slider { + id: lrcSlider + x: 221 + y: 95 + width: 281 + height: 33 + value: 6 + stepSize: 1 + onValueChanged: { + aiBridge.setShaves(value) + } + to: 16 + from: 0 + } + + Text { + id: text37 + x: 508 + y: 101 + width: 18 + height: 20 + color: "#ffffff" + text: qsTr("16") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + rotation: 0 + } + + Text { + id: text43 + x: 403 + y: 134 + width: 124 + height: 33 + color: "#ffffff" + text: qsTr("Full FOV") + font.pixelSize: 12 + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + font.weight: Font.Bold + } + + CheckBox { + id: checkBoxFullFov + x: 369 + y: 137 + width: 37 + height: 23 + onClicked: aiBridge.setFullFov(checkBoxFullFov.checked) + } + + Switch { + id: switch4 + x: 90 + y: 173 + width: 185 + height: 48 + text: qsTr("Sync NN and Preview") + font.family: "Courier" + autoExclusive: false + transformOrigin: Item.Center + font.preferShaping: false + font.kerning: false + onToggled: { + aiBridge.setSyncNN(switch1.checked) + } + } + } + + CheckBox { + id: aiAdvancedSwitch + x: 167 + y: 228 + text: qsTr("Show advanced options") + font.family: "Courier" + autoExclusive: false + transformOrigin: Item.Center + font.pointSize: 21 + checked: false + font.preferShaping: false + font.kerning: false + } + + Rectangle { + id: aiAdvancedRect + + states: State { + name: "hidden"; when: !aiAdvancedSwitch.checked + PropertyChanges { target: aiAdvancedRect; opacity: 0 } + } + + Text { + id: text41 + x: 90 + y: 288 + width: 124 + height: 33 + color: "#ffffff" + text: qsTr("OpenVINO version") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + font.weight: Font.Bold + } + + ComboBox { + id: comboBox2 + x: 220 + y: 288 + width: 141 + height: 33 + model: ovVersions + onActivated: function(index) { + aiBridge.setOvVersion(model[index]) + } + } + + Text { + id: text42 + x: 90 + y: 327 + width: 124 + height: 33 + color: "#ffffff" + text: qsTr("Label to count") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + font.weight: Font.Bold + } + + ComboBox { + id: comboBox3 + x: 220 + y: 327 + width: 141 + height: 33 + model: countLabels + onActivated: function(index) { + aiBridge.setCountLabel(model[index]) + } + } + + Switch { + id: switch3 + x: 90 + y: 375 + width: 185 + height: 48 + text: qsTr("Spatial Bounding Boxes") + font.family: "Courier" + autoExclusive: false + transformOrigin: Item.Center + font.preferShaping: false + font.kerning: false + onToggled: { + aiBridge.setSyncNN(switch1.checked) + } + } + + Text { + id: text40 + x: 266 + y: 383 + width: 106 + height: 33 + color: "#ffffff" + text: qsTr("SBB factor") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + font.weight: Font.Bold + } + + Text { + id: text38 + x: 378 + y: 389 + width: 18 + height: 20 + color: "#ffffff" + text: qsTr("0") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + rotation: 0 + } + + Text { + id: text39 + x: 507 + y: 389 + width: 18 + height: 20 + color: "#ffffff" + text: qsTr("1") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + rotation: 0 + } + + Slider { + id: lrcSlider1 + x: 403 + y: 383 + width: 96 + height: 33 + value: 6 + stepSize: 1 + onValueChanged: { + aiBridge.setSbbFactor(value) + } + to: 16 + from: 0 + } + } + + } +} +/*##^## +Designer { + D{i:0;autoSize:true;height:480;width:640} +} +##^##*/ diff --git a/gui/views/CameraProperties.qml b/gui/views/CameraProperties.qml index 95046cc34..7feea196f 100644 --- a/gui/views/CameraProperties.qml +++ b/gui/views/CameraProperties.qml @@ -5,7 +5,7 @@ import QtQuick.Window 2.1 import QtQuick.Controls.Material 2.1 ListView { - id: listView + id: cameraProperties Rectangle { id: backgroundRect1 @@ -44,191 +44,310 @@ ListView { font.family: "Courier" } - TextField { - id: textField - x: 85 - y: 80 - width: 106 - height: 25 - text: "" - bottomPadding: 5 - validator: IntValidator {} - placeholderText: "ISO" - font.family: "Courier" - onEditingFinished: { - colorCamBridge.setIsoExposure(text, textField1.text) + Rectangle { + id: colorCamRectBasic + + ComboBox { + id: comboBox + x: 85 + y: 105 + width: 140 + height: 33 + model: colorResolutionChoices + onActivated: function(index) { + colorCamBridge.setResolution(model[index]) + } } - } - Text { - id: text14 - x: -6 - y: 80 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("ISO") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Text { + id: text32 + x: -6 + y: 74 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("FPS") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } - TextField { - id: textField1 - x: 85 - y: 111 - width: 106 - height: 25 - text: "" - bottomPadding: 5 - font.family: "Courier" - placeholderText: qsTr("Exposure") - validator: IntValidator {} - onEditingFinished: { - colorCamBridge.setIsoExposure(textField.text, text) + TextField { + id: textField6 + x: 85 + y: 74 + width: 106 + height: 25 + text: "30" + bottomPadding: 5 + placeholderText: "FPS" + font.family: "Courier" + onEditingFinished: { + colorCamBridge.setFps(text) + } + validator: IntValidator {} + } + + Text { + id: text33 + x: -6 + y: 109 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Resolution") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" } } + Rectangle { + id: colorCamRectAdvanced + x: 0 + y: 180 - Text { - id: text15 - x: -6 - y: 111 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Exposure") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + states: State { + name: "hidden"; when: !advancedSwitch.checked + PropertyChanges { target: colorCamRectAdvanced; opacity: 0 } + } - Slider { - id: slider2 - x: 85 - y: 142 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - onValueChanged: { - colorCamBridge.setSaturation(value) + TextField { + id: textField + x: 85 + y: 80 + width: 106 + height: 25 + text: "" + bottomPadding: 5 + validator: IntValidator {} + placeholderText: "ISO" + font.family: "Courier" + onEditingFinished: { + colorCamBridge.setIsoExposure(text, textField1.text) + } } - } - Text { - id: text16 - x: -6 - y: 142 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Saturation") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Text { + id: text14 + x: -6 + y: 80 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("ISO") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } - Slider { - id: slider3 - x: 85 - y: 173 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - onValueChanged: { - colorCamBridge.setContrast(value) + TextField { + id: textField1 + x: 85 + y: 111 + width: 106 + height: 25 + text: "" + bottomPadding: 5 + font.family: "Courier" + placeholderText: qsTr("Exposure") + validator: IntValidator {} + onEditingFinished: { + colorCamBridge.setIsoExposure(textField.text, text) + } } - } - Text { - id: text17 - x: -6 - y: 173 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Contrast") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" + + Text { + id: text15 + x: -6 + y: 111 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Exposure") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider2 + x: 85 + y: 142 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + colorCamBridge.setSaturation(value) + } + } + + Text { + id: text16 + x: -6 + y: 142 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Saturation") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider3 + x: 85 + y: 173 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + colorCamBridge.setContrast(value) + } + } + + Text { + id: text17 + x: -6 + y: 173 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Contrast") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider4 + x: 85 + y: 204 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + colorCamBridge.setBrightness(value) + } + } + + Text { + id: text18 + x: -6 + y: 204 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Brightness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider5 + x: 85 + y: 235 + width: 106 + height: 25 + stepSize: 1 + to: 4 + from: 0 + value: 0 + onValueChanged: { + colorCamBridge.setSharpness(value) + } + } + + Text { + id: text19 + x: -6 + y: 235 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Sharpness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } } + } - Slider { - id: slider4 + Rectangle { + id: monoCamRectBasic + x: 309 + y: 0 + + ComboBox { + id: comboBox1 x: 85 - y: 204 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - onValueChanged: { - colorCamBridge.setBrightness(value) + y: 105 + width: 152 + height: 33 + model: monoResolutionChoices + onActivated: function(index) { + leftCamBridge.setResolution(model[index]) } } Text { - id: text18 + id: text34 x: -6 - y: 204 + y: 74 width: 90 height: 25 color: "#ffffff" - text: qsTr("Brightness") + text: qsTr("FPS") font.pixelSize: 12 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.family: "Courier" } - Slider { - id: slider5 + TextField { + id: textField7 x: 85 - y: 235 + y: 74 width: 106 height: 25 - stepSize: 1 - to: 4 - from: 0 - value: 0 - onValueChanged: { - colorCamBridge.setSharpness(value) + text: "30" + bottomPadding: 5 + placeholderText: "FPS" + font.family: "Courier" + onEditingFinished: { + leftCamBridge.setFps(text) } + validator: IntValidator {} } Text { - id: text19 + id: text35 x: -6 - y: 235 + y: 109 width: 90 height: 25 color: "#ffffff" - text: qsTr("Sharpness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Text { - id: text20 - x: 393 - y: 80 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("ISO") + text: qsTr("Resolution") font.pixelSize: 12 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter @@ -253,181 +372,192 @@ ListView { font.family: "Courier" } - Text { - id: text26 - x: 197 - y: 80 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("ISO") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Rectangle { + id: leftCamRectAdvanced + x: 0 + y: 180 - TextField { - id: textField4 - x: 288 - y: 80 - width: 106 - height: 25 - color: "#ddffffff" - text: "" - bottomPadding: 5 - placeholderText: "ISO" - font.family: "Courier" - validator: IntValidator {} - onEditingFinished: { - leftCamBridge.setIsoExposure(text, textField5.text) + states: State { + name: "hidden"; when: !advancedSwitch.checked + PropertyChanges { target: leftCamRectAdvanced; opacity: 0 } } - } - TextField { - id: textField5 - x: 288 - y: 111 - width: 106 - height: 25 - color: "#ddffffff" - text: "" - bottomPadding: 5 - placeholderText: qsTr("Exposure") - validator: IntValidator {} - onEditingFinished: { - leftCamBridge.setIsoExposure(textField4.text, text) + Text { + id: text26 + x: 197 + y: 80 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("ISO") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" } - } - Text { - id: text27 - x: 197 - y: 111 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Exposure") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + TextField { + id: textField4 + x: 288 + y: 80 + width: 106 + height: 25 + color: "#ddffffff" + text: "" + bottomPadding: 5 + placeholderText: "ISO" + font.family: "Courier" + validator: IntValidator {} + onEditingFinished: { + leftCamBridge.setIsoExposure(text, textField5.text) + } + } - Slider { - id: slider10 - x: 288 - y: 142 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - onValueChanged: { - leftCamBridge.setSaturation(value) + TextField { + id: textField5 + x: 288 + y: 111 + width: 106 + height: 25 + color: "#ddffffff" + text: "" + bottomPadding: 5 + placeholderText: qsTr("Exposure") + validator: IntValidator {} + onEditingFinished: { + leftCamBridge.setIsoExposure(textField4.text, text) + } } - } - Text { - id: text28 - x: 197 - y: 142 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Saturation") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Text { + id: text27 + x: 197 + y: 111 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Exposure") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } - Slider { - id: slider11 - x: 288 - y: 173 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - onValueChanged: { - leftCamBridge.setContrast(value) + Slider { + id: slider10 + x: 288 + y: 142 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + leftCamBridge.setSaturation(value) + } } - } - Text { - id: text29 - x: 197 - y: 173 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Contrast") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Text { + id: text28 + x: 197 + y: 142 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Saturation") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } - Slider { - id: slider12 - x: 288 - y: 204 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - onValueChanged: { - leftCamBridge.setBrightness(value) + Slider { + id: slider11 + x: 288 + y: 173 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + leftCamBridge.setContrast(value) + } } - } - Text { - id: text30 - x: 197 - y: 204 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Brightness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Text { + id: text29 + x: 197 + y: 173 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Contrast") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } - Slider { - id: slider13 - x: 288 - y: 235 - width: 106 - height: 25 - stepSize: 1 - to: 4 - from: 0 - value: 0 - onValueChanged: { - leftCamBridge.setSharpness(value) + Slider { + id: slider12 + x: 288 + y: 204 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + leftCamBridge.setBrightness(value) + } } - } - Text { - id: text31 - x: 197 - y: 235 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Sharpness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" + Text { + id: text30 + x: 197 + y: 204 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Brightness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider13 + x: 288 + y: 235 + width: 106 + height: 25 + stepSize: 1 + to: 4 + from: 0 + value: 0 + onValueChanged: { + leftCamBridge.setSharpness(value) + } + } + + Text { + id: text31 + x: 197 + y: 235 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Sharpness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } } } @@ -448,170 +578,209 @@ ListView { font.family: "Courier" } - TextField { - id: textField2 - x: 484 - y: 80 - width: 106 - height: 25 - color: "#ddffffff" - text: "" - bottomPadding: 5 - validator: IntValidator {} - placeholderText: "ISO" - font.family: "Courier" - onEditingFinished: { - rightCamBridge.setIsoExposure(text, textField3.text) + Rectangle { + id: rightCamRectAdvanced + x: 0 + y: 180 + + states: State { + name: "hidden"; when: !advancedSwitch.checked + PropertyChanges { target: rightCamRectAdvanced; opacity: 0 } } - } - TextField { - id: textField3 - x: 484 - y: 111 - width: 106 - height: 25 - color: "#ddffffff" - text: "" - bottomPadding: 5 - font.family: "Courier" - placeholderText: qsTr("Exposure") - validator: IntValidator {} - onEditingFinished: { - rightCamBridge.setIsoExposure(textField2.text, text) + Text { + id: text20 + x: 393 + y: 80 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("ISO") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" } - } - Text { - id: text21 - x: 393 - y: 111 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Exposure") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + TextField { + id: textField2 + x: 484 + y: 80 + width: 106 + height: 25 + color: "#ddffffff" + text: "" + bottomPadding: 5 + validator: IntValidator {} + placeholderText: "ISO" + font.family: "Courier" + onEditingFinished: { + rightCamBridge.setIsoExposure(text, textField3.text) + } + } - Slider { - id: slider6 - x: 484 - y: 142 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - onValueChanged: { - rightCamBridge.setSaturation(value) + TextField { + id: textField3 + x: 484 + y: 111 + width: 106 + height: 25 + color: "#ddffffff" + text: "" + bottomPadding: 5 + font.family: "Courier" + placeholderText: qsTr("Exposure") + validator: IntValidator {} + onEditingFinished: { + rightCamBridge.setIsoExposure(textField2.text, text) + } } - } - Text { - id: text22 - x: 393 - y: 142 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Saturation") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Text { + id: text21 + x: 393 + y: 111 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Exposure") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } - Slider { - id: slider7 - x: 484 - y: 173 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - onValueChanged: { - rightCamBridge.setContrast(value) + Slider { + id: slider6 + x: 484 + y: 142 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + rightCamBridge.setSaturation(value) + } } - } - Text { - id: text23 - x: 393 - y: 173 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Contrast") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Text { + id: text22 + x: 393 + y: 142 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Saturation") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } - Slider { - id: slider8 - x: 484 - y: 204 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - onValueChanged: { - rightCamBridge.setBrightness(value) + Slider { + id: slider7 + x: 484 + y: 173 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + rightCamBridge.setContrast(value) + } } - } - Text { - id: text24 - x: 393 - y: 204 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Brightness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } + Text { + id: text23 + x: 393 + y: 173 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Contrast") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } - Slider { - id: slider9 - x: 484 - y: 235 - width: 106 - height: 25 - stepSize: 1 - to: 4 - from: 0 - value: 0 - onValueChanged: { - rightCamBridge.setSharpness(value) + Slider { + id: slider8 + x: 484 + y: 204 + width: 106 + height: 25 + stepSize: 1 + to: 10 + from: -10 + value: 0 + onValueChanged: { + rightCamBridge.setBrightness(value) + } } - } - Text { - id: text25 - x: 393 - y: 235 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Sharpness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" + Text { + id: text24 + x: 393 + y: 204 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Brightness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + Slider { + id: slider9 + x: 484 + y: 235 + width: 106 + height: 25 + stepSize: 1 + to: 4 + from: 0 + value: 0 + onValueChanged: { + rightCamBridge.setSharpness(value) + } + } + + Text { + id: text25 + x: 393 + y: 235 + width: 90 + height: 25 + color: "#ffffff" + text: qsTr("Sharpness") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } } } + + CheckBox { + id: advancedSwitch + x: 132 + y: 216 + text: qsTr("Show advanced options") + font.pointSize: 21 + transformOrigin: Item.Center + autoExclusive: false + font.family: "Courier" + font.kerning: false + checked: false + font.preferShaping: false + } } } /*##^## diff --git a/gui/views/DepthProperties.qml b/gui/views/DepthProperties.qml index deb0d7bbc..5e240458d 100644 --- a/gui/views/DepthProperties.qml +++ b/gui/views/DepthProperties.qml @@ -5,7 +5,7 @@ import QtQuick.Window 2.1 import QtQuick.Controls.Material 2.1 ListView { - id: view + id: depthProperties delegate: Text { anchors.leftMargin: 50 font.pointSize: 15 diff --git a/gui/views/root.qml b/gui/views/root.qml index 958edd373..b0ec18d28 100644 --- a/gui/views/root.qml +++ b/gui/views/root.qml @@ -82,6 +82,9 @@ ApplicationWindow { PreviewBridge { id: previewBridge } + AIBridge { + id: aiBridge + } Rectangle { id: root @@ -106,6 +109,10 @@ ApplicationWindow { height: 50 width: 590 + TabButton { + text: "AI" + } + TabButton { text: "Depth" } @@ -119,6 +126,9 @@ ApplicationWindow { y: 70 width: 630 currentIndex: bar.currentIndex + Item { + AIProperties {} + } Item { DepthProperties {} } From 2c5c754f4986f8a39dbf22a9372a9d8f924f5bdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Thu, 28 Oct 2021 22:47:33 +0200 Subject: [PATCH 17/57] add stop method --- depthai_demo.py | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 88a5ce7f2..5b9de878c 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -66,7 +66,6 @@ def run_all(self): self.run() def __init__(self, conf: ConfigManager, displayFrames=True, onNewFrame = noop, onShowFrame = noop, onNn = noop, onReport = noop, onSetup = noop, onTeardown = noop, onIter = noop, shouldRun = lambda: True): - self._stack = ExitStack() self._conf = conf self._rgbRes = conf.getRgbResolution() self._monoRes = conf.getMonoResolution() @@ -105,6 +104,7 @@ def setCallbacks(self, onNewFrame=None, onShowFrame=None, onNn=None, onReport=No def setup(self): + self._stack = ExitStack() if self._conf.args.reportFile: reportFileP = Path(self._conf.args.reportFile).with_suffix('.csv') reportFileP.parent.mkdir(parents=True, exist_ok=True) @@ -253,10 +253,13 @@ def run(self): except StopIteration: pass finally: - if self._conf.useCamera and self._encManager is not None: - self._encManager.close() - self._stack.close() + self.stop() + def stop(self): + if self._conf.useCamera and self._encManager is not None: + self._encManager.close() + self._device.close() + self._stack.close() self._fps.printStatus() self.onTeardown(self) @@ -485,6 +488,7 @@ def _printSysInfo(self, info): class WorkerSignals(QObject): updatePreviewSignal = Signal(QImage) setDataSignal = Signal(list) + exitSignal = Signal(bool) class Worker(QRunnable): def __init__(self, instance, selectedPreview=None): @@ -497,10 +501,26 @@ def __init__(self, instance, selectedPreview=None): @Slot() def run(self): self.running = True + self.signals.exitSignal.connect(self.terminate) self.signals.setDataSignal.emit(["restartRequired", False]) self.instance.setCallbacks(shouldRun=self.shouldRun, onShowFrame=self.onShowFrame, onSetup=self.onSetup) self.instance.run_all() + def terminate(self, should_exit): + if should_exit: + current_mxid = self.instance._device.getMxId() + self.running = False + self.signals.setDataSignal.emit(["restartRequired", False]) + self.instance.stop() + + start = time.time() + while time.time() - start < 10: + if current_mxid in list(map(lambda info: info.getMxId(), dai.Device.getAllAvailableDevices())): + break + else: + raise RuntimeError("Device not available again after 10 seconds!") + + def shouldRun(self): return self.running @@ -554,16 +574,7 @@ def stop(self): self.worker.running = False self.threadpool.waitForDone(100) previous_device = self._demoInstance._deviceInfo - self._demoInstance._stack.close() - del self._demoInstance._device - del self._demoInstance - start = time.time() - while time.time() - start < 10: - if previous_device.getMxId() in list(map(lambda info: info.getMxId(), dai.Device.getAllAvailableDevices())): - self._demoInstance = Demo(confManager, displayFrames=False) - break - else: - raise RuntimeError("Device not available again after 10 seconds!") + self.worker.signals.exitSignal.emit(True) def restartDemo(self): From 010eda722c1e0180314099c1b0ccadd179c15fa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Thu, 28 Oct 2021 23:02:10 +0200 Subject: [PATCH 18/57] modify exit signal --- depthai_demo.py | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 5b9de878c..bae760cc8 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -69,7 +69,6 @@ def __init__(self, conf: ConfigManager, displayFrames=True, onNewFrame = noop, o self._conf = conf self._rgbRes = conf.getRgbResolution() self._monoRes = conf.getMonoResolution() - self._deviceInfo = getDeviceInfo(conf.args.deviceId) self._openvinoVersion = None if conf.args.openvinoVersion: self._openvinoVersion = getattr(dai.OpenVINO.Version, 'VERSION_' + conf.args.openvinoVersion) @@ -105,6 +104,7 @@ def setCallbacks(self, onNewFrame=None, onShowFrame=None, onNn=None, onReport=No def setup(self): self._stack = ExitStack() + self._deviceInfo = getDeviceInfo(self._conf.args.deviceId) if self._conf.args.reportFile: reportFileP = Path(self._conf.args.reportFile).with_suffix('.csv') reportFileP.parent.mkdir(parents=True, exist_ok=True) @@ -488,7 +488,7 @@ def _printSysInfo(self, info): class WorkerSignals(QObject): updatePreviewSignal = Signal(QImage) setDataSignal = Signal(list) - exitSignal = Signal(bool) + exitSignal = Signal() class Worker(QRunnable): def __init__(self, instance, selectedPreview=None): @@ -497,28 +497,19 @@ def __init__(self, instance, selectedPreview=None): self.selectedPreview = selectedPreview self.instance = instance self.signals = WorkerSignals() + self.signals.exitSignal.connect(self.terminate) @Slot() def run(self): self.running = True - self.signals.exitSignal.connect(self.terminate) self.signals.setDataSignal.emit(["restartRequired", False]) self.instance.setCallbacks(shouldRun=self.shouldRun, onShowFrame=self.onShowFrame, onSetup=self.onSetup) self.instance.run_all() - def terminate(self, should_exit): - if should_exit: - current_mxid = self.instance._device.getMxId() - self.running = False - self.signals.setDataSignal.emit(["restartRequired", False]) - self.instance.stop() - - start = time.time() - while time.time() - start < 10: - if current_mxid in list(map(lambda info: info.getMxId(), dai.Device.getAllAvailableDevices())): - break - else: - raise RuntimeError("Device not available again after 10 seconds!") + @Slot() + def terminate(self): + self.running = False + self.signals.setDataSignal.emit(["restartRequired", False]) def shouldRun(self): @@ -571,10 +562,15 @@ def start(self): raise SystemExit(exit_code) def stop(self): - self.worker.running = False + current_mxid = self._demoInstance._device.getMxId() + self.worker.signals.exitSignal.emit() self.threadpool.waitForDone(100) - previous_device = self._demoInstance._deviceInfo - self.worker.signals.exitSignal.emit(True) + start = time.time() + while time.time() - start < 10: + if current_mxid in list(map(lambda info: info.getMxId(), dai.Device.getAllAvailableDevices())): + break + else: + raise RuntimeError("Device not available again after 10 seconds!") def restartDemo(self): From 55aba31c9996bde54c16aa05dd178eece762e85b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Thu, 28 Oct 2021 23:59:02 +0200 Subject: [PATCH 19/57] add close queues --- depthai_demo.py | 18 ++++++++-- .../depthai_sdk/managers/encoding_manager.py | 3 ++ .../src/depthai_sdk/managers/nnet_manager.py | 8 +++++ .../depthai_sdk/managers/pipeline_manager.py | 36 ++++++++++++++----- .../depthai_sdk/managers/preview_manager.py | 9 +++++ 5 files changed, 63 insertions(+), 11 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index bae760cc8..a8361149e 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -4,6 +4,7 @@ import threading import time from contextlib import ExitStack +from functools import cmp_to_key from itertools import cycle from pathlib import Path @@ -103,6 +104,7 @@ def setCallbacks(self, onNewFrame=None, onShowFrame=None, onNn=None, onReport=No def setup(self): + print("Setting up demo...") self._stack = ExitStack() self._deviceInfo = getDeviceInfo(self._conf.args.deviceId) if self._conf.args.reportFile: @@ -256,10 +258,20 @@ def run(self): self.stop() def stop(self): - if self._conf.useCamera and self._encManager is not None: - self._encManager.close() + print("Stopping demo...") self._device.close() self._stack.close() + self._pm.closeDefaultQueues() + if self._conf.useCamera: + self._pv.closeQueues() + if self._encManager is not None: + self._encManager.close() + if self._conf.useNN: + self._nnManager.closeQueues() + if self._sbbOut is not None: + self._sbbOut.close() + if self._logOut is not None: + self._logOut.close() self._fps.printStatus() self.onTeardown(self) @@ -533,7 +545,7 @@ def onSetup(self, instance): self.signals.setDataSignal.emit(["monoResolutionChoices", monoChoices]) self.signals.setDataSignal.emit(["previewChoices", confManager.args.show]) self.selectedPreview = confManager.args.show[0] - self.signals.setDataSignal.emit(["availableModels", confManager.getAvailableZooModels()]) + self.signals.setDataSignal.emit(["modelChoices", sorted(confManager.getAvailableZooModels(), key=cmp_to_key(lambda a, b: -1 if a == "mobilenet-ssd" else 1 if b == "mobilenet-ssd" else -1 if a < b else 1))]) class App(DemoQtGui): diff --git a/depthai_sdk/src/depthai_sdk/managers/encoding_manager.py b/depthai_sdk/src/depthai_sdk/managers/encoding_manager.py index 6b4e5472d..7682ed7b2 100644 --- a/depthai_sdk/src/depthai_sdk/managers/encoding_manager.py +++ b/depthai_sdk/src/depthai_sdk/managers/encoding_manager.py @@ -76,6 +76,9 @@ def printManual(): for name, file in self._encodingFiles.items(): print(cmd.format(self._encodingNodes[name].getFrameRate(), file.name, str(Path(file.name).with_suffix('.mp4')))) + for queue in self._encodingQueues.values(): + queue.close() + for name, file in self._encodingFiles.items(): file.close() try: diff --git a/depthai_sdk/src/depthai_sdk/managers/nnet_manager.py b/depthai_sdk/src/depthai_sdk/managers/nnet_manager.py index 096dff05c..4c99a0a67 100644 --- a/depthai_sdk/src/depthai_sdk/managers/nnet_manager.py +++ b/depthai_sdk/src/depthai_sdk/managers/nnet_manager.py @@ -341,6 +341,14 @@ def createQueues(self, device): self.inputQueue = device.getInputQueue("nnIn", maxSize=1, blocking=False) self.outputQueue = device.getOutputQueue("nnOut", maxSize=1, blocking=False) + def closeQueues(self): + """ + Closes output queues created by :func:`createQueues` + """ + if self.source == "host": + self.inputQueue.close() + self.outputQueue.close() + def sendInputFrame(self, frame, seqNum=None): """ Sends a frame into :attr:`inputQueue` object. Handles scaling down the frame, creating a proper :obj:`depthai.ImgFrame` diff --git a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py index cad2d21f3..3f3a9cf2c 100644 --- a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py +++ b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py @@ -30,6 +30,11 @@ def __init__(self, openvinoVersion=None): _leftConfig = dai.CameraControl() _rightConfig = dai.CameraControl() + _depthConfigInputQueue = None + _rgbConfigInputQueue = None + _leftConfigInputQueue = None + _rightConfigInputQueue = None + def setNnManager(self, nnManager): """ Assigns NN manager. It also syncs the pipeline versions between those two objects @@ -45,15 +50,29 @@ def setNnManager(self, nnManager): def createDefaultQueues(self, device): """ - Creates queues for all requested XLinkOut's and XLinkIn's. + Creates default queues for config updates Args: device (depthai.Device): Running device instance """ - for xout in filter(lambda node: isinstance(node, dai.node.XLinkOut), vars(self.nodes).values()): - device.getOutputQueue(xout.getStreamName(), maxSize=1, blocking=False) - for xin in filter(lambda node: isinstance(node, dai.node.XLinkIn), vars(self.nodes).values()): - device.getInputQueue(xin.getStreamName(), maxSize=1, blocking=False) + + self._depthConfigInputQueue = device.getInputQueue("left_control") + self._rgbConfigInputQueue = device.getInputQueue("color_control") + self._leftConfigInputQueue = device.getInputQueue("right_control") + self._rightConfigInputQueue = device.getInputQueue("stereoConfig") + + def closeDefaultQueues(self): + """ + Creates default queues for config updates + + Args: + device (depthai.Device): Running device instance + """ + + self._depthConfigInputQueue.close() + self._rgbConfigInputQueue.close() + self._leftConfigInputQueue.close() + self._rightConfigInputQueue.close() def __calcEncodeableSize(self, sourceSize): w, h = sourceSize @@ -289,8 +308,6 @@ def _updateCamConfig(self, configRef: dai.CameraControl, cameraName, device, exp configRef.setContrast(contrast) if brightness is not None: configRef.setBrightness(brightness) - - device.getInputQueue(cameraName + "_control").send(configRef) def updateColorCamConfig(self, device, exposure=None, sensitivity=None, saturation=None, contrast=None, brightness=None, sharpness=None): """ @@ -306,6 +323,7 @@ def updateColorCamConfig(self, device, exposure=None, sensitivity=None, saturati sharpness (int, Optional): Image sharpness (Allowed range: 0..4) """ self._updateCamConfig(self._rgbConfig, Previews.color.name, device, exposure, sensitivity, saturation, contrast, brightness, sharpness) + self._rgbConfigInputQueue.send(self._rgbConfig) def updateLeftCamConfig(self, device, exposure=None, sensitivity=None, saturation=None, contrast=None, brightness=None, sharpness=None): """ @@ -321,6 +339,7 @@ def updateLeftCamConfig(self, device, exposure=None, sensitivity=None, saturatio sharpness (int, Optional): Image sharpness (Allowed range: 0..4) """ self._updateCamConfig(self._leftConfig, Previews.left.name, device, exposure, sensitivity, saturation, contrast, brightness, sharpness) + self._leftConfigInputQueue.send(self._leftConfig) def updateRightCamConfig(self, device, exposure=None, sensitivity=None, saturation=None, contrast=None, brightness=None, sharpness=None): """ @@ -336,6 +355,7 @@ def updateRightCamConfig(self, device, exposure=None, sensitivity=None, saturati sharpness (int, Optional): Image sharpness (Allowed range: 0..4) """ self._updateCamConfig(self._rightConfig, Previews.right.name, device, exposure, sensitivity, saturation, contrast, brightness, sharpness) + self._rightConfigInputQueue.send(self._rightConfig) def updateDepthConfig(self, device, dct=None, sigma=None, median=None, lrcThreshold=None): """ @@ -358,7 +378,7 @@ def updateDepthConfig(self, device, dct=None, sigma=None, median=None, lrcThresh if lrcThreshold is not None: self._depthConfig.setLeftRightCheckThreshold(lrcThreshold) - device.getInputQueue("stereoConfig").send(self._depthConfig) + self._depthConfigInputQueue.send(self._depthConfig) def addNn(self, nn, sync=False, useDepth=False, xoutNnInput=False, xoutSbb=False): """ diff --git a/depthai_sdk/src/depthai_sdk/managers/preview_manager.py b/depthai_sdk/src/depthai_sdk/managers/preview_manager.py index 19fbf8f5b..30aa68f93 100644 --- a/depthai_sdk/src/depthai_sdk/managers/preview_manager.py +++ b/depthai_sdk/src/depthai_sdk/managers/preview_manager.py @@ -86,6 +86,15 @@ def createQueues(self, device, callback=None): if Previews.depth.name in self._display and Previews.depthRaw.name not in self._display: self.outputQueues.append(device.getOutputQueue(name=Previews.depthRaw.name, maxSize=1, blocking=False)) + def closeQueues(self): + """ + Closes output queues for requested preview streams + """ + + for queue in self.outputQueues: + queue.close() + + def prepareFrames(self, blocking=False, callback=None): """ This function consumes output queues' packets and parses them to obtain ready to use frames. From edf61950ea956ec32a99a20627bf407afdf14ea4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Fri, 29 Oct 2021 00:30:43 +0200 Subject: [PATCH 20/57] add properties --- depthai_demo.py | 4 ++++ gui/views/AIProperties.qml | 16 ++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index a8361149e..98acc31f4 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -544,6 +544,10 @@ def onSetup(self, instance): monoChoices = list(filter(lambda name: name[0].isupper(), vars(dai.MonoCameraProperties.SensorResolution).keys())) self.signals.setDataSignal.emit(["monoResolutionChoices", monoChoices]) self.signals.setDataSignal.emit(["previewChoices", confManager.args.show]) + self.signals.setDataSignal.emit(["modelSourceChoices", [Previews.color.name, Previews.left.name, Previews.right.name]]) + versionChoices = list(filter(lambda name: name.startswith("VERSION_"), vars(dai.OpenVINO).keys())) + self.signals.setDataSignal.emit(["ovVersions", versionChoices]) + self.signals.setDataSignal.emit(["countLabels", instance._nnManager._labels]) self.selectedPreview = confManager.args.show[0] self.signals.setDataSignal.emit(["modelChoices", sorted(confManager.getAvailableZooModels(), key=cmp_to_key(lambda a, b: -1 if a == "mobilenet-ssd" else 1 if b == "mobilenet-ssd" else -1 if a < b else 1))]) diff --git a/gui/views/AIProperties.qml b/gui/views/AIProperties.qml index 7f5a9daf0..a5981afd5 100644 --- a/gui/views/AIProperties.qml +++ b/gui/views/AIProperties.qml @@ -126,7 +126,7 @@ ListView { aiBridge.setShaves(value) } to: 16 - from: 0 + from: 1 } Text { @@ -171,7 +171,7 @@ ListView { id: switch4 x: 90 y: 173 - width: 185 + width: 300 height: 48 text: qsTr("Sync NN and Preview") font.family: "Courier" @@ -226,7 +226,7 @@ ListView { id: comboBox2 x: 220 y: 288 - width: 141 + width: 170 height: 33 model: ovVersions onActivated: function(index) { @@ -265,7 +265,7 @@ ListView { id: switch3 x: 90 y: 375 - width: 185 + width: 250 height: 48 text: qsTr("Spatial Bounding Boxes") font.family: "Courier" @@ -280,7 +280,7 @@ ListView { Text { id: text40 - x: 266 + x: 320 y: 383 width: 106 height: 33 @@ -295,7 +295,7 @@ ListView { Text { id: text38 - x: 378 + x: 418 y: 389 width: 18 height: 20 @@ -309,7 +309,7 @@ ListView { Text { id: text39 - x: 507 + x: 547 y: 389 width: 18 height: 20 @@ -323,7 +323,7 @@ ListView { Slider { id: lrcSlider1 - x: 403 + x: 443 y: 383 width: 96 height: 33 From b423c1aa21222b0380145fecbd1aeeae8314d5dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Fri, 29 Oct 2021 12:08:48 +0200 Subject: [PATCH 21/57] bump dai version and fix arg handling --- depthai_helpers/version_check.py | 2 +- gui/main.py | 20 +++++++++++++------- requirements.txt | 2 +- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/depthai_helpers/version_check.py b/depthai_helpers/version_check.py index 1028a0792..2367a793a 100644 --- a/depthai_helpers/version_check.py +++ b/depthai_helpers/version_check.py @@ -45,7 +45,7 @@ def getVersion(module_name): def checkRequirementsVersion(): daiVersionRequired = getVersionFromRequirements('depthai', Path(__file__).parent / Path('../requirements.txt')) if daiVersionRequired is not None: - if depthai.__version__.endswith('+dev'): + if "dev" in depthai.__version__: print('Depthai development version found, skipping check.') elif daiVersionRequired != getVersion('depthai'): raise SystemExit(f"\033[1;5;31mVersion mismatch\033[0m\033[91m between installed depthai lib and the required one by the script.\033[0m \n\ diff --git a/gui/main.py b/gui/main.py index 6fa9c2859..d2cc14f6f 100644 --- a/gui/main.py +++ b/gui/main.py @@ -105,8 +105,7 @@ def setSbbFactor(self, value): @Slot(str) def setOvVersion(self, state): - value = getattr(dai.OpenVINO, state) - DemoQtGui.instance.guiOnAiSetupUpdate(ov=value) + DemoQtGui.instance.guiOnAiSetupUpdate(ov=state.replace("VERSION_", "")) @Slot(str) def setCountLabel(self, state): @@ -186,11 +185,18 @@ def setFps(self, value): @Slot(str) def setResolution(self, state): - if self.name == "color": - value = getattr(dai.ColorCameraProperties.SensorResolution, state) - else: - value = getattr(dai.MonoCameraProperties.SensorResolution, state) - DemoQtGui.instance.guiOnCameraSetupUpdate(self.name, resolution=value) + if state == "THE_1080_P": + DemoQtGui.instance.guiOnCameraSetupUpdate(self.name, resolution=1080) + elif state == "THE_4_K": + DemoQtGui.instance.guiOnCameraSetupUpdate(self.name, resolution=2160) + elif state == "THE_12_MP": + DemoQtGui.instance.guiOnCameraSetupUpdate(self.name, resolution=3040) + elif state == "THE_720_P": + DemoQtGui.instance.guiOnCameraSetupUpdate(self.name, resolution=720) + elif state == "THE_800_P": + DemoQtGui.instance.guiOnCameraSetupUpdate(self.name, resolution=800) + elif state == "THE_400_P": + DemoQtGui.instance.guiOnCameraSetupUpdate(self.name, resolution=400) @QmlElement diff --git a/requirements.txt b/requirements.txt index 596b1cf8a..508d4f9a6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ requests==2.24.0 argcomplete==1.12.1 -e ./depthai_sdk --extra-index-url https://artifacts.luxonis.com/artifactory/luxonis-python-snapshot-local/ -depthai==2.10.0.0.dev+7a0749a61597c086c5fd6e579618ae33accec8df +depthai==2.11.1.0.dev+dfd52ac01c3b7514e85cb894b9d5381e999859df PySide6==6.2.0 opencv-python==4.5.1.48 ; platform_machine != "aarch64" and platform_machine != "armv6l" and platform_machine != "armv7l" opencv-contrib-python==4.5.1.48 ; platform_machine != "aarch64" and platform_machine != "armv6l" and platform_machine != "armv7l" From 66c002bc7df2e86132823bd881980af02dfb6417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Fri, 29 Oct 2021 12:52:40 +0200 Subject: [PATCH 22/57] remove prints --- depthai_demo.py | 8 ++++---- .../src/depthai_sdk/managers/pipeline_manager.py | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 98acc31f4..5a51281ed 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -202,9 +202,7 @@ def setup(self): ) def run(self): - print("STARTING_PIPELINE") self._device.startPipeline(self._pm.pipeline) - print("STARTED_PIPELINE") self._pm.createDefaultQueues(self._device) if self._conf.useNN: self._nnManager.createQueues(self._device) @@ -548,7 +546,6 @@ def onSetup(self, instance): versionChoices = list(filter(lambda name: name.startswith("VERSION_"), vars(dai.OpenVINO).keys())) self.signals.setDataSignal.emit(["ovVersions", versionChoices]) self.signals.setDataSignal.emit(["countLabels", instance._nnManager._labels]) - self.selectedPreview = confManager.args.show[0] self.signals.setDataSignal.emit(["modelChoices", sorted(confManager.getAvailableZooModels(), key=cmp_to_key(lambda a, b: -1 if a == "mobilenet-ssd" else 1 if b == "mobilenet-ssd" else -1 if a < b else 1))]) @@ -556,6 +553,7 @@ class App(DemoQtGui): def __init__(self): super().__init__() self.running = False + self.selectedPreview = "color" self.dataInitialized = False self.appInitialized = False self.threadpool = QThreadPool() @@ -567,7 +565,7 @@ def updateArg(self, arg_name, arg_value): def start(self): self.running = True - self.worker = Worker(self._demoInstance) + self.worker = Worker(self._demoInstance, selectedPreview=self.selectedPreview) self.worker.signals.updatePreviewSignal.connect(self.updatePreview) self.worker.signals.setDataSignal.connect(self.setData) self.threadpool.start(self.worker) @@ -594,6 +592,7 @@ def restartDemo(self): self.start() def guiOnDepthConfigUpdate(self, median=None, dct=None, sigma=None, lrcThreshold=None): + print("median", median) self._demoInstance._pm.updateDepthConfig(self._demoInstance._device, median=median, dct=dct, sigma=sigma, lrcThreshold=lrcThreshold) def guiOnCameraConfigUpdate(self, name, exposure=None, sensitivity=None, saturation=None, contrast=None, brightness=None, sharpness=None): @@ -652,5 +651,6 @@ def guiOnAiSetupUpdate(self, cnn=None, shave=None, source=None, fullFov=None, sy def guiOnPreviewChangeSelected(self, selected): self.worker.selectedPreview = selected + self.selectedPreview = selected App().start() \ No newline at end of file diff --git a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py index 3f3a9cf2c..0abf5559d 100644 --- a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py +++ b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py @@ -12,6 +12,10 @@ class PipelineManager: def __init__(self, openvinoVersion=None): self.openvinoVersion=openvinoVersion + #: depthai.Pipeline: Ready to use requested pipeline. Can be passed to :obj:`depthai.Device` to start execution + self.pipeline = dai.Pipeline() + #: types.SimpleNamespace: Contains all nodes added to the :attr:`pipeline` object, can be used to conveniently access nodes by their name + self.nodes = SimpleNamespace() if openvinoVersion is not None: self.pipeline.setOpenVINOVersion(openvinoVersion) @@ -20,10 +24,6 @@ def __init__(self, openvinoVersion=None): openvinoVersion = None #: bool: If set to :code:`True`, manager will MJPEG-encode the packets sent from device to host to lower the bandwidth usage. **Can break** if more than 3 encoded outputs requested lowBandwidth = False - #: depthai.Pipeline: Ready to use requested pipeline. Can be passed to :obj:`depthai.Device` to start execution - pipeline = dai.Pipeline() - #: types.SimpleNamespace: Contains all nodes added to the :attr:`pipeline` object, can be used to conveniently access nodes by their name - nodes = SimpleNamespace() _depthConfig = dai.StereoDepthConfig() _rgbConfig = dai.CameraControl() @@ -56,10 +56,10 @@ def createDefaultQueues(self, device): device (depthai.Device): Running device instance """ - self._depthConfigInputQueue = device.getInputQueue("left_control") + self._depthConfigInputQueue = device.getInputQueue("stereoConfig") self._rgbConfigInputQueue = device.getInputQueue("color_control") - self._leftConfigInputQueue = device.getInputQueue("right_control") - self._rightConfigInputQueue = device.getInputQueue("stereoConfig") + self._leftConfigInputQueue = device.getInputQueue("left_control") + self._rightConfigInputQueue = device.getInputQueue("right_control") def closeDefaultQueues(self): """ @@ -377,7 +377,7 @@ def updateDepthConfig(self, device, dct=None, sigma=None, median=None, lrcThresh self._depthConfig.setMedianFilter(median) if lrcThreshold is not None: self._depthConfig.setLeftRightCheckThreshold(lrcThreshold) - + print("SENDING") self._depthConfigInputQueue.send(self._depthConfig) def addNn(self, nn, sync=False, useDepth=False, xoutNnInput=False, xoutSbb=False): From d97a2a594b08846bc8fa205bbd4d6608876c4d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Fri, 29 Oct 2021 16:17:30 +0200 Subject: [PATCH 23/57] remove errors and improve visibility --- depthai_demo.py | 39 +++++++++++---------- gui/main.py | 23 ++++++++++--- gui/views/AIProperties.qml | 64 ++++++++++------------------------- gui/views/DepthProperties.qml | 43 ++++++----------------- gui/views/root.qml | 13 ++++++- 5 files changed, 79 insertions(+), 103 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 5a51281ed..8bf597f1e 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -1,9 +1,6 @@ #!/usr/bin/env python3 import os -import queue -import threading import time -from contextlib import ExitStack from functools import cmp_to_key from itertools import cycle from pathlib import Path @@ -102,15 +99,13 @@ def setCallbacks(self, onNewFrame=None, onShowFrame=None, onNn=None, onReport=No if shouldRun is not None: self.shouldRun = shouldRun - def setup(self): print("Setting up demo...") - self._stack = ExitStack() self._deviceInfo = getDeviceInfo(self._conf.args.deviceId) if self._conf.args.reportFile: reportFileP = Path(self._conf.args.reportFile).with_suffix('.csv') reportFileP.parent.mkdir(parents=True, exist_ok=True) - self._reportFile = self._stack.enter_context(reportFileP.open('a')) + self._reportFile = reportFileP.open('a') self._pm = PipelineManager(self._openvinoVersion) if self._conf.args.xlinkChunkSize is not None: @@ -130,9 +125,7 @@ def setup(self): self._nnManager.countLabel(self._conf.getCountLabel(self._nnManager)) self._pm.setNnManager(self._nnManager) - self._device = self._stack.enter_context( - dai.Device(self._pm.pipeline.getOpenVINOVersion(), self._deviceInfo, usb2Mode=self._conf.args.usbSpeed == "usb2") - ) + self._device = dai.Device(self._pm.pipeline.getOpenVINOVersion(), self._deviceInfo, usb2Mode=self._conf.args.usbSpeed == "usb2") if self._deviceInfo.desc.protocol == dai.XLinkProtocol.X_LINK_USB_VSC: print("USB Connection speed: {}".format(self._device.getUsbSpeed())) self._conf.adjustParamsToDevice(self._device) @@ -258,7 +251,7 @@ def run(self): def stop(self): print("Stopping demo...") self._device.close() - self._stack.close() + del self._device self._pm.closeDefaultQueues() if self._conf.useCamera: self._pv.closeQueues() @@ -499,6 +492,7 @@ class WorkerSignals(QObject): updatePreviewSignal = Signal(QImage) setDataSignal = Signal(list) exitSignal = Signal() + errorSignal = Signal(str) class Worker(QRunnable): def __init__(self, instance, selectedPreview=None): @@ -514,13 +508,18 @@ def run(self): self.running = True self.signals.setDataSignal.emit(["restartRequired", False]) self.instance.setCallbacks(shouldRun=self.shouldRun, onShowFrame=self.onShowFrame, onSetup=self.onSetup) - self.instance.run_all() + try: + self.instance.run_all() + except Exception as ex: + self.onError(ex) @Slot() def terminate(self): self.running = False self.signals.setDataSignal.emit(["restartRequired", False]) + def onError(self, ex: Exception): + pass def shouldRun(self): return self.running @@ -568,6 +567,7 @@ def start(self): self.worker = Worker(self._demoInstance, selectedPreview=self.selectedPreview) self.worker.signals.updatePreviewSignal.connect(self.updatePreview) self.worker.signals.setDataSignal.connect(self.setData) + self.worker.signals.errorSignal.connect(self.showError) self.threadpool.start(self.worker) if not self.appInitialized: self.appInitialized = True @@ -576,15 +576,18 @@ def start(self): raise SystemExit(exit_code) def stop(self): - current_mxid = self._demoInstance._device.getMxId() + current_mxid = None + if hasattr(self._demoInstance, "_device"): + current_mxid = self._demoInstance._device.getMxId() self.worker.signals.exitSignal.emit() self.threadpool.waitForDone(100) - start = time.time() - while time.time() - start < 10: - if current_mxid in list(map(lambda info: info.getMxId(), dai.Device.getAllAvailableDevices())): - break - else: - raise RuntimeError("Device not available again after 10 seconds!") + if current_mxid is not None: + start = time.time() + while time.time() - start < 10: + if current_mxid in list(map(lambda info: info.getMxId(), dai.Device.getAllAvailableDevices())): + break + else: + raise RuntimeError("Device not available again after 10 seconds!") def restartDemo(self): diff --git a/gui/main.py b/gui/main.py index d2cc14f6f..eceba06e2 100644 --- a/gui/main.py +++ b/gui/main.py @@ -9,6 +9,7 @@ # To be used on the @QmlElement decorator # (QML_IMPORT_MINOR_VERSION is optional) from PySide6.QtQuick import QQuickPaintedItem +from PySide6.QtWidgets import QMessageBox QML_IMPORT_NAME = "dai.gui" QML_IMPORT_MAJOR_VERSION = 1 @@ -40,11 +41,16 @@ def update_frame(self, image): class DemoQtGui: instance = None writer = None + window = None def __init__(self): self.app = QGuiApplication() self.engine = QQmlApplicationEngine() self.setInstance() + self.engine.load(Path(__file__).parent / "views" / "root.qml") + self.window = self.engine.rootObjects()[0] + if not self.engine.rootObjects(): + raise RuntimeError("Unable to start GUI - no root objects!") def setInstance(self): DemoQtGui.instance = self @@ -52,16 +58,22 @@ def setInstance(self): @Slot(list) def setData(self, data): name, value = data - self.engine.rootContext().setContextProperty(name, value) + self.window.setProperty(name, value) + + @Slot(str) + def showError(self, error): + msgBox = QMessageBox() + msgBox.setIcon(QMessageBox.Information) + msgBox.setText(error) + msgBox.setWindowTitle("Error occured") + msgBox.setStandardButtons(QMessageBox.Ok) + msgBox.show() @Slot(QImage) def updatePreview(self, data): self.writer.update_frame(data) def startGui(self): - self.engine.load(Path(__file__).parent / "views" / "root.qml") - if not self.engine.rootObjects(): - raise RuntimeError("Unable to start GUI - no root objects!") self.writer = ImageWriter() return self.app.exec() @@ -101,7 +113,8 @@ def setSbb(self, value): @Slot(float) def setSbbFactor(self, value): - DemoQtGui.instance.guiOnAiSetupUpdate(sbbFactor=value) + if DemoQtGui.writer is not None: + DemoQtGui.instance.guiOnAiSetupUpdate(sbbFactor=value) @Slot(str) def setOvVersion(self, state): diff --git a/gui/views/AIProperties.qml b/gui/views/AIProperties.qml index a5981afd5..9b8b43ee7 100644 --- a/gui/views/AIProperties.qml +++ b/gui/views/AIProperties.qml @@ -100,25 +100,11 @@ ListView { font.weight: Font.Bold } - Text { - id: text35 - x: 196 - y: 101 - width: 18 - height: 20 - color: "#ffffff" - text: qsTr("0") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - rotation: 0 - } - Slider { id: lrcSlider x: 221 y: 95 - width: 281 + width: 261 height: 33 value: 6 stepSize: 1 @@ -131,12 +117,12 @@ ListView { Text { id: text37 - x: 508 + x: 482 y: 101 width: 18 height: 20 color: "#ffffff" - text: qsTr("16") + text: lrcSlider.value font.pixelSize: 12 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter @@ -293,48 +279,34 @@ ListView { font.weight: Font.Bold } - Text { - id: text38 - x: 418 - y: 389 - width: 18 - height: 20 - color: "#ffffff" - text: qsTr("0") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - rotation: 0 + Slider { + id: sbbFactorSlider + x: 423 + y: 383 + width: 96 + height: 33 + value: 6 + stepSize: 0.1 + onValueChanged: { + aiBridge.setSbbFactor(value) + } + to: 1 + from: 0.1 } Text { id: text39 - x: 547 + x: 527 y: 389 width: 18 height: 20 color: "#ffffff" - text: qsTr("1") + text: sbbFactorSlider.value.toFixed(1) font.pixelSize: 12 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter rotation: 0 } - - Slider { - id: lrcSlider1 - x: 443 - y: 383 - width: 96 - height: 33 - value: 6 - stepSize: 1 - onValueChanged: { - aiBridge.setSbbFactor(value) - } - to: 16 - from: 0 - } } } diff --git a/gui/views/DepthProperties.qml b/gui/views/DepthProperties.qml index 5e240458d..3bb4c06ba 100644 --- a/gui/views/DepthProperties.qml +++ b/gui/views/DepthProperties.qml @@ -32,7 +32,7 @@ ListView { } Slider { - id: slider + id: dctSlider x: 360 y: 89 width: 200 @@ -122,7 +122,7 @@ ListView { } Slider { - id: slider1 + id: sigmaSlider x: 362 y: 133 width: 200 @@ -136,25 +136,14 @@ ListView { } } - Text { - id: text4 - x: 340 - y: 89 - width: 14 - height: 25 - color: "#ffffff" - text: qsTr("0") - font.pixelSize: 12 - } - Text { id: text5 x: 566 - y: 89 + y: 95 width: 17 height: 25 color: "#ffffff" - text: qsTr("255") + text: dctSlider.value font.pixelSize: 12 } @@ -173,17 +162,6 @@ ListView { font.family: "Courier" } - Text { - id: text7 - x: 337 - y: 133 - width: 17 - height: 25 - color: "#ffffff" - text: qsTr("0") - font.pixelSize: 12 - } - Text { id: text8 x: 566 @@ -191,7 +169,7 @@ ListView { width: 17 height: 20 color: "#ffffff" - text: qsTr("255") + text: sigmaSlider.value font.pixelSize: 12 rotation: 0 } @@ -212,13 +190,13 @@ ListView { } RangeSlider { - id: rangeSlider + id: depthRangeSlider x: 364 y: 181 width: 198 height: 27 snapMode: RangeSlider.NoSnap - stepSize: 1 + stepSize: 100 to: 10000 focusPolicy: Qt.StrongFocus second.value: 10000 @@ -252,7 +230,7 @@ ListView { width: 17 height: 20 color: "#ffffff" - text: qsTr("10m") + text: (depthRangeSlider.second.value / 1000).toFixed(1) + "m" font.pixelSize: 12 rotation: 0 } @@ -264,7 +242,7 @@ ListView { width: 17 height: 20 color: "#ffffff" - text: qsTr("0m") + text: (depthRangeSlider.first.value / 1000).toFixed(1) + "m" font.pixelSize: 12 rotation: 0 } @@ -306,7 +284,7 @@ ListView { width: 17 height: 20 color: "#ffffff" - text: qsTr("10") + text: lrcSlider.value font.pixelSize: 12 rotation: 0 } @@ -318,7 +296,6 @@ ListView { width: 17 height: 20 color: "#ffffff" - text: qsTr("0") font.pixelSize: 12 rotation: 0 } diff --git a/gui/views/root.qml b/gui/views/root.qml index b0ec18d28..fe191b807 100644 --- a/gui/views/root.qml +++ b/gui/views/root.qml @@ -53,6 +53,7 @@ import QtQuick.Layouts 1.11 import QtQuick.Controls 2.1 import QtQuick.Window 2.1 import QtQuick.Controls.Material 2.1 +import Qt.labs.platform 1.1 import dai.gui 1.0 @@ -63,6 +64,16 @@ ApplicationWindow { Material.accent: Material.Red visible: true + property var previewChoices + property var modelChoices + property var modelSourceChoices + property var ovVersions + property var countLabels + property var medianChoices + property var colorResolutionChoices + property var monoResolutionChoices + property var restartRequired + AppBridge { id: appBridge } @@ -140,7 +151,7 @@ ApplicationWindow { Button { x: 667 y: 540 - enabled: restartRequired + enabled: restartRequired || false height: 60 width: 563 text: "Apply and Restart" From 18d18127a6b20620694d6cbaaf4cd850a9776247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Fri, 29 Oct 2021 16:32:16 +0200 Subject: [PATCH 24/57] add error handling --- depthai_demo.py | 15 ++++++++++++++- gui/main.py | 13 ++----------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 8bf597f1e..3d5421666 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 import os +import sys import time +import traceback from functools import cmp_to_key from itertools import cycle from pathlib import Path @@ -486,6 +488,7 @@ def _printSysInfo(self, info): from PySide6.QtGui import QImage from PySide6.QtCore import QRunnable, Slot, QThreadPool, QObject, Signal + from PySide6.QtWidgets import QMessageBox class WorkerSignals(QObject): @@ -519,7 +522,7 @@ def terminate(self): self.signals.setDataSignal.emit(["restartRequired", False]) def onError(self, ex: Exception): - pass + self.signals.errorSignal.emit(''.join(traceback.format_tb(ex.__traceback__))) def shouldRun(self): return self.running @@ -562,6 +565,16 @@ def updateArg(self, arg_name, arg_value): setattr(confManager.args, arg_name, arg_value) self.worker.signals.setDataSignal.emit(["restartRequired", True]) + @Slot(str) + def showError(self, error): + print(error, file=sys.stderr) + msgBox = QMessageBox() + msgBox.setIcon(QMessageBox.Information) + msgBox.setText(error) + msgBox.setWindowTitle("Error occured") + msgBox.setStandardButtons(QMessageBox.Ok) + msgBox.exec() + def start(self): self.running = True self.worker = Worker(self._demoInstance, selectedPreview=self.selectedPreview) diff --git a/gui/main.py b/gui/main.py index eceba06e2..a182562e9 100644 --- a/gui/main.py +++ b/gui/main.py @@ -9,7 +9,7 @@ # To be used on the @QmlElement decorator # (QML_IMPORT_MINOR_VERSION is optional) from PySide6.QtQuick import QQuickPaintedItem -from PySide6.QtWidgets import QMessageBox +from PySide6.QtWidgets import QMessageBox, QApplication QML_IMPORT_NAME = "dai.gui" QML_IMPORT_MAJOR_VERSION = 1 @@ -44,7 +44,7 @@ class DemoQtGui: window = None def __init__(self): - self.app = QGuiApplication() + self.app = QApplication() self.engine = QQmlApplicationEngine() self.setInstance() self.engine.load(Path(__file__).parent / "views" / "root.qml") @@ -60,15 +60,6 @@ def setData(self, data): name, value = data self.window.setProperty(name, value) - @Slot(str) - def showError(self, error): - msgBox = QMessageBox() - msgBox.setIcon(QMessageBox.Information) - msgBox.setText(error) - msgBox.setWindowTitle("Error occured") - msgBox.setStandardButtons(QMessageBox.Ok) - msgBox.show() - @Slot(QImage) def updatePreview(self, data): self.writer.update_frame(data) From 5d61fda4e7a1aee8f4218349e3af902ec7455d37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Fri, 29 Oct 2021 16:38:13 +0200 Subject: [PATCH 25/57] change icons --- depthai_demo.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 3d5421666..3dd7dc848 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -569,9 +569,9 @@ def updateArg(self, arg_name, arg_value): def showError(self, error): print(error, file=sys.stderr) msgBox = QMessageBox() - msgBox.setIcon(QMessageBox.Information) + msgBox.setIcon(QMessageBox.Critical) msgBox.setText(error) - msgBox.setWindowTitle("Error occured") + msgBox.setWindowTitle("An error occured") msgBox.setStandardButtons(QMessageBox.Ok) msgBox.exec() From 10c23e2f802e6a80946b2c40158c37e4142c761b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Fri, 29 Oct 2021 16:42:32 +0200 Subject: [PATCH 26/57] handle more queues gracefully --- depthai_demo.py | 2 +- depthai_sdk/src/depthai_sdk/managers/nnet_manager.py | 5 +++-- .../src/depthai_sdk/managers/pipeline_manager.py | 12 ++++++++---- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 3dd7dc848..2b8d2b0f4 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -522,7 +522,7 @@ def terminate(self): self.signals.setDataSignal.emit(["restartRequired", False]) def onError(self, ex: Exception): - self.signals.errorSignal.emit(''.join(traceback.format_tb(ex.__traceback__))) + self.signals.errorSignal.emit(''.join(traceback.format_tb(ex.__traceback__) + [str(ex)])) def shouldRun(self): return self.running diff --git a/depthai_sdk/src/depthai_sdk/managers/nnet_manager.py b/depthai_sdk/src/depthai_sdk/managers/nnet_manager.py index 4c99a0a67..6de9288ed 100644 --- a/depthai_sdk/src/depthai_sdk/managers/nnet_manager.py +++ b/depthai_sdk/src/depthai_sdk/managers/nnet_manager.py @@ -345,9 +345,10 @@ def closeQueues(self): """ Closes output queues created by :func:`createQueues` """ - if self.source == "host": + if self.source == "host" and self.inputQueue is not None: self.inputQueue.close() - self.outputQueue.close() + if self.outputQueue is not None: + self.outputQueue.close() def sendInputFrame(self, frame, seqNum=None): """ diff --git a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py index 0abf5559d..acf63bf16 100644 --- a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py +++ b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py @@ -69,10 +69,14 @@ def closeDefaultQueues(self): device (depthai.Device): Running device instance """ - self._depthConfigInputQueue.close() - self._rgbConfigInputQueue.close() - self._leftConfigInputQueue.close() - self._rightConfigInputQueue.close() + if self._depthConfigInputQueue is not None: + self._depthConfigInputQueue.close() + if self._rgbConfigInputQueue is not None: + self._rgbConfigInputQueue.close() + if self._leftConfigInputQueue is not None: + self._leftConfigInputQueue.close() + if self._rightConfigInputQueue is not None: + self._rightConfigInputQueue.close() def __calcEncodeableSize(self, sourceSize): w, h = sourceSize From 927603d3da58786d164fbb1884aa32456e355dfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Mon, 1 Nov 2021 08:41:12 +0100 Subject: [PATCH 27/57] enable LRC switch on runtime --- depthai_demo.py | 9 +++------ depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py | 7 +++++-- gui/main.py | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 2b8d2b0f4..f2065248f 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -607,9 +607,8 @@ def restartDemo(self): self.stop() self.start() - def guiOnDepthConfigUpdate(self, median=None, dct=None, sigma=None, lrcThreshold=None): - print("median", median) - self._demoInstance._pm.updateDepthConfig(self._demoInstance._device, median=median, dct=dct, sigma=sigma, lrcThreshold=lrcThreshold) + def guiOnDepthConfigUpdate(self, median=None, dct=None, sigma=None, lrc=None, lrcThreshold=None): + self._demoInstance._pm.updateDepthConfig(self._demoInstance._device, median=median, dct=dct, sigma=sigma, lrc=lrc, lrcThreshold=lrcThreshold) def guiOnCameraConfigUpdate(self, name, exposure=None, sensitivity=None, saturation=None, contrast=None, brightness=None, sharpness=None): if name == "color": @@ -620,7 +619,7 @@ def guiOnCameraConfigUpdate(self, name, exposure=None, sensitivity=None, saturat fun = self._demoInstance._pm.updateRightCamConfig fun(self._demoInstance._device, exposure, sensitivity, saturation, contrast, brightness, sharpness) - def guiOnDepthSetupUpdate(self, depthFrom=None, depthTo=None, subpixel=None, lrc=None, extended=None): + def guiOnDepthSetupUpdate(self, depthFrom=None, depthTo=None, subpixel=None, extended=None): if depthFrom is not None: self.updateArg("minDepth", depthFrom) if depthTo is not None: @@ -629,8 +628,6 @@ def guiOnDepthSetupUpdate(self, depthFrom=None, depthTo=None, subpixel=None, lrc self.updateArg("subpixel", subpixel) if extended is not None: self.updateArg("extendedDisparity", extended) - if lrc is not None: - self.updateArg("stereoLrCheck", lrc) def guiOnCameraSetupUpdate(self, name, fps=None, resolution=None): if fps is not None: diff --git a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py index acf63bf16..7fe200426 100644 --- a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py +++ b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py @@ -249,6 +249,7 @@ def createDepth(self, dct=245, median=dai.MedianFilter.KERNEL_7x7, sigma=0, lr=F self.nodes.stereo.initialConfig.setLeftRightCheckThreshold(lrcThreshold) self._depthConfig.setLeftRightCheckThreshold(lrcThreshold) + self.nodes.stereo.setRuntimeModeSwitch(True) self.nodes.stereo.setLeftRightCheck(lr) self.nodes.stereo.setExtendedDisparity(extended) self.nodes.stereo.setSubpixel(subpixel) @@ -361,7 +362,7 @@ def updateRightCamConfig(self, device, exposure=None, sensitivity=None, saturati self._updateCamConfig(self._rightConfig, Previews.right.name, device, exposure, sensitivity, saturation, contrast, brightness, sharpness) self._rightConfigInputQueue.send(self._rightConfig) - def updateDepthConfig(self, device, dct=None, sigma=None, median=None, lrcThreshold=None): + def updateDepthConfig(self, device, dct=None, sigma=None, median=None, lrc=None, lrcThreshold=None): """ Updates :obj:`depthai.node.StereoDepth` node config @@ -371,6 +372,7 @@ def updateDepthConfig(self, device, dct=None, sigma=None, median=None, lrcThresh are present in the depth map. median (depthai.MedianFilter, Optional): Median filter to be applied on the depth, use with :obj:`depthai.MedianFilter.MEDIANOFF` to disable median filtering sigma (int, Optional): Sigma value for bilateral filter (0..65535). If set to :code:`0`, the filter will be disabled. + lrc (bool, Optional): Enables or disables Left-Right Check mode lrcThreshold (int, Optional): Sets the Left-Right Check threshold value (0..10) """ if dct is not None: @@ -381,7 +383,8 @@ def updateDepthConfig(self, device, dct=None, sigma=None, median=None, lrcThresh self._depthConfig.setMedianFilter(median) if lrcThreshold is not None: self._depthConfig.setLeftRightCheckThreshold(lrcThreshold) - print("SENDING") + if lrc is not None: + self._depthConfig.setLeftRightCheck(lrc) self._depthConfigInputQueue.send(self._depthConfig) def addNn(self, nn, sync=False, useDepth=False, xoutNnInput=False, xoutSbb=False): diff --git a/gui/main.py b/gui/main.py index a182562e9..1f969a4f5 100644 --- a/gui/main.py +++ b/gui/main.py @@ -135,7 +135,7 @@ def toggleExtendedDisparity(self, state): @Slot(bool) def toggleLeftRightCheck(self, state): - DemoQtGui.instance.guiOnDepthSetupUpdate(lrc=state) + DemoQtGui.instance.guiOnDepthConfigUpdate(lrc=state) @Slot(int) def setDisparityConfidenceThreshold(self, value): From 650e85e34624bad1f8a434fbde0d396cce6ca0cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Mon, 1 Nov 2021 09:18:55 +0100 Subject: [PATCH 28/57] change xlinkin's size --- depthai_demo.py | 2 +- depthai_sdk/src/depthai_sdk/managers/nnet_manager.py | 1 + depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/depthai_demo.py b/depthai_demo.py index f2065248f..703c38d99 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -555,7 +555,7 @@ class App(DemoQtGui): def __init__(self): super().__init__() self.running = False - self.selectedPreview = "color" + self.selectedPreview = confManager.args.show[0] self.dataInitialized = False self.appInitialized = False self.threadpool = QThreadPool() diff --git a/depthai_sdk/src/depthai_sdk/managers/nnet_manager.py b/depthai_sdk/src/depthai_sdk/managers/nnet_manager.py index 6de9288ed..63f5e32bd 100644 --- a/depthai_sdk/src/depthai_sdk/managers/nnet_manager.py +++ b/depthai_sdk/src/depthai_sdk/managers/nnet_manager.py @@ -173,6 +173,7 @@ def createNN(self, pipeline, nodes, blobPath, source="color", flipDetection=Fals nodes.camRgb.preview.link(nodes.nn.input) elif self.source == "host": nodes.xinNn = pipeline.createXLinkIn() + self.nodes.xinRgbControl.setMaxDataSize(self.inputSize[0] * self.inputSize[1] * 3) nodes.xinNn.setStreamName("nnIn") nodes.xinNn.out.link(nodes.nn.input) elif self.source in ("left", "right", "rectifiedLeft", "rectifiedRight"): diff --git a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py index 7fe200426..feb96b3c3 100644 --- a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py +++ b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py @@ -157,6 +157,7 @@ def createColorCam(self, previewSize=None, res=dai.ColorCameraProperties.SensorR else: self.nodes.camRgb.video.link(self.nodes.xoutRgb.input) self.nodes.xinRgbControl = self.pipeline.createXLinkIn() + self.nodes.xinRgbControl.setMaxDataSize(1) self.nodes.xinRgbControl.setStreamName(Previews.color.name + "_control") self.nodes.xinRgbControl.out.link(self.nodes.camRgb.inputControl) @@ -186,6 +187,7 @@ def createLeftCam(self, res=dai.MonoCameraProperties.SensorResolution.THE_720_P, else: self.nodes.monoLeft.out.link(self.nodes.xoutLeft.input) self.nodes.xinLeftControl = self.pipeline.createXLinkIn() + self.nodes.xinLeftControl.setMaxDataSize(1) self.nodes.xinLeftControl.setStreamName(Previews.left.name + "_control") self.nodes.xinLeftControl.out.link(self.nodes.monoLeft.inputControl) @@ -214,6 +216,7 @@ def createRightCam(self, res=dai.MonoCameraProperties.SensorResolution.THE_720_P else: self.nodes.monoRight.out.link(self.nodes.xoutRight.input) self.nodes.xinRightControl = self.pipeline.createXLinkIn() + self.nodes.xinRightControl.setMaxDataSize(1) self.nodes.xinRightControl.setStreamName(Previews.right.name + "_control") self.nodes.xinRightControl.out.link(self.nodes.monoRight.inputControl) @@ -264,6 +267,7 @@ def createDepth(self, dct=245, median=dai.MedianFilter.KERNEL_7x7, sigma=0, lr=F self.nodes.monoRight.out.link(self.nodes.stereo.right) self.nodes.xinStereoConfig = self.pipeline.createXLinkIn() + self.nodes.xinStereoConfig.setMaxDataSize(1) self.nodes.xinStereoConfig.setStreamName("stereoConfig") self.nodes.xinStereoConfig.out.link(self.nodes.stereo.inputConfig) From 31fbd873254082979cfd2a415af3097299d2d238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Mon, 1 Nov 2021 09:40:01 +0100 Subject: [PATCH 29/57] enable better disparity mapping (with subpixel) --- depthai_demo.py | 5 +++-- .../src/depthai_sdk/managers/preview_manager.py | 6 ++++-- depthai_sdk/src/depthai_sdk/previews.py | 14 +++++++++++--- gui/views/DepthProperties.qml | 1 + 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 703c38d99..14d484f35 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -140,7 +140,8 @@ def setup(self): if self._conf.useCamera or self._conf.args.sync: self._pv = PreviewManager(display=self._conf.args.show, nnSource=self._conf.getModelSource(), colorMap=self._conf.getColorMap(), dispMultiplier=self._conf.dispMultiplier, mouseTracker=True, lowBandwidth=self._conf.lowBandwidth, - scale=self._conf.args.scale, sync=self._conf.args.sync, fpsHandler=self._fps, createWindows=self._displayFrames) + scale=self._conf.args.scale, sync=self._conf.args.sync, fpsHandler=self._fps, createWindows=self._displayFrames, + depthConfig=self._pm._depthConfig) if self._conf.leftCameraEnabled: self._pm.createLeftCam(self._monoRes, self._conf.args.monoFps, @@ -555,7 +556,7 @@ class App(DemoQtGui): def __init__(self): super().__init__() self.running = False - self.selectedPreview = confManager.args.show[0] + self.selectedPreview = confManager.args.show[0] if len(confManager.args.show) > 0 else "color" self.dataInitialized = False self.appInitialized = False self.threadpool = QThreadPool() diff --git a/depthai_sdk/src/depthai_sdk/managers/preview_manager.py b/depthai_sdk/src/depthai_sdk/managers/preview_manager.py index 30aa68f93..62086a659 100644 --- a/depthai_sdk/src/depthai_sdk/managers/preview_manager.py +++ b/depthai_sdk/src/depthai_sdk/managers/preview_manager.py @@ -13,7 +13,7 @@ class PreviewManager: #: dict: Contains name -> frame mapping that can be used to modify specific frames directly frames = {} - def __init__(self, display=[], nnSource=None, colorMap=cv2.COLORMAP_JET, dispMultiplier=255/96, mouseTracker=False, lowBandwidth=False, scale=None, sync=False, fpsHandler=None, createWindows=True): + def __init__(self, display=[], nnSource=None, colorMap=cv2.COLORMAP_JET, depthConfig=None, dispMultiplier=255/96, mouseTracker=False, lowBandwidth=False, scale=None, sync=False, fpsHandler=None, createWindows=True): """ Args: display (list, Optional): List of :obj:`depthai_sdk.Previews` objects representing the streams to display @@ -24,7 +24,8 @@ def __init__(self, display=[], nnSource=None, colorMap=cv2.COLORMAP_JET, dispMul colorMap (cv2 color map, Optional): Color map applied on the depth frames lowBandwidth (bool, Optional): If set to :code:`True`, will decode the received frames assuming they were encoded with MJPEG encoding scale (dict, Optional): Allows to scale down frames before preview. Useful when previewing e.g. 4K frames - dispMultiplier (float, Optional): Value used for depth <-> disparity calculations + dispMultiplier (float, Optional): Multiplier used for depth <-> disparity calculations (calculated on baseline and focal) + depthConfig (depthai.StereoDepthConfig, optional): Configuration used for depth <-> disparity calculations createWindows (bool, Optional): If True, will create preview windows using OpenCV (enabled by default) """ self.sync = sync @@ -33,6 +34,7 @@ def __init__(self, display=[], nnSource=None, colorMap=cv2.COLORMAP_JET, dispMul self.lowBandwidth = lowBandwidth self.scale = scale self.dispMultiplier = dispMultiplier + self._depthConfig = depthConfig self._fpsHandler = fpsHandler self._mouseTracker = MouseClickTracker() if mouseTracker else None self._display = display diff --git a/depthai_sdk/src/depthai_sdk/previews.py b/depthai_sdk/src/depthai_sdk/previews.py index 04c7d7823..5b1bc565b 100644 --- a/depthai_sdk/src/depthai_sdk/previews.py +++ b/depthai_sdk/src/depthai_sdk/previews.py @@ -143,6 +143,13 @@ def depth(depthRaw, manager=None): Returns: numpy.ndarray: Ready to use OpenCV frame """ + if getattr(manager, "_depthConfig", None) is None: + raise RuntimeError("Depth config has to be provided before decoding depth data") + + maxDisp = manager._depthConfig.getMaxDisparity() + subpixelLevels = pow(2, manager._depthConfig.get().algorithmControl.subpixelFractionalBits) + subpixel = manager._depthConfig.get().algorithmControl.enableSubpixel + dispIntegerLevels = maxDisp if not subpixel else maxDisp / subpixelLevels dispScaleFactor = getattr(manager, "dispScaleFactor", None) if dispScaleFactor is None: baseline = getattr(manager, 'baseline', 75) # mm @@ -151,10 +158,11 @@ def depth(depthRaw, manager=None): dispScaleFactor = baseline * focal if manager is not None: setattr(manager, "dispScaleFactor", dispScaleFactor) - - with np.errstate(divide='ignore'): # Should be safe to ignore div by zero here + with np.errstate(divide='ignore'): dispFrame = dispScaleFactor / depthRaw - dispFrame = (dispFrame * manager.dispMultiplier).astype(np.uint8) + + dispFrame = (dispFrame * 255. / dispIntegerLevels).astype(np.uint8) + return PreviewDecoder.disparityColor(dispFrame, manager) @staticmethod diff --git a/gui/views/DepthProperties.qml b/gui/views/DepthProperties.qml index 3bb4c06ba..4b2d9a58e 100644 --- a/gui/views/DepthProperties.qml +++ b/gui/views/DepthProperties.qml @@ -77,6 +77,7 @@ ListView { } Switch { + enabled: false id: switch2 x: 0 y: 233 From 54ec1149ebececd5e488fd48c69bf8d84de3ff27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Mon, 1 Nov 2021 10:22:15 +0100 Subject: [PATCH 30/57] Add device selection --- depthai_demo.py | 22 +++++++++++++++++++++- gui/main.py | 8 ++++++++ gui/views/CameraPreview.qml | 25 +++++++++++++++++++++++-- gui/views/root.qml | 1 + 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 14d484f35..64a5cc131 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -512,6 +512,16 @@ def run(self): self.running = True self.signals.setDataSignal.emit(["restartRequired", False]) self.instance.setCallbacks(shouldRun=self.shouldRun, onShowFrame=self.onShowFrame, onSetup=self.onSetup) + if confManager.args.deviceId is None: + devices = dai.Device.getAllAvailableDevices() + if len(devices) > 0: + defaultDevice = next(map( + lambda info: info.getMxId(), + filter(lambda info: info.desc.protocol == dai.XLinkProtocol.X_LINK_USB_VSC, devices) + ), None) + if defaultDevice is None: + defaultDevice = devices[0].getMxId() + confManager.args.deviceId = defaultDevice try: self.instance.run_all() except Exception as ex: @@ -548,6 +558,8 @@ def onSetup(self, instance): self.signals.setDataSignal.emit(["modelSourceChoices", [Previews.color.name, Previews.left.name, Previews.right.name]]) versionChoices = list(filter(lambda name: name.startswith("VERSION_"), vars(dai.OpenVINO).keys())) self.signals.setDataSignal.emit(["ovVersions", versionChoices]) + devices = [self.instance._deviceInfo.getMxId()] + list(map(lambda info: info.getMxId(), dai.Device.getAllAvailableDevices())) + self.signals.setDataSignal.emit(["deviceChoices", devices]) self.signals.setDataSignal.emit(["countLabels", instance._nnManager._labels]) self.signals.setDataSignal.emit(["modelChoices", sorted(confManager.getAvailableZooModels(), key=cmp_to_key(lambda a, b: -1 if a == "mobilenet-ssd" else 1 if b == "mobilenet-ssd" else -1 if a < b else 1))]) @@ -662,9 +674,17 @@ def guiOnAiSetupUpdate(self, cnn=None, shave=None, source=None, fullFov=None, sy if countLabel is not None: self.updateArg("countLabel", countLabel) - def guiOnPreviewChangeSelected(self, selected): self.worker.selectedPreview = selected self.selectedPreview = selected + def guiOnSelectDevice(self, selected): + self.updateArg("deviceId", selected) + + def guiOnReloadDevices(self): + devices = list(map(lambda info: info.getMxId(), dai.Device.getAllAvailableDevices())) + if hasattr(self._demoInstance, "_deviceInfo"): + devices.append(self._demoInstance._deviceInfo.getMxId()) + self.worker.signals.setDataSignal.emit(["deviceChoices", devices]) + App().start() \ No newline at end of file diff --git a/gui/main.py b/gui/main.py index 1f969a4f5..f3d4b47a8 100644 --- a/gui/main.py +++ b/gui/main.py @@ -75,6 +75,14 @@ class AppBridge(QObject): def applyAndRestart(self): DemoQtGui.instance.restartDemo() + @Slot() + def reloadDevices(self): + DemoQtGui.instance.guiOnReloadDevices() + + @Slot(str) + def selectDevice(self, value): + DemoQtGui.instance.guiOnSelectDevice(value) + @QmlElement class AIBridge(QObject): diff --git a/gui/views/CameraPreview.qml b/gui/views/CameraPreview.qml index cfc27de1f..7d22dc6ef 100644 --- a/gui/views/CameraPreview.qml +++ b/gui/views/CameraPreview.qml @@ -17,9 +17,9 @@ ListView { ComboBox { id: comboBoxImage - x: 210 + x: 100 y: 5 - width: 200 + width: 150 height: 30 model: previewChoices onActivated: function(index) { @@ -27,6 +27,27 @@ ListView { } } + ComboBox { + id: comboBoxDevices + x: 260 + y: 5 + width: 200 + height: 30 + model: deviceChoices + onActivated: function(index) { + appBridge.selectDevice(model[index]) + } + } + + Button { + x: 470 + y: 5 + height: 30 + width: 100 + text: "Reload" + onClicked: appBridge.reloadDevices() + } + ImageWriter { id: imageWriter x: 40 diff --git a/gui/views/root.qml b/gui/views/root.qml index fe191b807..69067f9a0 100644 --- a/gui/views/root.qml +++ b/gui/views/root.qml @@ -73,6 +73,7 @@ ApplicationWindow { property var colorResolutionChoices property var monoResolutionChoices property var restartRequired + property var deviceChoices AppBridge { id: appBridge From 3dba485c94f75558d884b02f228531f401d0004a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Mon, 1 Nov 2021 10:27:32 +0100 Subject: [PATCH 31/57] bump max data size --- depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py index feb96b3c3..15aff34d1 100644 --- a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py +++ b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py @@ -157,7 +157,7 @@ def createColorCam(self, previewSize=None, res=dai.ColorCameraProperties.SensorR else: self.nodes.camRgb.video.link(self.nodes.xoutRgb.input) self.nodes.xinRgbControl = self.pipeline.createXLinkIn() - self.nodes.xinRgbControl.setMaxDataSize(1) + self.nodes.xinRgbControl.setMaxDataSize(1024) self.nodes.xinRgbControl.setStreamName(Previews.color.name + "_control") self.nodes.xinRgbControl.out.link(self.nodes.camRgb.inputControl) @@ -187,7 +187,7 @@ def createLeftCam(self, res=dai.MonoCameraProperties.SensorResolution.THE_720_P, else: self.nodes.monoLeft.out.link(self.nodes.xoutLeft.input) self.nodes.xinLeftControl = self.pipeline.createXLinkIn() - self.nodes.xinLeftControl.setMaxDataSize(1) + self.nodes.xinLeftControl.setMaxDataSize(1024) self.nodes.xinLeftControl.setStreamName(Previews.left.name + "_control") self.nodes.xinLeftControl.out.link(self.nodes.monoLeft.inputControl) @@ -216,7 +216,7 @@ def createRightCam(self, res=dai.MonoCameraProperties.SensorResolution.THE_720_P else: self.nodes.monoRight.out.link(self.nodes.xoutRight.input) self.nodes.xinRightControl = self.pipeline.createXLinkIn() - self.nodes.xinRightControl.setMaxDataSize(1) + self.nodes.xinRightControl.setMaxDataSize(1024) self.nodes.xinRightControl.setStreamName(Previews.right.name + "_control") self.nodes.xinRightControl.out.link(self.nodes.monoRight.inputControl) @@ -267,7 +267,7 @@ def createDepth(self, dct=245, median=dai.MedianFilter.KERNEL_7x7, sigma=0, lr=F self.nodes.monoRight.out.link(self.nodes.stereo.right) self.nodes.xinStereoConfig = self.pipeline.createXLinkIn() - self.nodes.xinStereoConfig.setMaxDataSize(1) + self.nodes.xinStereoConfig.setMaxDataSize(1024) self.nodes.xinStereoConfig.setStreamName("stereoConfig") self.nodes.xinStereoConfig.out.link(self.nodes.stereo.inputConfig) From 5aef6b3395efa4161f4b8074f1690ebc9d3c723d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Mon, 1 Nov 2021 11:43:16 +0100 Subject: [PATCH 32/57] preserve config values after demo restart --- depthai_demo.py | 75 ++++++++++++++++--- depthai_helpers/arg_manager.py | 12 +-- depthai_helpers/config_manager.py | 2 - .../depthai_sdk/managers/pipeline_manager.py | 16 ++-- 4 files changed, 78 insertions(+), 27 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 64a5cc131..5ddd0f16c 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -209,7 +209,7 @@ def run(self): self._medianFilters = cycle([item for name, item in vars(dai.MedianFilter).items() if name.startswith('KERNEL_') or name.startswith('MEDIAN_')]) for medFilter in self._medianFilters: # move the cycle to the current median filter - if medFilter == self._pm._depthConfig.getMedianFilter(): + if medFilter == self._pm._depthConfig.postProcessing.median: break if self._conf.useCamera: @@ -390,18 +390,34 @@ def _createQueueCallback(self, queueName): lambda value: self._pm.updateDepthConfig(self._device, lrcThreshold=value)) def _updateCameraConfigs(self): - if self._conf.leftCameraEnabled: - self._pm.updateLeftCamConfig(self._device, **self._cameraConfig) - if self._conf.rightCameraEnabled: - self._pm.updateRightCamConfig(self._device, **self._cameraConfig) - if self._conf.rgbCameraEnabled: - self._pm.updateColorCamConfig(self._device, **self._cameraConfig) + parsedConfig = {} + print(self._cameraConfig) + for configOption, values in self._cameraConfig.items(): + if values is not None: + for cameraName, value in values: + newConfig = { + **parsedConfig.get(cameraName, {}), + configOption: value + } + if cameraName == "all": + parsedConfig[Previews.left.name] = newConfig + parsedConfig[Previews.right.name] = newConfig + parsedConfig[Previews.color.name] = newConfig + else: + parsedConfig[cameraName] = newConfig + + if self._conf.leftCameraEnabled and Previews.left.name in parsedConfig: + self._pm.updateLeftCamConfig(self._device, **parsedConfig[Previews.left.name]) + if self._conf.rightCameraEnabled and Previews.right.name in parsedConfig: + self._pm.updateRightCamConfig(self._device, **parsedConfig[Previews.right.name]) + if self._conf.rgbCameraEnabled and Previews.color.name in parsedConfig: + self._pm.updateColorCamConfig(self._device, **parsedConfig[Previews.color.name]) def _showFramesCallback(self, frame, name): self._fps.drawFps(frame, name) h, w = frame.shape[:2] if name in [Previews.disparityColor.name, Previews.disparity.name, Previews.depth.name, Previews.depthRaw.name]: - text = "Median filter: {} [M]".format(self._pm._depthConfig.getMedianFilter().name.lstrip("KERNEL_").lstrip("MEDIAN_")) + text = "Median filter: {} [M]".format(self._pm._depthConfig.postProcessing.median.name.lstrip("KERNEL_").lstrip("MEDIAN_")) cv2.putText(frame, text, (10, h - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, 0, 4) cv2.putText(frame, text, (10, h - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, 255, 1) elif self._conf.args.cameraControlls and name in [Previews.color.name, Previews.left.name, Previews.right.name]: @@ -574,9 +590,10 @@ def __init__(self): self.threadpool = QThreadPool() self._demoInstance = Demo(confManager, displayFrames=False) - def updateArg(self, arg_name, arg_value): + def updateArg(self, arg_name, arg_value, shouldUpdate=True): setattr(confManager.args, arg_name, arg_value) - self.worker.signals.setDataSignal.emit(["restartRequired", True]) + if shouldUpdate: + self.worker.signals.setDataSignal.emit(["restartRequired", True]) @Slot(str) def showError(self, error): @@ -622,6 +639,23 @@ def restartDemo(self): def guiOnDepthConfigUpdate(self, median=None, dct=None, sigma=None, lrc=None, lrcThreshold=None): self._demoInstance._pm.updateDepthConfig(self._demoInstance._device, median=median, dct=dct, sigma=sigma, lrc=lrc, lrcThreshold=lrcThreshold) + if median is not None: + if median == dai.MedianFilter.MEDIAN_OFF: + self.updateArg("stereoMedianSize", 0, False) + elif median == dai.MedianFilter.KERNEL_3x3: + self.updateArg("stereoMedianSize", 3, False) + elif median == dai.MedianFilter.KERNEL_5x5: + self.updateArg("stereoMedianSize", 5, False) + elif median == dai.MedianFilter.KERNEL_7x7: + self.updateArg("stereoMedianSize", 7, False) + if dct is not None: + self.updateArg("disparityConfidenceThreshold", dct, False) + if sigma is not None: + self.updateArg("sigma", sigma, False) + if lrc is not None: + self.updateArg("stereoLrCheck", lrc, False) + if lrcThreshold is not None: + self.updateArg("lrcThreshold", lrcThreshold, False) def guiOnCameraConfigUpdate(self, name, exposure=None, sensitivity=None, saturation=None, contrast=None, brightness=None, sharpness=None): if name == "color": @@ -632,6 +666,25 @@ def guiOnCameraConfigUpdate(self, name, exposure=None, sensitivity=None, saturat fun = self._demoInstance._pm.updateRightCamConfig fun(self._demoInstance._device, exposure, sensitivity, saturation, contrast, brightness, sharpness) + if exposure is not None: + newValue = list(filter(lambda item: item[0] == name, (confManager.args.cameraExposure or []))) + [(name, exposure)] + self.updateArg("cameraExposure", newValue, False) + if sensitivity is not None: + newValue = list(filter(lambda item: item[0] == name, (confManager.args.cameraSensitivity or []))) + [(name, sensitivity)] + self.updateArg("cameraSensitivity", newValue, False) + if saturation is not None: + newValue = list(filter(lambda item: item[0] == name, (confManager.args.cameraSaturation or []))) + [(name, saturation)] + self.updateArg("cameraSaturation", newValue, False) + if contrast is not None: + newValue = list(filter(lambda item: item[0] == name, (confManager.args.cameraContrast or []))) + [(name, contrast)] + self.updateArg("cameraContrast", newValue, False) + if brightness is not None: + newValue = list(filter(lambda item: item[0] == name, (confManager.args.cameraBrightness or []))) + [(name, brightness)] + self.updateArg("cameraBrightness", newValue, False) + if sharpness is not None: + newValue = list(filter(lambda item: item[0] == name, (confManager.args.cameraSharpness or []))) + [(name, sharpness)] + self.updateArg("cameraSharpness", newValue, False) + def guiOnDepthSetupUpdate(self, depthFrom=None, depthTo=None, subpixel=None, extended=None): if depthFrom is not None: self.updateArg("minDepth", depthFrom) @@ -686,5 +739,7 @@ def guiOnReloadDevices(self): if hasattr(self._demoInstance, "_deviceInfo"): devices.append(self._demoInstance._deviceInfo.getMxId()) self.worker.signals.setDataSignal.emit(["deviceChoices", devices]) + if len(devices) > 0: + self.worker.signals.setDataSignal.emit(["restartRequired", True]) App().start() \ No newline at end of file diff --git a/depthai_helpers/arg_manager.py b/depthai_helpers/arg_manager.py index f398bdb48..41e076b45 100644 --- a/depthai_helpers/arg_manager.py +++ b/depthai_helpers/arg_manager.py @@ -137,11 +137,11 @@ def parseArgs(): "Example: -camo color,ROTATE_180_DEG right,ROTATE_180_DEG left,ROTATE_180_DEG").format(', '.join(orientationChoices)) ) parser.add_argument("--cameraControlls", action="store_true", help="Show camera configuration options in GUI and control them using keyboard") - parser.add_argument("--cameraExposure", type=int, help="Specify camera saturation") - parser.add_argument("--cameraSensitivity", type=int, help="Specify camera sensitivity") - parser.add_argument("--cameraSaturation", type=checkRange(-10, 10), help="Specify image saturation") - parser.add_argument("--cameraContrast", type=checkRange(-10, 10), help="Specify image contrast") - parser.add_argument("--cameraBrightness", type=checkRange(-10, 10), help="Specify image brightness") - parser.add_argument("--cameraSharpness", type=checkRange(0, 4), help="Specify image sharpness") + parser.add_argument("--cameraExposure", type=_comaSeparated("all", int), nargs="+", help="Specify camera saturation") + parser.add_argument("--cameraSensitivity", type=_comaSeparated("all", int), nargs="+", help="Specify camera sensitivity") + parser.add_argument("--cameraSaturation", type=_comaSeparated("all", int), nargs="+", help="Specify image saturation") + parser.add_argument("--cameraContrast", type=_comaSeparated("all", int), nargs="+", help="Specify image contrast") + parser.add_argument("--cameraBrightness", type=_comaSeparated("all", int), nargs="+", help="Specify image brightness") + parser.add_argument("--cameraSharpness", type=_comaSeparated("all", int), nargs="+", help="Specify image sharpness") return parser.parse_args() diff --git a/depthai_helpers/config_manager.py b/depthai_helpers/config_manager.py index 79fd7af6f..f4bbb6e47 100644 --- a/depthai_helpers/config_manager.py +++ b/depthai_helpers/config_manager.py @@ -113,8 +113,6 @@ def getMonoResolution(self): return dai.MonoCameraProperties.SensorResolution.THE_400_P def getMedianFilter(self): - if self.args.subpixel: - return dai.MedianFilter.MEDIAN_OFF if self.args.stereoMedianSize == 3: return dai.MedianFilter.KERNEL_3x3 elif self.args.stereoMedianSize == 5: diff --git a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py index 15aff34d1..23008ce51 100644 --- a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py +++ b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py @@ -244,13 +244,11 @@ def createDepth(self, dct=245, median=dai.MedianFilter.KERNEL_7x7, sigma=0, lr=F self.nodes.stereo = self.pipeline.createStereoDepth() self.nodes.stereo.initialConfig.setConfidenceThreshold(dct) - self._depthConfig.setConfidenceThreshold(dct) self.nodes.stereo.initialConfig.setMedianFilter(median) - self._depthConfig.setMedianFilter(median) self.nodes.stereo.initialConfig.setBilateralFilterSigma(sigma) - self._depthConfig.setBilateralFilterSigma(sigma) self.nodes.stereo.initialConfig.setLeftRightCheckThreshold(lrcThreshold) - self._depthConfig.setLeftRightCheckThreshold(lrcThreshold) + + self._depthConfig = self.nodes.stereo.initialConfig.get() self.nodes.stereo.setRuntimeModeSwitch(True) self.nodes.stereo.setLeftRightCheck(lr) @@ -380,15 +378,15 @@ def updateDepthConfig(self, device, dct=None, sigma=None, median=None, lrc=None, lrcThreshold (int, Optional): Sets the Left-Right Check threshold value (0..10) """ if dct is not None: - self._depthConfig.setConfidenceThreshold(dct) + self._depthConfig.costMatching.confidenceThreshold = dct if sigma is not None: - self._depthConfig.setBilateralFilterSigma(sigma) + self._depthConfig.postProcessing.bilateralSigmaValue = sigma if median is not None: - self._depthConfig.setMedianFilter(median) + self._depthConfig.postProcessing.median = median if lrcThreshold is not None: - self._depthConfig.setLeftRightCheckThreshold(lrcThreshold) + self._depthConfig.algorithmControl.leftRightCheckThreshold = lrcThreshold if lrc is not None: - self._depthConfig.setLeftRightCheck(lrc) + self._depthConfig.algorithmControl.enableLeftRightCheck = lrc self._depthConfigInputQueue.send(self._depthConfig) def addNn(self, nn, sync=False, useDepth=False, xoutNnInput=False, xoutSbb=False): From 9c636d717b06d2e0643be6420ef44bfa70b2812c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Mon, 1 Nov 2021 15:40:17 +0100 Subject: [PATCH 33/57] make single config for mono cameras --- depthai_demo.py | 30 +++-- gui/main.py | 77 +++++++---- gui/views/CameraProperties.qml | 237 +++------------------------------ gui/views/root.qml | 7 +- 4 files changed, 85 insertions(+), 266 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 5ddd0f16c..b3d82e84d 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -406,12 +406,13 @@ def _updateCameraConfigs(self): else: parsedConfig[cameraName] = newConfig - if self._conf.leftCameraEnabled and Previews.left.name in parsedConfig: - self._pm.updateLeftCamConfig(self._device, **parsedConfig[Previews.left.name]) - if self._conf.rightCameraEnabled and Previews.right.name in parsedConfig: - self._pm.updateRightCamConfig(self._device, **parsedConfig[Previews.right.name]) - if self._conf.rgbCameraEnabled and Previews.color.name in parsedConfig: - self._pm.updateColorCamConfig(self._device, **parsedConfig[Previews.color.name]) + if hasattr(self, "_device"): + if self._conf.leftCameraEnabled and Previews.left.name in parsedConfig: + self._pm.updateLeftCamConfig(self._device, **parsedConfig[Previews.left.name]) + if self._conf.rightCameraEnabled and Previews.right.name in parsedConfig: + self._pm.updateRightCamConfig(self._device, **parsedConfig[Previews.right.name]) + if self._conf.rgbCameraEnabled and Previews.color.name in parsedConfig: + self._pm.updateColorCamConfig(self._device, **parsedConfig[Previews.color.name]) def _showFramesCallback(self, frame, name): self._fps.drawFps(frame, name) @@ -550,6 +551,7 @@ def terminate(self): def onError(self, ex: Exception): self.signals.errorSignal.emit(''.join(traceback.format_tb(ex.__traceback__) + [str(ex)])) + self.signals.setDataSignal.emit(["restartRequired", True]) def shouldRun(self): return self.running @@ -658,33 +660,33 @@ def guiOnDepthConfigUpdate(self, median=None, dct=None, sigma=None, lrc=None, lr self.updateArg("lrcThreshold", lrcThreshold, False) def guiOnCameraConfigUpdate(self, name, exposure=None, sensitivity=None, saturation=None, contrast=None, brightness=None, sharpness=None): - if name == "color": - fun = self._demoInstance._pm.updateColorCamConfig - elif name == "left": - fun = self._demoInstance._pm.updateLeftCamConfig - else: - fun = self._demoInstance._pm.updateRightCamConfig - fun(self._demoInstance._device, exposure, sensitivity, saturation, contrast, brightness, sharpness) - if exposure is not None: newValue = list(filter(lambda item: item[0] == name, (confManager.args.cameraExposure or []))) + [(name, exposure)] + self._demoInstance._cameraConfig["exposure"] = newValue self.updateArg("cameraExposure", newValue, False) if sensitivity is not None: newValue = list(filter(lambda item: item[0] == name, (confManager.args.cameraSensitivity or []))) + [(name, sensitivity)] + self._demoInstance._cameraConfig["sensitivity"] = newValue self.updateArg("cameraSensitivity", newValue, False) if saturation is not None: newValue = list(filter(lambda item: item[0] == name, (confManager.args.cameraSaturation or []))) + [(name, saturation)] + self._demoInstance._cameraConfig["saturation"] = newValue self.updateArg("cameraSaturation", newValue, False) if contrast is not None: newValue = list(filter(lambda item: item[0] == name, (confManager.args.cameraContrast or []))) + [(name, contrast)] + self._demoInstance._cameraConfig["contrast"] = newValue self.updateArg("cameraContrast", newValue, False) if brightness is not None: newValue = list(filter(lambda item: item[0] == name, (confManager.args.cameraBrightness or []))) + [(name, brightness)] + self._demoInstance._cameraConfig["brightness"] = newValue self.updateArg("cameraBrightness", newValue, False) if sharpness is not None: newValue = list(filter(lambda item: item[0] == name, (confManager.args.cameraSharpness or []))) + [(name, sharpness)] + self._demoInstance._cameraConfig["sharpness"] = newValue self.updateArg("cameraSharpness", newValue, False) + self._demoInstance._updateCameraConfigs() + def guiOnDepthSetupUpdate(self, depthFrom=None, depthTo=None, subpixel=None, extended=None): if depthFrom is not None: self.updateArg("minDepth", depthFrom) diff --git a/gui/main.py b/gui/main.py index f3d4b47a8..61cba3b55 100644 --- a/gui/main.py +++ b/gui/main.py @@ -167,63 +167,90 @@ def setMedianFilter(self, state): DemoQtGui.instance.guiOnDepthConfigUpdate(median=value) -class BaseCamBridge(QObject): - name = "base" +@QmlElement +class ColorCamBridge(QObject): + name = "color" @Slot(int, int) def setIsoExposure(self, iso, exposure): if iso > 0 and exposure > 0: - DemoQtGui.instance.guiOnCameraConfigUpdate(self.name, sensitivity=iso, exposure=exposure) + DemoQtGui.instance.guiOnCameraConfigUpdate("color", sensitivity=iso, exposure=exposure) @Slot(int) def setContrast(self, value): - DemoQtGui.instance.guiOnCameraConfigUpdate(self.name, contrast=value) + DemoQtGui.instance.guiOnCameraConfigUpdate("color", contrast=value) @Slot(int) def setBrightness(self, value): - DemoQtGui.instance.guiOnCameraConfigUpdate(self.name, brightness=value) + DemoQtGui.instance.guiOnCameraConfigUpdate("color", brightness=value) @Slot(int) def setSaturation(self, value): - DemoQtGui.instance.guiOnCameraConfigUpdate(self.name, saturation=value) + DemoQtGui.instance.guiOnCameraConfigUpdate("color", saturation=value) @Slot(int) def setSharpness(self, value): - DemoQtGui.instance.guiOnCameraConfigUpdate(self.name, sharpness=value) + DemoQtGui.instance.guiOnCameraConfigUpdate("color", sharpness=value) @Slot(int) def setFps(self, value): - DemoQtGui.instance.guiOnCameraSetupUpdate(self.name, fps=value) + DemoQtGui.instance.guiOnCameraSetupUpdate("color", fps=value) @Slot(str) def setResolution(self, state): if state == "THE_1080_P": - DemoQtGui.instance.guiOnCameraSetupUpdate(self.name, resolution=1080) + DemoQtGui.instance.guiOnCameraSetupUpdate("color", resolution=1080) elif state == "THE_4_K": - DemoQtGui.instance.guiOnCameraSetupUpdate(self.name, resolution=2160) + DemoQtGui.instance.guiOnCameraSetupUpdate("color", resolution=2160) elif state == "THE_12_MP": - DemoQtGui.instance.guiOnCameraSetupUpdate(self.name, resolution=3040) - elif state == "THE_720_P": - DemoQtGui.instance.guiOnCameraSetupUpdate(self.name, resolution=720) - elif state == "THE_800_P": - DemoQtGui.instance.guiOnCameraSetupUpdate(self.name, resolution=800) - elif state == "THE_400_P": - DemoQtGui.instance.guiOnCameraSetupUpdate(self.name, resolution=400) + DemoQtGui.instance.guiOnCameraSetupUpdate("color", resolution=3040) @QmlElement -class ColorCamBridge(BaseCamBridge): - name = "color" +class MonoCamBridge(QObject): + @Slot(int, int) + def setIsoExposure(self, iso, exposure): + if iso > 0 and exposure > 0: + DemoQtGui.instance.guiOnCameraConfigUpdate("left", sensitivity=iso, exposure=exposure) + DemoQtGui.instance.guiOnCameraConfigUpdate("right", sensitivity=iso, exposure=exposure) -@QmlElement -class LeftCamBridge(BaseCamBridge): - name = "left" + @Slot(int) + def setContrast(self, value): + DemoQtGui.instance.guiOnCameraConfigUpdate("left", contrast=value) + DemoQtGui.instance.guiOnCameraConfigUpdate("right", contrast=value) + @Slot(int) + def setBrightness(self, value): + DemoQtGui.instance.guiOnCameraConfigUpdate("left", brightness=value) + DemoQtGui.instance.guiOnCameraConfigUpdate("right", brightness=value) -@QmlElement -class RightCamBridge(BaseCamBridge): - name = "right" + @Slot(int) + def setSaturation(self, value): + DemoQtGui.instance.guiOnCameraConfigUpdate("left", saturation=value) + DemoQtGui.instance.guiOnCameraConfigUpdate("right", saturation=value) + + @Slot(int) + def setSharpness(self, value): + DemoQtGui.instance.guiOnCameraConfigUpdate("left", sharpness=value) + DemoQtGui.instance.guiOnCameraConfigUpdate("right", sharpness=value) + + @Slot(int) + def setFps(self, value): + DemoQtGui.instance.guiOnCameraSetupUpdate("left", fps=value) + DemoQtGui.instance.guiOnCameraSetupUpdate("right", fps=value) + + @Slot(str) + def setResolution(self, state): + if state == "THE_720_P": + DemoQtGui.instance.guiOnCameraSetupUpdate("left", resolution=720) + DemoQtGui.instance.guiOnCameraSetupUpdate("right", resolution=720) + elif state == "THE_800_P": + DemoQtGui.instance.guiOnCameraSetupUpdate("left", resolution=800) + DemoQtGui.instance.guiOnCameraSetupUpdate("right", resolution=800) + elif state == "THE_400_P": + DemoQtGui.instance.guiOnCameraSetupUpdate("left", resolution=400) + DemoQtGui.instance.guiOnCameraSetupUpdate("right", resolution=400) if __name__ == "__main__": diff --git a/gui/views/CameraProperties.qml b/gui/views/CameraProperties.qml index 7feea196f..f42d490e0 100644 --- a/gui/views/CameraProperties.qml +++ b/gui/views/CameraProperties.qml @@ -106,7 +106,7 @@ ListView { Rectangle { id: colorCamRectAdvanced - x: 0 + x: 30 y: 180 states: State { @@ -306,7 +306,7 @@ ListView { height: 33 model: monoResolutionChoices onActivated: function(index) { - leftCamBridge.setResolution(model[index]) + monoCamBridge.setResolution(model[index]) } } @@ -335,7 +335,7 @@ ListView { placeholderText: "FPS" font.family: "Courier" onEditingFinished: { - leftCamBridge.setFps(text) + monoCamBridge.setFps(text) } validator: IntValidator {} } @@ -356,16 +356,16 @@ ListView { } Rectangle { - id: leftCamRect + id: monoCamRect Text { id: text13 - x: 203 + x: 330 y: 44 width: 181 height: 30 color: "#ffffff" - text: qsTr("Left") + text: qsTr("Left + Right") font.pixelSize: 26 horizontalAlignment: Text.AlignHCenter font.styleName: "Regular" @@ -373,13 +373,13 @@ ListView { } Rectangle { - id: leftCamRectAdvanced - x: 0 + id: monoCamRectAdvanced + x: 110 y: 180 states: State { name: "hidden"; when: !advancedSwitch.checked - PropertyChanges { target: leftCamRectAdvanced; opacity: 0 } + PropertyChanges { target: monoCamRectAdvanced; opacity: 0 } } Text { @@ -409,7 +409,7 @@ ListView { font.family: "Courier" validator: IntValidator {} onEditingFinished: { - leftCamBridge.setIsoExposure(text, textField5.text) + monoCamBridge.setIsoExposure(text, textField5.text) } } @@ -425,7 +425,7 @@ ListView { placeholderText: qsTr("Exposure") validator: IntValidator {} onEditingFinished: { - leftCamBridge.setIsoExposure(textField4.text, text) + monoCamBridge.setIsoExposure(textField4.text, text) } } @@ -454,7 +454,7 @@ ListView { from: -10 value: 0 onValueChanged: { - leftCamBridge.setSaturation(value) + monoCamBridge.setSaturation(value) } } @@ -483,7 +483,7 @@ ListView { from: -10 value: 0 onValueChanged: { - leftCamBridge.setContrast(value) + monoCamBridge.setContrast(value) } } @@ -512,7 +512,7 @@ ListView { from: -10 value: 0 onValueChanged: { - leftCamBridge.setBrightness(value) + monoCamBridge.setBrightness(value) } } @@ -541,7 +541,7 @@ ListView { from: 0 value: 0 onValueChanged: { - leftCamBridge.setSharpness(value) + monoCamBridge.setSharpness(value) } } @@ -561,213 +561,6 @@ ListView { } } - Rectangle { - id: rightCamRect - - Text { - id: text12 - x: 385 - y: 44 - width: 197 - height: 30 - color: "#ffffff" - text: qsTr("Right") - font.pixelSize: 26 - horizontalAlignment: Text.AlignHCenter - font.styleName: "Regular" - font.family: "Courier" - } - - Rectangle { - id: rightCamRectAdvanced - x: 0 - y: 180 - - states: State { - name: "hidden"; when: !advancedSwitch.checked - PropertyChanges { target: rightCamRectAdvanced; opacity: 0 } - } - - Text { - id: text20 - x: 393 - y: 80 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("ISO") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - TextField { - id: textField2 - x: 484 - y: 80 - width: 106 - height: 25 - color: "#ddffffff" - text: "" - bottomPadding: 5 - validator: IntValidator {} - placeholderText: "ISO" - font.family: "Courier" - onEditingFinished: { - rightCamBridge.setIsoExposure(text, textField3.text) - } - } - - TextField { - id: textField3 - x: 484 - y: 111 - width: 106 - height: 25 - color: "#ddffffff" - text: "" - bottomPadding: 5 - font.family: "Courier" - placeholderText: qsTr("Exposure") - validator: IntValidator {} - onEditingFinished: { - rightCamBridge.setIsoExposure(textField2.text, text) - } - } - - Text { - id: text21 - x: 393 - y: 111 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Exposure") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider6 - x: 484 - y: 142 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - onValueChanged: { - rightCamBridge.setSaturation(value) - } - } - - Text { - id: text22 - x: 393 - y: 142 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Saturation") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider7 - x: 484 - y: 173 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - onValueChanged: { - rightCamBridge.setContrast(value) - } - } - - Text { - id: text23 - x: 393 - y: 173 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Contrast") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider8 - x: 484 - y: 204 - width: 106 - height: 25 - stepSize: 1 - to: 10 - from: -10 - value: 0 - onValueChanged: { - rightCamBridge.setBrightness(value) - } - } - - Text { - id: text24 - x: 393 - y: 204 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Brightness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - - Slider { - id: slider9 - x: 484 - y: 235 - width: 106 - height: 25 - stepSize: 1 - to: 4 - from: 0 - value: 0 - onValueChanged: { - rightCamBridge.setSharpness(value) - } - } - - Text { - id: text25 - x: 393 - y: 235 - width: 90 - height: 25 - color: "#ffffff" - text: qsTr("Sharpness") - font.pixelSize: 12 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Courier" - } - } - } - CheckBox { id: advancedSwitch x: 132 diff --git a/gui/views/root.qml b/gui/views/root.qml index 69067f9a0..950e1c01e 100644 --- a/gui/views/root.qml +++ b/gui/views/root.qml @@ -85,11 +85,8 @@ ApplicationWindow { ColorCamBridge { id: colorCamBridge } - LeftCamBridge { - id: leftCamBridge - } - RightCamBridge { - id: rightCamBridge + MonoCamBridge { + id: monoCamBridge } PreviewBridge { id: previewBridge From c51ff9f1e18b22f7e43453ebf1075279502018c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Tue, 2 Nov 2021 12:15:37 +0100 Subject: [PATCH 34/57] Add misc properties --- depthai_demo.py | 113 ++-- .../depthai_sdk/managers/pipeline_manager.py | 12 +- gui/depthai_demo.pyproject | 2 +- gui/main.py | 32 ++ gui/views/AIProperties.qml | 22 +- gui/views/DepthProperties.qml | 527 +++++++++--------- gui/views/MiscProperties.qml | 230 ++++++++ gui/views/root.qml | 6 + 8 files changed, 641 insertions(+), 303 deletions(-) create mode 100644 gui/views/MiscProperties.qml diff --git a/depthai_demo.py b/depthai_demo.py index b3d82e84d..3238595f2 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -113,6 +113,7 @@ def setup(self): if self._conf.args.xlinkChunkSize is not None: self._pm.setXlinkChunkSize(self._conf.args.xlinkChunkSize) + self._nnManager = None if self._conf.useNN: self._blobManager = BlobManager( zooDir=DEPTHAI_ZOO, @@ -175,7 +176,7 @@ def setup(self): ) self._encManager = None - if len(self._conf.args.encode) > 1: + if len(self._conf.args.encode) > 0: self._encManager = EncodingManager(self._conf.args.encode, self._conf.args.encodeOutput) self._encManager.createEncoders(self._pm) @@ -206,11 +207,14 @@ def run(self): self._sbbOut = self._device.getOutputQueue("sbb", maxSize=1, blocking=False) if self._conf.useNN and self._conf.args.spatialBoundingBox else None self._logOut = self._device.getOutputQueue("systemLogger", maxSize=30, blocking=False) if len(self._conf.args.report) > 0 else None - self._medianFilters = cycle([item for name, item in vars(dai.MedianFilter).items() if name.startswith('KERNEL_') or name.startswith('MEDIAN_')]) - for medFilter in self._medianFilters: - # move the cycle to the current median filter - if medFilter == self._pm._depthConfig.postProcessing.median: - break + if self._conf.useDepth: + self._medianFilters = cycle([item for name, item in vars(dai.MedianFilter).items() if name.startswith('KERNEL_') or name.startswith('MEDIAN_')]) + for medFilter in self._medianFilters: + # move the cycle to the current median filter + if medFilter == self._pm._depthConfig.postProcessing.median: + break + else: + self._medianFilters = [] if self._conf.useCamera: cameras = self._device.getConnectedCameras() @@ -260,7 +264,7 @@ def stop(self): self._pv.closeQueues() if self._encManager is not None: self._encManager.close() - if self._conf.useNN: + if self._nnManager is not None: self._nnManager.closeQueues() if self._sbbOut is not None: self._sbbOut.close() @@ -303,7 +307,7 @@ def loop(self): self._hostFrame = rawHostFrame self._fps.tick('host') - if self._conf.useNN: + if self._nnManager is not None: inNn = self._nnManager.outputQueue.tryGet() if inNn is not None: self.onNn(inNn) @@ -313,12 +317,12 @@ def loop(self): self._fps.tick('nn') if self._conf.useCamera: - if self._conf.useNN: + if self._nnManager is not None: self._nnManager.draw(self._pv, self._nnData) - self._pv.showFrames(callback=self._showFramesCallback) + self._pv.showFrames(callback=self._showFramesCallback) elif self._hostFrame is not None: debugHostFrame = self._hostFrame.copy() - if self._conf.useNN: + if self._nnManager is not None: self._nnManager.draw(debugHostFrame, self._nnData) self._fps.drawFps(debugHostFrame, "host") if self._displayFrames: @@ -416,36 +420,6 @@ def _updateCameraConfigs(self): def _showFramesCallback(self, frame, name): self._fps.drawFps(frame, name) - h, w = frame.shape[:2] - if name in [Previews.disparityColor.name, Previews.disparity.name, Previews.depth.name, Previews.depthRaw.name]: - text = "Median filter: {} [M]".format(self._pm._depthConfig.postProcessing.median.name.lstrip("KERNEL_").lstrip("MEDIAN_")) - cv2.putText(frame, text, (10, h - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, 0, 4) - cv2.putText(frame, text, (10, h - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, 255, 1) - elif self._conf.args.cameraControlls and name in [Previews.color.name, Previews.left.name, Previews.right.name]: - text = "Exposure: {} T [+] [-] G".format(self._cameraConfig["exposure"] if self._cameraConfig["exposure"] is not None else "auto") - label_width = cv2.getTextSize(text, cv2.FONT_HERSHEY_TRIPLEX, 0.5, 4)[0][0] - cv2.putText(frame, text, (w - label_width, h - 110), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (0, 0, 0), 4) - cv2.putText(frame, text, (w - label_width, h - 110), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255, 255, 255), 1) - text = "Sensitivity: {} Y [+] [-] H".format(self._cameraConfig["sensitivity"] if self._cameraConfig["sensitivity"] is not None else "auto") - label_width = cv2.getTextSize(text, cv2.FONT_HERSHEY_TRIPLEX, 0.5, 4)[0][0] - cv2.putText(frame, text, (w - label_width, h - 90), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (0, 0, 0), 4) - cv2.putText(frame, text, (w - label_width, h - 90), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255, 255, 255), 1) - text = "Saturation: {} U [+] [-] J".format(self._cameraConfig["saturation"] if self._cameraConfig["saturation"] is not None else "auto") - label_width = cv2.getTextSize(text, cv2.FONT_HERSHEY_TRIPLEX, 0.5, 4)[0][0] - cv2.putText(frame, text, (w - label_width, h - 70), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (0, 0, 0), 4) - cv2.putText(frame, text, (w - label_width, h - 70), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255, 255, 255), 1) - text = "Contrast: {} I [+] [-] K".format(self._cameraConfig["contrast"] if self._cameraConfig["contrast"] is not None else "auto") - label_width = cv2.getTextSize(text, cv2.FONT_HERSHEY_TRIPLEX, 0.5, 4)[0][0] - cv2.putText(frame, text, (w - label_width, h - 50), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (0, 0, 0), 4) - cv2.putText(frame, text, (w - label_width, h - 50), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255, 255, 255), 1) - text = "Brightness: {} O [+] [-] L".format(self._cameraConfig["brightness"] if self._cameraConfig["brightness"] is not None else "auto") - label_width = cv2.getTextSize(text, cv2.FONT_HERSHEY_TRIPLEX, 0.5, 4)[0][0] - cv2.putText(frame, text, (w - label_width, h - 30), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (0, 0, 0), 4) - cv2.putText(frame, text, (w - label_width, h - 30), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255, 255, 255), 1) - text = "Sharpness: {} P [+] [-] ;".format(self._cameraConfig["sharpness"] if self._cameraConfig["sharpness"] is not None else "auto") - label_width = cv2.getTextSize(text, cv2.FONT_HERSHEY_TRIPLEX, 0.5, 4)[0][0] - cv2.putText(frame, text, (w - label_width, h - 10), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (0, 0, 0), 4) - cv2.putText(frame, text, (w - label_width, h - 10), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255, 255, 255), 1) returnFrame = self.onShowFrame(frame, name) return returnFrame if returnFrame is not None else frame @@ -578,7 +552,10 @@ def onSetup(self, instance): self.signals.setDataSignal.emit(["ovVersions", versionChoices]) devices = [self.instance._deviceInfo.getMxId()] + list(map(lambda info: info.getMxId(), dai.Device.getAllAvailableDevices())) self.signals.setDataSignal.emit(["deviceChoices", devices]) - self.signals.setDataSignal.emit(["countLabels", instance._nnManager._labels]) + if instance._nnManager is not None: + self.signals.setDataSignal.emit(["countLabels", instance._nnManager._labels]) + else: + self.signals.setDataSignal.emit(["countLabels", []]) self.signals.setDataSignal.emit(["modelChoices", sorted(confManager.getAvailableZooModels(), key=cmp_to_key(lambda a, b: -1 if a == "mobilenet-ssd" else 1 if b == "mobilenet-ssd" else -1 if a < b else 1))]) @@ -744,4 +721,56 @@ def guiOnReloadDevices(self): if len(devices) > 0: self.worker.signals.setDataSignal.emit(["restartRequired", True]) + def guiOnToggleColorEncoding(self, enabled, fps): + oldConfig = confManager.args.encode or {} + print(enabled, fps) + if enabled: + oldConfig["color"] = fps + elif "color" in confManager.args.encode: + del oldConfig["color"] + self.updateArg("encode", oldConfig) + + def guiOnToggleLeftEncoding(self, enabled, fps): + oldConfig = confManager.args.encode or {} + if enabled: + oldConfig["left"] = fps + elif "color" in confManager.args.encode: + del oldConfig["left"] + self.updateArg("encode", oldConfig) + + def guiOnToggleRightEncoding(self, enabled, fps): + oldConfig = confManager.args.encode or {} + if enabled: + oldConfig["right"] = fps + elif "color" in confManager.args.encode: + del oldConfig["right"] + self.updateArg("encode", oldConfig) + + def guiOnSelectReportingOptions(self, temp, cpu, memory): + options = [] + if temp: + options.append("temp") + if cpu: + options.append("cpu") + if memory: + options.append("memory") + self.updateArg("report", options) + + def guiOnSelectReportingPath(self, value): + self.updateArg("reportFile", value) + + def guiOnSelectEncodingPath(self, value): + self.updateArg("encodeOutput", value) + + def guiOnToggleDepth(self, value): + self.updateArg("disableDepth", not value) + filtered = list(filter(lambda name: name not in (Previews.depth.name, Previews.depthRaw.name, Previews.disparity.name, Previews.disparityColor.name, Previews.rectifiedRight.name, Previews.rectifiedLeft.name), confManager.args.show)) + if value: + self.updateArg("show", filtered + [Previews.depth.name]) + else: + self.updateArg("show", filtered) + + def guiOnToggleNN(self, value): + self.updateArg("disableNeuralNetwork", not value) + App().start() \ No newline at end of file diff --git a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py index 23008ce51..5f2c3ec86 100644 --- a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py +++ b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py @@ -56,10 +56,14 @@ def createDefaultQueues(self, device): device (depthai.Device): Running device instance """ - self._depthConfigInputQueue = device.getInputQueue("stereoConfig") - self._rgbConfigInputQueue = device.getInputQueue("color_control") - self._leftConfigInputQueue = device.getInputQueue("left_control") - self._rightConfigInputQueue = device.getInputQueue("right_control") + if hasattr(self.nodes, "stereo"): + self._depthConfigInputQueue = device.getInputQueue("stereoConfig") + if hasattr(self.nodes, "camRgb"): + self._rgbConfigInputQueue = device.getInputQueue("color_control") + if hasattr(self.nodes, "monoLeft"): + self._leftConfigInputQueue = device.getInputQueue("left_control") + if hasattr(self.nodes, "monoRight"): + self._rightConfigInputQueue = device.getInputQueue("right_control") def closeDefaultQueues(self): """ diff --git a/gui/depthai_demo.pyproject b/gui/depthai_demo.pyproject index 9a9a4d494..c5510822a 100644 --- a/gui/depthai_demo.pyproject +++ b/gui/depthai_demo.pyproject @@ -1,4 +1,4 @@ { "files": ["main.py", "views/DepthProperties.qml", "views/root.qml", "views/CameraProperties.qml", - "views/CameraPreview.qml", "views/AIProperties.qml"] + "views/CameraPreview.qml", "views/AIProperties.qml", "views/MiscProperties.qml"] } diff --git a/gui/main.py b/gui/main.py index 61cba3b55..3da5f3fde 100644 --- a/gui/main.py +++ b/gui/main.py @@ -83,6 +83,38 @@ def reloadDevices(self): def selectDevice(self, value): DemoQtGui.instance.guiOnSelectDevice(value) + @Slot(bool, bool, bool) + def selectReportingOptions(self, temp, cpu, memory): + DemoQtGui.instance.guiOnSelectReportingOptions(temp, cpu, memory) + + @Slot(str) + def selectReportingPath(self, value): + DemoQtGui.instance.guiOnSelectReportingPath(value) + + @Slot(str) + def selectEncodingPath(self, value): + DemoQtGui.instance.guiOnSelectEncodingPath(value) + + @Slot(bool, int) + def toggleColorEncoding(self, enabled, fps): + DemoQtGui.instance.guiOnToggleColorEncoding(enabled, fps) + + @Slot(bool, int) + def toggleLeftEncoding(self, enabled, fps): + DemoQtGui.instance.guiOnToggleLeftEncoding(enabled, fps) + + @Slot(bool, int) + def toggleRightEncoding(self, enabled, fps): + DemoQtGui.instance.guiOnToggleRightEncoding(enabled, fps) + + @Slot(bool) + def toggleDepth(self, enabled): + DemoQtGui.instance.guiOnToggleDepth(enabled) + + @Slot(bool) + def toggleNN(self, enabled): + DemoQtGui.instance.guiOnToggleNN(enabled) + @QmlElement class AIBridge(QObject): diff --git a/gui/views/AIProperties.qml b/gui/views/AIProperties.qml index 9b8b43ee7..51895d37e 100644 --- a/gui/views/AIProperties.qml +++ b/gui/views/AIProperties.qml @@ -18,7 +18,7 @@ ListView { id: textAI x: 79 y: 8 - width: 433 + width: 322 height: 30 color: "#ffffff" text: qsTr("AI Properties") @@ -309,10 +309,28 @@ ListView { } } + Switch { + id: switch5 + x: 359 + y: 0 + width: 167 + height: 38 + text: qsTr("Enabled") + checked: true + autoExclusive: false + font.family: "Courier" + font.kerning: false + transformOrigin: Item.Center + font.preferShaping: false + onToggled: { + appBridge.toggleNN(switch5.checked) + } + } + } } /*##^## Designer { - D{i:0;autoSize:true;height:480;width:640} + D{i:0;autoSize:true;height:480;width:640}D{i:26} } ##^##*/ diff --git a/gui/views/DepthProperties.qml b/gui/views/DepthProperties.qml index 4b2d9a58e..674c3e31d 100644 --- a/gui/views/DepthProperties.qml +++ b/gui/views/DepthProperties.qml @@ -19,292 +19,311 @@ ListView { width: parent.width height: parent.height - ComboBox { - id: comboBox - x: 0 - y: 102 - width: 195 - height: 33 - model: medianChoices - onActivated: function(index) { - depthBridge.setMedianFilter(model[index]) + ComboBox { + id: comboBox + x: 0 + y: 102 + width: 195 + height: 33 + model: medianChoices + onActivated: function(index) { + depthBridge.setMedianFilter(model[index]) + } } - } - Slider { - id: dctSlider - x: 360 - y: 89 - width: 200 - height: 25 - snapMode: RangeSlider.NoSnap - stepSize: 1 - from: 0 - to: 255 - value: 240 - onValueChanged: { - depthBridge.setDisparityConfidenceThreshold(value) + Slider { + id: dctSlider + x: 360 + y: 89 + width: 200 + height: 25 + snapMode: RangeSlider.NoSnap + stepSize: 1 + from: 0 + to: 255 + value: 240 + onValueChanged: { + depthBridge.setDisparityConfidenceThreshold(value) + } } - } - Text { - id: text2 - x: 0 - y: 71 - width: 195 - height: 25 - color: "#ffffff" - text: qsTr("Median filtering") - font.pixelSize: 18 - font.styleName: "Regular" - font.weight: Font.Medium - font.family: "Courier" - } + Text { + id: text2 + x: 0 + y: 71 + width: 195 + height: 25 + color: "#ffffff" + text: qsTr("Median filtering") + font.pixelSize: 18 + font.styleName: "Regular" + font.weight: Font.Medium + font.family: "Courier" + } - Switch { - id: switch1 - x: 0 - y: 187 - text: qsTr("Left Right Check") - transformOrigin: Item.Center - font.preferShaping: false - font.kerning: false - font.family: "Courier" - autoExclusive: false - onToggled: { - depthBridge.toggleLeftRightCheck(switch1.checked) + Switch { + id: switch1 + x: 0 + y: 187 + text: qsTr("Left Right Check") + transformOrigin: Item.Center + font.preferShaping: false + font.kerning: false + font.family: "Courier" + autoExclusive: false + onToggled: { + depthBridge.toggleLeftRightCheck(switch1.checked) + } } - } - Switch { - enabled: false - id: switch2 - x: 0 - y: 233 - text: qsTr("Extended Disparity") - autoExclusive: false - font.kerning: false - font.family: "Courier" - font.preferShaping: false - transformOrigin: Item.Center - onToggled: { - depthBridge.toggleExtendedDisparity(switch2.checked) + Switch { + id: switch5 + x: 381 + y: 0 + width: 167 + height: 38 + text: qsTr("Enabled") + autoExclusive: false + font.family: "Courier" + checked: true + font.kerning: false + transformOrigin: Item.Center + font.preferShaping: false + onToggled: { + appBridge.toggleDepth(switch5.checked) + } } - } - Switch { - id: switch3 - x: 0 - y: 141 - text: qsTr("Subpixel") - autoExclusive: false - font.kerning: false - transformOrigin: Item.Center - font.preferShaping: false - font.family: "Courier" - onToggled: { - depthBridge.toggleSubpixel(switch3.checked) + Switch { + enabled: false + id: switch2 + x: 0 + y: 233 + text: qsTr("Extended Disparity") + autoExclusive: false + font.kerning: false + font.family: "Courier" + font.preferShaping: false + transformOrigin: Item.Center + onToggled: { + depthBridge.toggleExtendedDisparity(switch2.checked) + } } - } - Text { - id: text3 - x: 359 - y: 71 - width: 200 - height: 25 - color: "#ffffff" - text: qsTr("Confidence Threshold") - font.pixelSize: 18 - horizontalAlignment: Text.AlignHCenter - font.styleName: "Regular" - font.weight: Font.Medium - font.family: "Courier" - } + Switch { + id: switch3 + x: 0 + y: 141 + text: qsTr("Subpixel") + autoExclusive: false + font.kerning: false + transformOrigin: Item.Center + font.preferShaping: false + font.family: "Courier" + onToggled: { + depthBridge.toggleSubpixel(switch3.checked) + } + } - Slider { - id: sigmaSlider - x: 362 - y: 133 - width: 200 - height: 25 - stepSize: 1 - snapMode: RangeSlider.NoSnap - value: 0 - to: 255 - onValueChanged: { - depthBridge.setBilateralSigma(value) + Text { + id: text3 + x: 359 + y: 71 + width: 200 + height: 25 + color: "#ffffff" + text: qsTr("Confidence Threshold") + font.pixelSize: 18 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.weight: Font.Medium + font.family: "Courier" } - } - Text { - id: text5 - x: 566 - y: 95 - width: 17 - height: 25 - color: "#ffffff" - text: dctSlider.value - font.pixelSize: 12 - } + Slider { + id: sigmaSlider + x: 362 + y: 133 + width: 200 + height: 25 + stepSize: 1 + snapMode: RangeSlider.NoSnap + value: 0 + to: 255 + onValueChanged: { + depthBridge.setBilateralSigma(value) + } + } - Text { - id: text6 - x: 360 - y: 115 - width: 200 - height: 25 - color: "#ffffff" - text: qsTr("Bilateral Sigma") - font.pixelSize: 18 - horizontalAlignment: Text.AlignHCenter - font.styleName: "Regular" - font.weight: Font.Medium - font.family: "Courier" - } + Text { + id: text5 + x: 566 + y: 95 + width: 17 + height: 25 + color: "#ffffff" + text: dctSlider.value + font.pixelSize: 12 + } - Text { - id: text8 - x: 566 - y: 136 - width: 17 - height: 20 - color: "#ffffff" - text: sigmaSlider.value - font.pixelSize: 12 - rotation: 0 - } + Text { + id: text6 + x: 360 + y: 115 + width: 200 + height: 25 + color: "#ffffff" + text: qsTr("Bilateral Sigma") + font.pixelSize: 18 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.weight: Font.Medium + font.family: "Courier" + } - Text { - id: text9 - x: 362 - y: 158 - width: 200 - height: 25 - color: "#ffffff" - text: qsTr("Depth Range") - font.pixelSize: 18 - horizontalAlignment: Text.AlignHCenter - font.styleName: "Regular" - font.weight: Font.Medium - font.family: "Courier" - } + Text { + id: text8 + x: 566 + y: 136 + width: 17 + height: 20 + color: "#ffffff" + text: sigmaSlider.value + font.pixelSize: 12 + rotation: 0 + } - RangeSlider { - id: depthRangeSlider - x: 364 - y: 181 - width: 198 - height: 27 - snapMode: RangeSlider.NoSnap - stepSize: 100 - to: 10000 - focusPolicy: Qt.StrongFocus - second.value: 10000 - first.value: 0 - first.onMoved: { - depthBridge.setDepthRange(first.value, second.value) + Text { + id: text9 + x: 362 + y: 158 + width: 200 + height: 25 + color: "#ffffff" + text: qsTr("Depth Range") + font.pixelSize: 18 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.weight: Font.Medium + font.family: "Courier" } - second.onMoved: { - depthBridge.setDepthRange(first.value, second.value) + + RangeSlider { + id: depthRangeSlider + x: 364 + y: 181 + width: 198 + height: 27 + snapMode: RangeSlider.NoSnap + stepSize: 100 + to: 10000 + focusPolicy: Qt.StrongFocus + second.value: 10000 + first.value: 0 + first.onMoved: { + depthBridge.setDepthRange(first.value, second.value) + } + second.onMoved: { + depthBridge.setDepthRange(first.value, second.value) + } } - } - Text { - id: text1 - x: 79 - y: 0 - width: 433 - height: 30 - color: "#ffffff" - text: qsTr("Depth Properties") - font.pixelSize: 26 - horizontalAlignment: Text.AlignHCenter - font.styleName: "Regular" - font.family: "Courier" - } + Text { + id: text1 + x: 79 + y: 0 + width: 285 + height: 30 + color: "#ffffff" + text: qsTr("Depth Properties") + font.pixelSize: 26 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.family: "Courier" + } - Text { - id: text32 - x: 566 - y: 185 - width: 17 - height: 20 - color: "#ffffff" - text: (depthRangeSlider.second.value / 1000).toFixed(1) + "m" - font.pixelSize: 12 - rotation: 0 - } + Text { + id: text32 + x: 566 + y: 185 + width: 17 + height: 20 + color: "#ffffff" + text: (depthRangeSlider.second.value / 1000).toFixed(1) + "m" + font.pixelSize: 12 + rotation: 0 + } - Text { - id: text33 - x: 337 - y: 185 - width: 17 - height: 20 - color: "#ffffff" - text: (depthRangeSlider.first.value / 1000).toFixed(1) + "m" - font.pixelSize: 12 - rotation: 0 - } + Text { + id: text33 + x: 337 + y: 185 + width: 17 + height: 20 + color: "#ffffff" + text: (depthRangeSlider.first.value / 1000).toFixed(1) + "m" + font.pixelSize: 12 + rotation: 0 + } - Text { - id: text10 - x: 360 - y: 214 - width: 200 - height: 25 - color: "#ffffff" - text: qsTr("LRC Threshold") - font.pixelSize: 18 - horizontalAlignment: Text.AlignHCenter - font.styleName: "Regular" - font.weight: Font.Medium - font.family: "Courier" - } + Text { + id: text10 + x: 360 + y: 214 + width: 200 + height: 25 + color: "#ffffff" + text: qsTr("LRC Threshold") + font.pixelSize: 18 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.weight: Font.Medium + font.family: "Courier" + } - Slider { - id: lrcSlider - x: 361 - y: 233 - width: 198 - height: 27 - stepSize: 1 - to: 10 - value: 10 - from: 0 - onValueChanged: { - depthBridge.setLrcThreshold(value) + Slider { + id: lrcSlider + x: 361 + y: 233 + width: 198 + height: 27 + stepSize: 1 + to: 10 + value: 10 + from: 0 + onValueChanged: { + depthBridge.setLrcThreshold(value) + } } - } - Text { - id: text34 - x: 566 - y: 233 - width: 17 - height: 20 - color: "#ffffff" - text: lrcSlider.value - font.pixelSize: 12 - rotation: 0 - } + Text { + id: text34 + x: 566 + y: 233 + width: 17 + height: 20 + color: "#ffffff" + text: lrcSlider.value + font.pixelSize: 12 + rotation: 0 + } + + Text { + id: text35 + x: 337 + y: 233 + width: 17 + height: 20 + color: "#ffffff" + font.pixelSize: 12 + rotation: 0 + } - Text { - id: text35 - x: 337 - y: 233 - width: 17 - height: 20 - color: "#ffffff" - font.pixelSize: 12 - rotation: 0 - } } } /*##^## Designer { - D{i:0;autoSize:true;height:480;width:640} + D{i:0;autoSize:true;height:480;width:640}D{i:7} } ##^##*/ diff --git a/gui/views/MiscProperties.qml b/gui/views/MiscProperties.qml new file mode 100644 index 000000000..52531d06a --- /dev/null +++ b/gui/views/MiscProperties.qml @@ -0,0 +1,230 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.11 +import QtQuick.Controls 2.1 +import QtQuick.Window 2.1 +import QtQuick.Controls.Material 2.1 + +ListView { + id: miscProperties + delegate: Text { + anchors.leftMargin: 50 + font.pointSize: 15 + horizontalAlignment: Text.AlignHCenter + text: display + } + + Rectangle { + id: backgroundRect1 + color: "black" + width: parent.width + height: parent.height + + + Text { + id: text2 + x: 8 + y: 8 + width: 185 + height: 30 + color: "#ffffff" + text: qsTr("Recording") + font.pixelSize: 26 + horizontalAlignment: Text.AlignHCenter + font.family: "Courier" + font.styleName: "Regular" + } + + TextField { + id: encColorFps + x: 110 + y: 44 + width: 83 + height: 27 + bottomPadding: 7 + validator: IntValidator {} + placeholderText: qsTr("FPS") + onEditingFinished: { + appBridge.toggleColorEncoding(encColorSwitch.checked, encColorFps.text) + } + } + + Switch { + id: encColorSwitch + x: 8 + y: 44 + width: 96 + height: 27 + text: qsTr("Color") + bottomPadding: 5 + onToggled: { + appBridge.toggleColorEncoding(encColorSwitch.checked, encColorFps.text) + } + } + + TextField { + id: encLeftFps + x: 110 + y: 77 + width: 83 + height: 27 + bottomPadding: 7 + validator: IntValidator {} + placeholderText: qsTr("FPS") + onEditingFinished: { + appBridge.toggleLeftEncoding(encLeftSwitch.checked, encLeftFps.text) + } + } + + Switch { + id: encLeftSwitch + x: 8 + y: 77 + width: 96 + height: 27 + text: qsTr("Left") + bottomPadding: 5 + onToggled: { + appBridge.toggleLeftEncoding(encLeftSwitch.checked, encLeftFps.text) + } + } + + TextField { + id: encRightFps + x: 110 + y: 110 + width: 83 + height: 27 + bottomPadding: 7 + validator: IntValidator {} + placeholderText: qsTr("FPS") + onEditingFinished: { + appBridge.toggleRightEncoding(encRightSwitch.checked, encRightFps.text) + } + } + + Switch { + id: encRightSwitch + x: 8 + y: 110 + width: 96 + height: 27 + text: qsTr("Right") + bottomPadding: 5 + onToggled: { + appBridge.toggleRightEncoding(encLeftSwitch.checked, encLeftFps.text) + } + } + + Text { + id: text3 + x: 8 + y: 203 + width: 185 + height: 30 + color: "#ffffff" + text: qsTr("Reporting") + font.pixelSize: 26 + horizontalAlignment: Text.AlignHCenter + font.family: "Courier" + font.styleName: "Regular" + } + + Switch { + id: tempSwitch + x: 8 + y: 239 + width: 185 + height: 27 + text: qsTr("Temperature") + bottomPadding: 5 + onToggled: { + appBridge.selectReportingOptions(tempSwitch.checked, cpuSwitch.checked, memSwitch.checked) + } + } + + Switch { + id: cpuSwitch + x: 8 + y: 272 + width: 185 + height: 27 + text: qsTr("CPU") + bottomPadding: 5 + onToggled: { + appBridge.selectReportingOptions(tempSwitch.checked, cpuSwitch.checked, memSwitch.checked) + } + } + + Switch { + id: memSwitch + x: 8 + y: 305 + width: 185 + height: 27 + text: qsTr("Memory") + bottomPadding: 5 + onToggled: { + appBridge.selectReportingOptions(tempSwitch.checked, cpuSwitch.checked, memSwitch.checked) + } + } + + TextField { + id: textField3 + x: 110 + y: 352 + width: 227 + height: 27 + bottomPadding: 7 + placeholderText: qsTr("/path/to/report.csv") + onEditingFinished: { + appBridge.selectReportingPath(text) + } + } + + Text { + id: text26 + x: 8 + y: 352 + width: 90 + height: 27 + color: "#ffffff" + text: qsTr("Destination") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + + TextField { + id: textField4 + x: 116 + y: 150 + width: 227 + height: 27 + bottomPadding: 7 + placeholderText: qsTr("/path/to/output/directory/") + onEditingFinished: { + appBridge.selectEncodingPath(text) + } + } + + Text { + id: text27 + x: 14 + y: 150 + width: 90 + height: 27 + color: "#ffffff" + text: qsTr("Destination") + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: "Courier" + } + } +} +/*##^## +Designer { + D{i:0;autoSize:true;height:480;width:640}D{i:11}D{i:12}D{i:13}D{i:14} +} +##^##*/ diff --git a/gui/views/root.qml b/gui/views/root.qml index 950e1c01e..91f0d232a 100644 --- a/gui/views/root.qml +++ b/gui/views/root.qml @@ -128,6 +128,9 @@ ApplicationWindow { TabButton { text: "Camera" } + TabButton { + text: "Misc" + } } StackLayout { @@ -144,6 +147,9 @@ ApplicationWindow { Item { CameraProperties {} } + Item { + MiscProperties {} + } } Button { From 9e3550cccc7f4bb0e7ee615d9f75c6a9ef78a089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Tue, 2 Nov 2021 12:38:40 +0100 Subject: [PATCH 35/57] tweak report files --- depthai_demo.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 3238595f2..7cb8a93c5 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -426,7 +426,7 @@ def _showFramesCallback(self, frame, name): def _printSysInfo(self, info): m = 1024 * 1024 # MiB - if not self._conf.args.reportFile: + if not hasattr(self, "_reportFile"): if "memory" in self._conf.args.report: print(f"Drr used / total - {info.ddrMemoryUsage.used / m:.2f} / {info.ddrMemoryUsage.total / m:.2f} MiB") print(f"Cmx used / total - {info.cmxMemoryUsage.used / m:.2f} / {info.cmxMemoryUsage.total / m:.2f} MiB") @@ -474,7 +474,6 @@ def _printSysInfo(self, info): print(','.join(map(str, data.values())), file=self._reportFile) - if __name__ == "__main__": from gui.main import DemoQtGui from PySide6.QtGui import QImage From d104c328d9510b2cbb3d4496dc5c1048a2f500f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Wed, 3 Nov 2021 11:38:27 +0100 Subject: [PATCH 36/57] handle previews better --- depthai_demo.py | 42 ++++++++++++++++++++++++++++--- depthai_helpers/config_manager.py | 24 +++++++++--------- gui/main.py | 4 +++ gui/views/DepthProperties.qml | 25 +++++++++++++++--- 4 files changed, 76 insertions(+), 19 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 7cb8a93c5..3ac0be6a8 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -563,6 +563,7 @@ def __init__(self): super().__init__() self.running = False self.selectedPreview = confManager.args.show[0] if len(confManager.args.show) > 0 else "color" + self.useDisparity = False self.dataInitialized = False self.appInitialized = False self.threadpool = QThreadPool() @@ -763,13 +764,48 @@ def guiOnSelectEncodingPath(self, value): def guiOnToggleDepth(self, value): self.updateArg("disableDepth", not value) - filtered = list(filter(lambda name: name not in (Previews.depth.name, Previews.depthRaw.name, Previews.disparity.name, Previews.disparityColor.name, Previews.rectifiedRight.name, Previews.rectifiedLeft.name), confManager.args.show)) + selectedPreviews = [Previews.rectifiedRight.name, Previews.rectifiedLeft.name] + ([Previews.disparity.name, Previews.disparityColor.name] if self.useDisparity else [Previews.depth.name, Previews.depthRaw.name]) + depthPreviews = [Previews.rectifiedRight.name, Previews.rectifiedLeft.name, Previews.depth.name, Previews.depthRaw.name, Previews.disparity.name, Previews.disparityColor.name] + filtered = list(filter(lambda name: name not in depthPreviews, confManager.args.show)) if value: - self.updateArg("show", filtered + [Previews.depth.name]) + updated = filtered + selectedPreviews + if self.selectedPreview not in updated: + self.selectedPreview = updated[0] + self.updateArg("show", updated) else: - self.updateArg("show", filtered) + updated = filtered + [Previews.left.name, Previews.right.name] + if self.selectedPreview not in updated: + self.selectedPreview = updated[0] + self.updateArg("show", updated) def guiOnToggleNN(self, value): self.updateArg("disableNeuralNetwork", not value) + filtered = list(filter(lambda name: name != Previews.nnInput.name, confManager.args.show)) + if value: + updated = filtered + [Previews.nnInput.name] + if self.selectedPreview not in updated: + self.selectedPreview = updated[0] + self.updateArg("show", filtered + [Previews.nnInput.name]) + else: + if self.selectedPreview not in filtered: + self.selectedPreview = filtered[0] + self.updateArg("show", filtered) + + def guiOnToggleDisparity(self, value): + self.useDisparity = value + depthPreviews = [Previews.depth.name, Previews.depthRaw.name] + disparityPreviews = [Previews.disparity.name, Previews.disparityColor.name] + if value: + filtered = list(filter(lambda name: name not in depthPreviews, confManager.args.show)) + updated = filtered + disparityPreviews + if self.selectedPreview not in updated: + self.selectedPreview = updated[0] + self.updateArg("show", updated) + else: + filtered = list(filter(lambda name: name not in disparityPreviews, confManager.args.show)) + updated = filtered + depthPreviews + if self.selectedPreview not in updated: + self.selectedPreview = updated[0] + self.updateArg("show", updated) App().start() \ No newline at end of file diff --git a/depthai_helpers/config_manager.py b/depthai_helpers/config_manager.py index f4bbb6e47..8815c82fc 100644 --- a/depthai_helpers/config_manager.py +++ b/depthai_helpers/config_manager.py @@ -134,22 +134,22 @@ def adjustPreviewToOptions(self): if len(self.args.show) != 0: return - if Previews.color.name not in self.args.show: - self.args.show.append(Previews.color.name) + self.args.show.append(Previews.color.name) + if self.useNN: + self.args.show.append(Previews.nnInput.name) + if self.useDepth: - if self.lowBandwidth and Previews.disparityColor.name not in self.args.show: + if self.lowBandwidth: + self.args.show.append(Previews.disparity.name) self.args.show.append(Previews.disparityColor.name) - elif not self.lowBandwidth and Previews.depth.name not in self.args.show: + else: self.args.show.append(Previews.depth.name) - if Previews.rectifiedLeft.name not in self.args.show: - self.args.show.append(Previews.rectifiedLeft.name) - if Previews.rectifiedRight.name not in self.args.show: - self.args.show.append(Previews.rectifiedRight.name) + self.args.show.append(Previews.depthRaw.name) + self.args.show.append(Previews.rectifiedLeft.name) + self.args.show.append(Previews.rectifiedRight.name) else: - if Previews.left.name not in self.args.show: - self.args.show.append(Previews.left.name) - if Previews.right.name not in self.args.show: - self.args.show.append(Previews.right.name) + self.args.show.append(Previews.left.name) + self.args.show.append(Previews.right.name) def adjustParamsToDevice(self, device): deviceInfo = device.getDeviceInfo() diff --git a/gui/main.py b/gui/main.py index 3da5f3fde..92e38da73 100644 --- a/gui/main.py +++ b/gui/main.py @@ -115,6 +115,10 @@ def toggleDepth(self, enabled): def toggleNN(self, enabled): DemoQtGui.instance.guiOnToggleNN(enabled) + @Slot(bool) + def toggleDisparity(self, enabled): + DemoQtGui.instance.guiOnToggleDisparity(enabled) + @QmlElement class AIBridge(QObject): diff --git a/gui/views/DepthProperties.qml b/gui/views/DepthProperties.qml index 674c3e31d..2bd52bd63 100644 --- a/gui/views/DepthProperties.qml +++ b/gui/views/DepthProperties.qml @@ -78,7 +78,7 @@ ListView { Switch { id: switch5 - x: 381 + x: 328 y: 0 width: 167 height: 38 @@ -230,8 +230,8 @@ ListView { Text { id: text1 - x: 79 - y: 0 + x: 44 + y: 4 width: 285 height: 30 color: "#ffffff" @@ -319,11 +319,28 @@ ListView { rotation: 0 } + Switch { + id: switch6 + x: 443 + y: 0 + width: 169 + height: 38 + text: qsTr("Use Disparity") + autoExclusive: false + font.family: "Courier" + font.kerning: false + transformOrigin: Item.Center + font.preferShaping: false + onToggled: { + appBridge.toggleDisparity(switch6.checked) + } + } + } } /*##^## Designer { - D{i:0;autoSize:true;height:480;width:640}D{i:7} + D{i:0;autoSize:true;height:480;width:640}D{i:7}D{i:24} } ##^##*/ From 131a473d1b4ff230a5caade2f04f3985d64d3760 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Wed, 3 Nov 2021 12:42:01 +0100 Subject: [PATCH 37/57] sort openvino versions --- depthai_demo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depthai_demo.py b/depthai_demo.py index 3ac0be6a8..ec2d2eb28 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -547,7 +547,7 @@ def onSetup(self, instance): self.signals.setDataSignal.emit(["monoResolutionChoices", monoChoices]) self.signals.setDataSignal.emit(["previewChoices", confManager.args.show]) self.signals.setDataSignal.emit(["modelSourceChoices", [Previews.color.name, Previews.left.name, Previews.right.name]]) - versionChoices = list(filter(lambda name: name.startswith("VERSION_"), vars(dai.OpenVINO).keys())) + versionChoices = sorted(filter(lambda name: name.startswith("VERSION_"), vars(dai.OpenVINO).keys()), reverse=True) self.signals.setDataSignal.emit(["ovVersions", versionChoices]) devices = [self.instance._deviceInfo.getMxId()] + list(map(lambda info: info.getMxId(), dai.Device.getAllAvailableDevices())) self.signals.setDataSignal.emit(["deviceChoices", devices]) From 2d732fc97c5e95c061383865b8b75e164c38411a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Wed, 3 Nov 2021 12:42:32 +0100 Subject: [PATCH 38/57] change sbb factor default to 0.3 --- gui/views/AIProperties.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/views/AIProperties.qml b/gui/views/AIProperties.qml index 51895d37e..8f3e72c32 100644 --- a/gui/views/AIProperties.qml +++ b/gui/views/AIProperties.qml @@ -285,7 +285,7 @@ ListView { y: 383 width: 96 height: 33 - value: 6 + value: 0.3 stepSize: 0.1 onValueChanged: { aiBridge.setSbbFactor(value) From 712185dfe7da04a8537384b491e5c60ef638a227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Wed, 3 Nov 2021 12:43:14 +0100 Subject: [PATCH 39/57] update set sbb --- gui/views/AIProperties.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/views/AIProperties.qml b/gui/views/AIProperties.qml index 8f3e72c32..fbb62d375 100644 --- a/gui/views/AIProperties.qml +++ b/gui/views/AIProperties.qml @@ -260,7 +260,7 @@ ListView { font.preferShaping: false font.kerning: false onToggled: { - aiBridge.setSyncNN(switch1.checked) + aiBridge.setSbb(switch3.checked) } } From 089f8758fc4805a34b32a8851f800b95038b1098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Wed, 3 Nov 2021 12:47:56 +0100 Subject: [PATCH 40/57] fix scale on sync --- depthai_demo.py | 5 +++++ gui/views/AIProperties.qml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/depthai_demo.py b/depthai_demo.py index ec2d2eb28..7fdde6cd4 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -697,6 +697,11 @@ def guiOnAiSetupUpdate(self, cnn=None, shave=None, source=None, fullFov=None, sy self.updateArg("disableFullFovNn", not fullFov) if sync is not None: self.updateArg("sync", sync) + if sync: + self.updateArg("scale", {}) + else: + self.updateArg("scale", {"color": 0.37}) + if sbb is not None: self.updateArg("spatialBoundingBox", sbb) if sbbFactor is not None: diff --git a/gui/views/AIProperties.qml b/gui/views/AIProperties.qml index fbb62d375..9c7167dc9 100644 --- a/gui/views/AIProperties.qml +++ b/gui/views/AIProperties.qml @@ -166,7 +166,7 @@ ListView { font.preferShaping: false font.kerning: false onToggled: { - aiBridge.setSyncNN(switch1.checked) + aiBridge.setSyncNN(switch4.checked) } } } From 1e620988f675251fa5035e98f6c8fd54094b86c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Wed, 3 Nov 2021 12:48:53 +0100 Subject: [PATCH 41/57] make full fov default --- gui/views/AIProperties.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/gui/views/AIProperties.qml b/gui/views/AIProperties.qml index 9c7167dc9..3274cc2b9 100644 --- a/gui/views/AIProperties.qml +++ b/gui/views/AIProperties.qml @@ -150,6 +150,7 @@ ListView { y: 137 width: 37 height: 23 + checked: true onClicked: aiBridge.setFullFov(checkBoxFullFov.checked) } From 05a03e84cf50e24b13d987afe103f963597aa3b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Wed, 3 Nov 2021 12:55:58 +0100 Subject: [PATCH 42/57] update condition check --- depthai_demo.py | 2 +- gui/main.py | 2 +- gui/views/AIProperties.qml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 7fdde6cd4..1a0cf8069 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -708,7 +708,7 @@ def guiOnAiSetupUpdate(self, cnn=None, shave=None, source=None, fullFov=None, sy self.updateArg("sbbScaleFactor", sbbFactor) if ov is not None: self.updateArg("openvinoVersion", ov) - if countLabel is not None: + if countLabel is not None or cnn is not None: self.updateArg("countLabel", countLabel) def guiOnPreviewChangeSelected(self, selected): diff --git a/gui/main.py b/gui/main.py index 92e38da73..00ad282af 100644 --- a/gui/main.py +++ b/gui/main.py @@ -148,7 +148,7 @@ def setSbb(self, value): @Slot(float) def setSbbFactor(self, value): - if DemoQtGui.writer is not None: + if DemoQtGui.instance.writer is not None: DemoQtGui.instance.guiOnAiSetupUpdate(sbbFactor=value) @Slot(str) diff --git a/gui/views/AIProperties.qml b/gui/views/AIProperties.qml index 3274cc2b9..dfba629f6 100644 --- a/gui/views/AIProperties.qml +++ b/gui/views/AIProperties.qml @@ -288,11 +288,11 @@ ListView { height: 33 value: 0.3 stepSize: 0.1 + to: 1 + from: 0.1 onValueChanged: { aiBridge.setSbbFactor(value) } - to: 1 - from: 0.1 } Text { From 738ba3c742ffa4de475e2e669256bc6dc5e7cb85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Wed, 3 Nov 2021 12:58:40 +0100 Subject: [PATCH 43/57] move ov resolution to setup --- depthai_demo.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 1a0cf8069..b5632f0e9 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -70,8 +70,6 @@ def __init__(self, conf: ConfigManager, displayFrames=True, onNewFrame = noop, o self._rgbRes = conf.getRgbResolution() self._monoRes = conf.getMonoResolution() self._openvinoVersion = None - if conf.args.openvinoVersion: - self._openvinoVersion = getattr(dai.OpenVINO.Version, 'VERSION_' + conf.args.openvinoVersion) self._displayFrames = displayFrames self.onNewFrame = onNewFrame @@ -103,6 +101,8 @@ def setCallbacks(self, onNewFrame=None, onShowFrame=None, onNn=None, onReport=No def setup(self): print("Setting up demo...") + if self._conf.args.openvinoVersion: + self._openvinoVersion = getattr(dai.OpenVINO.Version, 'VERSION_' + self._conf.args.openvinoVersion) self._deviceInfo = getDeviceInfo(self._conf.args.deviceId) if self._conf.args.reportFile: reportFileP = Path(self._conf.args.reportFile).with_suffix('.csv') From 5293e62c117c7c0a8534d603cefa444b31ffd795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Wed, 3 Nov 2021 13:01:09 +0100 Subject: [PATCH 44/57] remove debug prints --- depthai_demo.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index b5632f0e9..0ac8443c0 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -395,7 +395,6 @@ def _createQueueCallback(self, queueName): def _updateCameraConfigs(self): parsedConfig = {} - print(self._cameraConfig) for configOption, values in self._cameraConfig.items(): if values is not None: for cameraName, value in values: @@ -728,7 +727,6 @@ def guiOnReloadDevices(self): def guiOnToggleColorEncoding(self, enabled, fps): oldConfig = confManager.args.encode or {} - print(enabled, fps) if enabled: oldConfig["color"] = fps elif "color" in confManager.args.encode: From f1f50447c015821be135e10b5e477fc5cdc893c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Wed, 3 Nov 2021 13:27:24 +0100 Subject: [PATCH 45/57] remove sync --- depthai_demo.py | 9 +-------- gui/main.py | 4 ---- gui/views/AIProperties.qml | 17 ----------------- 3 files changed, 1 insertion(+), 29 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 0ac8443c0..55f015ad6 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -685,7 +685,7 @@ def guiOnCameraSetupUpdate(self, name, fps=None, resolution=None): else: self.updateArg("monoResolution", resolution) - def guiOnAiSetupUpdate(self, cnn=None, shave=None, source=None, fullFov=None, sync=None, sbb=None, sbbFactor=None, ov=None, countLabel=None): + def guiOnAiSetupUpdate(self, cnn=None, shave=None, source=None, fullFov=None, sbb=None, sbbFactor=None, ov=None, countLabel=None): if cnn is not None: self.updateArg("cnnModel", cnn) if shave is not None: @@ -694,13 +694,6 @@ def guiOnAiSetupUpdate(self, cnn=None, shave=None, source=None, fullFov=None, sy self.updateArg("camera", source) if fullFov is not None: self.updateArg("disableFullFovNn", not fullFov) - if sync is not None: - self.updateArg("sync", sync) - if sync: - self.updateArg("scale", {}) - else: - self.updateArg("scale", {"color": 0.37}) - if sbb is not None: self.updateArg("spatialBoundingBox", sbb) if sbbFactor is not None: diff --git a/gui/main.py b/gui/main.py index 00ad282af..dbe12be00 100644 --- a/gui/main.py +++ b/gui/main.py @@ -138,10 +138,6 @@ def setModelSource(self, value): def setFullFov(self, value): DemoQtGui.instance.guiOnAiSetupUpdate(fullFov=value) - @Slot(bool) - def setSyncNN(self, value): - DemoQtGui.instance.guiOnAiSetupUpdate(sync=value) - @Slot(bool) def setSbb(self, value): DemoQtGui.instance.guiOnAiSetupUpdate(sbb=value) diff --git a/gui/views/AIProperties.qml b/gui/views/AIProperties.qml index dfba629f6..a821dbf79 100644 --- a/gui/views/AIProperties.qml +++ b/gui/views/AIProperties.qml @@ -153,23 +153,6 @@ ListView { checked: true onClicked: aiBridge.setFullFov(checkBoxFullFov.checked) } - - Switch { - id: switch4 - x: 90 - y: 173 - width: 300 - height: 48 - text: qsTr("Sync NN and Preview") - font.family: "Courier" - autoExclusive: false - transformOrigin: Item.Center - font.preferShaping: false - font.kerning: false - onToggled: { - aiBridge.setSyncNN(switch4.checked) - } - } } CheckBox { From 4f69f049ce6db7388302b5620dabd87e61eb9e57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Thu, 4 Nov 2021 11:01:36 +0100 Subject: [PATCH 46/57] make preview responsive --- depthai_demo.py | 13 ++++++++----- gui/views/CameraPreview.qml | 5 +++-- gui/views/root.qml | 8 ++++---- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 55f015ad6..8133dfb94 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -488,11 +488,12 @@ class WorkerSignals(QObject): errorSignal = Signal(str) class Worker(QRunnable): - def __init__(self, instance, selectedPreview=None): + def __init__(self, instance, parent, selectedPreview=None): super(Worker, self).__init__() self.running = False self.selectedPreview = selectedPreview self.instance = instance + self.parent = parent self.signals = WorkerSignals() self.signals.exitSignal.connect(self.terminate) @@ -529,12 +530,14 @@ def shouldRun(self): return self.running def onShowFrame(self, frame, source): + writerObject = self.parent.window.findChild(QObject, "writer") + w, h = int(writerObject.width()), int(writerObject.height()) if source == self.selectedPreview: - scaledFrame = resizeLetterbox(frame, (560, 560)) + scaledFrame = resizeLetterbox(frame, (w, h)) if len(frame.shape) == 3: - img = QImage(scaledFrame.data, 560, 560, frame.shape[2] * 560, QImage.Format_BGR888) + img = QImage(scaledFrame.data, w, h, frame.shape[2] * w, QImage.Format_BGR888) else: - img = QImage(scaledFrame.data, 560, 560, 560, QImage.Format_Grayscale8) + img = QImage(scaledFrame.data, w, h, w, QImage.Format_Grayscale8) self.signals.updatePreviewSignal.emit(img) def onSetup(self, instance): @@ -585,7 +588,7 @@ def showError(self, error): def start(self): self.running = True - self.worker = Worker(self._demoInstance, selectedPreview=self.selectedPreview) + self.worker = Worker(self._demoInstance, parent=self, selectedPreview=self.selectedPreview) self.worker.signals.updatePreviewSignal.connect(self.updatePreview) self.worker.signals.setDataSignal.connect(self.setData) self.worker.signals.errorSignal.connect(self.showError) diff --git a/gui/views/CameraPreview.qml b/gui/views/CameraPreview.qml index 7d22dc6ef..0c85aac3d 100644 --- a/gui/views/CameraPreview.qml +++ b/gui/views/CameraPreview.qml @@ -50,10 +50,11 @@ ListView { ImageWriter { id: imageWriter + objectName: "writer" x: 40 y: 40 - width: 560 - height: 560 + width: parent.width - 80 + height: parent.height - 80 } } } diff --git a/gui/views/root.qml b/gui/views/root.qml index 91f0d232a..c8271a213 100644 --- a/gui/views/root.qml +++ b/gui/views/root.qml @@ -107,13 +107,13 @@ ApplicationWindow { CameraPreview { x: 0 y: 0 - width: 640 + width: parent.width - 630 height: parent.height } TabBar { id: bar - x: 640 + x: parent.width - 630 y: 0 height: 50 width: 590 @@ -134,7 +134,7 @@ ApplicationWindow { } StackLayout { - x: 640 + x: parent.width - 630 y: 70 width: 630 currentIndex: bar.currentIndex @@ -153,7 +153,7 @@ ApplicationWindow { } Button { - x: 667 + x: parent.width - 600 y: 540 enabled: restartRequired || false height: 60 From 4600fe81a97515039067724469147fd3336018d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Thu, 4 Nov 2021 11:08:56 +0100 Subject: [PATCH 47/57] apply better colormap --- depthai_helpers/config_manager.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/depthai_helpers/config_manager.py b/depthai_helpers/config_manager.py index 8815c82fc..c68131c79 100644 --- a/depthai_helpers/config_manager.py +++ b/depthai_helpers/config_manager.py @@ -4,6 +4,7 @@ from pathlib import Path import cv2 import depthai as dai +import numpy as np from depthai_helpers.cli_utils import cliPrint, PrintColors from depthai_sdk.previews import Previews @@ -94,7 +95,9 @@ def convert(path: Path): return list(map(convert, filter(verify, DEPTHAI_ZOO.rglob("**/*.json")))) def getColorMap(self): - return getattr(cv2, "COLORMAP_{}".format(self.args.colorMap)) + cvColorMap = cv2.applyColorMap(np.arange(256, dtype=np.uint8), getattr(cv2, "COLORMAP_{}".format(self.args.colorMap))) + cvColorMap[0] = [0, 0, 0] + return cvColorMap def getRgbResolution(self): if self.args.rgbResolution == 2160: From 3ffb898a2dda3edf1c376172c87cf44632db3bb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Thu, 4 Nov 2021 11:15:01 +0100 Subject: [PATCH 48/57] remove run config from main gui file --- gui/main.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/gui/main.py b/gui/main.py index dbe12be00..b1192fccc 100644 --- a/gui/main.py +++ b/gui/main.py @@ -283,10 +283,3 @@ def setResolution(self, state): elif state == "THE_400_P": DemoQtGui.instance.guiOnCameraSetupUpdate("left", resolution=400) DemoQtGui.instance.guiOnCameraSetupUpdate("right", resolution=400) - - -if __name__ == "__main__": - medianChoices = list(filter(lambda name: name.startswith('KERNEL_') or name.startswith('MEDIAN_'), vars(dai.MedianFilter).keys()))[::-1] - gui = DemoQtGui() - gui.setData("medianChoices", medianChoices) - gui.startGui() From 1b51754f7e1714e54e15a30fb1375097612013de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Mon, 8 Nov 2021 10:17:19 +0100 Subject: [PATCH 49/57] move camera properties a bit down and remove flip --- depthai_sdk/src/depthai_sdk/previews.py | 8 ++++---- gui/views/CameraProperties.qml | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/depthai_sdk/src/depthai_sdk/previews.py b/depthai_sdk/src/depthai_sdk/previews.py index 5b1bc565b..99caee970 100644 --- a/depthai_sdk/src/depthai_sdk/previews.py +++ b/depthai_sdk/src/depthai_sdk/previews.py @@ -92,9 +92,9 @@ def rectifiedLeft(packet, manager=None): numpy.ndarray: Ready to use OpenCV frame """ if manager is not None and manager.lowBandwidth and not manager.sync: # TODO remove sync check once passthrough is supported for MJPEG encoding - return cv2.flip(cv2.imdecode(packet.getData(), cv2.IMREAD_GRAYSCALE), 1) + return cv2.imdecode(packet.getData(), cv2.IMREAD_GRAYSCALE) else: - return cv2.flip(packet.getCvFrame(), 1) + return packet.getCvFrame() @staticmethod def rectifiedRight(packet, manager=None): @@ -109,9 +109,9 @@ def rectifiedRight(packet, manager=None): numpy.ndarray: Ready to use OpenCV frame """ if manager is not None and manager.lowBandwidth: # TODO remove sync check once passthrough is supported for MJPEG encoding - return cv2.flip(cv2.imdecode(packet.getData(), cv2.IMREAD_GRAYSCALE), 1) + return cv2.imdecode(packet.getData(), cv2.IMREAD_GRAYSCALE) else: - return cv2.flip(packet.getCvFrame(), 1) + return packet.getCvFrame() @staticmethod def depthRaw(packet, manager=None): diff --git a/gui/views/CameraProperties.qml b/gui/views/CameraProperties.qml index f42d490e0..f6f482520 100644 --- a/gui/views/CameraProperties.qml +++ b/gui/views/CameraProperties.qml @@ -50,7 +50,7 @@ ListView { ComboBox { id: comboBox x: 85 - y: 105 + y: 115 width: 140 height: 33 model: colorResolutionChoices @@ -62,7 +62,7 @@ ListView { Text { id: text32 x: -6 - y: 74 + y: 84 width: 90 height: 25 color: "#ffffff" @@ -76,7 +76,7 @@ ListView { TextField { id: textField6 x: 85 - y: 74 + y: 84 width: 106 height: 25 text: "30" @@ -92,7 +92,7 @@ ListView { Text { id: text33 x: -6 - y: 109 + y: 119 width: 90 height: 25 color: "#ffffff" @@ -301,7 +301,7 @@ ListView { ComboBox { id: comboBox1 x: 85 - y: 105 + y: 115 width: 152 height: 33 model: monoResolutionChoices @@ -313,7 +313,7 @@ ListView { Text { id: text34 x: -6 - y: 74 + y: 84 width: 90 height: 25 color: "#ffffff" @@ -327,7 +327,7 @@ ListView { TextField { id: textField7 x: 85 - y: 74 + y: 84 width: 106 height: 25 text: "30" @@ -343,7 +343,7 @@ ListView { Text { id: text35 x: -6 - y: 109 + y: 119 width: 90 height: 25 color: "#ffffff" From 5f23ea4d55c850fb3277c76265ef7e2e7d9a1697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Tue, 9 Nov 2021 14:27:50 +0100 Subject: [PATCH 50/57] add poeQuality param --- depthai_demo.py | 25 ++++++++++--------- depthai_helpers/arg_manager.py | 1 + depthai_helpers/config_manager.py | 3 +++ .../depthai_sdk/managers/pipeline_manager.py | 19 +++++++++++--- 4 files changed, 32 insertions(+), 16 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 8133dfb94..94ece2bcf 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -61,14 +61,11 @@ class Demo: LRCT_MIN = int(os.getenv("LRCT_MIN", 0)) LRCT_MAX = int(os.getenv("LRCT_MAX", 10)) - def run_all(self): - self.setup() + def run_all(self, conf): + self.setup(conf) self.run() - def __init__(self, conf: ConfigManager, displayFrames=True, onNewFrame = noop, onShowFrame = noop, onNn = noop, onReport = noop, onSetup = noop, onTeardown = noop, onIter = noop, shouldRun = lambda: True): - self._conf = conf - self._rgbRes = conf.getRgbResolution() - self._monoRes = conf.getMonoResolution() + def __init__(self, displayFrames=True, onNewFrame = noop, onShowFrame = noop, onNn = noop, onReport = noop, onSetup = noop, onTeardown = noop, onIter = noop, shouldRun = lambda: True): self._openvinoVersion = None self._displayFrames = displayFrames @@ -99,8 +96,11 @@ def setCallbacks(self, onNewFrame=None, onShowFrame=None, onNn=None, onReport=No if shouldRun is not None: self.shouldRun = shouldRun - def setup(self): + def setup(self, conf: ConfigManager): print("Setting up demo...") + self._conf = conf + self._rgbRes = conf.getRgbResolution() + self._monoRes = conf.getMonoResolution() if self._conf.args.openvinoVersion: self._openvinoVersion = getattr(dai.OpenVINO.Version, 'VERSION_' + self._conf.args.openvinoVersion) self._deviceInfo = getDeviceInfo(self._conf.args.deviceId) @@ -108,7 +108,7 @@ def setup(self): reportFileP = Path(self._conf.args.reportFile).with_suffix('.csv') reportFileP.parent.mkdir(parents=True, exist_ok=True) self._reportFile = reportFileP.open('a') - self._pm = PipelineManager(self._openvinoVersion) + self._pm = PipelineManager(openvinoVersion=self._openvinoVersion) if self._conf.args.xlinkChunkSize is not None: self._pm.setXlinkChunkSize(self._conf.args.xlinkChunkSize) @@ -134,7 +134,7 @@ def setup(self): self._conf.adjustParamsToDevice(self._device) self._conf.adjustPreviewToOptions() if self._conf.lowBandwidth: - self._pm.enableLowBandwidth() + self._pm.enableLowBandwidth(poeQuality=self._conf.args.poeQuality) self._cap = cv2.VideoCapture(self._conf.args.video) if not self._conf.useCamera else None self._fps = FPSHandler() if self._conf.useCamera else FPSHandler(self._cap) @@ -502,6 +502,7 @@ def run(self): self.running = True self.signals.setDataSignal.emit(["restartRequired", False]) self.instance.setCallbacks(shouldRun=self.shouldRun, onShowFrame=self.onShowFrame, onSetup=self.onSetup) + confManager.args.bandwidth = "auto" if confManager.args.deviceId is None: devices = dai.Device.getAllAvailableDevices() if len(devices) > 0: @@ -513,7 +514,7 @@ def run(self): defaultDevice = devices[0].getMxId() confManager.args.deviceId = defaultDevice try: - self.instance.run_all() + self.instance.run_all(confManager) except Exception as ex: self.onError(ex) @@ -569,7 +570,7 @@ def __init__(self): self.dataInitialized = False self.appInitialized = False self.threadpool = QThreadPool() - self._demoInstance = Demo(confManager, displayFrames=False) + self._demoInstance = Demo(displayFrames=False) def updateArg(self, arg_name, arg_value, shouldUpdate=True): setattr(confManager.args, arg_name, arg_value) @@ -716,7 +717,7 @@ def guiOnSelectDevice(self, selected): def guiOnReloadDevices(self): devices = list(map(lambda info: info.getMxId(), dai.Device.getAllAvailableDevices())) if hasattr(self._demoInstance, "_deviceInfo"): - devices.append(self._demoInstance._deviceInfo.getMxId()) + devices.insert(0, self._demoInstance._deviceInfo.getMxId()) self.worker.signals.setDataSignal.emit(["deviceChoices", devices]) if len(devices) > 0: self.worker.signals.setDataSignal.emit(["restartRequired", True]) diff --git a/depthai_helpers/arg_manager.py b/depthai_helpers/arg_manager.py index 41e076b45..d4a2cdcf8 100644 --- a/depthai_helpers/arg_manager.py +++ b/depthai_helpers/arg_manager.py @@ -131,6 +131,7 @@ def parseArgs(): "Example: -enc color right,10 left,10") parser.add_argument('-encout', '--encodeOutput', type=Path, default=projectRoot, help="Path to directory where to store encoded files. Default: %(default)s") parser.add_argument('-xls', '--xlinkChunkSize', type=int, help="Specify XLink chunk size") + parser.add_argument('-poeq', '--poeQuality', type=checkRange(1, 100), help="Specify PoE encoding video quality (1-100)") parser.add_argument('-camo', '--cameraOrientation', type=_comaSeparated(default="AUTO", cast=orientationCast), nargs="+", default=[], help=("Define cameras orientation (available: {}) \n" "Format: camera_name,camera_orientation \n" diff --git a/depthai_helpers/config_manager.py b/depthai_helpers/config_manager.py index c68131c79..2d32d403d 100644 --- a/depthai_helpers/config_manager.py +++ b/depthai_helpers/config_manager.py @@ -184,6 +184,9 @@ def adjustParamsToDevice(self, device): if deviceInfo.desc.protocol != dai.XLinkProtocol.X_LINK_USB_VSC: print("Enabling low-bandwidth mode due to connection mode... (protocol: {})".format(deviceInfo.desc.protocol)) self.args.bandwidth = "low" + if self.args.poeQuality is None: + print("Setting PoE video quality to 50 to reduce latency...") + self.args.poeQuality = 50 elif device.getUsbSpeed() not in [dai.UsbSpeed.SUPER, dai.UsbSpeed.SUPER_PLUS]: print("Enabling low-bandwidth mode due to low USB speed... (speed: {})".format(device.getUsbSpeed())) self.args.bandwidth = "low" diff --git a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py index 5f2c3ec86..d58d513d6 100644 --- a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py +++ b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py @@ -10,8 +10,10 @@ class PipelineManager: and connection logic onto a set of convenience functions. """ - def __init__(self, openvinoVersion=None): + def __init__(self, openvinoVersion=None, poeQuality=100): self.openvinoVersion=openvinoVersion + self.poeQuality = poeQuality + #: depthai.Pipeline: Ready to use requested pipeline. Can be passed to :obj:`depthai.Device` to start execution self.pipeline = dai.Pipeline() #: types.SimpleNamespace: Contains all nodes added to the :attr:`pipeline` object, can be used to conveniently access nodes by their name @@ -22,6 +24,8 @@ def __init__(self, openvinoVersion=None): #: depthai.OpenVINO.Version: OpenVINO version which will be used in pipeline openvinoVersion = None + #: int, Optional: PoE encoding quality, can decrease frame quality but decrease latency + poeQuality = None #: bool: If set to :code:`True`, manager will MJPEG-encode the packets sent from device to host to lower the bandwidth usage. **Can break** if more than 3 encoded outputs requested lowBandwidth = False @@ -129,6 +133,7 @@ def _mjpegLink(self, node, xout, nodeOutput): manip.out.link(videnc.input) else: raise NotImplementedError("Unable to create mjpeg link for encountered node type: {}".format(type(node))) + videnc.setQuality(self.poeQuality) videnc.bitstream.link(xout.input) def createColorCam(self, previewSize=None, res=dai.ColorCameraProperties.SensorResolution.THE_1080_P, fps=30, fullFov=True, orientation: dai.CameraImageOrientation=None, xout=False): @@ -462,13 +467,14 @@ def createSystemLogger(self, rate=1): self.nodes.xoutSystemLogger.setStreamName("systemLogger") self.nodes.systemLogger.out.link(self.nodes.xoutSystemLogger.input) - def createEncoder(self, cameraName, encFps=30): + def createEncoder(self, cameraName, encFps=30, encQuality=100): """ Creates H.264 / H.265 video encoder (:obj:`depthai.node.VideoEncoder` instance) Args: cameraName (str): Camera name to create the encoder for encFps (int, Optional): Specify encoding FPS + encQuality (int, Optional): Specify encoding quality (1-100) Raises: ValueError: if cameraName is not a supported camera name @@ -504,6 +510,7 @@ def createEncoder(self, cameraName, encFps=30): enc = self.pipeline.createVideoEncoder() enc.setDefaultProfilePreset(*encResolution, encFps, encProfile) + enc.setQuality(encQuality) encIn.link(enc.input) setattr(self.nodes, nodeName, enc) @@ -512,11 +519,15 @@ def createEncoder(self, cameraName, encFps=30): encXout.setStreamName(xoutName) setattr(self.nodes, xoutName, encXout) - def enableLowBandwidth(self): + def enableLowBandwidth(self, poeQuality): """ - Enables low-bandwidth mode. + Enables low-bandwidth mode + + Args: + poeQuality (int, Optional): PoE encoding quality, can decrease frame quality but decrease latency """ self.lowBandwidth = True + self.poeQuality = poeQuality def setXlinkChunkSize(self, chunkSize): self.pipeline.setXLinkChunkSize(chunkSize) From d73ae67f22a6afe359dc7396434b78bb91f9a0f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Tue, 9 Nov 2021 14:42:13 +0100 Subject: [PATCH 51/57] dont wait for PoE devices to come available --- depthai_demo.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/depthai_demo.py b/depthai_demo.py index 94ece2bcf..590562e4b 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -602,11 +602,14 @@ def start(self): def stop(self): current_mxid = None + protocol = None if hasattr(self._demoInstance, "_device"): current_mxid = self._demoInstance._device.getMxId() + protocol = self._demoInstance._deviceInfo.desc.protocol self.worker.signals.exitSignal.emit() self.threadpool.waitForDone(100) - if current_mxid is not None: + + if current_mxid is not None and protocol == dai.XLinkProtocol.X_LINK_USB_VSC: start = time.time() while time.time() - start < 10: if current_mxid in list(map(lambda info: info.getMxId(), dai.Device.getAllAvailableDevices())): From 8d803230fe9aaaa64a0db8d46a7860cb3a46b2aa Mon Sep 17 00:00:00 2001 From: Martin Peterlin Date: Fri, 12 Nov 2021 03:05:48 +0100 Subject: [PATCH 52/57] Fixed Windows installer --- launcher/windows/installer_win64.iss | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/launcher/windows/installer_win64.iss b/launcher/windows/installer_win64.iss index aeaa55ae0..9de67794f 100644 --- a/launcher/windows/installer_win64.iss +++ b/launcher/windows/installer_win64.iss @@ -150,6 +150,7 @@ begin Result := 1; end; +{* Handles uninstallation if previous DepthAI version is installed and shortcut creation *} procedure CurStepChanged(CurStep: TSetupStep); var ResultCode: Integer; @@ -159,12 +160,14 @@ begin if (IsUpgrade()) then begin UnInstallOldVersion(); - Log('Creating main shortcut'); - ExtractTemporaryFile('create_shortcut.ps1'); - ForceDirectories(ExpandConstant('{app}')); - FileCopy(ExpandConstant('{tmp}\create_shortcut.ps1'), ExpandConstant('{app}\create_shortcut.ps1'), False); - Exec('powershell.exe', ExpandConstant('-ExecutionPolicy Bypass -File {app}\create_shortcut.ps1'), ExpandConstant('{app}'), SW_HIDE, ewWaitUntilTerminated, ResultCode); end; + + Log('Creating main shortcut'); + ExtractTemporaryFile('create_shortcut.ps1'); + ForceDirectories(ExpandConstant('{app}')); + FileCopy(ExpandConstant('{tmp}\create_shortcut.ps1'), ExpandConstant('{app}\create_shortcut.ps1'), False); + Exec('powershell.exe', ExpandConstant('-ExecutionPolicy Bypass -File {app}\create_shortcut.ps1'), ExpandConstant('{app}'), SW_HIDE, ewWaitUntilTerminated, ResultCode); + end; end; From 1677e22d3ccb31ac2bf63f3e04fa1db734a5f429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Fri, 12 Nov 2021 14:10:11 +0100 Subject: [PATCH 53/57] split options bootstrap --- depthai_demo.py | 9 --------- gui/main.py | 10 ++++++++++ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 590562e4b..6c19f0a87 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -542,16 +542,7 @@ def onShowFrame(self, frame, source): self.signals.updatePreviewSignal.emit(img) def onSetup(self, instance): - medianChoices = list(filter(lambda name: name.startswith('KERNEL_') or name.startswith('MEDIAN_'), vars(dai.MedianFilter).keys()))[::-1] - self.signals.setDataSignal.emit(["medianChoices", medianChoices]) - colorChoices = list(filter(lambda name: name[0].isupper(), vars(dai.ColorCameraProperties.SensorResolution).keys())) - self.signals.setDataSignal.emit(["colorResolutionChoices", colorChoices]) - monoChoices = list(filter(lambda name: name[0].isupper(), vars(dai.MonoCameraProperties.SensorResolution).keys())) - self.signals.setDataSignal.emit(["monoResolutionChoices", monoChoices]) self.signals.setDataSignal.emit(["previewChoices", confManager.args.show]) - self.signals.setDataSignal.emit(["modelSourceChoices", [Previews.color.name, Previews.left.name, Previews.right.name]]) - versionChoices = sorted(filter(lambda name: name.startswith("VERSION_"), vars(dai.OpenVINO).keys()), reverse=True) - self.signals.setDataSignal.emit(["ovVersions", versionChoices]) devices = [self.instance._deviceInfo.getMxId()] + list(map(lambda info: info.getMxId(), dai.Device.getAllAvailableDevices())) self.signals.setDataSignal.emit(["deviceChoices", devices]) if instance._nnManager is not None: diff --git a/gui/main.py b/gui/main.py index b1192fccc..f53a0ad66 100644 --- a/gui/main.py +++ b/gui/main.py @@ -10,6 +10,7 @@ # (QML_IMPORT_MINOR_VERSION is optional) from PySide6.QtQuick import QQuickPaintedItem from PySide6.QtWidgets import QMessageBox, QApplication +from depthai_sdk import Previews QML_IMPORT_NAME = "dai.gui" QML_IMPORT_MAJOR_VERSION = 1 @@ -66,6 +67,15 @@ def updatePreview(self, data): def startGui(self): self.writer = ImageWriter() + medianChoices = list(filter(lambda name: name.startswith('KERNEL_') or name.startswith('MEDIAN_'), vars(dai.MedianFilter).keys()))[::-1] + self.setData(["medianChoices", medianChoices]) + colorChoices = list(filter(lambda name: name[0].isupper(), vars(dai.ColorCameraProperties.SensorResolution).keys())) + self.setData(["colorResolutionChoices", colorChoices]) + monoChoices = list(filter(lambda name: name[0].isupper(), vars(dai.MonoCameraProperties.SensorResolution).keys())) + self.setData(["monoResolutionChoices", monoChoices]) + self.setData(["modelSourceChoices", [Previews.color.name, Previews.left.name, Previews.right.name]]) + versionChoices = sorted(filter(lambda name: name.startswith("VERSION_"), vars(dai.OpenVINO).keys()), reverse=True) + self.setData(["ovVersions", versionChoices]) return self.app.exec() From 4134a06ced97d581eb61dbaa599a483de152e893 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Fri, 12 Nov 2021 14:31:55 +0100 Subject: [PATCH 54/57] tweak poe quality option --- depthai_helpers/arg_manager.py | 2 +- depthai_helpers/config_manager.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/depthai_helpers/arg_manager.py b/depthai_helpers/arg_manager.py index d4a2cdcf8..e423f360a 100644 --- a/depthai_helpers/arg_manager.py +++ b/depthai_helpers/arg_manager.py @@ -131,7 +131,7 @@ def parseArgs(): "Example: -enc color right,10 left,10") parser.add_argument('-encout', '--encodeOutput', type=Path, default=projectRoot, help="Path to directory where to store encoded files. Default: %(default)s") parser.add_argument('-xls', '--xlinkChunkSize', type=int, help="Specify XLink chunk size") - parser.add_argument('-poeq', '--poeQuality', type=checkRange(1, 100), help="Specify PoE encoding video quality (1-100)") + parser.add_argument('-poeq', '--poeQuality', type=checkRange(1, 100), default=100, help="Specify PoE encoding video quality (1-100)") parser.add_argument('-camo', '--cameraOrientation', type=_comaSeparated(default="AUTO", cast=orientationCast), nargs="+", default=[], help=("Define cameras orientation (available: {}) \n" "Format: camera_name,camera_orientation \n" diff --git a/depthai_helpers/config_manager.py b/depthai_helpers/config_manager.py index 2d32d403d..69956c34f 100644 --- a/depthai_helpers/config_manager.py +++ b/depthai_helpers/config_manager.py @@ -184,9 +184,8 @@ def adjustParamsToDevice(self, device): if deviceInfo.desc.protocol != dai.XLinkProtocol.X_LINK_USB_VSC: print("Enabling low-bandwidth mode due to connection mode... (protocol: {})".format(deviceInfo.desc.protocol)) self.args.bandwidth = "low" - if self.args.poeQuality is None: - print("Setting PoE video quality to 50 to reduce latency...") - self.args.poeQuality = 50 + print("Setting PoE video quality to 50 to reduce latency...") + self.args.poeQuality = 50 elif device.getUsbSpeed() not in [dai.UsbSpeed.SUPER, dai.UsbSpeed.SUPER_PLUS]: print("Enabling low-bandwidth mode due to low USB speed... (speed: {})".format(device.getUsbSpeed())) self.args.bandwidth = "low" From 5d61ef85ea46afd61102c2000f0c0d66846cf3a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Fri, 12 Nov 2021 14:59:27 +0100 Subject: [PATCH 55/57] change to exit code --- depthai_demo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depthai_demo.py b/depthai_demo.py index 6c19f0a87..48455184f 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -589,7 +589,7 @@ def start(self): self.appInitialized = True exit_code = self.startGui() self.stop() - raise SystemExit(exit_code) + sys.exit(exit_code) def stop(self): current_mxid = None From cb0c3df7bf44bb1ff5b78e648d1caf820fdd7a7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Fri, 12 Nov 2021 15:15:56 +0100 Subject: [PATCH 56/57] add wait param --- depthai_demo.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 48455184f..20a84b1c3 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -588,10 +588,10 @@ def start(self): if not self.appInitialized: self.appInitialized = True exit_code = self.startGui() - self.stop() + self.stop(wait=False) sys.exit(exit_code) - def stop(self): + def stop(self, wait=True): current_mxid = None protocol = None if hasattr(self._demoInstance, "_device"): @@ -600,7 +600,7 @@ def stop(self): self.worker.signals.exitSignal.emit() self.threadpool.waitForDone(100) - if current_mxid is not None and protocol == dai.XLinkProtocol.X_LINK_USB_VSC: + if wait and current_mxid is not None and protocol == dai.XLinkProtocol.X_LINK_USB_VSC: start = time.time() while time.time() - start < 10: if current_mxid in list(map(lambda info: info.getMxId(), dai.Device.getAllAvailableDevices())): @@ -608,7 +608,6 @@ def stop(self): else: raise RuntimeError("Device not available again after 10 seconds!") - def restartDemo(self): self.stop() self.start() From e5df395c187e8187a14f298167a2856ea06851f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Fri, 12 Nov 2021 18:55:28 +0100 Subject: [PATCH 57/57] add --skipVersionCheck param --- depthai_demo.py | 5 +++-- depthai_helpers/arg_manager.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 20a84b1c3..e63c0a2eb 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -19,10 +19,11 @@ print('Using depthai module from: ', dai.__file__) print('Depthai version installed: ', dai.__version__) -if platform.machine() not in ['armv6l', 'aarch64']: +args = parseArgs() +if not args.skipVersionCheck and platform.machine() not in ['armv6l', 'aarch64']: checkRequirementsVersion() -confManager = ConfigManager(parseArgs()) +confManager = ConfigManager(args) confManager.linuxCheckApplyUsbRules() if not confManager.useCamera: if str(confManager.args.video).startswith('https'): diff --git a/depthai_helpers/arg_manager.py b/depthai_helpers/arg_manager.py index e423f360a..74c394402 100644 --- a/depthai_helpers/arg_manager.py +++ b/depthai_helpers/arg_manager.py @@ -144,5 +144,5 @@ def parseArgs(): parser.add_argument("--cameraContrast", type=_comaSeparated("all", int), nargs="+", help="Specify image contrast") parser.add_argument("--cameraBrightness", type=_comaSeparated("all", int), nargs="+", help="Specify image brightness") parser.add_argument("--cameraSharpness", type=_comaSeparated("all", int), nargs="+", help="Specify image sharpness") - + parser.add_argument('--skipVersionCheck', action="store_true", help="Disable libraries version check") return parser.parse_args()