Project

General

Profile

Feature #1155 ยป Commands.py

Chia-Chi TSAI, 10/31/2024 02:10 PM

 
1
import cv2 as cv
2
import numpy as np
3
import tkinter as tk
4
from tkinter import filedialog, messagebox
5
import os
6
from PIL import Image, ImageTk
7
import configparser
8
from ImageIO import ImageIO
9

    
10
class Commands:
11
    ## \brief A class to handle various commands related to image processing and display.
12
    #
13
    # The Commands class provides methods for loading, displaying, and adjusting the overlap region
14
    # for images within a graphical user interface (GUI). It also supports image blending for overlapping
15
    # regions with smooth gradient transitions.
16
    #
17

    
18
    def __init__(self, gui, shared_data):
19
        ## \brief Initializes the Commands instance.
20
        #
21
        # Sets up the GUI interface, shared data, and ImageIO for image operations.
22
        #
23
        # \param gui The GUI instance used for displaying images and receiving user input.
24
        # \param shared_data The shared data structure that holds images and other state information.
25
        # \return Nothing returned.
26
        self.gui = gui
27
        self.shared_data = shared_data
28
        self.io = ImageIO(shared_data)
29

    
30
    def load_left_image(self):
31
        ## \brief Loads the left image from a file.
32
        #
33
        # Opens a file dialog for the user to select a left image file. If a file is selected, it is loaded
34
        # into the shared data.
35
        #
36
        # \warning This method does not check the file format or image content.
37
        # \return Nothing returned.
38
        filepath = filedialog.askopenfilename(title="Select Left Image")
39
        if filepath:
40
            self.shared_data.left_image = self.io.load_image(filepath)
41
            print("Left image loaded.")
42

    
43
    def load_right_image(self):
44
        ## \brief Loads the right image from a file.
45
        #
46
        # Opens a file dialog for the user to select a right image file. If a file is selected, it is loaded
47
        # into the shared data.
48
        #
49
        # \warning This method does not check the file format or image content.
50
        # \return Nothing returned.
51
        filepath = filedialog.askopenfilename(title="Select Right Image")
52
        if filepath:
53
            self.shared_data.right_image = self.io.load_image(filepath)
54
            print("Right image loaded.")
55

    
56
    def smooth_gradient(self, length, rate):
57
        ## \brief Creates a smooth gradient for the overlap region.
58
        #
59
        # Generates a gradient that transitions from full brightness to zero using a non-linear quadratic falloff.
60
        # The gradient is scaled by the specified rate and clipped to be between 0 and 1.
61
        #
62
        # \param length The length of the gradient.
63
        # \param rate A scaling factor to control the gradient's intensity.
64
        # \return A numpy array containing the gradient.
65
        x = np.linspace(0, 1, length)
66
        gradient = 1 - (x ** 2)
67
        gradient = np.clip(gradient * rate, 0, 1)
68
        return gradient
69

    
70
    def show_left_image(self):
71
        ## \brief Displays the left image with a smooth gradient applied to the overlap region.
72
        #
73
        # If a left image is available, this method applies a smooth gradient to its overlapping region
74
        # and displays it on the GUI canvas. If no left image is loaded, an error message is shown.
75
        #
76
        # \return Nothing returned.
77
        if self.shared_data.left_image is not None:
78
            self.shared_data.isLeft = True
79
            left = self.shared_data.left_image.copy()
80
            height = left.shape[0]
81
            left_overlap_start = left.shape[1] - self.shared_data.overlap_region
82
            gradient_alpha = np.linspace(1, 0, self.shared_data.overlap_region)
83
            gradient_alpha = np.tile(gradient_alpha, (height, 1))
84
            left_overlap = left[:, left_overlap_start:, :].copy()
85
            left_overlap = (left_overlap * gradient_alpha[:, :, np.newaxis]).astype(np.uint8)
86
            left[:, left_overlap_start:, :] = left_overlap
87
            self.io.show_image(left, canvas=self.gui.canvas)
88
            print("Left image displayed.")
