diff --git a/.clangd b/.clangd new file mode 100644 index 000000000..359a391ee --- /dev/null +++ b/.clangd @@ -0,0 +1,2 @@ +CompileFlags: + Add: [-std=c++20] diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 012f3509a..ce46a7bdd 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -31,7 +31,7 @@ { "type": "shell", "label": "CMake: build", - "command": "build\\generators\\conanbuild.bat && cmake --build --preset conan-relwithdebinfo", + "command": "build\\generators\\conanbuild.bat && cmake --build --preset conan-release", "group": { "kind": "build", "isDefault": true @@ -56,4 +56,4 @@ } } ] -} +} \ No newline at end of file diff --git a/Backend/cuda_includes/morlet_wavelet.cuh b/Backend/cuda_includes/morlet_wavelet.cuh new file mode 100644 index 000000000..58ea932e8 --- /dev/null +++ b/Backend/cuda_includes/morlet_wavelet.cuh @@ -0,0 +1,8 @@ +#pragma once +#include +#include +#include +#include "complex_utils.cuh" + +void createMorletKernel(cuComplex* d_kernel, int N, float dt, + float scale, float omega0, const cudaStream_t stream); \ No newline at end of file diff --git a/Backend/cuda_includes/wavelet_transform.cuh b/Backend/cuda_includes/wavelet_transform.cuh new file mode 100644 index 000000000..2028fd2aa --- /dev/null +++ b/Backend/cuda_includes/wavelet_transform.cuh @@ -0,0 +1,6 @@ +#pragma once +#include "complex_utils.cuh" +#include "morlet_wavelet.cuh" +#include "frame_desc.hh" + +void wavelet_transform(cuComplex* output, cuComplex* input, const cufftHandle plan1d, const camera::FrameDescriptor& fd, int tranformation_size, const cudaStream_t stream, float target_freq); \ No newline at end of file diff --git a/Backend/cuda_sources/angular_spectrum.cu b/Backend/cuda_sources/angular_spectrum.cu index 65fb19fdf..3ee476f89 100644 --- a/Backend/cuda_sources/angular_spectrum.cu +++ b/Backend/cuda_sources/angular_spectrum.cu @@ -28,7 +28,7 @@ void angular_spectrum_lens(cuFloatComplex* output, kernel_spectral_lens<<>>(output, Nx, Ny, z, lambda, x_step, y_step); cudaXStreamSynchronize(stream); cudaCheckError(); -} +} void angular_spectrum(cuComplex* input, cuComplex* output, @@ -48,6 +48,7 @@ void angular_spectrum(cuComplex* input, // Lens and Mask already shifted // thus we don't have to shift the 'input' buffer each time + apply_mask(input, lens, output, frame_res, batch_size, stream); if (store_frame) { diff --git a/Backend/cuda_sources/masks.cu b/Backend/cuda_sources/masks.cu index 82a51c18e..85f5a0596 100644 --- a/Backend/cuda_sources/masks.cu +++ b/Backend/cuda_sources/masks.cu @@ -4,6 +4,9 @@ using camera::FrameDescriptor; +#define PI_F 3.14159265358979323846f +#include // for M_PI + __global__ void kernel_quadratic_lens( cuComplex* output, const uint lens_side_size, const float lambda, const float dist, const float pixel_size) { @@ -39,6 +42,46 @@ __global__ void kernel_spectral_lens(cuFloatComplex* output, int x = blockIdx.x * blockDim.x + threadIdx.x; int y = blockIdx.y * blockDim.y + threadIdx.y; + if (x >= Nx || y >= Ny) + return; + + // Physical frequencies in cycles per meter + float u_step = 1.0f / (Nx * x_step); + float v_step = 1.0f / (Ny * y_step); + + // Center the frequency grid + float u = (x - Nx / 2.0f) * u_step; + float v = (y - Ny / 2.0f) * v_step; + + // Convert to angular spatial frequencies + float kx = 2.0f * M_PI * u; + float ky = 2.0f * M_PI * v; + + // Wave number + float k = 2.0f * M_PI / lambda; + + // Compute kz (propagation along z) + float kz2 = k * k - kx * kx - ky * ky; + float kz = (kz2 > 0.0f) ? sqrtf(kz2) : 0.0f; + + // Compute phase + float phase = kz * z; + + // Store as complex exponential + output[y * Nx + x] = make_cuFloatComplex(cosf(phase), sinf(phase)); +} + +/* __global__ void kernel_spectral_lens(cuFloatComplex* output, + const int Nx, + const int Ny, + const float z, + const float lambda, + const float x_step, + const float y_step) +{ + int x = blockIdx.x * blockDim.x + threadIdx.x; + int y = blockIdx.y * blockDim.y + threadIdx.y; + if (x < Nx && y < Ny) { float u_step = 1.0f / (Nx * x_step); @@ -56,8 +99,7 @@ __global__ void kernel_spectral_lens(cuFloatComplex* output, // Store result as complex exponential. output[y * Nx + x] = make_cuFloatComplex(cosf(phase), sinf(phase)); } -} - +} */ __global__ void kernel_circular_mask(float* output, short width, short height, float center_X, float center_Y, float radius) { diff --git a/Backend/cuda_sources/morlet_wavelet.cu b/Backend/cuda_sources/morlet_wavelet.cu new file mode 100644 index 000000000..52cc36934 --- /dev/null +++ b/Backend/cuda_sources/morlet_wavelet.cu @@ -0,0 +1,44 @@ +#include +#include +#include +#include "complex_utils.cuh" +#include "morlet_wavelet.cuh" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + + + +// Kernel to compute Morlet wavelet in frequency domain (simplified version correction terms omitted) +__global__ void buildMorletKernel(cuComplex* kernel, + int N, float dt, + float scale, float omega0) +{ + int k = blockIdx.x * blockDim.x + threadIdx.x; + if (k >= N) return; + + float freq_hz; + if (k < N/2 + 1) { + // Positive frequencies (0 to N/2) + freq_hz = k / (N * dt); + } else { + // Negative frequencies (-N/2+1 to -1) + freq_hz = (k - N) / (N * dt); + } + + float omega = 2.0f * M_PI * freq_hz; + float arg = scale * omega - omega0; + float value = sqrtf(scale) * expf(-0.5f * arg * arg); + + kernel[k] = make_cuComplex(value, 0.0f); +} + +void createMorletKernel(cuComplex* d_kernel, int N, float dt, + float scale, float omega0, const cudaStream_t stream) +{ + uint threads = get_max_threads_1d(); + uint blocks = map_blocks_to_problem(N, threads); + + buildMorletKernel<<>>(d_kernel, N, dt, scale, omega0); +} diff --git a/Backend/cuda_sources/wavelet_transform.cu b/Backend/cuda_sources/wavelet_transform.cu new file mode 100644 index 000000000..1d78b6d98 --- /dev/null +++ b/Backend/cuda_sources/wavelet_transform.cu @@ -0,0 +1,65 @@ +#include "hardware_limits.hh" +#include "wavelet_transform.cuh" +#include "complex_utils.cuh" +#include "morlet_wavelet.cuh" +#include "frame_desc.hh" +#include +using camera::FrameDescriptor; + + +__global__ void mul_conj_kernel(const cuComplex* X, + const cuComplex* Psi, + cuComplex* Y, + int N, + int total) +{ + int idx = blockIdx.x * blockDim.x + threadIdx.x; + if (idx >= total) return; + + int frame_res = total / N; + int k = idx / frame_res; // freq bin within the transform + float xr = X[idx].x, xi = X[idx].y; + float pr = Psi[k].x, pi = Psi[k].y; + + // multiply X[idx] by conjugate(Psi[k]) + Y[idx].x = xr * pr + xi * pi; + Y[idx].y = xi * pr - xr * pi; +} + +__global__ void scale_kernel(cuComplex* data, int total_elements) +{ + int k = threadIdx.x + blockIdx.x * blockDim.x; + if (k >= total_elements) return; + float s = 1.0f / float(total_elements); + data[k].x *= s; + data[k].y *= s; +} + +void wavelet_transform(cuComplex* output, cuComplex* input, const cufftHandle plan1d, const FrameDescriptor& fd, int tranformation_size, const cudaStream_t stream, float target_freq) +{ + int N = tranformation_size; + float dt = 1.0f; // time step can be set to 1.0 as we work in normalized units (we dont care about the actual time scale here) + float omega0 = 6.0f; // central frequency (standard) + float scale = omega0 / (2.0f * M_PI * target_freq); + + cuComplex* d_kernel; + cudaMalloc(&d_kernel, N * sizeof(cuComplex)); + + createMorletKernel(d_kernel, N, dt, scale, omega0, stream); + + cufftExecC2C(plan1d, input, input, CUFFT_FORWARD); + + // Multiply by wavelet in frequency domain + int threads = get_max_threads_1d(); + int total = N * fd.get_frame_res(); + + int blocks = map_blocks_to_problem(total, threads); + + mul_conj_kernel<<>>(input, d_kernel, output, N, total); + + // Scale by 1/N to normalize FFT + scale_kernel<<>>(output, N); + + cudaFree(d_kernel); +} + diff --git a/Backend/includes/api/transform_api.hh b/Backend/includes/api/transform_api.hh index 36232e303..98f3677eb 100644 --- a/Backend/includes/api/transform_api.hh +++ b/Backend/includes/api/transform_api.hh @@ -138,6 +138,20 @@ class TransformApi : public IApi */ inline uint get_time_transformation_size() const { return GET_SETTING(TimeTransformationSize); } + + /*! \brief Sets the wavelet transform target frequency. + * + * \return ApiCode the status of the modification: OK, NO_CHANGE or WRONG_COMP_MODE (if in raw mode). + */ + ApiCode set_target_frequency_wavelet(float value) const; + + /*! \brief Returns the wavelet target frequency. + * + * \return float the wavelet target frequency + */ + inline float get_target_frequency_wavelet() const { return GET_SETTING(TargetFrequencyWavelet); } + + /*! \brief Modifies the time transformation size. It's the number of frames used for one time transformation. Must * be greater than 0. * diff --git a/Backend/includes/compute/fourier_transform.hh b/Backend/includes/compute/fourier_transform.hh index 57ea939b1..c4bee04d4 100644 --- a/Backend/includes/compute/fourier_transform.hh +++ b/Backend/includes/compute/fourier_transform.hh @@ -49,6 +49,7 @@ holovibes::settings::TimeTransformation, \ holovibes::settings::Lambda, \ holovibes::settings::ZDistance, \ + holovibes::settings::TargetFrequencyWavelet, \ holovibes::settings::PixelSize, \ holovibes::settings::SpaceTransformation @@ -167,6 +168,9 @@ class FourierTransform /*! \brief Enqueue stft time filtering. */ void insert_stft(); + /*! \brief Enqueue wavelet transform time filtering. */ + void insert_wavelet_transform(); + /*! \brief Enqueue functions relative to filtering using diagonalization and eigen values. * * This should eventually replace stft @@ -174,6 +178,7 @@ class FourierTransform void insert_pca(); void insert_ssa_stft(); + void insert_stft_ssa(); /*! * \brief Helper function to get a settings value. diff --git a/Backend/includes/core/holovibes.hh b/Backend/includes/core/holovibes.hh index 6ba2f8e64..b9ef0bcd2 100644 --- a/Backend/includes/core/holovibes.hh +++ b/Backend/includes/core/holovibes.hh @@ -102,6 +102,7 @@ holovibes::settings::TimeTransformation, \ holovibes::settings::Lambda, \ holovibes::settings::ZDistance, \ + holovibes::settings::TargetFrequencyWavelet, \ holovibes::settings::ConvolutionMatrix, \ holovibes::settings::DivideConvolutionEnabled, \ holovibes::settings::ConvolutionFileName, \ @@ -423,6 +424,7 @@ class Holovibes settings::TimeTransformation{TimeTransformation::NONE}, settings::Lambda{852e-9f}, settings::ZDistance{0.0f}, + settings::TargetFrequencyWavelet{1.5f}, settings::ConvolutionMatrix{std::vector{}}, settings::DivideConvolutionEnabled{false}, settings::ConvolutionFileName{std::string("")}, diff --git a/Backend/includes/enum/enum_time_transformation.hh b/Backend/includes/enum/enum_time_transformation.hh index a0a04917d..45d4f99e0 100644 --- a/Backend/includes/enum/enum_time_transformation.hh +++ b/Backend/includes/enum/enum_time_transformation.hh @@ -18,7 +18,9 @@ enum class TimeTransformation NONE = 0, /*!< No transformation */ STFT, /*!< Short-time Fourier transformation */ PCA, /*!< Principal component analysis */ - SSA_STFT /*!< Self-adaptive Spectrum Analysis Short-time Fourier transformation */ + SSA_STFT, /*!< Self-adaptive Spectrum Analysis Short-time Fourier transformation */ + STFT_SSA, /*!< Short-time Fourier transformation Self-adaptive Spectrum Analysis */ + WAVELET /*!< Wavelet Transform */ }; // clang-format off @@ -26,7 +28,9 @@ SERIALIZE_JSON_ENUM(TimeTransformation, { {TimeTransformation::STFT, "STFT"}, {TimeTransformation::PCA, "PCA"}, {TimeTransformation::NONE, "NONE"}, - {TimeTransformation::SSA_STFT, "SSA_STFT"}, + {TimeTransformation::SSA_STFT, "SSA+STFT"}, + {TimeTransformation::STFT_SSA, "STFT+SSA"}, + {TimeTransformation::WAVELET, "WAVELET"}, {TimeTransformation::NONE, "None"}, // Compat }) diff --git a/Backend/includes/settings/settings.hh b/Backend/includes/settings/settings.hh index e9bfc3883..adab81647 100644 --- a/Backend/includes/settings/settings.hh +++ b/Backend/includes/settings/settings.hh @@ -171,6 +171,7 @@ DECLARE_SETTING(SpaceTransformation, holovibes::SpaceTransformation); DECLARE_SETTING(TimeTransformation, holovibes::TimeTransformation); DECLARE_SETTING(Lambda, float); DECLARE_SETTING(ZDistance, float); +DECLARE_SETTING(TargetFrequencyWavelet, float); DECLARE_SETTING(ConvolutionMatrix, std::vector); DECLARE_SETTING(DivideConvolutionEnabled, bool); diff --git a/Backend/sources/api/transform_api.cc b/Backend/sources/api/transform_api.cc index 9c386b68b..a1897c2ea 100644 --- a/Backend/sources/api/transform_api.cc +++ b/Backend/sources/api/transform_api.cc @@ -117,6 +117,21 @@ ApiCode TransformApi::set_z_distance(float value) const #pragma region Time Tr. +ApiCode TransformApi::set_target_frequency_wavelet(float value) const +{ + NOT_SAME_AND_NOT_RAW(get_target_frequency_wavelet(), value); + + if (value < 0) + { + LOG_WARN("Target frequency for wavelet cannot be negative. Setting it to 0"); + value = 0; + } + + UPDATE_SETTING(TargetFrequencyWavelet, value); + + return ApiCode::OK; +} + ApiCode TransformApi::set_time_transformation_size(uint time_transformation_size) const { NOT_SAME_AND_NOT_RAW(get_time_transformation_size(), time_transformation_size); diff --git a/Backend/sources/compute/fourier_transform.cc b/Backend/sources/compute/fourier_transform.cc index 96166a4dc..dfa377e20 100644 --- a/Backend/sources/compute/fourier_transform.cc +++ b/Backend/sources/compute/fourier_transform.cc @@ -14,12 +14,14 @@ #include "angular_spectrum.cuh" #include "masks.cuh" #include "stft.cuh" +#include "wavelet_transform.cuh" #include "frame_reshape.cuh" #include "cuda_tools/cufft_handle.hh" #include "cuda_memory.cuh" #include "queue.hh" #include "shift_corners.cuh" #include "apply_mask.cuh" +#include "API.hh" #include "matrix_operations.hh" #include "logger.hh" @@ -54,7 +56,7 @@ void FourierTransform::insert_fft(const uint width, const uint height) stream_); } - // In ANGULARSP we do an optimisation to compute the filter2d in the same + // In ANGULARSP we do an optimisation to compute the filtxer2d in the same // reciprocal space to reduce the number of fft calculation if (space_transformation != SpaceTransformation::ANGULARSP) insert_filter2d(); @@ -151,6 +153,7 @@ void FourierTransform::insert_angular_spectrum(bool filter2d_enabled) fd_, stream_); }); + } void FourierTransform::init_lens_queue() @@ -204,9 +207,15 @@ void FourierTransform::insert_time_transform() case TimeTransformation::STFT: insert_stft(); break; + case TimeTransformation::WAVELET: + insert_wavelet_transform(); + break; case TimeTransformation::PCA: insert_pca(); break; + case TimeTransformation::STFT_SSA: + insert_ssa_stft(); + break; case TimeTransformation::SSA_STFT: insert_ssa_stft(); break; @@ -241,6 +250,22 @@ void FourierTransform::insert_stft() }); } +void FourierTransform::insert_wavelet_transform() +{ + LOG_FUNC(); + fn_compute_vect_->push_back( + [=]() + { + auto& api = API; + wavelet_transform( + time_transformation_env_.gpu_p_acc_buffer, + static_cast(time_transformation_env_.gpu_time_transformation_queue->get_data()) , //reinterpret_cast(time_transformation_env_.gpu_time_transformation_queue.get()->get_data()), + time_transformation_env_.stft_plan, + fd_, + setting(), stream_, api.transform.get_target_frequency_wavelet()); + }); +} + void FourierTransform::insert_moments() { LOG_FUNC(); @@ -384,7 +409,7 @@ void FourierTransform::insert_ssa_stft() CUBLAS_OP_N, CUBLAS_OP_C); - // H = H * tmp + // H = H * tmp (projection) matrix_multiply_complex(H, tmp_matrix, static_cast(fd_.get_frame_res()), @@ -398,6 +423,73 @@ void FourierTransform::insert_ssa_stft() }); } +void FourierTransform::insert_stft_ssa() +{ + LOG_FUNC(); + + uint time_transformation_size = setting(); + + cusolver_work_buffer_size_ = eigen_values_vectors_work_buffer_size(time_transformation_size); + cusolver_work_buffer_.resize(cusolver_work_buffer_size_); + + static cuda_tools::CudaUniquePtr tmp_matrix = nullptr; + tmp_matrix.resize(time_transformation_size * time_transformation_size); + + fn_compute_vect_->push_back( + [=]() + { + cuComplex* H = static_cast(time_transformation_env_.gpu_time_transformation_queue->get_data()); + cuComplex* cov = time_transformation_env_.pca_cov.get(); + cuComplex* V = nullptr; + + + stft(H, H, time_transformation_env_.stft_plan); + // stft(H, H, plan1d); // H now contains the STFT of the input data, size: [frames × nb_freq_bins] + + // cov = H' * H + cov_matrix(H, static_cast(fd_.get_frame_res()), time_transformation_size, cov); + + // pca_eigen_values = sorted eigen values of cov + // cov and V = eigen vectors of cov + eigen_values_vectors(cov, + time_transformation_size, + time_transformation_env_.pca_eigen_values, + &V, + cusolver_work_buffer_, + cusolver_work_buffer_size_, + time_transformation_env_.pca_dev_info); + + // filter eigen vectors + // only keep vectors between q and q + q_acc + ViewPQ q_struct = setting(); + int q = q_struct.width != 0 ? q_struct.start : 0; + int q_acc = q_struct.width != 0 ? q_struct.width : time_transformation_size; + int q_index = q * time_transformation_size; + int q_acc_index = q_acc * time_transformation_size; + cudaXMemsetAsync(V, 0, q_index * sizeof(cuComplex), stream_); + int copy_size = time_transformation_size * (time_transformation_size - (q + q_acc)); + cudaXMemsetAsync(V + q_index + q_acc_index, 0, copy_size * sizeof(cuComplex), stream_); + + // tmp = V * V' + matrix_multiply_complex(V, + V, + time_transformation_size, + time_transformation_size, + time_transformation_size, + tmp_matrix, + CUBLAS_OP_N, + CUBLAS_OP_C); + + // H = H * tmp (projection) + matrix_multiply_complex(H, + tmp_matrix, + static_cast(fd_.get_frame_res()), + time_transformation_size, + time_transformation_size, + time_transformation_env_.gpu_p_acc_buffer); + }); +} + void FourierTransform::insert_store_p_frame() { LOG_FUNC(); diff --git a/Backend/sources/core/icompute.cc b/Backend/sources/core/icompute.cc index a4662e3f0..36046a8d5 100644 --- a/Backend/sources/core/icompute.cc +++ b/Backend/sources/core/icompute.cc @@ -131,10 +131,18 @@ void ICompute::perform_time_transformation_setting_specific_tasks(const unsigned update_stft(size); update_pca(0); // Clear the PCA buffer when switching to STFT break; + case TimeTransformation::WAVELET: + update_stft(size); + update_pca(0); // Clear the PCA buffer when switching to WAVELET + break; case TimeTransformation::SSA_STFT: update_stft(size); update_pca(size); break; + case TimeTransformation::STFT_SSA: + update_pca(size); + update_stft(size); + break; case TimeTransformation::PCA: update_pca(size); time_transformation_env_.stft_plan.reset(); // Clear memory used by the FFT plan diff --git a/Ui/assets/ui/mainwindow.ui b/Ui/assets/ui/mainwindow.ui index 531bece92..0f0003acc 100644 --- a/Ui/assets/ui/mainwindow.ui +++ b/Ui/assets/ui/mainwindow.ui @@ -373,7 +373,17 @@ - SSA_STFT + SSA+STFT + + + + + STFT+SSA + + + + + WAVELET @@ -543,6 +553,55 @@ + + + + + Target frequency for wavelet transformation + + + Target Freq. Wavelet + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + + + + + + 0 + 0 + + + + Target frequency for wavelet transformation + + + 2 + + + 0.010000000000000 + + + 100.000000000000000 + + + 0.100000000000000 + + + 1.500000000000000 + + + false + + + + @@ -773,6 +832,8 @@ The range of frequencies kept is [z2, z2 + width]. + + diff --git a/Ui/includes/gui/windows/Filter2DWindow.hh b/Ui/includes/gui/windows/Filter2DWindow.hh index 67e340ecc..bebdb492e 100644 --- a/Ui/includes/gui/windows/Filter2DWindow.hh +++ b/Ui/includes/gui/windows/Filter2DWindow.hh @@ -6,7 +6,7 @@ #include "BasicOpenGLWindow.hh" #include "CudaTexture.hh" - +#include "TextureWindowHelper.hh" namespace holovibes::gui { class MainWindow; @@ -15,7 +15,7 @@ class MainWindow; * * \brief Class that represents a Filter2D window in the GUI. */ -class Filter2DWindow : public BasicOpenGLWindow +class Filter2DWindow : public TextureWindowHelper { public: Filter2DWindow(QPoint p, QSize s, DisplayQueue* q); @@ -25,12 +25,9 @@ class Filter2DWindow : public BasicOpenGLWindow cudaArray_t cuArray; cudaResourceDesc cuArrRD; cudaSurfaceObject_t cuSurface; - CudaTexture* cudaTexture; - void initShaders() override; - void initializeGL() override; - void paintGL() override; + void initShaders() override; void focusInEvent(QFocusEvent*) override; void closeEvent(QCloseEvent*) override; }; diff --git a/Ui/includes/gui/windows/RawWindow.hh b/Ui/includes/gui/windows/RawWindow.hh index f39a65433..2b2cb397d 100644 --- a/Ui/includes/gui/windows/RawWindow.hh +++ b/Ui/includes/gui/windows/RawWindow.hh @@ -7,7 +7,7 @@ #include "BasicOpenGLWindow.hh" #include "CudaTexture.hh" #include "rect.hh" - +#include "TextureWindowHelper.hh" namespace holovibes::gui { @@ -17,7 +17,7 @@ class SliceWindow; * * \brief Class that represents a raw window in the GUI. */ -class RawWindow : public BasicOpenGLWindow +class RawWindow : public TextureWindowHelper { public: RawWindow(QPoint p, QSize s, DisplayQueue* q, float ratio = 0.f, KindOfView k = KindOfView::Raw); @@ -29,13 +29,14 @@ class RawWindow : public BasicOpenGLWindow void set_is_resize(bool b); void save_gui(std::string window); + void forceResizeGL(int w, int h); protected: int texDepth, texType; cudaArray_t cuArray; cudaResourceDesc cuArrRD; cudaSurfaceObject_t cuSurface; - CudaTexture* cudaTexture; + int old_width = -1; int old_height = -1; @@ -47,16 +48,15 @@ class RawWindow : public BasicOpenGLWindow const float translation_step_ = 0.05f; - void initShaders() override; - void initializeGL() override; void resizeGL(int width, int height) override; - void paintGL() override; + void mousePressEvent(QMouseEvent* e) override; void mouseMoveEvent(QMouseEvent* e) override; void mouseReleaseEvent(QMouseEvent* e) override; void keyPressEvent(QKeyEvent* e) override; void wheelEvent(QWheelEvent* e) override; + void initShaders() override; void closeEvent(QCloseEvent* event) override; }; diff --git a/Ui/includes/gui/windows/SliceWindow.hh b/Ui/includes/gui/windows/SliceWindow.hh index 4b998d684..a37cc600d 100644 --- a/Ui/includes/gui/windows/SliceWindow.hh +++ b/Ui/includes/gui/windows/SliceWindow.hh @@ -6,7 +6,7 @@ #include "BasicOpenGLWindow.hh" #include "CudaTexture.hh" - +#include "TextureWindowHelper.hh" namespace holovibes::gui { class MainWindow; @@ -15,7 +15,7 @@ class MainWindow; * * \brief Class that represents a slice window in the GUI. */ -class SliceWindow : public BasicOpenGLWindow +class SliceWindow : public TextureWindowHelper { public: SliceWindow(QPoint p, QSize s, DisplayQueue* q, KindOfView k); @@ -25,11 +25,8 @@ class SliceWindow : public BasicOpenGLWindow cudaArray_t cuArray; cudaResourceDesc cuArrRD; cudaSurfaceObject_t cuSurface; - CudaTexture* cudaTexture; void initShaders() override; - void initializeGL() override; - void paintGL() override; void mousePressEvent(QMouseEvent*) override; void mouseMoveEvent(QMouseEvent*) override; diff --git a/Ui/includes/gui/windows/TextureWindowHelper.hh b/Ui/includes/gui/windows/TextureWindowHelper.hh new file mode 100644 index 000000000..7c576e289 --- /dev/null +++ b/Ui/includes/gui/windows/TextureWindowHelper.hh @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CudaTexture.hh" +#include "display_queue.hh" +#include "overlay_manager.hh" +#include "BasicOpenGLWindow.hh" + +namespace holovibes::gui +{ +class TextureWindowHelper : public BasicOpenGLWindow +{ + public: + TextureWindowHelper(QPoint p, QSize s, DisplayQueue* q, KindOfView k); + virtual ~TextureWindowHelper(); + + void initializeGL(); + void initShaders(); + void paintGL(); + + protected: + // OpenGL/CUDA resources + CudaTexture* cudaTexture = nullptr; +}; +} // namespace holovibes::gui \ No newline at end of file diff --git a/Ui/includes/gui/windows/panels/view_panel.hh b/Ui/includes/gui/windows/panels/view_panel.hh index 70e341083..ec2054039 100644 --- a/Ui/includes/gui/windows/panels/view_panel.hh +++ b/Ui/includes/gui/windows/panels/view_panel.hh @@ -46,6 +46,12 @@ class ViewPanel : public Panel */ void set_img_type(const QString& value); + /*! \brief Modifies target frequency for wavelet time transformation + * + * \param value The new target frequency + */ + void onTargetFrequencyWaveletChanged(double value); + /*! \brief Enables or Disables unwrapping 2d * * \param value true: enable, false: disable diff --git a/Ui/sources/gui/GUI.cc b/Ui/sources/gui/GUI.cc index a249fa080..573d09fd7 100644 --- a/Ui/sources/gui/GUI.cc +++ b/Ui/sources/gui/GUI.cc @@ -145,6 +145,7 @@ void refresh_window(ushort window_size) UI.mainDisplay->setScale(old_scale); UI.mainDisplay->setTranslate(old_translation[0], old_translation[1]); + } void set_filter2d_view(bool enabled, uint auxiliary_window_max_size) diff --git a/Ui/sources/gui/windows/Filter2DWindow.cc b/Ui/sources/gui/windows/Filter2DWindow.cc index 8eb603e80..2ad7a5989 100644 --- a/Ui/sources/gui/windows/Filter2DWindow.cc +++ b/Ui/sources/gui/windows/Filter2DWindow.cc @@ -15,7 +15,7 @@ namespace holovibes::gui { Filter2DWindow::Filter2DWindow(QPoint p, QSize s, DisplayQueue* q) - : BasicOpenGLWindow(p, s, q, KindOfView::Filter2D) + : TextureWindowHelper(p, s, q, KindOfView::Filter2D) { LOG_FUNC(); @@ -34,122 +34,10 @@ Filter2DWindow::~Filter2DWindow() #endif } -void Filter2DWindow::initShaders() -{ - Program = new QOpenGLShaderProgram(); - Program->addShaderFromSourceFile( - QOpenGLShader::Vertex, - gui::create_absolute_qt_path(RELATIVE_PATH(__SHADER_FOLDER_PATH__ / "vertex.holo.glsl").string())); - Program->addShaderFromSourceFile( - QOpenGLShader::Fragment, - gui::create_absolute_qt_path(RELATIVE_PATH(__SHADER_FOLDER_PATH__ / "fragment.tex.glsl").string())); - Program->link(); -} - -void Filter2DWindow::initializeGL() -{ - makeCurrent(); - initializeOpenGLFunctions(); - glClearColor(0.f, 0.f, 0.f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glBlendEquation(GL_FUNC_ADD); - - initShaders(); - Vao.create(); - Vao.bind(); - Program->bind(); - -#pragma region Texture - cudaTexture = new CudaTexture(fd_.width, fd_.height, fd_.depth, cuStream); - if (!cudaTexture->init()) - { - LOG_ERROR("Failed to initialize CUDA Texture"); - } -#pragma endregion - -#pragma region Vertex Buffer Object - const float data[] = {// Top-left - -1.f, - 1.f, // vertex coord (-1.0f <-> 1.0f) - 0.0f, - 0.0f, // texture coord (0.0f <-> 1.0f) - // Top-right - 1.f, - 1.f, - 1.f, - 0.0f, - // Bottom-right - 1.f, - -1.f, - 1.f, - 1.f, - // Bottom-left - -1.f, - -1.f, - 0.0f, - 1.f}; - glGenBuffers(1, &Vbo); - glBindBuffer(GL_ARRAY_BUFFER, Vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); - - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0); - - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), reinterpret_cast(2 * sizeof(float))); - - glDisableVertexAttribArray(1); - glDisableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); -#pragma endregion -#pragma region Element Buffer Object - const GLuint elements[] = {0, 1, 2, 2, 3, 0}; - glGenBuffers(1, &Ebo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Ebo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(GLuint), elements, GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -#pragma endregion - - setTransform(); - - Program->release(); - Vao.release(); - - glViewport(0, 0, width(), height()); - startTimer(1000 / UserInterfaceDescriptor::instance().display_rate_); -} - -void Filter2DWindow::paintGL() +void Filter2DWindow::initShaders() { - void* frame = output_->get_last_image(); - if (!frame) - return; - - makeCurrent(); - glClear(GL_COLOR_BUFFER_BIT); - Vao.bind(); - Program->bind(); - - cudaTexture->update(frame, output_->get_fd()); - - glBindTexture(GL_TEXTURE_2D, cudaTexture->getTextureID()); - glGenerateMipmap(GL_TEXTURE_2D); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Ebo); - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); - - glDisableVertexAttribArray(1); - glDisableVertexAttribArray(0); - glBindTexture(GL_TEXTURE_2D, 0); - Program->release(); - Vao.release(); - - overlay_manager_.draw(); + TextureWindowHelper::initShaders(); } void Filter2DWindow::focusInEvent(QFocusEvent* e) diff --git a/Ui/sources/gui/windows/MainWindow.cc b/Ui/sources/gui/windows/MainWindow.cc index 22ac9b74b..78342d61a 100644 --- a/Ui/sources/gui/windows/MainWindow.cc +++ b/Ui/sources/gui/windows/MainWindow.cc @@ -83,7 +83,7 @@ MainWindow::MainWindow(QWidget* parent) ui_->ImportPanel, ui_->ExportPanel, ui_->InfoPanel}; - + if (ui_->actionPCO_Edge4_2lt) connect(ui_->actionPCO_Edge4_2lt, &QAction::triggered, this, &MainWindow::camera_PCO_Edge4_2lt); if (ui_->actionPCO_Edge4_2ltSettings) @@ -263,6 +263,8 @@ void MainWindow::on_notify() resize(baseSize()); adjustSize(); + + } void MainWindow::notify_error(const std::exception& e) @@ -788,6 +790,12 @@ void MainWindow::init_tooltips() ui_->TimeTransformationComboBox->setItemData(static_cast(TimeTransformation::SSA_STFT), "Self-adaptive Spectrum Analysis Short-Time Fourier Transformation", Qt::ToolTipRole); + ui_->TimeTransformationComboBox->setItemData(static_cast(TimeTransformation::STFT_SSA), + "Short-Time Fourier Transformation Self-adaptive Spectrum Analysis", + Qt::ToolTipRole); + ui_->TimeTransformationComboBox->setItemData(static_cast(TimeTransformation::WAVELET), + "Wavelet Transformation", + Qt::ToolTipRole); } #pragma endregion diff --git a/Ui/sources/gui/windows/PlotWindow.cc b/Ui/sources/gui/windows/PlotWindow.cc index ab4d2700f..98c3e2e50 100644 --- a/Ui/sources/gui/windows/PlotWindow.cc +++ b/Ui/sources/gui/windows/PlotWindow.cc @@ -39,7 +39,7 @@ void PlotWindow::start_drawing() { curve_plot_.start(); } void PlotWindow::stop_drawing() { curve_plot_.stop(); } -void PlotWindow::auto_scale() { curve_plot_.auto_scale(); } +void PlotWindow::auto_scale() { curve_plot_.auto_scale();} void PlotWindow::change_points_nb(int n) { curve_plot_.set_points_nb(n); } diff --git a/Ui/sources/gui/windows/RawWindow.cc b/Ui/sources/gui/windows/RawWindow.cc index 3173d1037..503282837 100644 --- a/Ui/sources/gui/windows/RawWindow.cc +++ b/Ui/sources/gui/windows/RawWindow.cc @@ -1,3 +1,4 @@ +#include "TextureWindowHelper.hh" #ifdef WIN32 #include #endif @@ -33,7 +34,7 @@ using camera::FrameDescriptor; namespace holovibes::gui { RawWindow::RawWindow(QPoint p, QSize s, DisplayQueue* q, float ratio, KindOfView k) - : BasicOpenGLWindow(p, s, q, k) + : TextureWindowHelper(p, s, q, k) , texDepth(0) , texType(0) { @@ -64,91 +65,10 @@ RawWindow::~RawWindow() void RawWindow::initShaders() { - Program = new QOpenGLShaderProgram(); - Program->addShaderFromSourceFile( - QOpenGLShader::Vertex, - gui::create_absolute_qt_path(RELATIVE_PATH(__SHADER_FOLDER_PATH__ / "vertex.raw.glsl").string())); - Program->addShaderFromSourceFile( - QOpenGLShader::Fragment, - gui::create_absolute_qt_path(RELATIVE_PATH(__SHADER_FOLDER_PATH__ / "fragment.tex.raw.glsl").string())); - Program->link(); + TextureWindowHelper::initShaders(); overlay_manager_.create_default(); } -void RawWindow::initializeGL() -{ - makeCurrent(); - initializeOpenGLFunctions(); - glClearColor(0.f, 0.f, 0.f, 1.0f); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glBlendEquation(GL_FUNC_ADD); - - initShaders(); - Vao.create(); - Vao.bind(); - Program->bind(); - -#pragma region Texture - cudaTexture = new CudaTexture(fd_.width, fd_.height, fd_.depth, cuStream); - if (!cudaTexture->init()) - { - LOG_ERROR("Failed to initialize CUDA Texture"); - } - -#pragma endregion - -#pragma region Vertex Buffer Object - const float data[16] = {// Top-left - -1.f, - 1.f, // vertex coord (-1.0f <-> 1.0f) - 0.f, - 0.f, // texture coord (0.0f <-> 1.0f) - // Top-right - 1.f, - 1.f, - 1.f, - 0.f, - // Bottom-right - 1.f, - -1.f, - 1.f, - 1.f, - // Bottom-left - -1.f, - -1.f, - 0.f, - 1.f}; - glGenBuffers(1, &Vbo); - glBindBuffer(GL_ARRAY_BUFFER, Vbo); - glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), data, GL_STATIC_DRAW); - - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0); - - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), reinterpret_cast(2 * sizeof(float))); - - glDisableVertexAttribArray(1); - glDisableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); -#pragma endregion - -#pragma region Element Buffer Object - const GLuint elements[6] = {0, 1, 2, 2, 3, 0}; - glGenBuffers(1, &Ebo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Ebo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(GLuint), elements, GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -#pragma endregion - - setTransform(); - - Program->release(); - Vao.release(); - glViewport(0, 0, width(), height()); - startTimer(1000 / UserInterfaceDescriptor::instance().display_rate_); -} /* This part of code makes a resizing of the window displaying image to a rectangle format. It also avoids the window to move when resizing. @@ -157,101 +77,48 @@ void RawWindow::initializeGL() void RawWindow::resizeGL(int w, int h) { if (ratio == 0.0f) - return; - int tmp_width = old_width; - int tmp_height = old_height; - - auto point = this->position(); - - if ((API.compute.get_compute_mode() == Computation::Hologram && - API.transform.get_space_transformation() == SpaceTransformation::NONE) || - API.compute.get_compute_mode() == Computation::Raw) - { - if (w != old_width) - { - old_width = w; - old_height = w / ratio; - } - else if (h != old_height) - { - old_width = h * ratio; - old_height = h; - } - } - else - { - if (is_resize) - { - if (w != old_width) - { - old_height = w; - old_width = w; - } - else if (h != old_height) - { - old_height = h; - old_width = h; - } - } - else - { - old_height = std::max(h, w); - old_width = old_height; - } - is_resize = true; - - if (old_height < 140 || old_width < 140) - { - old_height = tmp_height; - old_width = tmp_width; - } - is_resize = true; - } - - QRect screen = QGuiApplication::primaryScreen()->geometry(); - if (old_height > screen.height() || old_width > screen.width()) - { - old_height = tmp_height; - old_width = tmp_width; - } - resize(old_width, old_height); - this->setPosition(point); + return; + + auto point = this->position(); + + if ((API.compute.get_compute_mode() == Computation::Hologram && + API.transform.get_space_transformation() == SpaceTransformation::NONE) || + API.compute.get_compute_mode() == Computation::Raw || API.transform.get_space_transformation() == SpaceTransformation::ANGULARSP) + { + if (w != old_width) + { + old_width = w; + old_height = w / ratio; + } + else if (h != old_height) + { + old_width = h * ratio; + old_height = h; + } + } + else + { + old_height = std::max(h, w); + old_width = old_height; + + } + + QRect screen = QGuiApplication::primaryScreen()->geometry(); + if (old_height > screen.height() || old_width > screen.width()) + { + old_height = screen.height() - 10; + old_width = screen.width() - 10; + } + resize(old_width, old_height); + this->setPosition(point); } -void RawWindow::paintGL() +void RawWindow::forceResizeGL(int w, int h) { - void* frame = output_->get_last_image(); - if (!frame) - return; - - glViewport(0, 0, width(), height()); - makeCurrent(); - glClear(GL_COLOR_BUFFER_BIT); - - Vao.bind(); - Program->bind(); - - cudaTexture->update(frame, fd_); - - glBindTexture(GL_TEXTURE_2D, cudaTexture->getTextureID()); - glGenerateMipmap(GL_TEXTURE_2D); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Ebo); - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); - - glDisableVertexAttribArray(1); - glDisableVertexAttribArray(0); - glBindTexture(GL_TEXTURE_2D, 0); - - Program->release(); - Vao.release(); - - overlay_manager_.draw(); + resizeGL(w, h); } + void RawWindow::mousePressEvent(QMouseEvent* e) { overlay_manager_.press(e); } void RawWindow::mouseMoveEvent(QMouseEvent* e) { overlay_manager_.move(e); } diff --git a/Ui/sources/gui/windows/SliceWindow.cc b/Ui/sources/gui/windows/SliceWindow.cc index 009875733..ca13c8e5b 100644 --- a/Ui/sources/gui/windows/SliceWindow.cc +++ b/Ui/sources/gui/windows/SliceWindow.cc @@ -9,14 +9,13 @@ #include "SliceWindow.hh" #include "MainWindow.hh" #include "tools.hh" -#include "API.hh" #include "GUI.hh" #include "user_interface_descriptor.hh" namespace holovibes::gui { SliceWindow::SliceWindow(QPoint p, QSize s, DisplayQueue* q, KindOfView k) - : BasicOpenGLWindow(p, s, q, k) + : TextureWindowHelper(p, s, q, k) , cuArray(nullptr) , cuSurface(0) { @@ -34,126 +33,13 @@ SliceWindow::~SliceWindow() void SliceWindow::initShaders() { - Program = new QOpenGLShaderProgram(); - Program->addShaderFromSourceFile( - QOpenGLShader::Vertex, - gui::create_absolute_qt_path(RELATIVE_PATH(__SHADER_FOLDER_PATH__ / "vertex.holo.glsl").string())); - Program->addShaderFromSourceFile( - QOpenGLShader::Fragment, - gui::create_absolute_qt_path(RELATIVE_PATH(__SHADER_FOLDER_PATH__ / "fragment.tex.glsl").string())); - Program->link(); + TextureWindowHelper::initShaders(); if (API.compute.get_img_type() == ImgType::Composite) overlay_manager_.enable(); else overlay_manager_.create_default(); } -void SliceWindow::initializeGL() -{ - makeCurrent(); - initializeOpenGLFunctions(); - glClearColor(0.f, 0.f, 0.f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glBlendEquation(GL_FUNC_ADD); - - initShaders(); - Vao.create(); - Vao.bind(); - Program->bind(); - -#pragma region Texture - cudaTexture = new CudaTexture(fd_.width, fd_.height, fd_.depth, cuStream); - if (!cudaTexture->init()) - { - LOG_ERROR("Failed to initialize CUDA Texture"); - } -#pragma endregion - -#pragma region Vertex Buffer Object - const float data[] = {// Top-left - -1.f, - 1.f, // vertex coord (-1.0f <-> 1.0f) - 0.0f, - 0.0f, // texture coord (0.0f <-> 1.0f) - // Top-right - 1.f, - 1.f, - 1.f, - 0.0f, - // Bottom-right - 1.f, - -1.f, - 1.f, - 1.f, - // Bottom-left - -1.f, - -1.f, - 0.0f, - 1.f}; - glGenBuffers(1, &Vbo); - glBindBuffer(GL_ARRAY_BUFFER, Vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); - - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0); - - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), reinterpret_cast(2 * sizeof(float))); - - glDisableVertexAttribArray(1); - glDisableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); -#pragma endregion - -#pragma region Element Buffer Object - const GLuint elements[] = {0, 1, 2, 2, 3, 0}; - glGenBuffers(1, &Ebo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Ebo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(GLuint), elements, GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -#pragma endregion - - setTransform(); - - Program->release(); - Vao.release(); - - glViewport(0, 0, width(), height()); - startTimer(1000 / UserInterfaceDescriptor::instance().display_rate_); -} - -void SliceWindow::paintGL() -{ - void* frame = output_->get_last_image(); - if (!frame) - return; - - makeCurrent(); - glClear(GL_COLOR_BUFFER_BIT); - Vao.bind(); - Program->bind(); - - cudaTexture->update(frame, output_->get_fd()); - - glBindTexture(GL_TEXTURE_2D, cudaTexture->getTextureID()); - glGenerateMipmap(GL_TEXTURE_2D); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Ebo); - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); - - glDisableVertexAttribArray(1); - glDisableVertexAttribArray(0); - glBindTexture(GL_TEXTURE_2D, 0); - Program->release(); - Vao.release(); - - overlay_manager_.draw(); -} - void SliceWindow::mousePressEvent(QMouseEvent* e) { overlay_manager_.press(e); } void SliceWindow::mouseMoveEvent(QMouseEvent* e) { overlay_manager_.move(e); } diff --git a/Ui/sources/gui/windows/TextureWindowHelper.cc b/Ui/sources/gui/windows/TextureWindowHelper.cc new file mode 100644 index 000000000..611efc8d3 --- /dev/null +++ b/Ui/sources/gui/windows/TextureWindowHelper.cc @@ -0,0 +1,138 @@ +#include "TextureWindowHelper.hh" +#include "GUI.hh" +#include "user_interface_descriptor.hh" +#include +#include "API.hh" + +namespace holovibes::gui +{ + +TextureWindowHelper::TextureWindowHelper(QPoint p, QSize s, DisplayQueue* q, KindOfView k) + : BasicOpenGLWindow(p, s, q, k) +{ +} + +TextureWindowHelper::~TextureWindowHelper() {} + +// Initialization +void TextureWindowHelper::initializeGL() +{ + + makeCurrent(); + initializeOpenGLFunctions(); + glClearColor(0.f, 0.f, 0.f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendEquation(GL_FUNC_ADD); + + initShaders(); + Vao.create(); + Vao.bind(); + Program->bind(); + +#pragma region Texture + cudaTexture = new CudaTexture(fd_.width, fd_.height, fd_.depth, cuStream); + if (!cudaTexture->init()) + { + LOG_ERROR("Failed to initialize CUDA Texture"); + } +#pragma endregion + +#pragma region Vertex Buffer Object + const float data[] = {// Top-left + -1.f, + 1.f, // vertex coord (-1.0f <-> 1.0f) + 0.0f, + 0.0f, // texture coord (0.0f <-> 1.0f) + // Top-right + 1.f, + 1.f, + 1.f, + 0.0f, + // Bottom-right + 1.f, + -1.f, + 1.f, + 1.f, + // Bottom-left + -1.f, + -1.f, + 0.0f, + 1.f}; + glGenBuffers(1, &Vbo); + glBindBuffer(GL_ARRAY_BUFFER, Vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0); + + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), reinterpret_cast(2 * sizeof(float))); + + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); +#pragma endregion + +#pragma region Element Buffer Object + const GLuint elements[] = {0, 1, 2, 2, 3, 0}; + glGenBuffers(1, &Ebo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Ebo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(GLuint), elements, GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +#pragma endregion + + setTransform(); + + Program->release(); + Vao.release(); + + glViewport(0, 0, width(), height()); + startTimer(1000 / UserInterfaceDescriptor::instance().display_rate_); +} +void TextureWindowHelper::initShaders() +{ + std::string vertex_shader_path = "vertex.holo.glsl"; + std::string fragment_shader_path = "fragment.tex.glsl"; + Program = new QOpenGLShaderProgram(); + Program->addShaderFromSourceFile( + QOpenGLShader::Vertex, + gui::create_absolute_qt_path(RELATIVE_PATH(__SHADER_FOLDER_PATH__ / vertex_shader_path).string())); + Program->addShaderFromSourceFile( + QOpenGLShader::Fragment, + gui::create_absolute_qt_path(RELATIVE_PATH(__SHADER_FOLDER_PATH__ / fragment_shader_path).string())); + Program->link(); +} +// Rendering +void TextureWindowHelper::paintGL() +{ + void* frame = output_->get_last_image(); + if (!frame) + return; + + makeCurrent(); + glClear(GL_COLOR_BUFFER_BIT); + Vao.bind(); + Program->bind(); + + cudaTexture->update(frame, output_->get_fd()); + + glBindTexture(GL_TEXTURE_2D, cudaTexture->getTextureID()); + glGenerateMipmap(GL_TEXTURE_2D); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Ebo); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(0); + glBindTexture(GL_TEXTURE_2D, 0); + Program->release(); + Vao.release(); + + overlay_manager_.draw(); +} + +} // namespace holovibes::gui \ No newline at end of file diff --git a/Ui/sources/gui/windows/panels/image_rendering_panel.cc b/Ui/sources/gui/windows/panels/image_rendering_panel.cc index b70e75b48..e4d630639 100644 --- a/Ui/sources/gui/windows/panels/image_rendering_panel.cc +++ b/Ui/sources/gui/windows/panels/image_rendering_panel.cc @@ -83,6 +83,11 @@ void ImageRenderingPanel::on_notify() ui_->ZSlider->setEnabled(not_raw_not_moments); ui_->BoundaryDoubleSpinBox->setValue(api_.information.get_boundary() * 1000); + //WAVELET + bool isWavelet = api_.transform.get_time_transformation() == TimeTransformation::WAVELET; + ui_->TargetFrequencyWaveletLabel->setVisible(isWavelet); + ui_->TargetFrequencyWaveletDoubleSpinBox->setVisible(isWavelet); + // Filter2D bool filter2D_enabled = !is_raw && api_.filter2d.get_filter2d_enabled(); ui_->Filter2D->setEnabled(!is_raw); @@ -212,6 +217,15 @@ void ImageRenderingPanel::set_space_transformation(const QString& value) if (api_.transform.set_space_transformation(st) == ApiCode::OK) parent_->notify(); + + auto& api = API; + const camera::FrameDescriptor& fd = api.input.get_input_fd(); + unsigned short width = fd.width; + unsigned short height = fd.height; + + auto raw = dynamic_cast(UserInterfaceDescriptor::instance().mainDisplay.get()); + if (raw) + raw->forceResizeGL(width, height); } void ImageRenderingPanel::set_time_transformation(const QString& value) @@ -238,6 +252,7 @@ void ImageRenderingPanel::set_lambda(const double value) void ImageRenderingPanel::set_z_distance_slider(int value) { + api_.transform.set_z_distance(value / 1000.0f); // Keep consistency between the slider and double box @@ -248,7 +263,6 @@ void ImageRenderingPanel::set_z_distance_slider(int value) void ImageRenderingPanel::set_z_distance(const double value) { api_.transform.set_z_distance(static_cast(value) / 1000.0f); - const QSignalBlocker blocker(ui_->ZSlider); ui_->ZSlider->setValue(value); ui_->ZDoubleSpinBox->setValue(value); diff --git a/Ui/sources/gui/windows/panels/view_panel.cc b/Ui/sources/gui/windows/panels/view_panel.cc index 36fb8b698..58e0e07ae 100644 --- a/Ui/sources/gui/windows/panels/view_panel.cc +++ b/Ui/sources/gui/windows/panels/view_panel.cc @@ -30,6 +30,10 @@ ViewPanel::ViewPanel(QWidget* parent) p_right_shortcut_ = new QShortcut(QKeySequence("Right"), this); p_right_shortcut_->setContext(Qt::ApplicationShortcut); connect(p_right_shortcut_, SIGNAL(activated()), this, SLOT(increment_p())); + + // Connect the target frequency spinbox + connect(ui_->TargetFrequencyWaveletDoubleSpinBox, &QDoubleSpinBox::valueChanged, + this, &ViewPanel::onTargetFrequencyWaveletChanged); } ViewPanel::~ViewPanel() @@ -168,7 +172,7 @@ void ViewPanel::on_notify() // q accu bool is_q_visible = - api_.transform.get_time_transformation() == TimeTransformation::SSA_STFT && !is_raw && is_data_not_moments; + (api_.transform.get_time_transformation() == TimeTransformation::SSA_STFT || api_.transform.get_time_transformation() == TimeTransformation::STFT_SSA) && !is_raw && is_data_not_moments; ui_->Q_AccSpinBox->setVisible(is_q_visible); ui_->Q_SpinBox->setVisible(is_q_visible); ui_->Q_Label->setVisible(is_q_visible); @@ -408,4 +412,14 @@ void ViewPanel::update_registration_zone(double value) if (UserInterfaceDescriptor::instance().mainDisplay) UserInterfaceDescriptor::instance().mainDisplay->getOverlayManager().enable(false, 1000); } + +void ViewPanel::onTargetFrequencyWaveletChanged(double value) +{ + // Handle the value change here + // This function will be called whenever the spinbox value changes + + // Update your backend or processing with the new value + api_.transform.set_target_frequency_wavelet(static_cast(value)); +} + } // namespace holovibes::gui diff --git a/conanfile.py b/conanfile.py index 02f929b1d..3af086253 100644 --- a/conanfile.py +++ b/conanfile.py @@ -30,8 +30,8 @@ def requirements(self): self.requires("libpng/1.6.42", override=True) def build_requirements(self): - #self.tool_requires("doxygen/1.9.4") pass + #self.tool_requires("doxygen/1.9.4") def layout(self): cmake_layout(self)