Add features to create polygons from visible contour map geometry

This commit is contained in:
Magne Sjaastad
2025-01-16 17:06:25 +01:00
parent 510a0f8b37
commit a184af264b
16 changed files with 884 additions and 27 deletions

View File

@@ -99,6 +99,10 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RicNewWellTargetCandidatesGeneratorFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicNewStatisticsContourMapFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicNewStatisticsContourMapViewFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicCreateContourMapPolygonFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicCreateContourMapPolygonAdvancedFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicCreateContourMapPolygonTools.h
${CMAKE_CURRENT_LIST_DIR}/RicPolygonFromImageDialog.h
)
set(SOURCE_GROUP_SOURCE_FILES
@@ -202,6 +206,10 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RicNewWellTargetCandidatesGeneratorFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicNewStatisticsContourMapFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicNewStatisticsContourMapViewFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicCreateContourMapPolygonFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicCreateContourMapPolygonAdvancedFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicCreateContourMapPolygonTools.cpp
${CMAKE_CURRENT_LIST_DIR}/RicPolygonFromImageDialog.cpp
)
if(RESINSIGHT_USE_QT_CHARTS)

View File

@@ -0,0 +1,60 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicCreateContourMapPolygonAdvancedFeature.h"
#include "RicCreateContourMapPolygonTools.h"
#include "RicPolygonFromImageDialog.h"
#include <QAction>
CAF_CMD_SOURCE_INIT( RicCreateContourMapPolygonAdvancedFeature, "RicCreateContourMapPolygonAdvancedFeature" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCreateContourMapPolygonAdvancedFeature::onActionTriggered( bool isChecked )
{
auto rigContourMapProjection = RicCreateContourMapPolygonTools::findCurrentContourMapProjection();
if ( !rigContourMapProjection ) return;
auto sourceImage = RicCreateContourMapPolygonTools::convertToBinaryImage( rigContourMapProjection );
ImageProcessingDialog dlg;
dlg.setSourceImageData( sourceImage );
dlg.show();
dlg.updateAndShowImages();
if ( dlg.exec() == QDialog::Rejected ) return;
auto processedImage = dlg.processedImageData();
if ( processedImage.empty() ) return;
RicCreateContourMapPolygonTools::createAndAddBoundaryPolygonFromImage( processedImage, rigContourMapProjection );
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCreateContourMapPolygonAdvancedFeature::setupActionLook( QAction* actionToSetup )
{
actionToSetup->setIcon( QIcon( ":/PolylinesFromFile16x16.png" ) );
actionToSetup->setText( "Create Polygon From Contour Map (Developers Only)" );
}

View File

@@ -0,0 +1,33 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafCmdFeature.h"
//==================================================================================================
///
//==================================================================================================
class RicCreateContourMapPolygonAdvancedFeature : public caf::CmdFeature
{
CAF_CMD_HEADER_INIT;
protected:
void onActionTriggered( bool isChecked ) override;
void setupActionLook( QAction* actionToSetup ) override;
};

View File

@@ -0,0 +1,58 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicCreateContourMapPolygonFeature.h"
#include "RicCreateContourMapPolygonTools.h"
#include "RigPolygonTools.h"
#include <QAction>
CAF_CMD_SOURCE_INIT( RicCreateContourMapPolygonFeature, "RicCreateContourMapPolygonFeature" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCreateContourMapPolygonFeature::onActionTriggered( bool isChecked )
{
auto rigContourMapProjection = RicCreateContourMapPolygonTools::findCurrentContourMapProjection();
if ( !rigContourMapProjection ) return;
auto sourceImage = RicCreateContourMapPolygonTools::convertToBinaryImage( rigContourMapProjection );
const int kernelSize = 3;
auto floodFilled = RigPolygonTools::fillInterior( sourceImage );
auto eroded = RigPolygonTools::erode( floodFilled, kernelSize );
auto dilated = RigPolygonTools::dilate( eroded, kernelSize );
if ( dilated.empty() ) return;
RicCreateContourMapPolygonTools::createAndAddBoundaryPolygonFromImage( dilated, rigContourMapProjection );
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCreateContourMapPolygonFeature::setupActionLook( QAction* actionToSetup )
{
actionToSetup->setIcon( QIcon( ":/PolylinesFromFile16x16.png" ) );
actionToSetup->setText( "Create Polygon From Contour Map" );
}

View File

@@ -0,0 +1,33 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafCmdFeature.h"
//==================================================================================================
///
//==================================================================================================
class RicCreateContourMapPolygonFeature : public caf::CmdFeature
{
CAF_CMD_HEADER_INIT;
protected:
void onActionTriggered( bool isChecked ) override;
void setupActionLook( QAction* actionToSetup ) override;
};

View File

@@ -0,0 +1,250 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2024- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicCreateContourMapPolygonTools.h"
#include "RicExportContourMapToTextFeature.h"
#include "RigContourMapProjection.h"
#include "RigPolygonTools.h"
#include "Polygons/RimPolygon.h"
#include "Polygons/RimPolygonCollection.h"
#include "RimContourMapProjection.h"
#include "RimEclipseContourMapView.h"
#include "RimGeoMechContourMapView.h"
#include "RimTools.h"
#include "cvfBase.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QImage RicCreateContourMapPolygonTools::convertBinaryToImage( const std::vector<std::vector<int>>& data, QColor color, int transparency )
{
if ( data.empty() || data[0].empty() )
{
qWarning( "Data is empty. Cannot export an image." );
return {};
}
// Get dimensions
int height = static_cast<int>( data[0].size() );
int width = static_cast<int>( data.size() );
// Create a QImage
QImage image( width, height, QImage::Format_ARGB32 );
// Fill QImage with data
for ( int y = 0; y < height; ++y )
{
for ( int x = 0; x < width; ++x )
{
int value = std::clamp( data[x][y], 0, 255 );
if ( value > 0 )
image.setPixel( x, height - y - 1, qRgba( color.red(), color.green(), color.blue(), transparency ) ); // Grayscale
else
{
image.setPixel( x, height - y - 1, qRgba( 0, 0, 0, transparency ) );
}
}
}
return image;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QImage RicCreateContourMapPolygonTools::convertBinaryToGrayscaleImage( const std::vector<std::vector<int>>& data, int colorValue )
{
if ( data.empty() || data[0].empty() )
{
qWarning( "Data is empty. Cannot export an image." );
return {};
}
// Get dimensions
int height = static_cast<int>( data[0].size() );
int width = static_cast<int>( data.size() );
// Create a QImage
QImage image( width, height, QImage::Format_Grayscale8 );
// Fill QImage with data
for ( int y = 0; y < height; ++y )
{
for ( int x = 0; x < width; ++x )
{
int value = std::clamp( data[x][y] * colorValue, 0, 255 ); // Ensure value is in [0, 255]
image.setPixel( x, height - y - 1, qRgb( value, value, value ) ); // Grayscale
}
}
return image;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCreateContourMapPolygonTools::exportVectorAsImage( const std::vector<std::vector<int>>& data, int transparency, const QString& filename )
{
if ( data.empty() || data[0].empty() )
{
qWarning( "Data is empty. Cannot export an image." );
return;
}
auto image = convertBinaryToImage( data, QColorConstants::Green, transparency );
if ( !image.save( filename, "PNG" ) )
{
qWarning( "Failed to save image as PNG." );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCreateContourMapPolygonTools::exportVectorAsGrayscaleImage( const std::vector<std::vector<int>>& data, const QString& filename )
{
if ( data.empty() || data[0].empty() )
{
qWarning( "Data is empty. Cannot export an image." );
return;
}
auto image = convertBinaryToGrayscaleImage( data, 255 );
// Save the QImage as a PNG file
if ( !image.save( filename, "PNG" ) )
{
qWarning( "Failed to save image as PNG." );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::vector<int>> RicCreateContourMapPolygonTools::convertImageToBinary( QImage image )
{
std::vector<std::vector<int>> binaryImage( image.width(), std::vector<int>( image.height(), 0 ) );
for ( int i = 0; i < image.width(); ++i )
{
for ( int j = 0; j < image.height(); ++j )
{
auto pixelColor = image.pixel( i, j );
auto gray = qGray( pixelColor );
binaryImage[i][image.height() - j - 1] = gray > 0 ? 1 : 0;
}
}
return binaryImage;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::vector<int>> RicCreateContourMapPolygonTools::convertToBinaryImage( const RigContourMapProjection* rigContourMapProjection )
{
if ( !rigContourMapProjection ) return {};
auto vertexSizeIJ = rigContourMapProjection->numberOfVerticesIJ();
std::vector<std::vector<int>> image( vertexSizeIJ.x(), std::vector<int>( vertexSizeIJ.y(), 0 ) );
for ( cvf::uint i = 0; i < vertexSizeIJ.x(); i++ )
{
for ( cvf::uint j = 0; j < vertexSizeIJ.y(); j++ )
{
double valueAtVertex = rigContourMapProjection->filteredValueAtVertex( i, j );
if ( !std::isinf( valueAtVertex ) )
{
image[i][j] = 1;
}
else
{
image[i][j] = 0;
}
}
}
return image;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimPolygon* RicCreateContourMapPolygonTools::createAndAddBoundaryPolygonFromImage( std::vector<std::vector<int>> image,
const RigContourMapProjection* contourMapProjection )
{
if ( !contourMapProjection ) return nullptr;
if ( image.empty() ) return nullptr;
std::vector<cvf::Vec3d> polygonDomainCoords;
auto xVertexPositions = contourMapProjection->xVertexPositions();
auto yVertexPositions = contourMapProjection->yVertexPositions();
auto origin3d = contourMapProjection->origin3d();
auto depth = contourMapProjection->topDepthBoundingBox();
auto boundaryPoints = RigPolygonTools::boundary( image );
for ( auto [i, j] : boundaryPoints )
{
double xDomain = xVertexPositions.at( i ) + origin3d.x();
double yDomain = yVertexPositions.at( j ) + origin3d.y();
polygonDomainCoords.emplace_back( cvf::Vec3d( xDomain, yDomain, depth ) );
}
// Epsilon used to simplify polygon. Useful range typical value in [5..50]
const double defaultEpsilon = 40.0;
RigPolygonTools::simplifyPolygon( polygonDomainCoords, defaultEpsilon );
if ( polygonDomainCoords.size() >= 3 )
{
auto polygonCollection = RimTools::polygonCollection();
auto newPolygon = polygonCollection->appendUserDefinedPolygon();
newPolygon->setPointsInDomainCoords( polygonDomainCoords );
newPolygon->coordinatesChanged.send();
polygonCollection->uiCapability()->updateAllRequiredEditors();
return newPolygon;
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const RigContourMapProjection* RicCreateContourMapPolygonTools::findCurrentContourMapProjection()
{
RimContourMapProjection* contourMapProjection = nullptr;
auto [existingEclipseContourMap, existingGeoMechContourMap] = RicExportContourMapToTextFeature::findContourMapView();
if ( existingEclipseContourMap ) contourMapProjection = existingEclipseContourMap->contourMapProjection();
if ( existingGeoMechContourMap ) contourMapProjection = existingGeoMechContourMap->contourMapProjection();
if ( !contourMapProjection ) return nullptr;
return contourMapProjection->mapProjection();
}

View File

@@ -0,0 +1,47 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2024- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <QImage>
#include <QString>
#include <vector>
class RigContourMapProjection;
class RimPolygon;
//==================================================================================================
///
//==================================================================================================
namespace RicCreateContourMapPolygonTools
{
QImage convertBinaryToImage( const std::vector<std::vector<int>>& data, QColor color, int transparency );
QImage convertBinaryToGrayscaleImage( const std::vector<std::vector<int>>& data, int colorValue );
void exportVectorAsImage( const std::vector<std::vector<int>>& data, int transparency, const QString& filename );
void exportVectorAsGrayscaleImage( const std::vector<std::vector<int>>& data, const QString& filename );
std::vector<std::vector<int>> convertImageToBinary( QImage image );
std::vector<std::vector<int>> convertToBinaryImage( const RigContourMapProjection* contourMapProjection );
RimPolygon* createAndAddBoundaryPolygonFromImage( std::vector<std::vector<int>> image, const RigContourMapProjection* contourMapProjection );
const RigContourMapProjection* findCurrentContourMapProjection();
}; // namespace RicCreateContourMapPolygonTools

View File

@@ -27,9 +27,7 @@
#include "RigContourMapProjection.h"
#include "RimContourMapProjection.h"
#include "RimEclipseContourMapProjection.h"
#include "RimEclipseContourMapView.h"
#include "RimGeoMechContourMapProjection.h"
#include "RimGeoMechContourMapView.h"
#include "RimProject.h"
#include "RimViewWindow.h"

View File

@@ -41,6 +41,8 @@ public:
RicExportContourMapToTextFeature();
caf::PdmScriptResponse execute() override;
static std::pair<RimEclipseContourMapView*, RimGeoMechContourMapView*> findContourMapView();
protected:
bool isCommandEnabled() const override;
void onActionTriggered( bool isChecked ) override;
@@ -57,9 +59,6 @@ protected:
const QString& undefinedValueLabel,
bool excludeUndefinedValues );
private:
static std::pair<RimEclipseContourMapView*, RimGeoMechContourMapView*> findContourMapView();
private:
caf::PdmField<QString> m_exportFileName;
caf::PdmField<bool> m_exportLocalCoordinates;

View File

@@ -0,0 +1,287 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2024- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicPolygonFromImageDialog.h"
#include "RicCreateContourMapPolygonTools.h"
#include "RigPolygonTools.h"
#include <QGuiApplication>
#include <QScreen>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
ImageProcessingDialog::ImageProcessingDialog( QWidget* parent /*= nullptr */ )
: QDialog( parent )
{
setWindowTitle( "Image Morphology Tool" );
// Layout and widgets
QVBoxLayout* mainLayout = new QVBoxLayout( this );
QHBoxLayout* centerLayout = new QHBoxLayout( this );
mainLayout->addLayout( centerLayout );
QVBoxLayout* settingsLayout = new QVBoxLayout( this );
centerLayout->addLayout( settingsLayout );
QLabel* kernelLabel = new QLabel( "Kernel Size:", this );
settingsLayout->addWidget( kernelLabel );
kernelSpinBox = new QSpinBox( this );
kernelSpinBox->setRange( 1, 31 );
kernelSpinBox->setValue( 3 );
settingsLayout->addWidget( kernelSpinBox );
QLabel* transparencyLabel = new QLabel( "Transparency (0-100):", this );
settingsLayout->addWidget( transparencyLabel );
transparencySlider = new QSlider( Qt::Horizontal, this );
transparencySlider->setRange( 0, 100 );
transparencySlider->setValue( 90 );
settingsLayout->addWidget( transparencySlider );
showInput = new QCheckBox( "Show Input Image", this );
showInput->setChecked( true );
settingsLayout->addWidget( showInput );
showDilated = new QCheckBox( "Show Dilated Image", this );
showDilated->setChecked( false );
settingsLayout->addWidget( showDilated );
showEroded = new QCheckBox( "Show Eroded Image", this );
showEroded->setChecked( false );
settingsLayout->addWidget( showEroded );
showFinal = new QCheckBox( "Show Final Image", this );
showFinal->setChecked( true );
settingsLayout->addWidget( showFinal );
settingsLayout->addStretch();
graphicsView = new QGraphicsView( this );
graphicsScene = new QGraphicsScene( this );
graphicsView->setScene( graphicsScene );
centerLayout->addWidget( graphicsView );
// Give more space to graphics view
centerLayout->setStretch( 0, 3 );
centerLayout->setStretch( 1, 7 );
// Create a button box
QDialogButtonBox* buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this );
mainLayout->addWidget( buttonBox );
// Connect the button box signals
connect( buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept );
connect( buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject );
// Connect signals and slots
connect( showInput, &QCheckBox::clicked, this, &ImageProcessingDialog::showImages );
connect( showEroded, &QCheckBox::clicked, this, &ImageProcessingDialog::showImages );
connect( showDilated, &QCheckBox::clicked, this, &ImageProcessingDialog::showImages );
connect( showFinal, &QCheckBox::clicked, this, &ImageProcessingDialog::showImages );
connect( kernelSpinBox, &QSpinBox::valueChanged, this, &ImageProcessingDialog::updateAndShowImages );
connect( transparencySlider, &QSlider::valueChanged, this, &ImageProcessingDialog::updateAndShowImages );
resizeAndCenterDialog( 0.6 ); // 1.0 means to the full screen size
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ImageProcessingDialog::performDilation()
{
if ( sourceData.empty() )
{
QMessageBox::warning( this, "Error", "No image loaded." );
return;
}
int kernelSize = kernelAdjustedSize();
dilatedData = RigPolygonTools::dilate( sourceData, kernelSize );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ImageProcessingDialog::performErosion()
{
if ( sourceData.empty() )
{
QMessageBox::warning( this, "Error", "No image loaded." );
return;
}
int kernelSize = kernelAdjustedSize();
erodedData = RigPolygonTools::erode( sourceData, kernelSize );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ImageProcessingDialog::updateAndShowImages()
{
performErosion();
performDilation();
computeFinal();
showImages();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ImageProcessingDialog::showImages()
{
if ( sourceData.empty() )
{
QMessageBox::warning( this, "Error", "No image loaded." );
return;
}
const auto transparency = 180;
auto original = RicCreateContourMapPolygonTools::convertBinaryToGrayscaleImage( sourceData, transparency );
auto dilatedImage = RicCreateContourMapPolygonTools::convertBinaryToImage( dilatedData, QColorConstants::Green, transparency );
auto erodedImage = RicCreateContourMapPolygonTools::convertBinaryToImage( erodedData, QColorConstants::Red, transparency );
auto finalImage = RicCreateContourMapPolygonTools::convertBinaryToImage( processedData, QColorConstants::Yellow, transparency );
graphicsScene->clear();
// Add a black background image
if ( !original.isNull() )
{
QImage blackImage( original.size(), QImage::Format_RGB32 );
blackImage.fill( Qt::black );
QPixmap basePixmap = QPixmap::fromImage( blackImage );
QGraphicsPixmapItem* baseItem = new QGraphicsPixmapItem( basePixmap );
graphicsScene->addItem( baseItem );
}
double alpha = transparencySlider->value() / 100.0;
if ( showInput->isChecked() )
{
QPixmap basePixmap = QPixmap::fromImage( original );
QGraphicsPixmapItem* baseItem = new QGraphicsPixmapItem( basePixmap );
baseItem->setOpacity( alpha );
graphicsScene->addItem( baseItem );
}
if ( showDilated->isChecked() && !dilatedImage.isNull() )
{
QPixmap dilatePixmap = QPixmap::fromImage( dilatedImage );
QGraphicsPixmapItem* dilateItem = new QGraphicsPixmapItem( dilatePixmap );
dilateItem->setOpacity( alpha );
graphicsScene->addItem( dilateItem );
}
if ( showEroded->isChecked() && !erodedImage.isNull() )
{
QPixmap erodePixmap = QPixmap::fromImage( erodedImage );
QGraphicsPixmapItem* erodeItem = new QGraphicsPixmapItem( erodePixmap );
erodeItem->setOpacity( alpha );
graphicsScene->addItem( erodeItem );
}
if ( showFinal->isChecked() && !finalImage.isNull() )
{
QPixmap erodePixmap = QPixmap::fromImage( finalImage );
QGraphicsPixmapItem* erodeItem = new QGraphicsPixmapItem( erodePixmap );
erodeItem->setOpacity( alpha );
graphicsScene->addItem( erodeItem );
}
graphicsView->fitInView( graphicsScene->sceneRect(), Qt::KeepAspectRatio );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::vector<int>> ImageProcessingDialog::processedImageData() const
{
return processedData;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ImageProcessingDialog::setSourceImageData( std::vector<std::vector<int>> imageData )
{
sourceData = imageData;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int ImageProcessingDialog::kernelAdjustedSize() const
{
// The kernel size should be odd and positive
return kernelSpinBox->value() * 2 - 1;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ImageProcessingDialog::computeFinal()
{
if ( sourceData.empty() )
{
QMessageBox::warning( this, "Error", "No image loaded." );
return;
}
auto floodFilled = RigPolygonTools::fillInterior( sourceData );
int kernelSize = kernelAdjustedSize();
auto eroded = RigPolygonTools::erode( floodFilled, kernelSize );
auto dilated = RigPolygonTools::dilate( eroded, kernelSize );
processedData = dilated;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ImageProcessingDialog::resizeAndCenterDialog( double scale )
{
QScreen* screen = QGuiApplication::primaryScreen();
if ( !screen ) return;
QRect screenGeometry = screen->geometry();
int width = static_cast<int>( screenGeometry.width() * scale );
int height = static_cast<int>( screenGeometry.height() * scale );
resize( width, height );
int x = screenGeometry.x() + ( screenGeometry.width() - width ) / 2;
int y = screenGeometry.y() + ( screenGeometry.height() - height ) / 2;
move( x, y );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ImageProcessingDialog::resizeEvent( QResizeEvent* event )
{
QDialog::resizeEvent( event );
showImages();
}

View File

@@ -0,0 +1,73 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2024- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <QCheckBox>
#include <QDialog>
#include <QFileDialog>
#include <QGraphicsPixmapItem>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QImage>
#include <QLabel>
#include <QMessageBox>
#include <QPixmap>
#include <QPushButton>
#include <QSlider>
#include <QSpinBox>
#include <QVBoxLayout>
class ImageProcessingDialog : public QDialog
{
Q_OBJECT
public:
ImageProcessingDialog( QWidget* parent = nullptr );
std::vector<std::vector<int>> processedImageData() const;
void setSourceImageData( std::vector<std::vector<int>> imageData );
public slots:
void updateAndShowImages();
private slots:
void performDilation();
void performErosion();
void showImages();
private:
int kernelAdjustedSize() const;
void computeFinal();
void resizeAndCenterDialog( double scale );
void resizeEvent( QResizeEvent* event ) override;
private:
QSpinBox* kernelSpinBox;
QSlider* transparencySlider;
QGraphicsView* graphicsView;
QGraphicsScene* graphicsScene;
QCheckBox* showInput;
QCheckBox* showDilated;
QCheckBox* showEroded;
QCheckBox* showFinal;
std::vector<std::vector<int>> sourceData, dilatedData, erodedData, processedData;
};

View File

@@ -77,7 +77,7 @@ RimGeoMechContourMapView::RimGeoMechContourMapView()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimGeoMechContourMapProjection* RimGeoMechContourMapView::contourMapProjection() const
RimContourMapProjection* RimGeoMechContourMapView::contourMapProjection() const
{
return m_contourMapProjection().p();
}

View File

@@ -23,6 +23,7 @@
enum class RimLegendConfigChangeType;
class RimGeoMechContourMapProjection;
class RimContourMapProjection;
class RimRegularLegendConfig;
class RimViewNameConfig;
class RimScaleLegendConfig;
@@ -34,7 +35,7 @@ class RimGeoMechContourMapView : public RimGeoMechView
public:
RimGeoMechContourMapView();
RimGeoMechContourMapProjection* contourMapProjection() const;
RimContourMapProjection* contourMapProjection() const;
RiaDefines::View3dContent viewContent() const override;

View File

@@ -52,7 +52,6 @@
#include "RimEclipseView.h"
#include "RimFaultInViewCollection.h"
#include "RimGeoMechCase.h"
#include "RimGeoMechContourMapProjection.h"
#include "RimGeoMechContourMapView.h"
#include "RimGeoMechResultDefinition.h"
#include "RimGeoMechView.h"

View File

@@ -33,7 +33,6 @@
#include "RimEclipseContourMapView.h"
#include "RimEclipseView.h"
#include "RimGeoMechCase.h"
#include "RimGeoMechContourMapProjection.h"
#include "RimGeoMechContourMapView.h"
#include "RimGeoMechResultDefinition.h"
#include "RimGeoMechView.h"

View File

@@ -20,6 +20,7 @@
#include "RiuViewerCommands.h"
#include "RiaDefines.h"
#include "RiaOptionItemFactory.h"
#include "GeoMechCommands/RicGeoMechPropertyFilterNewExec.h"
#include "MeasurementCommands/RicMeasurementPickEventHandler.h"
@@ -39,13 +40,13 @@
#include "RigMainGrid.h"
#include "RigVirtualPerforationTransmissibilities.h"
#include "RiaOptionItemFactory.h"
#include "Rim2dIntersectionView.h"
#include "RimBoxIntersection.h"
#include "RimCellEdgeColors.h"
#include "RimContextCommandBuilder.h"
#include "RimEclipseCase.h"
#include "RimEclipseCellColors.h"
#include "RimEclipseContourMapView.h"
#include "RimEclipseFaultColors.h"
#include "RimEclipseView.h"
#include "RimEllipseFractureTemplate.h"
@@ -55,6 +56,7 @@
#include "RimFracture.h"
#include "RimGeoMechCase.h"
#include "RimGeoMechCellColors.h"
#include "RimGeoMechContourMapView.h"
#include "RimGeoMechView.h"
#include "RimIntersectionResultDefinition.h"
#include "RimLegendConfig.h"
@@ -593,28 +595,38 @@ void RiuViewerCommands::displayContextMenu( QMouseEvent* event )
if ( gridView )
{
menuBuilder.addSeparator();
menuBuilder << "RicNewGridTimeHistoryCurveFeature";
menuBuilder << "RicShowFlowCharacteristicsPlotFeature";
if ( dynamic_cast<RimEclipseView*>( gridView ) )
bool isContourView = dynamic_cast<RimEclipseContourMapView*>( gridView ) || dynamic_cast<RimGeoMechContourMapView*>( gridView );
if ( isContourView )
{
menuBuilder << "RicCreateGridCrossPlotFeature";
menuBuilder << "RicCreateContourMapPolygonFeature";
menuBuilder << "RicCreateContourMapPolygonAdvancedFeature";
menuBuilder.addSeparator();
menuBuilder << "RicExportContourMapToTextFeature";
}
menuBuilder.addSeparator();
menuBuilder.subMenuStart( "Export" );
menuBuilder << "RicExportEclipseInputGridFeature";
menuBuilder << "RicSaveEclipseInputActiveVisibleCellsFeature";
menuBuilder << "RicSaveEclipseResultAsInputPropertyFeature";
menuBuilder << "RicExportContourMapToTextFeature";
menuBuilder.subMenuEnd();
menuBuilder.addSeparator();
else
{
menuBuilder.addSeparator();
menuBuilder << "RicNewGridTimeHistoryCurveFeature";
menuBuilder << "RicShowFlowCharacteristicsPlotFeature";
if ( dynamic_cast<RimEclipseView*>( gridView ) )
{
menuBuilder << "RicCreateGridCrossPlotFeature";
}
menuBuilder.addSeparator();
menuBuilder.subMenuStart( "Export" );
menuBuilder << "RicExportEclipseInputGridFeature";
menuBuilder << "RicSaveEclipseInputActiveVisibleCellsFeature";
menuBuilder << "RicSaveEclipseResultAsInputPropertyFeature";
menuBuilder.subMenuEnd();
menuBuilder.addSeparator();
#ifdef USE_QTCHARTS
menuBuilder << "RicCreateGridStatisticsPlotFeature";
menuBuilder << "RicCreateGridStatisticsPlotFeature";
#endif
menuBuilder << "RicShowGridStatisticsFeature";
menuBuilder << "RicCopyGridStatisticsToClipboardFeature";
menuBuilder << "RicSelectColorResult";
menuBuilder << "RicShowGridStatisticsFeature";
menuBuilder << "RicCopyGridStatisticsToClipboardFeature";
menuBuilder << "RicSelectColorResult";
}
}
if ( firstHitPart )