Compare commits

...

8 Commits

Author SHA1 Message Date
61767661e6 Add QDebug 2023-06-26 22:48:45 +02:00
6cefc7bd18 change slider layout 2023-06-26 22:25:11 +02:00
96097b614d Use qt as a graphical display 2023-06-26 22:19:05 +02:00
dff0311eac Setup cmake and conan 2023-06-26 22:18:42 +02:00
54b04d0dc9 add gtk to readme 2023-06-25 16:18:54 +02:00
82b6094c1e Switch qt to gtk 2023-06-25 18:15:25 +02:00
7c2cd2fff0 Implement updateDenoisedImage(), call TVdenoising 2023-06-25 16:07:35 +02:00
8b1bec6fa5 Add QT widgets 2023-06-25 16:07:05 +02:00
5 changed files with 286 additions and 91 deletions

View File

@@ -1,14 +1,21 @@
cmake_minimum_required(VERSION 3.18) cmake_minimum_required(VERSION 3.18)
project(TV_Denoising_CUDA) project(TV_Denoising_CUDA)
# Find CUDA set(CMAKE_BUILD_TYPE "Release")
enable_language(CUDA)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
# Find the Qt5 package
find_package(Qt5 COMPONENTS Widgets REQUIRED)
# Find OpenCV # Find OpenCV
set(VCPKG_INSTALLED_DIR "E:/programming/vcpkg/installed") set(OpenCV_DIR "C:/Users/Culis/.conan2/p/b/openc720995090ff52/b/")
set(OpenCV_DIR "${VCPKG_INSTALLED_DIR}/x64-windows/share/opencv2")
find_package(OpenCV REQUIRED) find_package(OpenCV REQUIRED)
# Find CUDA
enable_language(CUDA)
# Set CUDA flags and properties # Set CUDA flags and properties
set(CUDA_SEPARABLE_COMPILATION ON) set(CUDA_SEPARABLE_COMPILATION ON)
set(CUDA_PROPAGATE_HOST_FLAGS OFF) set(CUDA_PROPAGATE_HOST_FLAGS OFF)
@@ -21,10 +28,21 @@ set_source_files_properties(${CUDA_SOURCE_FILES} PROPERTIES CUDA_SOURCE_PROPERTY
file(GLOB CPP_SOURCE_FILES "src/*.cpp") file(GLOB CPP_SOURCE_FILES "src/*.cpp")
# Set the include directories # Set the include directories
include_directories(${OpenCV_DIR} ${CUDA_INCLUDE_DIRS} "include") include_directories(${OpenCV_DIR} ${CUDA_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS} ${Qt5Widgets_INCLUDE_DIRS} "include")
# Create the executable # Create the executable
add_executable(TV_Denoising_CUDA ${CPP_SOURCE_FILES} ${CUDA_SOURCE_FILES}) add_executable(TV_Denoising_CUDA ${CPP_SOURCE_FILES} ${CUDA_SOURCE_FILES})
# Link CUDA libraries # Link CUDA libraries
target_link_libraries(TV_Denoising_CUDA ${CUDA_LIBRARIES}) target_link_libraries(TV_Denoising_CUDA ${CUDA_LIBRARIES} ${OpenCV_LIBS} Qt5::Widgets)
set_property(TARGET TV_Denoising_CUDA PROPERTY ENVIRONMENT "PATH=${CMAKE_CURRENT_BINARY_DIR}/Debug;${CMAKE_CURRENT_BINARY_DIR}/Release")
set_target_properties(TV_Denoising_CUDA PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" WIN32_EXECUTABLE TRUE)
# Copy necessary DLLs and runtime files to the release directory
install(
DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/"
FILES_MATCHING PATTERN "*.dll"
)

9
CMakeUserPresets.json Normal file
View File

@@ -0,0 +1,9 @@
{
"version": 4,
"vendor": {
"conan": {}
},
"include": [
"E:\\programming\\C++\\tv-image-denoising\\build\\CMakePresets.json"
]
}

View File

@@ -6,6 +6,7 @@ Using the TV algorithm to denoise images with c++ and cuda.
g++ g++
vcpkg vcpkg
cmake cmake
gtk
opencv2 opencv2
cuda cuda
## Build ## Build

11
conanfile.txt Normal file
View File

@@ -0,0 +1,11 @@
[requires]
opencv/4.5.5
qt/5.15.8
[options]
qt/5.15.8:qttools=True
qt/5.15.8:shared=True
[generators]
CMakeDeps
CMakeToolchain

View File

@@ -15,29 +15,35 @@ Description:
- <iterations> is the number of iterations for TV denoising (optional, default: 10). - <iterations> is the number of iterations for TV denoising (optional, default: 10).
*/ */
#include <iostream> #include <iostream>
#include <QApplication>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QDebug>
#include <QLineEdit>
#include <QPushButton>
#include <QSlider>
#include <QFileDialog>
#include <QMessageBox>
#include <QImageReader>
#include <QImage>
#include <opencv2/opencv.hpp> #include <opencv2/opencv.hpp>
#include "tv_denoising.hpp" #include "tv_denoising.hpp"
int main(int argc, char** argv) // Global variables for GUI elements
QLabel *originalImageLabel;
QLabel *resultImageLabel;
QLineEdit *inputImagePathEdit;
QLineEdit *outputImagePathEdit;
QSlider *lambdaSlider;
QSlider *iterationsSlider;
void updateDenoisedImage()
{ {
// Check if the required arguments are provided std::string inputImagePath = inputImagePathEdit->text().toStdString();
if (argc < 3) std::string outputImagePath = outputImagePathEdit->text().toStdString();
{ float lambda = lambdaSlider->value() / 100.0;
std::cerr << "Usage: ./TV_Denoising_CUDA <input_image> <output_image> [<lambda>] [<iterations>]" << std::endl; int iterations = iterationsSlider->value();
return 1;
}
// Read the input arguments
std::string inputImagePath = argv[1];
std::string outputImagePath = argv[2];
float lambda = 0.02;
int iterations = 10;
// Check if optional arguments are provided and update the corresponding variables
if (argc >= 4)
lambda = std::stof(argv[3]);
if (argc >= 5)
iterations = std::stoi(argv[4]);
// Read the input image // Read the input image
cv::Mat image = cv::imread(inputImagePath, cv::IMREAD_GRAYSCALE); cv::Mat image = cv::imread(inputImagePath, cv::IMREAD_GRAYSCALE);
@@ -45,17 +51,167 @@ int main(int argc, char** argv)
// Check if the image was successfully loaded // Check if the image was successfully loaded
if (image.empty()) if (image.empty())
{ {
std::cerr << "Failed to read the input image." << std::endl; QMessageBox::critical(nullptr, "Error", "Failed to read the input image.");
return 1; return;
} }
// Perform TV denoising // Perform TV denoising
TVDenoising(image, lambda, iterations); TVDenoising(image, lambda, iterations);
// Display and save the denoised image // Display the denoised image
cv::imshow("Denoised Image", image); QImage resultImage(image.data, image.cols, image.rows, QImage::Format_Grayscale8);
cv::waitKey(0); resultImageLabel->setPixmap(QPixmap::fromImage(resultImage));
cv::imwrite(outputImagePath, image);
return 0; // Save the denoised image
cv::imwrite(outputImagePath, image);
}
void openInputImage()
{
QString filePath = QFileDialog::getOpenFileName(nullptr, "Select Input Image");
if (!filePath.isEmpty())
inputImagePathEdit->setText(filePath);
}
void openOutputImage()
{
QString filePath = QFileDialog::getSaveFileName(nullptr, "Select Output Image");
if (!filePath.isEmpty())
outputImagePathEdit->setText(filePath);
}
int main(int argc, char **argv)
{
QApplication app(argc, argv);
// Create the main window
QWidget window;
window.setWindowTitle("TV Image Denoising");
window.resize(800, 600);
// Create the layout
QGridLayout *layout = new QGridLayout(&window);
// Create the original image label
QLabel *originalImageLabel = new QLabel("Original Image");
layout->addWidget(originalImageLabel, 0, 0, 1, 2); // Row 0, spanning 1 row, 2 columns
// Create the original image display widget
QLabel *originalImageDisplay = new QLabel();
originalImageDisplay->setAlignment(Qt::AlignCenter);
layout->addWidget(originalImageDisplay, 1, 0, 1, 2); // Row 1, spanning 1 row, 2 columns
// Create the result image label
QLabel *resultImageLabel = new QLabel("Result Image");
layout->addWidget(resultImageLabel, 0, 2, 1, 2); // Row 0, spanning 1 row, 2 columns
// Create the result image display widget
QLabel *resultImageDisplay = new QLabel();
resultImageDisplay->setAlignment(Qt::AlignCenter);
layout->addWidget(resultImageDisplay, 1, 2, 1, 2); // Row 1, spanning 1 row, 2 columns
// Create the input image path input field
QHBoxLayout *inputLayout = new QHBoxLayout;
QLabel *inputLabel = new QLabel("Input Image:");
QLineEdit *inputImagePathEdit = new QLineEdit;
QPushButton *inputBrowseButton = new QPushButton("Browse");
QObject::connect(inputBrowseButton, &QPushButton::clicked, openInputImage);
inputLayout->addWidget(inputLabel);
inputLayout->addWidget(inputImagePathEdit);
inputLayout->addWidget(inputBrowseButton);
layout->addLayout(inputLayout, 2, 0, 1, 4); // Row 2, spanning 1 row, 4 columns
// Create the output image path input field
QHBoxLayout *outputLayout = new QHBoxLayout;
QLabel *outputLabel = new QLabel("Output Image:");
QLineEdit *outputImagePathEdit = new QLineEdit;
QPushButton *outputBrowseButton = new QPushButton("Browse");
QObject::connect(outputBrowseButton, &QPushButton::clicked, openOutputImage);
outputLayout->addWidget(outputLabel);
outputLayout->addWidget(outputImagePathEdit);
outputLayout->addWidget(outputBrowseButton);
layout->addLayout(outputLayout, 3, 0, 1, 4); // Row 3, spanning 1 row, 4 columns
// Create the lambda slider
QLabel *lambdaLabel = new QLabel("Lambda:");
QSlider *lambdaSlider = new QSlider(Qt::Horizontal);
lambdaSlider->setObjectName("LambdaSlider"); // Set object name for styling
lambdaSlider->setMinimum(0);
lambdaSlider->setMaximum(100);
// Create the iterations slider
QLabel *iterationsLabel = new QLabel("Iterations:");
QSlider *iterationsSlider = new QSlider(Qt::Horizontal);
iterationsSlider->setObjectName("IterationsSlider"); // Set object name for styling
iterationsSlider->setMinimum(1);
iterationsSlider->setMaximum(100);
// Create labels to display slider values
QLabel *lambdaValueLabel = new QLabel();
QLabel *iterationsValueLabel = new QLabel();
// Set stylesheet for dark design
QString styleSheet = "QLabel { color: white; }" // Set label text color to white
"QSlider::groove:horizontal { background-color: #555555; height: 6px; }" // Set groove color and height
"QSlider::handle:horizontal { background-color: #ffffff; width: 10px; margin: -6px 0; }"; // Set handle color and size
lambdaSlider->setStyleSheet(styleSheet);
iterationsSlider->setStyleSheet(styleSheet);
// Set size policies for sliders
lambdaSlider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
iterationsSlider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
// Create the denoise button
QPushButton *denoiseButton = new QPushButton("Denoise");
QObject::connect(denoiseButton, &QPushButton::clicked, updateDenoisedImage);
// Add the lambda slider and its label
layout->addWidget(lambdaLabel, 4, 0); // Row 4, column 0
layout->addWidget(lambdaSlider, 4, 1); // Row 4, column 1
layout->addWidget(lambdaValueLabel, 5, 0); // Row 5, column 0
// Add the iterations slider and its label
layout->addWidget(iterationsLabel, 4, 2); // Row 4, column 2
layout->addWidget(iterationsSlider, 4, 3); // Row 4, column 3
layout->addWidget(iterationsValueLabel, 5, 2); // Row 5, column 2
// Add the denoise button
layout->addWidget(denoiseButton, 6, 0, 1, 4); // Row 6, spanning 1 row, 4 columns
QList<QByteArray> supportedFormats = QImageReader::supportedImageFormats();
qDebug() << "Supported image formats:" << supportedFormats;
// Load and display the input image
QString inputImagePath = inputImagePathEdit->text();
QImage inputImage(inputImagePath);
if (inputImage.isNull())
{
qDebug() << "Failed to load input image";
}
else
{
qDebug() << "Input image loaded successfully";
}
QPixmap inputPixmap = QPixmap::fromImage(inputImage);
originalImageDisplay->setPixmap(inputPixmap.scaled(originalImageDisplay->size(), Qt::KeepAspectRatio));
// Load and display the output image
QString outputImagePath = outputImagePathEdit->text();
QImage outputImage(outputImagePath);
if (outputImage.isNull())
{
qDebug() << "Failed to load input image";
}
else
{
qDebug() << "Input image loaded successfully";
}
QPixmap outputPixmap = QPixmap::fromImage(outputImage);
resultImageDisplay->setPixmap(outputPixmap.scaled(resultImageDisplay->size(), Qt::KeepAspectRatio));
// Show the main window
window.show();
return app.exec();
} }