1+ import logging
12import os
2- import subprocess
33import sys
4+ import threading
45import tkinter as tk
56from tkinter import filedialog , messagebox
67
7- SCRIPT_PATH = os .path .join (os .path .dirname (__file__ ), "correct_images.py" )
8+ from imgcorrect import corrections
9+
10+ logger = logging .getLogger (__name__ )
11+
12+
13+ class TextHandler (logging .Handler ):
14+ def __init__ (self , text_widget ):
15+ super ().__init__ ()
16+ self .text_widget = text_widget
17+
18+ def emit (self , record ):
19+ msg = self .format (record )
20+ # Get the index of the last line
21+ last_line_index = self .text_widget .index ("end-2l" )
22+ last_line_text = self .text_widget .get (last_line_index , "end-1c" ).strip ()
23+ if last_line_text and last_line_text [0 ].isdigit ():
24+ # Replace the last line
25+ self .text_widget .after (
26+ 0 , self .text_widget .delete , last_line_index , "end-1c"
27+ )
28+ self .text_widget .after (0 , self .text_widget .insert , tk .END , msg + "\n " )
29+ else :
30+ self .text_widget .after (0 , self .text_widget .insert , tk .END , msg + "\n " )
31+ self .text_widget .after (0 , self .text_widget .see , tk .END )
832
933
1034class CorrectImagesApp (tk .Tk ):
1135 def __init__ (self ):
1236 super ().__init__ ()
1337 self .title ("Sentera Radiometric Corrections" )
14- self .geometry ("600x500" )
15- self .iconbitmap ("sentera_radiometric_corrections_icon.ico" )
38+ self .geometry ("800x500" )
39+ try :
40+ self .iconbitmap (
41+ os .path .join (sys ._MEIPASS , "sentera_radiometric_corrections_icon.ico" )
42+ )
43+ except Exception :
44+ self .iconbitmap ("sentera_radiometric_corrections_icon.ico" )
1645 self .create_widgets ()
1746
1847 def create_widgets (self ):
1948 row = 0
20- tk .Label (self , text = "Input Path" ).grid (row = row , column = 0 , sticky = "w" , padx = 15 )
49+ tk .Label (self , text = "Input Path" ).grid (
50+ row = row , column = 0 , sticky = "w" , padx = (15 , 0 )
51+ )
2152 self .input_path_var = tk .StringVar ()
2253 tk .Entry (
23- self , textvariable = self .input_path_var , width = 50 , justify = "right"
24- ).grid (row = row , column = 1 , sticky = "e" , padx = ( 0 , 5 ) )
54+ self , textvariable = self .input_path_var , width = 90 , justify = "right"
55+ ).grid (row = row , column = 1 , sticky = "e" )
2556 self .browse_input_button = tk .Button (
2657 self , text = "Browse" , command = self .browse_input
2758 )
2859 self .browse_input_button .grid (row = row , column = 2 )
2960 row += 1
3061
31- tk .Label (self , text = "Output Path" ).grid (row = row , column = 0 , sticky = "w" , padx = 15 )
62+ tk .Label (self , text = "Output Path" ).grid (
63+ row = row , column = 0 , sticky = "w" , padx = (15 , 0 )
64+ )
3265 self .output_path_var = tk .StringVar ()
33- tk .Entry (
34- self , textvariable = self .output_path_var , width = 50 , justify = "right"
35- ).grid (row = row , column = 1 , sticky = "e" , padx = (0 , 5 ))
66+ self .output_path_text = tk .Entry (
67+ self , textvariable = self .output_path_var , width = 90 , justify = "right"
68+ )
69+ self .output_path_text .grid (row = row , column = 1 , sticky = "e" )
3670 self .browse_output_button = tk .Button (
3771 self , text = "Browse" , command = self .browse_output
3872 )
@@ -62,11 +96,11 @@ def create_widgets(self):
6296
6397 self .exiftool_path_var = tk .StringVar ()
6498 self .exiftool_path_label = tk .Label (self , text = "ExifTool Path (optional)" )
65- self .exiftool_path_label .grid (row = row , column = 0 , sticky = "w" , padx = 15 )
99+ self .exiftool_path_label .grid (row = row , column = 0 , sticky = "w" , padx = ( 15 , 0 ) )
66100 self .exiftool_entry = tk .Entry (
67- self , textvariable = self .exiftool_path_var , width = 50 , justify = "right"
101+ self , textvariable = self .exiftool_path_var , width = 90 , justify = "right"
68102 )
69- self .exiftool_entry .grid (row = row , column = 1 , sticky = "w" , padx = ( 0 , 5 ) )
103+ self .exiftool_entry .grid (row = row , column = 1 , sticky = "e" )
70104 self .exiftool_path_browse_button = tk .Button (
71105 self , text = "Browse" , command = self .browse_exiftool
72106 )
@@ -92,8 +126,9 @@ def create_widgets(self):
92126 self .delete_original_var = tk .BooleanVar ()
93127 self .delete_overwrite_checkbutton = tk .Checkbutton (
94128 self ,
95- text = "Delete/Overwrite Original Images " ,
129+ text = "Delete/Overwrite Original" ,
96130 variable = self .delete_original_var ,
131+ command = self .toggle_overwrite ,
97132 )
98133 self .delete_overwrite_checkbutton .grid (row = row , column = 0 , sticky = "w" , padx = 15 )
99134 row += 1
@@ -144,12 +179,24 @@ def toggle_advanced_options(self):
144179 for widget in widgets :
145180 widget .grid ()
146181
182+ def toggle_overwrite (self ):
183+ if self .delete_original_var .get ():
184+ self .output_path_var .set (self .input_path_var .get ())
185+ self .browse_output_button ["state" ] = "disabled"
186+ self .output_path_text ["state" ] = "disabled"
187+ else :
188+ self .browse_output_button ["state" ] = "normal"
189+ self .output_path_text ["state" ] = "normal"
190+
147191 def browse_input (self ):
148192 path = filedialog .askdirectory ()
149193 if path :
150194 self .input_path_var .set (path )
151195 # Set output path to input path + '-calibrated'
152- calibrated_path = path .rstrip ("/\\ " ) + "-calibrated"
196+ if not self .delete_original_var .get ():
197+ calibrated_path = path .rstrip ("/\\ " ) + "-calibrated"
198+ else :
199+ calibrated_path = path
153200 self .output_path_var .set (calibrated_path )
154201 # Scroll input Entry to the end
155202 entry_widget = self .nametowidget (self .children ["!entry" ])
@@ -187,94 +234,66 @@ def enable_buttons(self):
187234 self .exiftool_path_browse_button ["state" ] = "normal"
188235
189236 def run_correction (self ):
190- import threading
191237
192238 self .disable_buttons ()
193239 input_path = self .input_path_var .get ()
194240 if not input_path :
195241 messagebox .showerror ("Error" , "Input path is required." )
242+ self .enable_buttons ()
196243 return
197- cmd = ["python" , "-u" , SCRIPT_PATH , input_path ]
198- if self .calibration_id_var .get ():
199- cmd += ["--calibration_id" , self .calibration_id_var .get ()]
200- if self .output_path_var .get ():
201- cmd += ["--output_path" , self .output_path_var .get ()]
202- if not self .ils_var .get ():
203- cmd .append ("--no_ils_correct" )
204- if not self .reflectance_var .get ():
205- cmd .append ("--no_reflectance_correct" )
206- if self .all_panels_var .get ():
207- cmd .append ("--all_panels" )
208- if self .delete_original_var .get ():
209- cmd .append ("--delete_original" )
244+ calibration_id = self .calibration_id_var .get ()
245+ output_path = self .output_path_var .get ()
246+ no_ils_correct = not self .ils_var .get ()
247+ no_reflectance_correct = not self .reflectance_var .get ()
248+ all_panels = self .all_panels_var .get ()
249+ delete_original = self .delete_original_var .get ()
250+
210251 if self .exiftool_path_var .get ():
211- cmd += [ "--exiftool_path" , self .exiftool_path_var .get ()]
252+ exiftool_path = self .exiftool_path_var .get ()
212253 else :
213- cmd += [ "--exiftool_path" , os .path .join (sys ._MEIPASS , "exiftool.exe" )]
214- if self .uint16_var .get ():
215- cmd . append ( "--uint16_output" )
254+ exiftool_path = os .path .join (sys ._MEIPASS , "exiftool.exe" )
255+ uint16_output = self .uint16_var .get ()
256+
216257 self .output_text .delete (1.0 , tk .END )
217- self .output_text .insert (tk .END , f"Running: { ' ' .join (cmd )} \n " )
218258
219259 os .makedirs (self .output_path_var .get (), exist_ok = True )
220260
221- def run_subprocess ():
222- try :
223- # Open the output file for writing
224- with open (
225- os .path .join (
226- os .path .split (self .output_path_var .get ())[0 ],
227- f"{ os .path .split (self .output_path_var .get ())[1 ]} _corrections_log.txt" ,
228- ),
229- "w" ,
230- encoding = "utf-8" ,
231- ) as outfile :
232- process = subprocess .Popen (
233- cmd ,
234- stdout = subprocess .PIPE ,
235- stderr = subprocess .PIPE ,
236- text = True ,
237- bufsize = 1 ,
238- )
239-
240- def read_stdout (stream ):
241- for line in iter (stream .readline , "" ):
242- if line :
243- self .output_text .after (
244- 0 , self .output_text .insert , tk .END , line
245- )
246- outfile .write (line )
247- outfile .flush ()
248- stream .close ()
249-
250- def read_stderr (stream ):
251- for line in iter (stream .readline , "" ):
252- if line :
253- self .output_text .after (
254- 0 , self .output_text .delete , 1.0 , tk .END
255- )
256- self .output_text .after (
257- 0 , self .output_text .insert , tk .END , line
258- )
259- outfile .write (line )
260- outfile .flush ()
261- stream .close ()
262-
263- stdout_thread = threading .Thread (
264- target = read_stdout , args = (process .stdout ,)
265- )
266- stderr_thread = threading .Thread (
267- target = read_stderr , args = (process .stderr ,)
268- )
269- stdout_thread .start ()
270- stderr_thread .start ()
271- stdout_thread .join ()
272- stderr_thread .join ()
273- except Exception as e :
274- self .output_text .after (0 , self .display_exception , e )
261+ def run_corrections ():
262+ handler = TextHandler (self .output_text )
263+ logging .basicConfig (
264+ filename = os .path .join (
265+ os .path .split (output_path )[0 ],
266+ f"{ os .path .basename (output_path )} _radiometric_corrections.log" ,
267+ ),
268+ level = logging .INFO ,
269+ format = "%(asctime)s %(levelname)s:%(message)s" ,
270+ )
271+ logging .getLogger ().addHandler (handler )
272+ logger .info ("Running Corrections" )
273+ logger .info (f"Input Path: { input_path } " )
274+ logger .info (f"Output Path: { output_path } " )
275+ logger .info (f"ExifTool Path: { exiftool_path } " )
276+ logger .info (f"Reflectance Correction: { not no_reflectance_correct } " )
277+ logger .info (f"ILS Correction: { not no_ils_correct } " )
278+ logger .info (f"Calibration ID: { calibration_id } " )
279+ logger .info (f"All Panels: { all_panels } " )
280+ logger .info (f"Delete Original: { delete_original } " )
281+ logger .info (f"UInt16 Output: { uint16_output } " )
282+ corrections .correct_images (
283+ input_path ,
284+ calibration_id ,
285+ output_path ,
286+ no_ils_correct ,
287+ no_reflectance_correct ,
288+ all_panels ,
289+ delete_original ,
290+ exiftool_path ,
291+ uint16_output ,
292+ )
275293 self .enable_buttons ()
294+ logger .info ("Corrections complete!" )
276295
277- threading .Thread (target = run_subprocess , daemon = True ).start ()
296+ threading .Thread (target = run_corrections , daemon = True ).start ()
278297
279298 def display_output (self , stdout , stderr ):
280299 if stdout :
0 commit comments