89
        else:
90
            messagebox.showerror("Error", "No left image loaded!")
91

    
92
    def show_right_image(self):
93
        ## \brief Displays the right image with a smooth gradient applied to the overlap region.
94
        #
95
        # If a right image is available, this method applies a smooth gradient to its overlapping region
96
        # and displays it on the GUI canvas. If no right image is loaded, an error message is shown.
97
        #
98
        # \return Nothing returned.
99
        if self.shared_data.right_image is not None:
100
            self.shared_data.isLeft = False
101
            right = self.shared_data.right_image.copy()
102
            height = right.shape[0]
103
            right_overlap_end = self.shared_data.overlap_region
104
            gradient_alpha = np.linspace(0, 1, right_overlap_end)
105
            gradient_alpha = np.tile(gradient_alpha, (height, 1))
106
            right_overlap = right[:, :right_overlap_end, :].copy()
107
            right_overlap = (right_overlap * gradient_alpha[:, :, np.newaxis]).astype(np.uint8)
108
            right[:, :right_overlap_end, :] = right_overlap
109
            self.io.show_image(right, canvas=self.gui.canvas)
110
            print("Right image displayed.")
111
        else:
112
            messagebox.showerror("Error", "No right image loaded!")
113

    
114
    def show_left_original(self):
115
        ## \brief Displays the original left image without any modifications.
116
        #
117
        # If a left image is loaded, it displays the original left image on the GUI canvas.
118
        #
119
        # \return Nothing returned.
120
        if self.shared_data.left_image is not None:
121
            self.shared_data.isLeft = True
122
            left = self.shared_data.left_image.copy()
123
            self.io.show_image(left, canvas=self.gui.canvas)
124
            print("Left image displayed.")
125
        else:
126
            messagebox.showerror("Error", "No left image loaded!")
127

    
128
    def show_right_original(self):
129
        ## \brief Displays the original right image without any modifications.
130
        #
131
        # If a right image is loaded, it displays the original right image on the GUI canvas.
132
        #
133
        # \return Nothing returned.
134
        if self.shared_data.right_image is not None:
135
            self.shared_data.isLeft = False
136
            right = self.shared_data.right_image.copy()
137
            self.io.show_image(right, canvas=self.gui.canvas)
138
            print("Right image displayed.")
139
        else:
140
            messagebox.showerror("Error", "No right image loaded!")
141

    
142
    def set_overlap_region(self):
143
        ## \brief Sets the overlap region for image processing.
144
        #
145
        # Updates the overlap region value from the GUI input, updates the shared data, and
146
        # redisplays the current image (left or right) with the new overlap setting.
147
        #
148
        # \return Nothing returned.
149
        self.shared_data.overlap_region = self.gui.overlap.get()
150
        print(f"Overlap region set to {self.shared_data.overlap_region}")
151
        if self.shared_data.isLeft:
152
            self.show_left_image()
153
        else:
154
            self.show_right_image()
155

    
156
    def increase_overlap(self):
157
        ## \brief Increases the overlap region value by one.
158
        #
159
        # Increments the overlap region by one and redisplays the current image with the updated overlap.
160
        #
161
        # \return Nothing returned.
162
        current_overlap = self.gui.overlap.get()
163
        self.gui.overlap.set(current_overlap + 1)
164
        self.set_overlap_region()
165
        if self.shared_data.isLeft:
166
            self.show_left_image()
167
        else:
168
            self.show_right_image()
169

    
170
    def decrease_overlap(self):
171
        ## \brief Decreases the overlap region value by one.
172
        #
173
        # Decrements the overlap region by one (ensuring it does not go negative) and redisplays
174
        # the current image with the updated overlap.
175
        #
176
        # \return Nothing returned.
177
        current_overlap = self.gui.overlap.get()
178
        self.gui.overlap.set(max(0, current_overlap - 1))
179
        self.set_overlap_region()
180
        if self.shared_data.isLeft:
181
            self.show_left_image()
182
        else:
183
            self.show_right_image()
    (1-1/1)