Use qt as a graphical display
This commit is contained in:
203
src/main.cpp
203
src/main.cpp
@@ -15,24 +15,33 @@ 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 <gtk/gtk.h>
|
#include <QApplication>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QSlider>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QImage>
|
||||||
#include <opencv2/opencv.hpp>
|
#include <opencv2/opencv.hpp>
|
||||||
#include "tv_denoising.hpp"
|
#include "tv_denoising.hpp"
|
||||||
|
|
||||||
// Global variables for GUI elements
|
// Global variables for GUI elements
|
||||||
GtkLabel* originalImageLabel;
|
QLabel *originalImageLabel;
|
||||||
GtkLabel* resultImageLabel;
|
QLabel *resultImageLabel;
|
||||||
GtkEntry* inputImagePathEntry;
|
QLineEdit *inputImagePathEdit;
|
||||||
GtkEntry* outputImagePathEntry;
|
QLineEdit *outputImagePathEdit;
|
||||||
GtkScale* lambdaScale;
|
QSlider *lambdaSlider;
|
||||||
GtkScale* iterationsScale;
|
QSlider *iterationsSlider;
|
||||||
|
|
||||||
static void updateDenoisedImage(GtkWidget* widget, gpointer data)
|
void updateDenoisedImage()
|
||||||
{
|
{
|
||||||
std::string inputImagePath = gtk_entry_get_text(inputImagePathEntry);
|
std::string inputImagePath = inputImagePathEdit->text().toStdString();
|
||||||
std::string outputImagePath = gtk_entry_get_text(outputImagePathEntry);
|
std::string outputImagePath = outputImagePathEdit->text().toStdString();
|
||||||
float lambda = gtk_range_get_value(GTK_RANGE(lambdaScale)) / 100.0;
|
float lambda = lambdaSlider->value() / 100.0;
|
||||||
int iterations = gtk_range_get_value(GTK_RANGE(iterationsScale));
|
int iterations = iterationsSlider->value();
|
||||||
|
|
||||||
// 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);
|
||||||
@@ -40,10 +49,7 @@ static void updateDenoisedImage(GtkWidget* widget, gpointer data)
|
|||||||
// Check if the image was successfully loaded
|
// Check if the image was successfully loaded
|
||||||
if (image.empty())
|
if (image.empty())
|
||||||
{
|
{
|
||||||
GtkWidget* dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
|
QMessageBox::critical(nullptr, "Error", "Failed to read the input image.");
|
||||||
"Failed to read the input image.");
|
|
||||||
gtk_dialog_run(GTK_DIALOG(dialog));
|
|
||||||
gtk_widget_destroy(dialog);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,126 +57,117 @@ static void updateDenoisedImage(GtkWidget* widget, gpointer data)
|
|||||||
TVDenoising(image, lambda, iterations);
|
TVDenoising(image, lambda, iterations);
|
||||||
|
|
||||||
// Display the denoised image
|
// Display the denoised image
|
||||||
GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(image.data, GDK_COLORSPACE_RGB, FALSE, 8, image.cols, image.rows,
|
QImage resultImage(image.data, image.cols, image.rows, QImage::Format_Grayscale8);
|
||||||
image.step, NULL, NULL);
|
resultImageLabel->setPixmap(QPixmap::fromImage(resultImage));
|
||||||
gtk_image_set_from_pixbuf(GTK_IMAGE(resultImageLabel), pixbuf);
|
|
||||||
g_object_unref(pixbuf);
|
|
||||||
|
|
||||||
// Save the denoised image
|
// Save the denoised image
|
||||||
cv::imwrite(outputImagePath, image);
|
cv::imwrite(outputImagePath, image);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void openInputImage(GtkWidget* widget, gpointer data)
|
void openInputImage()
|
||||||
{
|
{
|
||||||
GtkWidget* dialog = gtk_file_chooser_dialog_new("Select Input Image", GTK_WINDOW(data), GTK_FILE_CHOOSER_ACTION_OPEN,
|
QString filePath = QFileDialog::getOpenFileName(nullptr, "Select Input Image");
|
||||||
"Cancel", GTK_RESPONSE_CANCEL, "Open", GTK_RESPONSE_ACCEPT, NULL);
|
if (!filePath.isEmpty())
|
||||||
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
|
inputImagePathEdit->setText(filePath);
|
||||||
{
|
|
||||||
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)
|
void openOutputImage()
|
||||||
{
|
{
|
||||||
GtkWidget* dialog = gtk_file_chooser_dialog_new("Select Output Image", GTK_WINDOW(data), GTK_FILE_CHOOSER_ACTION_SAVE,
|
QString filePath = QFileDialog::getSaveFileName(nullptr, "Select Output Image");
|
||||||
"Cancel", GTK_RESPONSE_CANCEL, "Save", GTK_RESPONSE_ACCEPT, NULL);
|
if (!filePath.isEmpty())
|
||||||
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
|
outputImagePathEdit->setText(filePath);
|
||||||
{
|
|
||||||
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)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
// Initialize GTK
|
QApplication app(argc, argv);
|
||||||
gtk_init(&argc, &argv);
|
|
||||||
|
|
||||||
// Create the main window
|
// Create the main window
|
||||||
GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
QWidget window;
|
||||||
gtk_window_set_title(GTK_WINDOW(window), "TV Image Denoising");
|
window.setWindowTitle("TV Image Denoising");
|
||||||
gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
|
window.resize(800, 600);
|
||||||
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
|
|
||||||
|
|
||||||
// Create the main vertical box layout
|
// Create the layout
|
||||||
GtkWidget* vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
|
QVBoxLayout *layout = new QVBoxLayout(&window);
|
||||||
gtk_container_add(GTK_CONTAINER(window), vbox);
|
|
||||||
|
|
||||||
// Create the original image label
|
// Create the original image label
|
||||||
originalImageLabel = GTK_LABEL(gtk_label_new("Original Image"));
|
originalImageLabel = new QLabel("Original Image");
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(originalImageLabel), FALSE, FALSE, 0);
|
layout->addWidget(originalImageLabel);
|
||||||
|
|
||||||
// Create the result image label
|
// Create the result image label
|
||||||
resultImageLabel = GTK_LABEL(gtk_label_new("Result Image"));
|
resultImageLabel = new QLabel("Result Image");
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(resultImageLabel), FALSE, FALSE, 0);
|
layout->addWidget(resultImageLabel);
|
||||||
|
|
||||||
// Create the input image path input field
|
// Create the input image path input field
|
||||||
GtkWidget* inputImageHBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
|
QHBoxLayout *inputLayout = new QHBoxLayout;
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), inputImageHBox, FALSE, FALSE, 0);
|
QLabel *inputLabel = new QLabel("Input Image:");
|
||||||
|
inputImagePathEdit = new QLineEdit;
|
||||||
GtkWidget* inputImageLabel = gtk_label_new("Input Image:");
|
QPushButton *inputBrowseButton = new QPushButton("Browse");
|
||||||
gtk_box_pack_start(GTK_BOX(inputImageHBox), inputImageLabel, FALSE, FALSE, 0);
|
QObject::connect(inputBrowseButton, &QPushButton::clicked, openInputImage);
|
||||||
|
inputLayout->addWidget(inputLabel);
|
||||||
inputImagePathEntry = GTK_ENTRY(gtk_entry_new());
|
inputLayout->addWidget(inputImagePathEdit);
|
||||||
gtk_box_pack_start(GTK_BOX(inputImageHBox), GTK_WIDGET(inputImagePathEntry), TRUE, TRUE, 0);
|
inputLayout->addWidget(inputBrowseButton);
|
||||||
|
layout->addLayout(inputLayout);
|
||||||
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
|
// Create the output image path input field
|
||||||
GtkWidget* outputImageHBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
|
QHBoxLayout *outputLayout = new QHBoxLayout;
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), outputImageHBox, FALSE, FALSE, 0);
|
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);
|
||||||
|
|
||||||
GtkWidget* outputImageLabel = gtk_label_new("Output Image:");
|
// Create the lambda slider
|
||||||
gtk_box_pack_start(GTK_BOX(outputImageHBox), outputImageLabel, FALSE, FALSE, 0);
|
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);
|
||||||
|
|
||||||
outputImagePathEntry = GTK_ENTRY(gtk_entry_new());
|
// Create the iterations slider
|
||||||
gtk_box_pack_start(GTK_BOX(outputImageHBox), GTK_WIDGET(outputImagePathEntry), TRUE, TRUE, 0);
|
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);
|
||||||
|
|
||||||
GtkWidget* outputBrowseButton = gtk_button_new_with_label("Browse");
|
// Create labels to display slider values
|
||||||
g_signal_connect(outputBrowseButton, "clicked", G_CALLBACK(openOutputImage), window);
|
QLabel *lambdaValueLabel = new QLabel();
|
||||||
gtk_box_pack_start(GTK_BOX(outputImageHBox), outputBrowseButton, FALSE, FALSE, 0);
|
QLabel *iterationsValueLabel = new QLabel();
|
||||||
|
|
||||||
// Create the lambda scale
|
// Set stylesheet for dark design
|
||||||
GtkWidget* lambdaHBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
|
QString styleSheet = "QLabel { color: white; }" // Set label text color to white
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), lambdaHBox, FALSE, FALSE, 0);
|
"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
|
||||||
|
|
||||||
GtkWidget* lambdaLabel = gtk_label_new("Lambda:");
|
lambdaSlider->setStyleSheet(styleSheet);
|
||||||
gtk_box_pack_start(GTK_BOX(lambdaHBox), lambdaLabel, FALSE, FALSE, 0);
|
iterationsSlider->setStyleSheet(styleSheet);
|
||||||
|
|
||||||
lambdaScale = GTK_SCALE(gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, 0, 100, 1));
|
// Create layout and add widgets
|
||||||
gtk_scale_set_value_pos(lambdaScale, GTK_POS_RIGHT);
|
layout->addWidget(lambdaLabel);
|
||||||
gtk_scale_set_digits(lambdaScale, 2);
|
layout->addWidget(lambdaSlider);
|
||||||
gtk_box_pack_start(GTK_BOX(lambdaHBox), GTK_WIDGET(lambdaScale), TRUE, TRUE, 0);
|
layout->addWidget(lambdaValueLabel);
|
||||||
|
layout->addWidget(iterationsLabel);
|
||||||
|
layout->addWidget(iterationsSlider);
|
||||||
|
layout->addWidget(iterationsValueLabel);
|
||||||
|
|
||||||
// Create the iterations scale
|
// Connect slider value changes to label updates
|
||||||
GtkWidget* iterationsHBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
|
QObject::connect(lambdaSlider, &QSlider::valueChanged, [=](int value)
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), iterationsHBox, FALSE, FALSE, 0);
|
{ lambdaValueLabel->setText(QString::number(value)); });
|
||||||
|
|
||||||
GtkWidget* iterationsLabel = gtk_label_new("Iterations:");
|
QObject::connect(iterationsSlider, &QSlider::valueChanged, [=](int value)
|
||||||
gtk_box_pack_start(GTK_BOX(iterationsHBox), iterationsLabel, FALSE, FALSE, 0);
|
{ iterationsValueLabel->setText(QString::number(value)); });
|
||||||
|
|
||||||
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
|
// Create the denoise button
|
||||||
GtkWidget* denoiseButton = gtk_button_new_with_label("Denoise");
|
QPushButton *denoiseButton = new QPushButton("Denoise");
|
||||||
g_signal_connect(denoiseButton, "clicked", G_CALLBACK(updateDenoisedImage), NULL);
|
QObject::connect(denoiseButton, &QPushButton::clicked, updateDenoisedImage);
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), denoiseButton, FALSE, FALSE, 0);
|
layout->addWidget(denoiseButton);
|
||||||
|
|
||||||
// Show all widgets
|
// Show the main window
|
||||||
gtk_widget_show_all(window);
|
window.show();
|
||||||
|
|
||||||
// Run the GTK main loop
|
return app.exec();
|
||||||
gtk_main();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
Reference in New Issue
Block a user