From 82b6094c1e146c5a7517d733c5f16e88ce353abb Mon Sep 17 00:00:00 2001 From: Vargha Csongor Date: Sun, 25 Jun 2023 18:15:25 +0200 Subject: [PATCH] Switch qt to gtk --- CMakeLists.txt | 70 ++++++----- src/main.cpp | 322 +++++++++++++++++++++++++++---------------------- 2 files changed, 215 insertions(+), 177 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c59ffbb..6398d63 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,30 +1,40 @@ -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 tool chain +set(VCPKG_DIR "E:/programming/vcpkg") +set(VCPKG_INSTALLED_DIR "${VCPKG_DIR}/installed") +set(CMAKE_TOOLCHAIN_FILE "${VCPKG_DIR}/scripts/buildsystems/vcpkg.cmake" CACHE STRING "Vcpkg toolchain file") + +# Find GTK3 +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK3 REQUIRED gtk+-3.0) + +# Find OpenCV +set(OpenCV_DIR "${VCPKG_INSTALLED_DIR}/x64-windows/share/opencv2") +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} ${GTK3_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} ${GTK3_LIBRARIES}) + +target_compile_options(TV_Denoising_CUDA PUBLIC ${GTK3_CFLAGS_OTHER}) \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index f5076ff..4c56b3a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,148 +1,176 @@ -/* -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 - where: - - is the path to the input image file you want to denoise. - - is the path to the output denoised image file. - - is the regularization parameter for TV denoising (optional, default: 0.02). - - is the number of iterations for TV denoising (optional, default: 10). -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 - QVBoxLayout* layout = new QVBoxLayout(&window); - - // Create the original image label - originalImageLabel = new QLabel("Original Image"); - layout->addWidget(originalImageLabel); - - // Create the result image label - resultImageLabel = new QLabel("Result Image"); - layout->addWidget(resultImageLabel); - - // Create the input image path input field - QHBoxLayout* inputLayout = new QHBoxLayout; - QLabel* inputLabel = new QLabel("Input Image:"); - 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); - - // Create the output image path input field - QHBoxLayout* outputLayout = new QHBoxLayout; - QLabel* outputLabel = new QLabel("Output Image:"); - 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); - - // Create the lambda slider - QLabel* lambdaLabel = new QLabel("Lambda:"); - lambdaSlider = new QSlider(Qt::Horizontal); - lambdaSlider->setMinimum(0); - lambdaSlider->setMaximum(100); - layout->addWidget(lambdaLabel); - layout->addWidget(lambdaSlider); - - // Create the iterations slider - QLabel* iterationsLabel = new QLabel("Iterations:"); - iterationsSlider = new QSlider(Qt::Horizontal); - iterationsSlider->setMinimum(1); - iterationsSlider->setMaximum(100); - layout->addWidget(iterationsLabel); - layout->addWidget(iterationsSlider); - - // Create the denoise button - QPushButton* denoiseButton = new QPushButton("Denoise"); - QObject::connect(denoiseButton, &QPushButton::clicked, updateDenoisedImage); - layout->addWidget(denoiseButton); - - // Show the main window - window.show(); - - return app.exec(); +/* +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 + where: + - is the path to the input image file you want to denoise. + - is the path to the output denoised image file. + - is the regularization parameter for TV denoising (optional, default: 0.02). + - is the number of iterations for TV denoising (optional, default: 10). +*/ +#include +#include +#include +#include "tv_denoising.hpp" + +// Global variables for GUI elements +GtkLabel* originalImageLabel; +GtkLabel* resultImageLabel; +GtkEntry* inputImagePathEntry; +GtkEntry* outputImagePathEntry; +GtkScale* lambdaScale; +GtkScale* iterationsScale; + +static void updateDenoisedImage(GtkWidget* widget, gpointer data) +{ + std::string inputImagePath = gtk_entry_get_text(inputImagePathEntry); + std::string outputImagePath = gtk_entry_get_text(outputImagePathEntry); + float lambda = gtk_range_get_value(GTK_RANGE(lambdaScale)) / 100.0; + int iterations = gtk_range_get_value(GTK_RANGE(iterationsScale)); + + // Read the input image + cv::Mat image = cv::imread(inputImagePath, cv::IMREAD_GRAYSCALE); + + // Check if the image was successfully loaded + if (image.empty()) + { + GtkWidget* dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, + "Failed to read the input image."); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + return; + } + + // Perform TV denoising + TVDenoising(image, lambda, iterations); + + // Display the denoised image + GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(image.data, GDK_COLORSPACE_RGB, FALSE, 8, image.cols, image.rows, + image.step, NULL, NULL); + gtk_image_set_from_pixbuf(GTK_IMAGE(resultImageLabel), pixbuf); + g_object_unref(pixbuf); + + // Save the denoised image + cv::imwrite(outputImagePath, image); +} + +static void openInputImage(GtkWidget* widget, gpointer data) +{ + GtkWidget* dialog = gtk_file_chooser_dialog_new("Select Input Image", GTK_WINDOW(data), GTK_FILE_CHOOSER_ACTION_OPEN, + "Cancel", GTK_RESPONSE_CANCEL, "Open", GTK_RESPONSE_ACCEPT, NULL); + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + char* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + gtk_entry_set_text(inputImagePathEntry, filename); + g_free(filename); + } + gtk_widget_destroy(dialog); +} + +static void openOutputImage(GtkWidget* widget, gpointer data) +{ + GtkWidget* dialog = gtk_file_chooser_dialog_new("Select Output Image", GTK_WINDOW(data), GTK_FILE_CHOOSER_ACTION_SAVE, + "Cancel", GTK_RESPONSE_CANCEL, "Save", GTK_RESPONSE_ACCEPT, NULL); + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + char* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + gtk_entry_set_text(outputImagePathEntry, filename); + g_free(filename); + } + gtk_widget_destroy(dialog); +} + +int main(int argc, char** argv) +{ + // Initialize GTK + gtk_init(&argc, &argv); + + // Create the main window + GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(window), "TV Image Denoising"); + gtk_window_set_default_size(GTK_WINDOW(window), 800, 600); + g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); + + // Create the main vertical box layout + GtkWidget* vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); + gtk_container_add(GTK_CONTAINER(window), vbox); + + // Create the original image label + originalImageLabel = GTK_LABEL(gtk_label_new("Original Image")); + gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(originalImageLabel), FALSE, FALSE, 0); + + // Create the result image label + resultImageLabel = GTK_LABEL(gtk_label_new("Result Image")); + gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(resultImageLabel), FALSE, FALSE, 0); + + // Create the input image path input field + GtkWidget* inputImageHBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); + gtk_box_pack_start(GTK_BOX(vbox), inputImageHBox, FALSE, FALSE, 0); + + GtkWidget* inputImageLabel = gtk_label_new("Input Image:"); + gtk_box_pack_start(GTK_BOX(inputImageHBox), inputImageLabel, FALSE, FALSE, 0); + + inputImagePathEntry = GTK_ENTRY(gtk_entry_new()); + gtk_box_pack_start(GTK_BOX(inputImageHBox), GTK_WIDGET(inputImagePathEntry), TRUE, TRUE, 0); + + GtkWidget* inputBrowseButton = gtk_button_new_with_label("Browse"); + g_signal_connect(inputBrowseButton, "clicked", G_CALLBACK(openInputImage), window); + gtk_box_pack_start(GTK_BOX(inputImageHBox), inputBrowseButton, FALSE, FALSE, 0); + + // Create the output image path input field + GtkWidget* outputImageHBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); + gtk_box_pack_start(GTK_BOX(vbox), outputImageHBox, FALSE, FALSE, 0); + + GtkWidget* outputImageLabel = gtk_label_new("Output Image:"); + gtk_box_pack_start(GTK_BOX(outputImageHBox), outputImageLabel, FALSE, FALSE, 0); + + outputImagePathEntry = GTK_ENTRY(gtk_entry_new()); + gtk_box_pack_start(GTK_BOX(outputImageHBox), GTK_WIDGET(outputImagePathEntry), TRUE, TRUE, 0); + + GtkWidget* outputBrowseButton = gtk_button_new_with_label("Browse"); + g_signal_connect(outputBrowseButton, "clicked", G_CALLBACK(openOutputImage), window); + gtk_box_pack_start(GTK_BOX(outputImageHBox), outputBrowseButton, FALSE, FALSE, 0); + + // Create the lambda scale + GtkWidget* lambdaHBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); + gtk_box_pack_start(GTK_BOX(vbox), lambdaHBox, FALSE, FALSE, 0); + + GtkWidget* lambdaLabel = gtk_label_new("Lambda:"); + gtk_box_pack_start(GTK_BOX(lambdaHBox), lambdaLabel, FALSE, FALSE, 0); + + lambdaScale = GTK_SCALE(gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, 0, 100, 1)); + gtk_scale_set_value_pos(lambdaScale, GTK_POS_RIGHT); + gtk_scale_set_digits(lambdaScale, 2); + gtk_box_pack_start(GTK_BOX(lambdaHBox), GTK_WIDGET(lambdaScale), TRUE, TRUE, 0); + + // Create the iterations scale + GtkWidget* iterationsHBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); + gtk_box_pack_start(GTK_BOX(vbox), iterationsHBox, FALSE, FALSE, 0); + + GtkWidget* iterationsLabel = gtk_label_new("Iterations:"); + gtk_box_pack_start(GTK_BOX(iterationsHBox), iterationsLabel, FALSE, FALSE, 0); + + iterationsScale = GTK_SCALE(gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, 1, 100, 1)); + gtk_scale_set_value_pos(iterationsScale, GTK_POS_RIGHT); + gtk_scale_set_digits(iterationsScale, 0); + gtk_box_pack_start(GTK_BOX(iterationsHBox), GTK_WIDGET(iterationsScale), TRUE, TRUE, 0); + + // Create the denoise button + GtkWidget* denoiseButton = gtk_button_new_with_label("Denoise"); + g_signal_connect(denoiseButton, "clicked", G_CALLBACK(updateDenoisedImage), NULL); + gtk_box_pack_start(GTK_BOX(vbox), denoiseButton, FALSE, FALSE, 0); + + // Show all widgets + gtk_widget_show_all(window); + + // Run the GTK main loop + gtk_main(); + + return 0; } \ No newline at end of file