From 2c24aef51c133e5c712d708897d6be9ff7362d24 Mon Sep 17 00:00:00 2001 From: Rainer Kartmann <rainer.kartmann@kit.edu> Date: Wed, 1 Sep 2021 14:46:33 +0200 Subject: [PATCH] Handle image in visitors and InstanceView --- .../armem_gui/instance/ImageView.cpp | 1 - .../libraries/armem_gui/instance/ImageView.h | 4 +- .../armem_gui/instance/InstanceView.cpp | 119 ++++++++++++++++-- .../display_visitors/DataDisplayVisitor.cpp | 3 +- .../TypedDataDisplayVisitor.cpp | 8 ++ .../TypedDataDisplayVisitor.h | 1 + .../navigator/visitors/TypedDataVisitor.cpp | 4 + .../navigator/visitors/TypedDataVisitor.h | 11 ++ 8 files changed, 137 insertions(+), 14 deletions(-) diff --git a/source/RobotAPI/libraries/armem_gui/instance/ImageView.cpp b/source/RobotAPI/libraries/armem_gui/instance/ImageView.cpp index 05979fe8f..8c75fbd87 100644 --- a/source/RobotAPI/libraries/armem_gui/instance/ImageView.cpp +++ b/source/RobotAPI/libraries/armem_gui/instance/ImageView.cpp @@ -13,7 +13,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * -* @package ArmarX:: * @author Rainer Kartmann ( rainer dot kartmann at kit dot edu) * @date 2021 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt diff --git a/source/RobotAPI/libraries/armem_gui/instance/ImageView.h b/source/RobotAPI/libraries/armem_gui/instance/ImageView.h index d684bbccc..4b85e093a 100644 --- a/source/RobotAPI/libraries/armem_gui/instance/ImageView.h +++ b/source/RobotAPI/libraries/armem_gui/instance/ImageView.h @@ -13,7 +13,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * -* @package ArmarX:: * @author Rainer Kartmann ( rainer dot kartmann at kit dot edu) * @date 2021 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt @@ -29,6 +28,9 @@ namespace armarx::armem::gui::instance { + /** + * @brief A widget drawing an image in itself. + */ class ImageView : public QWidget { Q_OBJECT diff --git a/source/RobotAPI/libraries/armem_gui/instance/InstanceView.cpp b/source/RobotAPI/libraries/armem_gui/instance/InstanceView.cpp index 8fda3cc4b..8108d64a9 100644 --- a/source/RobotAPI/libraries/armem_gui/instance/InstanceView.cpp +++ b/source/RobotAPI/libraries/armem_gui/instance/InstanceView.cpp @@ -15,6 +15,7 @@ #include <QVBoxLayout> #include <SimoxUtility/algorithm/string.h> +#include <SimoxUtility/color/cmaps.h> #include <ArmarXCore/core/exceptions/local/ExpressionException.h> @@ -266,6 +267,7 @@ namespace armarx::armem::gui::instance aron::type::Descriptor type = static_cast<aron::type::Descriptor>(item->data(int(Columns::TYPE), Qt::UserRole).toInt()); switch (type) { + case aron::type::Descriptor::eImage: case aron::type::Descriptor::eIVTCByteImage: { if (const std::optional<aron::Path> path = getElementPath(item)) @@ -395,11 +397,11 @@ namespace armarx::armem::gui::instance void InstanceView::showImageView(const aron::Path& elementPath) { - if (!currentInstance) + if (not currentInstance) { return; } - if (!imageView) + if (not imageView) { WidgetsWithToolbar* toolbar = new WidgetsWithToolbar(); @@ -425,15 +427,75 @@ namespace armarx::armem::gui::instance } + static + QImage convertDepth32ToRGB32(const aron::datanavigator::NDArrayNavigator& aron) + { + const std::vector<int> shape = aron.getDimensions(); + ARMARX_CHECK_EQUAL(shape.size(), 3); + ARMARX_CHECK_EQUAL(shape.at(2), 4) << "Expected Depth32 image to have 4 bytes per pixel."; + + const int rows = shape.at(0); + const int cols = shape.at(1); + + // Rendering seems to be optimized for RGB32 + // rows go along 0 = height, cols go along 1 = width + QImage image(cols, rows, QImage::Format::Format_RGB32); + const float* data = reinterpret_cast<float*>(aron.getData()); + + // Find data range and adapt cmap. + simox::ColorMap cmap = simox::color::cmaps::plasma(); + float min = data[0]; + float max = data[0]; + + { + const float* sourceRow = data; + for (int row = 0; row < rows; ++row) + { + for (int col = 0; col < cols; ++col) + { + float value = sourceRow[col]; + min = std::min(min, value); + max = std::max(max, value); + } + sourceRow += cols; + } + cmap.set_vlimits(min, max); + } + { + const float* sourceRow = data; + + const int bytesPerLine = image.bytesPerLine(); + uchar* targetRow = image.bits(); + + for (int row = 0; row < rows; ++row) + { + for (int col = 0; col < cols; ++col) + { + float value = sourceRow[col]; + simox::Color color = cmap(value); + targetRow[col*4 + 0] = color.b; + targetRow[col*4 + 1] = color.g; + targetRow[col*4 + 2] = color.r; + targetRow[col*4 + 3] = color.a; + } + sourceRow += cols; + targetRow += bytesPerLine; + } + } + + return image; + } + + void InstanceView::updateImageView(const aron::datanavigator::DictNavigatorPtr& data) { using aron::datanavigator::NDArrayNavigator; - if (!imageView) + if (not imageView) { return; } - if (!data) + if (not data) { removeImageView(); return; @@ -460,39 +522,74 @@ namespace armarx::armem::gui::instance } NDArrayNavigator::PointerType imageData = NDArrayNavigator::DynamicCast(element); - if (!imageData) + if (not imageData) { showErrorMessage("Expected NDArrayNavigator, but got: " + simox::meta::get_type_name(element)); return; } - std::vector<int> shape = imageData->getDimensions(); + const std::vector<int> shape = imageData->getDimensions(); if (shape.size() != 3) { showErrorMessage("Expected array shape with 3 dimensions, but got: " + NDArrayNavigator::DimensionsToString(shape)); return; } + const int rows = shape.at(0); + const int cols = shape.at(1); + + using aron::typenavigator::ImagePixelType; + std::optional<ImagePixelType> pixelType; + try + { + pixelType = aron::typenavigator::ImageNavigator::pixelTypeFromName(imageData->getType()); + } + catch (const aron::error::AronException&) + { + } - QImage::Format format = QImage::Format::Format_Invalid; - switch (shape.at(2)) + std::optional<QImage> image; + if (pixelType) { + switch (pixelType.value()) + { + case ImagePixelType::RGB24: + ARMARX_CHECK_EQUAL(shape.at(2), 3) << "Expected Rgb24 image to have 3 bytes per pixel."; + image = QImage(imageData->getData(), cols, rows, QImage::Format::Format_RGB888); + break; + + case ImagePixelType::DEPTH32: + image = convertDepth32ToRGB32(*imageData); + break; + } + } + else + { + QImage::Format format = QImage::Format_Invalid; + switch (shape.at(2)) + { case 1: format = QImage::Format::Format_Grayscale8; break; + case 3: format = QImage::Format::Format_RGB888; break; + default: showErrorMessage("Expected 1 or 3 elements in last dimension, but got shape: " + NDArrayNavigator::DimensionsToString(shape)); return; + } + image = QImage(imageData->getData(), cols, rows, format); } + ARMARX_CHECK(image.has_value()); + std::stringstream title; - title << "Image element '" << imageView->elementPath.toString() << "'"; // of entity instance " << currentInstance->id(); + title << "Image element '" << imageView->elementPath.toString() << "'"; // of entity instance " << currentInstance->id(); imageView->setTitle(QString::fromStdString(title.str())); - imageView->view->setImage(QImage(imageData->getData(), shape.at(0), shape.at(1), format)); + imageView->view->setImage(image.value()); } @@ -501,7 +598,7 @@ namespace armarx::armem::gui::instance setLayout(new QHBoxLayout()); int margin = 2; layout()->setContentsMargins(margin, margin, margin, margin); - if (false) + if (/* DISABLES CODE */ (false)) { QFont font = this->font(); font.setPointSizeF(font.pointSize() * 0.75); diff --git a/source/RobotAPI/libraries/armem_gui/instance/display_visitors/DataDisplayVisitor.cpp b/source/RobotAPI/libraries/armem_gui/instance/display_visitors/DataDisplayVisitor.cpp index f41f5d4cb..af2192c2a 100644 --- a/source/RobotAPI/libraries/armem_gui/instance/display_visitors/DataDisplayVisitor.cpp +++ b/source/RobotAPI/libraries/armem_gui/instance/display_visitors/DataDisplayVisitor.cpp @@ -68,7 +68,8 @@ namespace armarx::aron bool DataDisplayVisitor::visit(NDArrayDataNavigator& n) { - value << "shape " << aron::datanavigator::NDArrayNavigator::DimensionsToString(n.getDimensions()); + value << "shape " << aron::datanavigator::NDArrayNavigator::DimensionsToString(n.getDimensions()) + << ", type '" << n.getType() << "'"; return false; } diff --git a/source/RobotAPI/libraries/armem_gui/instance/display_visitors/TypedDataDisplayVisitor.cpp b/source/RobotAPI/libraries/armem_gui/instance/display_visitors/TypedDataDisplayVisitor.cpp index eb1cda5fd..16c54007a 100644 --- a/source/RobotAPI/libraries/armem_gui/instance/display_visitors/TypedDataDisplayVisitor.cpp +++ b/source/RobotAPI/libraries/armem_gui/instance/display_visitors/TypedDataDisplayVisitor.cpp @@ -140,6 +140,14 @@ namespace armarx::aron return false; } + bool TypedDataDisplayVisitor::visit(ImageNavigator&, NDArrayDataNavigator& data) + { + // aron::typenavigator::ImagePixelType pixelType = ImageNavigator::pixelTypeFromName(data.getType()); + //value << DataDisplayVisitor::getValue(data) << " pixel type: " << data.getType()"; + value << DataDisplayVisitor::getValue(data); + return false; + } + bool TypedDataDisplayVisitor::visit(IVTCByteImageTypeNavigator&, NDArrayDataNavigator& data) { value << DataDisplayVisitor::getValue(data); diff --git a/source/RobotAPI/libraries/armem_gui/instance/display_visitors/TypedDataDisplayVisitor.h b/source/RobotAPI/libraries/armem_gui/instance/display_visitors/TypedDataDisplayVisitor.h index 87220babb..4bf2ec5d8 100644 --- a/source/RobotAPI/libraries/armem_gui/instance/display_visitors/TypedDataDisplayVisitor.h +++ b/source/RobotAPI/libraries/armem_gui/instance/display_visitors/TypedDataDisplayVisitor.h @@ -44,6 +44,7 @@ namespace armarx::aron bool visit(EigenMatrixTypeNavigator&, NDArrayDataNavigator& data) override; bool visit(EigenQuaternionTypeNavigator&, NDArrayDataNavigator& data) override; + bool visit(ImageNavigator&, NDArrayDataNavigator& data) override; bool visit(IVTCByteImageTypeNavigator&, NDArrayDataNavigator& data) override; bool visit(OpenCVMatTypeNavigator&, NDArrayDataNavigator& data) override; bool visit(PCLPointCloudTypeNavigator&, NDArrayDataNavigator& data) override; diff --git a/source/RobotAPI/libraries/aron/core/navigator/visitors/TypedDataVisitor.cpp b/source/RobotAPI/libraries/aron/core/navigator/visitors/TypedDataVisitor.cpp index e99a7f916..fe98e3abe 100644 --- a/source/RobotAPI/libraries/aron/core/navigator/visitors/TypedDataVisitor.cpp +++ b/source/RobotAPI/libraries/aron/core/navigator/visitors/TypedDataVisitor.cpp @@ -155,6 +155,10 @@ namespace armarx::aron::visitor { return visit(*t, key, dynamic_cast<NDArrayDataNavigator&>(data)); } + else if (auto t = dynamic_cast<ImageNavigator*>(&type)) + { + return visit(*t, key, dynamic_cast<NDArrayDataNavigator&>(data)); + } else if (auto t = dynamic_cast<IVTCByteImageTypeNavigator*>(&type)) { return visit(*t, key, dynamic_cast<NDArrayDataNavigator&>(data)); diff --git a/source/RobotAPI/libraries/aron/core/navigator/visitors/TypedDataVisitor.h b/source/RobotAPI/libraries/aron/core/navigator/visitors/TypedDataVisitor.h index f577903a4..b2efdaa79 100644 --- a/source/RobotAPI/libraries/aron/core/navigator/visitors/TypedDataVisitor.h +++ b/source/RobotAPI/libraries/aron/core/navigator/visitors/TypedDataVisitor.h @@ -79,6 +79,7 @@ namespace armarx::aron::visitor // Array-valued using EigenMatrixTypeNavigator = typenavigator::EigenMatrixNavigator; using EigenQuaternionTypeNavigator = typenavigator::EigenQuaternionNavigator; + using ImageNavigator = typenavigator::ImageNavigator; using IVTCByteImageTypeNavigator = typenavigator::IVTCByteImageNavigator; using OpenCVMatTypeNavigator = typenavigator::OpenCVMatNavigator; using PCLPointCloudTypeNavigator = typenavigator::PCLPointCloudNavigator; @@ -193,6 +194,11 @@ namespace armarx::aron::visitor (void) type, (void) data; return true; } + virtual bool visit(ImageNavigator& type, NDArrayDataNavigator& data) + { + (void) type, (void) data; + return true; + } virtual bool visit(IVTCByteImageTypeNavigator& type, NDArrayDataNavigator& data) { (void) type, (void) data; @@ -323,6 +329,11 @@ namespace armarx::aron::visitor (void) type, (void) key; return visit(type, data); } + virtual bool visit(ImageNavigator& type, const std::string& key, NDArrayDataNavigator& data) + { + (void) type, (void) key; + return visit(type, data); + } virtual bool visit(IVTCByteImageTypeNavigator& type, const std::string& key, NDArrayDataNavigator& data) { (void) type, (void) key; -- GitLab