Code » History » Version 8
Faiq Sayyidan SETIAWAN, 10/31/2024 03:35 PM
1 | 1 | Faiq Sayyidan SETIAWAN | --- |
---|---|---|---|
2 | |||
3 | 6 | Faiq Sayyidan SETIAWAN | *[[/|Home]]* | *[[Team Members]]* | *[[Project Description]]* | *[[Code]]* | *[[UML Diagrams]]* | *[[Results]]* | |
4 | 1 | Faiq Sayyidan SETIAWAN | |
5 | --- |
||
6 | 2 | Faiq Sayyidan SETIAWAN | |
7 | h1=. <pre> |
||
8 | 3 | Faiq Sayyidan SETIAWAN | Code </pre> |
9 | 4 | Faiq Sayyidan SETIAWAN | |
10 | h2. alpha_blending_v2.py: everything |
||
11 | |||
12 | <pre><code class="python"> |
||
13 | import tkinter as tk |
||
14 | |||
15 | from tkinter import filedialog, messagebox |
||
16 | |||
17 | from tkinter import ttk |
||
18 | |||
19 | import configparser |
||
20 | |||
21 | import cv2 |
||
22 | |||
23 | import numpy as np |
||
24 | |||
25 | import os |
||
26 | |||
27 | import logging |
||
28 | |||
29 | from PIL import Image, ImageTk |
||
30 | |||
31 | # Setup logging |
||
32 | |||
33 | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') |
||
34 | |||
35 | # ConfigReader class definition |
||
36 | |||
37 | class ConfigReader: |
||
38 | |||
39 | 7 | Faiq Sayyidan SETIAWAN | def __init__(self, config_path=None): |
40 | # Assume some initialization using config_path |
||
41 | self.config_path = config_path |
||
42 | # Add other initialization logic here |
||
43 | 1 | Faiq Sayyidan SETIAWAN | self.config_parser = configparser.ConfigParser() |
44 | 7 | Faiq Sayyidan SETIAWAN | if config_path is not None and os.path.exists(config_path): |
45 | self.config_parser.read(config_path) |
||
46 | 4 | Faiq Sayyidan SETIAWAN | |
47 | def getImageName(self): |
||
48 | |||
49 | return str(self.config_parser['DEFAULT']['image_name']) |
||
50 | |||
51 | def getProjectedImageWidth(self): |
||
52 | |||
53 | return int(self.config_parser['DEFAULT']['projected_image_width']) |
||
54 | |||
55 | def getProjectedOverlapWidth(self): |
||
56 | |||
57 | return int(self.config_parser['DEFAULT']['projected_overlap_width']) |
||
58 | |||
59 | def getGamma(self): |
||
60 | |||
61 | return float(self.config_parser['DEFAULT']['gamma']) |
||
62 | |||
63 | def getImageSide(self): |
||
64 | |||
65 | return int(self.config_parser['DEFAULT']['image_side']) |
||
66 | |||
67 | 1 | Faiq Sayyidan SETIAWAN | def getTransparencyFactor(self): |
68 | |||
69 | return float(self.config_parser['DEFAULT'].get('transparency_factor', 1.0)) |
||
70 | |||
71 | 7 | Faiq Sayyidan SETIAWAN | def setParameters(self, parameters): |
72 | # The parameters is a dictionary with key-value pairs |
||
73 | if 'DEFAULT' not in self.config_parser: |
||
74 | self.config_parser['DEFAULT'] = {} |
||
75 | |||
76 | for key, value in parameters.items(): |
||
77 | self.config_parser['DEFAULT'][key] = str(value) |
||
78 | |||
79 | def save_config(self, path): |
||
80 | with open(path, 'w') as configfile: |
||
81 | self.config_parser.write(configfile) |
||
82 | |||
83 | |||
84 | 4 | Faiq Sayyidan SETIAWAN | # MainDisplay class definition |
85 | |||
86 | class MainDisplay: |
||
87 | |||
88 | def readImage(self, image_path): |
||
89 | |||
90 | # Loads an image from the specified path with 3 channels (BGR) |
||
91 | |||
92 | image = cv2.imread(image_path, cv2.IMREAD_COLOR) |
||
93 | |||
94 | if image is None: |
||
95 | |||
96 | logging.error(f"Error loading image at {image_path}") |
||
97 | |||
98 | else: |
||
99 | |||
100 | logging.info(f"Loaded image {image_path} with shape: {image.shape}") |
||
101 | |||
102 | return image |
||
103 | |||
104 | def setImage(self, image): |
||
105 | |||
106 | # Placeholder for image processing if necessary |
||
107 | |||
108 | # Here you can modify or prepare the image before displaying |
||
109 | |||
110 | logging.info(f"Setting image with shape: {image.shape}") |
||
111 | |||
112 | return image |
||
113 | |||
114 | # MaskCreator class definition |
||
115 | |||
116 | class MaskCreator: |
||
117 | |||
118 | def __init__(self, image, transparency_factor): |
||
119 | |||
120 | self.__image = image |
||
121 | |||
122 | self.__alpha_gradient = None |
||
123 | |||
124 | self.__gamma_corrected = None |
||
125 | |||
126 | self.result_image = None |
||
127 | |||
128 | self.__mask = None |
||
129 | |||
130 | self.transparency_factor = transparency_factor |
||
131 | |||
132 | def smoothstep(self, edge0, edge1, x): |
||
133 | |||
134 | # Smoothstep function for smoother transition (non-linear gradient) |
||
135 | |||
136 | x = np.clip((x - edge0) / (edge1 - edge0), 0, 1) |
||
137 | |||
138 | return x * x * (3 - 2 * x) |
||
139 | |||
140 | def create_mask(self, image_side, mask_width, image_width): |
||
141 | |||
142 | self.__mask = self.__image.shape[1] * mask_width // image_width |
||
143 | |||
144 | gradient = np.linspace(0, 1, self.__mask) |
||
145 | |||
146 | # Apply smoothstep to create a smoother gradient |
||
147 | |||
148 | smooth_gradient = self.smoothstep(0, 1, gradient) |
||
149 | |||
150 | # Apply transparency factor to adjust the strength of the blending |
||
151 | |||
152 | smooth_gradient = smooth_gradient * self.transparency_factor |
||
153 | |||
154 | if image_side == 1: |
||
155 | |||
156 | # Gradient from transparent to opaque (middle to right) |
||
157 | |||
158 | self.__alpha_gradient = smooth_gradient |
||
159 | |||
160 | elif image_side == 0: |
||
161 | |||
162 | # Gradient from opaque to transparent (left to middle) |
||
163 | |||
164 | self.__alpha_gradient = smooth_gradient[::-1] # Reverse for the left side |
||
165 | |||
166 | def gammaCorrection(self, gamma): |
||
167 | |||
168 | # Apply gamma correction |
||
169 | |||
170 | inv_gamma = 1.0 / gamma |
||
171 | |||
172 | table = np.array([((i / 255.0) ** inv_gamma) * 255 |
||
173 | |||
174 | for i in np.arange(256)]).astype("uint8") |
||
175 | |||
176 | self.__gamma_corrected = cv2.LUT(self.__image, table) |
||
177 | |||
178 | logging.info(f"Applied gamma correction with gamma={gamma}") |
||
179 | |||
180 | # Save gamma corrected image for inspection |
||
181 | |||
182 | cv2.imwrite("gamma_corrected.png", self.__gamma_corrected) |
||
183 | |||
184 | def alpha_blending(self, image_side): |
||
185 | |||
186 | """ |
||
187 | |||
188 | Applies alpha blending on the gamma-corrected image. |
||
189 | |||
190 | Combines the gamma-corrected part of the image with a black background using the alpha gradient mask. |
||
191 | |||
192 | """ |
||
193 | |||
194 | # Initialize result_image to be the gamma-corrected image |
||
195 | |||
196 | self.result_image = self.__gamma_corrected.copy() |
||
197 | |||
198 | if image_side == 1: # Right side |
||
199 | |||
200 | # Create a region of interest (ROI) where blending will occur (right side of the image) |
||
201 | |||
202 | roi = self.result_image[:, :self.__mask].astype(np.float32) |
||
203 | |||
204 | # Create black background for blending |
||
205 | |||
206 | black_background = np.zeros_like(roi, dtype=np.float32) |
||
207 | |||
208 | # Apply the alpha mask to blend gamma-corrected image with black background |
||
209 | |||
210 | alpha = self.__alpha_gradient.reshape(1, -1, 1).astype(np.float32) |
||
211 | |||
212 | blended = (alpha * roi + (1 - alpha) * black_background) |
||
213 | |||
214 | blended = np.clip(blended, 0, 255).astype(np.uint8) |
||
215 | |||
216 | # Place the blended region back in the result image |
||
217 | |||
218 | self.result_image[:, :self.__mask] = blended |
||
219 | |||
220 | logging.info(f"Applied alpha blending on the right side with mask width {self.__mask}") |
||
221 | |||
222 | # Save blended region for debugging |
||
223 | |||
224 | cv2.imwrite("blended_right_side.png", blended) |
||
225 | |||
226 | elif image_side == 0: # Left side |
||
227 | |||
228 | # Create a region of interest (ROI) where blending will occur (left side of the image) |
||
229 | |||
230 | roi = self.result_image[:, -self.__mask:].astype(np.float32) |
||
231 | |||
232 | # Create black background for blending |
||
233 | |||
234 | black_background = np.zeros_like(roi, dtype=np.float32) |
||
235 | |||
236 | # Apply the alpha mask to blend gamma-corrected image with black background |
||
237 | |||
238 | alpha = self.__alpha_gradient.reshape(1, -1, 1).astype(np.float32) |
||
239 | |||
240 | blended = (alpha * roi + (1 - alpha) * black_background) |
||
241 | |||
242 | blended = np.clip(blended, 0, 255).astype(np.uint8) |
||
243 | |||
244 | # Place the blended region back in the result image |
||
245 | |||
246 | self.result_image[:, -self.__mask:] = blended |
||
247 | |||
248 | logging.info(f"Applied alpha blending on the left side with mask width {self.__mask}") |
||
249 | 1 | Faiq Sayyidan SETIAWAN | |
250 | # Save blended region for debugging |
||
251 | |||
252 | cv2.imwrite("blended_left_side.png", blended) |
||
253 | 4 | Faiq Sayyidan SETIAWAN | |
254 | |||
255 | 7 | Faiq Sayyidan SETIAWAN | def process_image(image_path, params, main_display): |
256 | 1 | Faiq Sayyidan SETIAWAN | """ |
257 | 7 | Faiq Sayyidan SETIAWAN | Processes an image based on the provided parameters. |
258 | 1 | Faiq Sayyidan SETIAWAN | |
259 | Args: |
||
260 | 7 | Faiq Sayyidan SETIAWAN | image_path (str): Path to the image file. |
261 | params (dict): Parameters for image processing. |
||
262 | 4 | Faiq Sayyidan SETIAWAN | main_display (MainDisplay): Instance of MainDisplay for image operations. |
263 | |||
264 | Returns: |
||
265 | tuple: Processed image and its corresponding name. |
||
266 | 1 | Faiq Sayyidan SETIAWAN | """ |
267 | 4 | Faiq Sayyidan SETIAWAN | |
268 | 7 | Faiq Sayyidan SETIAWAN | # Retrieve parameters from params dictionary |
269 | mask_width = params.get('projected_overlap_width') |
||
270 | image_width = params.get('projected_image_width') |
||
271 | gamma = params.get('gamma') |
||
272 | image_side = params.get('image_side') |
||
273 | transparency_factor = params.get('transparency_factor') |
||
274 | 4 | Faiq Sayyidan SETIAWAN | |
275 | # Determine image side name |
||
276 | if image_side == 0: |
||
277 | image_name = 'left' |
||
278 | elif image_side == 1: |
||
279 | image_name = 'right' |
||
280 | else: |
||
281 | 7 | Faiq Sayyidan SETIAWAN | logging.error(f"Invalid ImageSide value. Use 0 for left image, 1 for right image.") |
282 | 4 | Faiq Sayyidan SETIAWAN | return None, None |
283 | |||
284 | # Load image |
||
285 | image = main_display.readImage(image_path) |
||
286 | |||
287 | if image is None: |
||
288 | logging.error(f"Image loading failed for {image_path}. Skipping...") |
||
289 | return None, None |
||
290 | |||
291 | # Initialize result image |
||
292 | result_image = main_display.setImage(image).copy() |
||
293 | cv2.imwrite("initial_result_image.png", result_image) # Save initial image |
||
294 | |||
295 | # Initialize MaskCreator |
||
296 | mask_creator = MaskCreator(image, transparency_factor) |
||
297 | |||
298 | # Apply image modifications |
||
299 | 1 | Faiq Sayyidan SETIAWAN | mask_creator.create_mask(image_side, mask_width, image_width) |
300 | mask_creator.gammaCorrection(gamma) |
||
301 | mask_creator.result_image = result_image |
||
302 | mask_creator.alpha_blending(image_side) |
||
303 | |||
304 | # Save final result for inspection |
||
305 | 4 | Faiq Sayyidan SETIAWAN | cv2.imwrite("final_result_image.png", mask_creator.result_image) |
306 | 1 | Faiq Sayyidan SETIAWAN | |
307 | return mask_creator.result_image, image_name |
||
308 | |||
309 | 7 | Faiq Sayyidan SETIAWAN | |
310 | 1 | Faiq Sayyidan SETIAWAN | def save_image(image, name): |
311 | |||
312 | """ |
||
313 | 4 | Faiq Sayyidan SETIAWAN | |
314 | 1 | Faiq Sayyidan SETIAWAN | Save the processed image to the project folder. |
315 | |||
316 | 4 | Faiq Sayyidan SETIAWAN | Args: |
317 | 1 | Faiq Sayyidan SETIAWAN | |
318 | image (np.ndarray): The image to be saved. |
||
319 | 4 | Faiq Sayyidan SETIAWAN | |
320 | 1 | Faiq Sayyidan SETIAWAN | name (str): Name of the image (left or right). |
321 | 4 | Faiq Sayyidan SETIAWAN | |
322 | 1 | Faiq Sayyidan SETIAWAN | """ |
323 | |||
324 | # Define the output path |
||
325 | |||
326 | output_dir = os.path.join(os.getcwd(), "processed_images") |
||
327 | |||
328 | os.makedirs(output_dir, exist_ok=True) |
||
329 | |||
330 | # Create the output file name |
||
331 | |||
332 | output_path = os.path.join(output_dir, f"processed_image_{name}.png") |
||
333 | |||
334 | # Save the image |
||
335 | |||
336 | cv2.imwrite(output_path, image) |
||
337 | |||
338 | logging.info(f"Saved processed image: {output_path}") |
||
339 | |||
340 | # GUI Application class definition |
||
341 | |||
342 | class ImageProcessingApp: |
||
343 | def __init__(self, root): |
||
344 | self.root = root |
||
345 | self.root.title("Image Processing Application") |
||
346 | |||
347 | 7 | Faiq Sayyidan SETIAWAN | # Initialize variables |
348 | self.left_image_path = "" |
||
349 | self.right_image_path = "" |
||
350 | self.left_params = {} |
||
351 | self.right_params = {} |
||
352 | self.processed_images = {} |
||
353 | 1 | Faiq Sayyidan SETIAWAN | |
354 | 7 | Faiq Sayyidan SETIAWAN | # Create notebook (tabs) |
355 | self.notebook = ttk.Notebook(root) |
||
356 | self.notebook.pack(expand=True, fill='both') |
||
357 | 1 | Faiq Sayyidan SETIAWAN | |
358 | 7 | Faiq Sayyidan SETIAWAN | # Create frames for each tab |
359 | self.tab_left = ttk.Frame(self.notebook) |
||
360 | self.tab_right = ttk.Frame(self.notebook) |
||
361 | self.tab_settings = ttk.Frame(self.notebook) |
||
362 | self.tab_preview = ttk.Frame(self.notebook) |
||
363 | 1 | Faiq Sayyidan SETIAWAN | |
364 | 7 | Faiq Sayyidan SETIAWAN | self.notebook.add(self.tab_left, text='Left Image') |
365 | self.notebook.add(self.tab_right, text='Right Image') |
||
366 | self.notebook.add(self.tab_settings, text='Settings') |
||
367 | self.notebook.add(self.tab_preview, text='Preview') |
||
368 | 1 | Faiq Sayyidan SETIAWAN | |
369 | 7 | Faiq Sayyidan SETIAWAN | # Setup each tab |
370 | self.setup_left_tab() |
||
371 | self.setup_right_tab() |
||
372 | self.setup_settings_tab() |
||
373 | self.setup_preview_tab() |
||
374 | 1 | Faiq Sayyidan SETIAWAN | |
375 | 7 | Faiq Sayyidan SETIAWAN | # Process and Save Button |
376 | self.process_button = tk.Button(root, text="Process and Save Images", command=self.process_and_save) |
||
377 | self.process_button.pack(pady=10) |
||
378 | 1 | Faiq Sayyidan SETIAWAN | |
379 | 7 | Faiq Sayyidan SETIAWAN | # Progress Bar |
380 | self.progress_bar = ttk.Progressbar(root, orient="horizontal", length=400, mode="determinate") |
||
381 | self.progress_bar.pack(pady=10) |
||
382 | 1 | Faiq Sayyidan SETIAWAN | |
383 | 7 | Faiq Sayyidan SETIAWAN | def setup_left_tab(self): |
384 | frame = self.tab_left |
||
385 | 1 | Faiq Sayyidan SETIAWAN | |
386 | 7 | Faiq Sayyidan SETIAWAN | # Select Image Button |
387 | btn_select = tk.Button(frame, text="Select Left Image", command=self.select_left_image) |
||
388 | btn_select.pack(pady=5) |
||
389 | 1 | Faiq Sayyidan SETIAWAN | |
390 | 7 | Faiq Sayyidan SETIAWAN | # Display selected image path |
391 | self.left_image_label = tk.Label(frame, text="No image selected", wraplength=300, anchor="w", justify="left") |
||
392 | self.left_image_label.pack(padx=10, pady=5) |
||
393 | 1 | Faiq Sayyidan SETIAWAN | |
394 | 7 | Faiq Sayyidan SETIAWAN | # Parameters for left image |
395 | params_frame = tk.LabelFrame(frame, text="Left Image Parameters", padx=10, pady=10) |
||
396 | params_frame.pack(padx=10, pady=10, fill="x") |
||
397 | 1 | Faiq Sayyidan SETIAWAN | |
398 | 7 | Faiq Sayyidan SETIAWAN | # Projected Image Width |
399 | tk.Label(params_frame, text="Projected Image Width:").grid(row=0, column=0, sticky="e") |
||
400 | self.left_projected_image_width = tk.Entry(params_frame) |
||
401 | self.left_projected_image_width.insert(0, "800") |
||
402 | self.left_projected_image_width.grid(row=0, column=1, pady=2, sticky="w") |
||
403 | 1 | Faiq Sayyidan SETIAWAN | |
404 | 7 | Faiq Sayyidan SETIAWAN | # Projected Overlap Width |
405 | tk.Label(params_frame, text="Projected Overlap Width:").grid(row=1, column=0, sticky="e") |
||
406 | self.left_projected_overlap_width = tk.Entry(params_frame) |
||
407 | self.left_projected_overlap_width.insert(0, "100") |
||
408 | self.left_projected_overlap_width.grid(row=1, column=1, pady=2, sticky="w") |
||
409 | 1 | Faiq Sayyidan SETIAWAN | |
410 | 7 | Faiq Sayyidan SETIAWAN | # Gamma |
411 | tk.Label(params_frame, text="Gamma:").grid(row=2, column=0, sticky="e") |
||
412 | self.left_gamma = tk.Entry(params_frame) |
||
413 | self.left_gamma.insert(0, "1.0") |
||
414 | self.left_gamma.grid(row=2, column=1, pady=2, sticky="w") |
||
415 | 1 | Faiq Sayyidan SETIAWAN | |
416 | 7 | Faiq Sayyidan SETIAWAN | # Image Side |
417 | tk.Label(params_frame, text="Image Side:").grid(row=3, column=0, sticky="e") |
||
418 | self.left_image_side = tk.IntVar(value=0) # Default to left |
||
419 | tk.Radiobutton(params_frame, text="Left", variable=self.left_image_side, value=0).grid(row=3, column=1, sticky="w") |
||
420 | tk.Radiobutton(params_frame, text="Right", variable=self.left_image_side, value=1).grid(row=3, column=1, padx=60, sticky="w") |
||
421 | 1 | Faiq Sayyidan SETIAWAN | |
422 | 7 | Faiq Sayyidan SETIAWAN | # Transparency Factor |
423 | tk.Label(params_frame, text="Transparency Factor:").grid(row=4, column=0, sticky="e") |
||
424 | self.left_transparency_factor = tk.Entry(params_frame) |
||
425 | self.left_transparency_factor.insert(0, "1.0") |
||
426 | self.left_transparency_factor.grid(row=4, column=1, pady=2, sticky="w") |
||
427 | 1 | Faiq Sayyidan SETIAWAN | |
428 | 7 | Faiq Sayyidan SETIAWAN | def setup_right_tab(self): |
429 | frame = self.tab_right |
||
430 | 1 | Faiq Sayyidan SETIAWAN | |
431 | 7 | Faiq Sayyidan SETIAWAN | # Select Image Button |
432 | btn_select = tk.Button(frame, text="Select Right Image", command=self.select_right_image) |
||
433 | btn_select.pack(pady=5) |
||
434 | 1 | Faiq Sayyidan SETIAWAN | |
435 | 7 | Faiq Sayyidan SETIAWAN | # Display selected image path |
436 | self.right_image_label = tk.Label(frame, text="No image selected", wraplength=300, anchor="w", justify="left") |
||
437 | self.right_image_label.pack(padx=10, pady=5) |
||
438 | 1 | Faiq Sayyidan SETIAWAN | |
439 | 7 | Faiq Sayyidan SETIAWAN | # Parameters for right image |
440 | params_frame = tk.LabelFrame(frame, text="Right Image Parameters", padx=10, pady=10) |
||
441 | params_frame.pack(padx=10, pady=10, fill="x") |
||
442 | 1 | Faiq Sayyidan SETIAWAN | |
443 | 7 | Faiq Sayyidan SETIAWAN | # Projected Image Width |
444 | tk.Label(params_frame, text="Projected Image Width:").grid(row=0, column=0, sticky="e") |
||
445 | self.right_projected_image_width = tk.Entry(params_frame) |
||
446 | self.right_projected_image_width.insert(0, "800") |
||
447 | self.right_projected_image_width.grid(row=0, column=1, pady=2, sticky="w") |
||
448 | 1 | Faiq Sayyidan SETIAWAN | |
449 | 7 | Faiq Sayyidan SETIAWAN | # Projected Overlap Width |
450 | tk.Label(params_frame, text="Projected Overlap Width:").grid(row=1, column=0, sticky="e") |
||
451 | self.right_projected_overlap_width = tk.Entry(params_frame) |
||
452 | self.right_projected_overlap_width.insert(0, "100") |
||
453 | self.right_projected_overlap_width.grid(row=1, column=1, pady=2, sticky="w") |
||
454 | 1 | Faiq Sayyidan SETIAWAN | |
455 | 7 | Faiq Sayyidan SETIAWAN | # Gamma |
456 | tk.Label(params_frame, text="Gamma:").grid(row=2, column=0, sticky="e") |
||
457 | self.right_gamma = tk.Entry(params_frame) |
||
458 | self.right_gamma.insert(0, "1.0") |
||
459 | self.right_gamma.grid(row=2, column=1, pady=2, sticky="w") |
||
460 | 1 | Faiq Sayyidan SETIAWAN | |
461 | 7 | Faiq Sayyidan SETIAWAN | # Image Side |
462 | tk.Label(params_frame, text="Image Side:").grid(row=3, column=0, sticky="e") |
||
463 | self.right_image_side = tk.IntVar(value=1) # Default to right |
||
464 | tk.Radiobutton(params_frame, text="Left", variable=self.right_image_side, value=0).grid(row=3, column=1, sticky="w") |
||
465 | tk.Radiobutton(params_frame, text="Right", variable=self.right_image_side, value=1).grid(row=3, column=1, padx=60, sticky="w") |
||
466 | 1 | Faiq Sayyidan SETIAWAN | |
467 | 7 | Faiq Sayyidan SETIAWAN | # Transparency Factor |
468 | tk.Label(params_frame, text="Transparency Factor:").grid(row=4, column=0, sticky="e") |
||
469 | self.right_transparency_factor = tk.Entry(params_frame) |
||
470 | self.right_transparency_factor.insert(0, "1.0") |
||
471 | self.right_transparency_factor.grid(row=4, column=1, pady=2, sticky="w") |
||
472 | 1 | Faiq Sayyidan SETIAWAN | |
473 | 7 | Faiq Sayyidan SETIAWAN | def setup_settings_tab(self): |
474 | frame = self.tab_settings |
||
475 | 1 | Faiq Sayyidan SETIAWAN | |
476 | 7 | Faiq Sayyidan SETIAWAN | # Configurations can be saved or loaded here |
477 | save_config_btn = tk.Button(frame, text="Save Configuration", command=self.save_configuration) |
||
478 | save_config_btn.pack(pady=10) |
||
479 | 1 | Faiq Sayyidan SETIAWAN | |
480 | 7 | Faiq Sayyidan SETIAWAN | load_config_btn = tk.Button(frame, text="Load Configuration", command=self.load_configuration) |
481 | load_config_btn.pack(pady=10) |
||
482 | 1 | Faiq Sayyidan SETIAWAN | |
483 | 7 | Faiq Sayyidan SETIAWAN | def setup_preview_tab(self): |
484 | frame = self.tab_preview |
||
485 | 1 | Faiq Sayyidan SETIAWAN | |
486 | 7 | Faiq Sayyidan SETIAWAN | # Labels to display images |
487 | self.original_image_label = tk.Label(frame, text="Original Image") |
||
488 | self.original_image_label.pack(side="left", padx=10, pady=10) |
||
489 | 1 | Faiq Sayyidan SETIAWAN | |
490 | 7 | Faiq Sayyidan SETIAWAN | self.processed_image_label = tk.Label(frame, text="Processed Image") |
491 | self.processed_image_label.pack(side="right", padx=10, pady=10) |
||
492 | 1 | Faiq Sayyidan SETIAWAN | |
493 | 7 | Faiq Sayyidan SETIAWAN | def select_left_image(self): |
494 | path = filedialog.askopenfilename(title="Select Left Image", |
||
495 | filetypes=[("Image files", "*.png *.jpg *.jpeg *.bmp")]) |
||
496 | if path: |
||
497 | self.left_image_path = path |
||
498 | self.left_image_label.config(text=os.path.basename(path)) |
||
499 | logging.info(f"Selected left image: {path}") |
||
500 | 1 | Faiq Sayyidan SETIAWAN | |
501 | 7 | Faiq Sayyidan SETIAWAN | def select_right_image(self): |
502 | path = filedialog.askopenfilename(title="Select Right Image", |
||
503 | filetypes=[("Image files", "*.png *.jpg *.jpeg *.bmp")]) |
||
504 | if path: |
||
505 | self.right_image_path = path |
||
506 | self.right_image_label.config(text=os.path.basename(path)) |
||
507 | logging.info(f"Selected right image: {path}") |
||
508 | 1 | Faiq Sayyidan SETIAWAN | |
509 | 7 | Faiq Sayyidan SETIAWAN | def save_configuration(self): |
510 | config = ConfigReader() |
||
511 | 1 | Faiq Sayyidan SETIAWAN | |
512 | 7 | Faiq Sayyidan SETIAWAN | # Left Image Parameters |
513 | if self.left_image_path: |
||
514 | config.setParameters({ |
||
515 | 'image_name': self.left_image_path, |
||
516 | 'projected_image_width': self.left_projected_image_width.get(), |
||
517 | 'projected_overlap_width': self.left_projected_overlap_width.get(), |
||
518 | 'gamma': self.left_gamma.get(), |
||
519 | 'image_side': self.left_image_side.get(), |
||
520 | 'transparency_factor': self.left_transparency_factor.get() |
||
521 | }) |
||
522 | 1 | Faiq Sayyidan SETIAWAN | |
523 | 7 | Faiq Sayyidan SETIAWAN | # Right Image Parameters |
524 | if self.right_image_path: |
||
525 | config.setParameters({ |
||
526 | 'image_name': self.right_image_path, |
||
527 | 'projected_image_width': self.right_projected_image_width.get(), |
||
528 | 'projected_overlap_width': self.right_projected_overlap_width.get(), |
||
529 | 'gamma': self.right_gamma.get(), |
||
530 | 'image_side': self.right_image_side.get(), |
||
531 | 'transparency_factor': self.right_transparency_factor.get() |
||
532 | }) |
||
533 | 1 | Faiq Sayyidan SETIAWAN | |
534 | 7 | Faiq Sayyidan SETIAWAN | # Save to file |
535 | save_path = filedialog.asksaveasfilename(title="Save Configuration", |
||
536 | defaultextension=".ini", |
||
537 | filetypes=[("INI files", "*.ini")]) |
||
538 | if save_path: |
||
539 | config.save_config(save_path) |
||
540 | messagebox.showinfo("Success", f"Configuration saved to {save_path}") |
||
541 | logging.info(f"Configuration saved to {save_path}") |
||
542 | 1 | Faiq Sayyidan SETIAWAN | |
543 | 7 | Faiq Sayyidan SETIAWAN | def load_configuration(self): |
544 | load_path = filedialog.askopenfilename(title="Load Configuration", |
||
545 | filetypes=[("INI files", "*.ini")]) |
||
546 | if load_path and os.path.exists(load_path): |
||
547 | config = ConfigReader(load_path) |
||
548 | 1 | Faiq Sayyidan SETIAWAN | |
549 | 7 | Faiq Sayyidan SETIAWAN | # Load left image parameters |
550 | self.left_image_path = config.getImageName() |
||
551 | if self.left_image_path and os.path.exists(self.left_image_path): |
||
552 | self.left_image_label.config(text=os.path.basename(self.left_image_path)) |
||
553 | self.left_projected_image_width.delete(0, tk.END) |
||
554 | self.left_projected_image_width.insert(0, config.getProjectedImageWidth()) |
||
555 | self.left_projected_overlap_width.delete(0, tk.END) |
||
556 | self.left_projected_overlap_width.insert(0, config.getProjectedOverlapWidth()) |
||
557 | self.left_gamma.delete(0, tk.END) |
||
558 | self.left_gamma.insert(0, config.getGamma()) |
||
559 | self.left_image_side.set(config.getImageSide()) |
||
560 | self.left_transparency_factor.delete(0, tk.END) |
||
561 | self.left_transparency_factor.insert(0, config.getTransparencyFactor()) |
||
562 | 4 | Faiq Sayyidan SETIAWAN | |
563 | 7 | Faiq Sayyidan SETIAWAN | # Load right image parameters |
564 | self.right_image_path = config.getImageName() |
||
565 | if self.right_image_path and os.path.exists(self.right_image_path): |
||
566 | self.right_image_label.config(text=os.path.basename(self.right_image_path)) |
||
567 | self.right_projected_image_width.delete(0, tk.END) |
||
568 | self.right_projected_image_width.insert(0, config.getProjectedImageWidth()) |
||
569 | self.right_projected_overlap_width.delete(0, tk.END) |
||
570 | self.right_projected_overlap_width.insert(0, config.getProjectedOverlapWidth()) |
||
571 | self.right_gamma.delete(0, tk.END) |
||
572 | self.right_gamma.insert(0, config.getGamma()) |
||
573 | self.right_image_side.set(config.getImageSide()) |
||
574 | self.right_transparency_factor.delete(0, tk.END) |
||
575 | self.right_transparency_factor.insert(0, config.getTransparencyFactor()) |
||
576 | 4 | Faiq Sayyidan SETIAWAN | |
577 | 7 | Faiq Sayyidan SETIAWAN | messagebox.showinfo("Success", f"Configuration loaded from {load_path}") |
578 | logging.info(f"Configuration loaded from {load_path}") |
||
579 | else: |
||
580 | messagebox.showerror("Error", "Failed to load configuration.") |
||
581 | 4 | Faiq Sayyidan SETIAWAN | |
582 | 7 | Faiq Sayyidan SETIAWAN | def process_and_save(self): |
583 | # Validate inputs |
||
584 | if not self.left_image_path or not self.right_image_path: |
||
585 | messagebox.showerror("Error", "Please select both left and right images.") |
||
586 | return |
||
587 | 4 | Faiq Sayyidan SETIAWAN | |
588 | 7 | Faiq Sayyidan SETIAWAN | # Collect parameters for left image |
589 | left_params = { |
||
590 | 'image_name': self.left_image_path, |
||
591 | 'projected_image_width': int(self.left_projected_image_width.get()), |
||
592 | 'projected_overlap_width': int(self.left_projected_overlap_width.get()), |
||
593 | 'gamma': float(self.left_gamma.get()), |
||
594 | 'image_side': self.left_image_side.get(), |
||
595 | 'transparency_factor': float(self.left_transparency_factor.get()) |
||
596 | } |
||
597 | 4 | Faiq Sayyidan SETIAWAN | |
598 | 7 | Faiq Sayyidan SETIAWAN | # Collect parameters for right image |
599 | right_params = { |
||
600 | 'image_name': self.right_image_path, |
||
601 | 'projected_image_width': int(self.right_projected_image_width.get()), |
||
602 | 'projected_overlap_width': int(self.right_projected_overlap_width.get()), |
||
603 | 'gamma': float(self.right_gamma.get()), |
||
604 | 'image_side': self.right_image_side.get(), |
||
605 | 'transparency_factor': float(self.right_transparency_factor.get()) |
||
606 | } |
||
607 | 4 | Faiq Sayyidan SETIAWAN | |
608 | 7 | Faiq Sayyidan SETIAWAN | # Initialize main display |
609 | main_display = MainDisplay() |
||
610 | 4 | Faiq Sayyidan SETIAWAN | |
611 | 7 | Faiq Sayyidan SETIAWAN | # Process left image |
612 | self.progress_bar["value"] = 0 |
||
613 | self.root.update_idletasks() |
||
614 | left_processed, left_name = process_image(self.left_image_path, left_params, main_display) |
||
615 | if left_processed is not None and left_name is not None: |
||
616 | self.processed_images[left_name] = left_processed |
||
617 | save_image(left_processed, left_name) |
||
618 | self.progress_bar["value"] += 50 |
||
619 | self.root.update_idletasks() |
||
620 | 4 | Faiq Sayyidan SETIAWAN | |
621 | 7 | Faiq Sayyidan SETIAWAN | # Process right image |
622 | right_processed, right_name = process_image(self.right_image_path, right_params, main_display) |
||
623 | if right_processed is not None and right_name is not None: |
||
624 | self.processed_images[right_name] = right_processed |
||
625 | save_image(right_processed, right_name) |
||
626 | self.progress_bar["value"] += 50 |
||
627 | self.root.update_idletasks() |
||
628 | 4 | Faiq Sayyidan SETIAWAN | |
629 | 7 | Faiq Sayyidan SETIAWAN | # Display images |
630 | self.display_preview() |
||
631 | 4 | Faiq Sayyidan SETIAWAN | |
632 | 7 | Faiq Sayyidan SETIAWAN | # Finalize progress |
633 | self.progress_bar["value"] = 100 |
||
634 | self.root.update_idletasks() |
||
635 | 4 | Faiq Sayyidan SETIAWAN | messagebox.showinfo("Processing Complete", "Images processed and saved successfully.") |
636 | |||
637 | 7 | Faiq Sayyidan SETIAWAN | def display_preview(self): |
638 | # Display the first processed image as preview |
||
639 | if self.processed_images: |
||
640 | # For simplicity, display the first image |
||
641 | name, img = next(iter(self.processed_images.items())) |
||
642 | 4 | Faiq Sayyidan SETIAWAN | img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) |
643 | pil_img = Image.fromarray(img_rgb) |
||
644 | 7 | Faiq Sayyidan SETIAWAN | pil_img = pil_img.resize((400, 300), Image.ANTIALIAS) |
645 | 4 | Faiq Sayyidan SETIAWAN | img_tk = ImageTk.PhotoImage(pil_img) |
646 | 7 | Faiq Sayyidan SETIAWAN | self.processed_image_label.config(image=img_tk) |
647 | self.processed_image_label.image = img_tk |
||
648 | 4 | Faiq Sayyidan SETIAWAN | |
649 | 7 | Faiq Sayyidan SETIAWAN | # Load and display original image |
650 | original_img = cv2.imread(self.left_image_path if name == 'left' else self.right_image_path, cv2.IMREAD_COLOR) |
||
651 | if original_img is not None: |
||
652 | original_rgb = cv2.cvtColor(original_img, cv2.COLOR_BGR2RGB) |
||
653 | pil_original = Image.fromarray(original_rgb) |
||
654 | pil_original = pil_original.resize((400, 300), Image.ANTIALIAS) |
||
655 | original_tk = ImageTk.PhotoImage(pil_original) |
||
656 | self.original_image_label.config(image=original_tk) |
||
657 | self.original_image_label.image = original_tk |
||
658 | 4 | Faiq Sayyidan SETIAWAN | |
659 | 7 | Faiq Sayyidan SETIAWAN | def display_image(self, processed_images): |
660 | # This method can be expanded to display multiple images if needed |
||
661 | pass |
||
662 | 4 | Faiq Sayyidan SETIAWAN | |
663 | def main(): |
||
664 | |||
665 | root = tk.Tk() |
||
666 | |||
667 | app = ImageProcessingApp(root) |
||
668 | |||
669 | root.mainloop() |
||
670 | |||
671 | if __name__ == "__main__": |
||
672 | |||
673 | 1 | Faiq Sayyidan SETIAWAN | main() |
674 | |||
675 | 8 | Faiq Sayyidan SETIAWAN | |
676 | 1 | Faiq Sayyidan SETIAWAN | </code></pre> |