Compare commits

9 Commits

Author SHA1 Message Date
658bc88550 try to install deps with cmake in the release dir 2023-06-27 20:00:45 +02:00
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 310 additions and 91 deletions

View File

@@ -1,30 +1,72 @@
cmake_minimum_required(VERSION 3.18)
project(TV_Denoising_CUDA)
# Find CUDA
enable_language(CUDA)
# Find OpenCV
set(VCPKG_INSTALLED_DIR "E:/programming/vcpkg/installed")
set(OpenCV_DIR "${VCPKG_INSTALLED_DIR}/x64-windows/share/opencv2")
find_package(OpenCV REQUIRED)
# Set CUDA flags and properties
set(CUDA_SEPARABLE_COMPILATION ON)
set(CUDA_PROPAGATE_HOST_FLAGS OFF)
# Add the CUDA source files
file(GLOB CUDA_SOURCE_FILES "src/*.cu")
set_source_files_properties(${CUDA_SOURCE_FILES} PROPERTIES CUDA_SOURCE_PROPERTY_FORMAT OBJ)
# Add the C++ source files
file(GLOB CPP_SOURCE_FILES "src/*.cpp")
# Set the include directories
include_directories(${OpenCV_DIR} ${CUDA_INCLUDE_DIRS} "include")
# Create the executable
add_executable(TV_Denoising_CUDA ${CPP_SOURCE_FILES} ${CUDA_SOURCE_FILES})
# Link CUDA libraries
target_link_libraries(TV_Denoising_CUDA ${CUDA_LIBRARIES})
cmake_minimum_required(VERSION 3.18)
project(TV_Denoising_CUDA)
set(CMAKE_BUILD_TYPE "Release")
list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
# Find the Qt5 package
find_package(Qt5 COMPONENTS Widgets REQUIRED)
# Find OpenCV
if(NOT DEFINED OpenCV_DIR)
set(OpenCV_DIR "C:/Users/Culis/.conan2/p/b/openc720995090ff52/b/")
# message(FATAL_ERROR "OpenCV_DIR is set to ${OpenCV_DIR}. Please set it to the appropriate directory.")
endif()
find_package(OpenCV REQUIRED)
if(NOT OpenCV_FOUND)
message(FATAL_ERROR "OpenCV package not found. Please make sure OpenCV is installed and OpenCV_DIR is set correctly.")
endif()
find_package(OpenCV REQUIRED)
# Find CUDA
enable_language(CUDA)
# Set CUDA flags and properties
set(CUDA_SEPARABLE_COMPILATION ON)
set(CUDA_PROPAGATE_HOST_FLAGS OFF)
# Add the CUDA source files
file(GLOB CUDA_SOURCE_FILES "src/*.cu")
set_source_files_properties(${CUDA_SOURCE_FILES} PROPERTIES CUDA_SOURCE_PROPERTY_FORMAT OBJ)
# Add the C++ source files
file(GLOB CPP_SOURCE_FILES "src/*.cpp")
# Set the include directories
include_directories(${OpenCV_DIR} ${CUDA_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS} ${Qt5Widgets_INCLUDE_DIRS} "include")
# Create the executable
add_executable(TV_Denoising_CUDA ${CPP_SOURCE_FILES} ${CUDA_SOURCE_FILES})
# Link 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")
if(WIN32)
set_target_properties(TV_Denoising_CUDA PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" WIN32_EXECUTABLE TRUE)
endif()
# Copy necessary DLLs and runtime files to the release directory
install(
DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/Release/"
FILES_MATCHING PATTERN "*.dll"
)
install(
TARGETS TV_Denoising_CUDA
RUNTIME DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/"
LIBRARY DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/"
ARCHIVE DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/"
)
install(
DIRECTORY "${OpenCV_INSTALL_PATH}/"
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++
vcpkg
cmake
gtk
opencv2
cuda
## 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

@@ -1,61 +1,217 @@
/*
Author: Vargha Csongor Csaba
Created: 2023-06-25 10:10:13
Description:
This file contains the main function for the TV image denoising cli tool.
It reads an image file, denoises it using the TV denoising algorithm,
and saves the denoised image to a file.
You can run it with the following command:
./TV_Denoising_CUDA <input_image> <output_image> <lambda> <iterations>
where:
- <input_image> is the path to the input image file you want to denoise.
- <output_image> is the path to the output denoised image file.
- <lambda> is the regularization parameter for TV denoising (optional, default: 0.02).
- <iterations> is the number of iterations for TV denoising (optional, default: 10).
*/
#include <iostream>
#include <opencv2/opencv.hpp>
#include "tv_denoising.hpp"
int main(int argc, char** argv)
{
// Check if the required arguments are provided
if (argc < 3)
{
std::cerr << "Usage: ./TV_Denoising_CUDA <input_image> <output_image> [<lambda>] [<iterations>]" << std::endl;
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
cv::Mat image = cv::imread(inputImagePath, cv::IMREAD_GRAYSCALE);
// Check if the image was successfully loaded
if (image.empty())
{
std::cerr << "Failed to read the input image." << std::endl;
return 1;
}
// Perform TV denoising
TVDenoising(image, lambda, iterations);
// Display and save the denoised image
cv::imshow("Denoised Image", image);
cv::waitKey(0);
cv::imwrite(outputImagePath, image);
return 0;
}
/*
Author: Vargha Csongor Csaba
Created: 2023-06-25 10:10:13
Description:
This file contains the main function for the TV image denoising cli tool.
It reads an image file, denoises it using the TV denoising algorithm,
and saves the denoised image to a file.
You can run it with the following command:
./TV_Denoising_CUDA <input_image> <output_image> <lambda> <iterations>
where:
- <input_image> is the path to the input image file you want to denoise.
- <output_image> is the path to the output denoised image file.
- <lambda> is the regularization parameter for TV denoising (optional, default: 0.02).
- <iterations> is the number of iterations for TV denoising (optional, default: 10).
*/
#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 "tv_denoising.hpp"
// Global variables for GUI elements
QLabel *originalImageLabel;
QLabel *resultImageLabel;
QLineEdit *inputImagePathEdit;
QLineEdit *outputImagePathEdit;
QSlider *lambdaSlider;
QSlider *iterationsSlider;
void updateDenoisedImage()
{
std::string inputImagePath = inputImagePathEdit->text().toStdString();
std::string outputImagePath = outputImagePathEdit->text().toStdString();
float lambda = lambdaSlider->value() / 100.0;
int iterations = iterationsSlider->value();
// Read the input image
cv::Mat image = cv::imread(inputImagePath, cv::IMREAD_GRAYSCALE);
// Check if the image was successfully loaded
if (image.empty())
{
QMessageBox::critical(nullptr, "Error", "Failed to read the input image.");
return;
}
// Perform TV denoising
TVDenoising(image, lambda, iterations);
// Display the denoised image
QImage resultImage(image.data, image.cols, image.rows, QImage::Format_Grayscale8);
resultImageLabel->setPixmap(QPixmap::fromImage(resultImage));
// 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();
}