Semapp 1.0.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- semapp/Layout/__init__.py +26 -0
- semapp/Layout/create_button.py +1248 -0
- semapp/Layout/main_window_att.py +54 -0
- semapp/Layout/settings.py +170 -0
- semapp/Layout/styles.py +152 -0
- semapp/Layout/toast.py +157 -0
- semapp/Plot/__init__.py +8 -0
- semapp/Plot/frame_attributes.py +690 -0
- semapp/Plot/overview_window.py +355 -0
- semapp/Plot/styles.py +55 -0
- semapp/Plot/utils.py +295 -0
- semapp/Processing/__init__.py +4 -0
- semapp/Processing/detection.py +513 -0
- semapp/Processing/klarf_reader.py +461 -0
- semapp/Processing/processing.py +686 -0
- semapp/Processing/rename_tif.py +498 -0
- semapp/Processing/split_tif.py +323 -0
- semapp/Processing/threshold.py +777 -0
- semapp/__init__.py +10 -0
- semapp/asset/icon.png +0 -0
- semapp/main.py +103 -0
- semapp-1.0.5.dist-info/METADATA +300 -0
- semapp-1.0.5.dist-info/RECORD +27 -0
- semapp-1.0.5.dist-info/WHEEL +5 -0
- semapp-1.0.5.dist-info/entry_points.txt +2 -0
- semapp-1.0.5.dist-info/licenses/LICENSE +674 -0
- semapp-1.0.5.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module for splitting multi-page TIFF files into individual TIFF files.
|
|
3
|
+
Supports KRONOS, COMPLUS4T, and normal modes.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
import glob
|
|
8
|
+
from PIL import Image
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def split_tiff(tiff_path, output_dir, coordinates=None, is_kronos=False, is_complus4t=False):
|
|
12
|
+
"""
|
|
13
|
+
Split a merged TIFF file into individual TIFF files.
|
|
14
|
+
Main function that detects the mode and calls the appropriate splitter.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
tiff_path: Path to the multi-page TIFF file
|
|
18
|
+
output_dir: Directory where split files will be saved
|
|
19
|
+
coordinates: DataFrame with columns ["defect_id", "X", "Y", "defect_size"] (for COMPLUS4T)
|
|
20
|
+
is_kronos: Boolean indicating if this is KRONOS mode
|
|
21
|
+
is_complus4t: Boolean indicating if this is COMPLUS4T mode
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
list: List of file paths of the generated TIFF files
|
|
25
|
+
"""
|
|
26
|
+
if is_complus4t:
|
|
27
|
+
return _split_tiff_complus4t(tiff_path, output_dir, coordinates)
|
|
28
|
+
elif is_kronos:
|
|
29
|
+
return _split_tiff_kronos(tiff_path, output_dir)
|
|
30
|
+
else:
|
|
31
|
+
return _split_tiff_normal(tiff_path, output_dir)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def split_tiff_all(dirname, coordinates_dict=None, is_kronos=False, is_complus4t=False):
|
|
35
|
+
"""
|
|
36
|
+
Split all merged TIFF files in all subdirectories into individual TIFF files.
|
|
37
|
+
Main function that detects the mode and calls the appropriate splitter.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
dirname: Base directory containing subdirectories
|
|
41
|
+
coordinates_dict: Dictionary mapping wafer_num to coordinates DataFrame (for COMPLUS4T)
|
|
42
|
+
is_kronos: Boolean indicating if this is KRONOS mode
|
|
43
|
+
is_complus4t: Boolean indicating if this is COMPLUS4T mode
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
list: List of all generated TIFF file paths
|
|
47
|
+
"""
|
|
48
|
+
if is_complus4t:
|
|
49
|
+
return _split_tiff_all_complus4t(dirname, coordinates_dict)
|
|
50
|
+
elif is_kronos:
|
|
51
|
+
return _split_tiff_all_kronos(dirname)
|
|
52
|
+
else:
|
|
53
|
+
return _split_tiff_all_normal(dirname)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _split_tiff_kronos(tiff_path, output_dir):
|
|
57
|
+
"""
|
|
58
|
+
Split TIFF file for KRONOS mode.
|
|
59
|
+
Splits all pages sequentially.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
tiff_path: Path to the multi-page TIFF file
|
|
63
|
+
output_dir: Directory where split files will be saved
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
list: List of file paths of the generated TIFF files
|
|
67
|
+
"""
|
|
68
|
+
if not os.path.exists(tiff_path):
|
|
69
|
+
return []
|
|
70
|
+
|
|
71
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
72
|
+
output_files = []
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
img = Image.open(tiff_path)
|
|
76
|
+
page_index = 0
|
|
77
|
+
|
|
78
|
+
while True:
|
|
79
|
+
output_file = os.path.join(output_dir, f"data_page_{page_index + 1}.tiff")
|
|
80
|
+
img.save(output_file, format="TIFF")
|
|
81
|
+
output_files.append(output_file)
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
img.seek(page_index + 1)
|
|
85
|
+
page_index += 1
|
|
86
|
+
except EOFError:
|
|
87
|
+
break
|
|
88
|
+
except Exception as error:
|
|
89
|
+
raise RuntimeError(f"Error splitting TIFF file: {error}") from error
|
|
90
|
+
|
|
91
|
+
return output_files
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _split_tiff_complus4t(tiff_path, output_dir, coordinates):
|
|
95
|
+
"""
|
|
96
|
+
Split TIFF file for COMPLUS4T mode.
|
|
97
|
+
Only splits pages corresponding to defect_id from coordinates.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
tiff_path: Path to the multi-page TIFF file
|
|
101
|
+
output_dir: Directory where split files will be saved
|
|
102
|
+
coordinates: DataFrame with columns ["defect_id", "X", "Y", "defect_size"]
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
list: List of file paths of the generated TIFF files
|
|
106
|
+
"""
|
|
107
|
+
if not os.path.exists(tiff_path):
|
|
108
|
+
return []
|
|
109
|
+
|
|
110
|
+
if coordinates is None or coordinates.empty:
|
|
111
|
+
print(f"Warning: No coordinates provided for COMPLUS4T split")
|
|
112
|
+
return []
|
|
113
|
+
|
|
114
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
115
|
+
output_files = []
|
|
116
|
+
|
|
117
|
+
try:
|
|
118
|
+
img = Image.open(tiff_path)
|
|
119
|
+
|
|
120
|
+
# COMPLUS4T: only split pages corresponding to defect_id
|
|
121
|
+
# Pages in TIFF correspond to defect_id (331, 332, 333...)
|
|
122
|
+
# defect_id are 1-based in KLARF, but TIFF pages are 0-based
|
|
123
|
+
# So defect_id 331 = page index 330 (331 - 1)
|
|
124
|
+
for idx, row in coordinates.iterrows():
|
|
125
|
+
defect_id = int(row['defect_id'])
|
|
126
|
+
page_index = defect_id - 1 # Convert to 0-based index
|
|
127
|
+
|
|
128
|
+
try:
|
|
129
|
+
img.seek(page_index)
|
|
130
|
+
output_file = os.path.join(output_dir, f"data_page_{defect_id}.tiff")
|
|
131
|
+
img.save(output_file, format="TIFF")
|
|
132
|
+
output_files.append(output_file)
|
|
133
|
+
except EOFError:
|
|
134
|
+
print(f"Warning: Page {page_index} (defect_id {defect_id}) not found in TIFF")
|
|
135
|
+
continue
|
|
136
|
+
except Exception as error:
|
|
137
|
+
raise RuntimeError(f"Error splitting TIFF file: {error}") from error
|
|
138
|
+
|
|
139
|
+
return output_files
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _split_tiff_normal(tiff_path, output_dir):
|
|
143
|
+
"""
|
|
144
|
+
Split TIFF file for normal mode.
|
|
145
|
+
Splits all pages sequentially.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
tiff_path: Path to the multi-page TIFF file
|
|
149
|
+
output_dir: Directory where split files will be saved
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
list: List of file paths of the generated TIFF files
|
|
153
|
+
"""
|
|
154
|
+
if not os.path.exists(tiff_path):
|
|
155
|
+
return []
|
|
156
|
+
|
|
157
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
158
|
+
output_files = []
|
|
159
|
+
|
|
160
|
+
try:
|
|
161
|
+
img = Image.open(tiff_path)
|
|
162
|
+
page_index = 0
|
|
163
|
+
|
|
164
|
+
while True:
|
|
165
|
+
output_file = os.path.join(output_dir, f"data_page_{page_index + 1}.tiff")
|
|
166
|
+
img.save(output_file, format="TIFF")
|
|
167
|
+
output_files.append(output_file)
|
|
168
|
+
|
|
169
|
+
try:
|
|
170
|
+
img.seek(page_index + 1)
|
|
171
|
+
page_index += 1
|
|
172
|
+
except EOFError:
|
|
173
|
+
break
|
|
174
|
+
except Exception as error:
|
|
175
|
+
raise RuntimeError(f"Error splitting TIFF file: {error}") from error
|
|
176
|
+
|
|
177
|
+
return output_files
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _split_tiff_all_kronos(dirname):
|
|
181
|
+
"""
|
|
182
|
+
Split all TIFF files for KRONOS mode across all subdirectories.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
dirname: Base directory containing subdirectories
|
|
186
|
+
|
|
187
|
+
Returns:
|
|
188
|
+
list: List of all generated TIFF file paths
|
|
189
|
+
"""
|
|
190
|
+
all_output_files = []
|
|
191
|
+
|
|
192
|
+
for subdir, _, _ in os.walk(dirname):
|
|
193
|
+
if subdir == dirname:
|
|
194
|
+
continue
|
|
195
|
+
|
|
196
|
+
tiff_path = os.path.join(subdir, "data.tif")
|
|
197
|
+
|
|
198
|
+
if not os.path.exists(tiff_path):
|
|
199
|
+
continue
|
|
200
|
+
|
|
201
|
+
try:
|
|
202
|
+
img = Image.open(tiff_path)
|
|
203
|
+
page_index = 0
|
|
204
|
+
|
|
205
|
+
while True:
|
|
206
|
+
output_file = tiff_path.replace(".tif", "") + f"_page_{page_index + 1}.tiff"
|
|
207
|
+
img.save(output_file, format="TIFF")
|
|
208
|
+
all_output_files.append(output_file)
|
|
209
|
+
|
|
210
|
+
try:
|
|
211
|
+
img.seek(page_index + 1)
|
|
212
|
+
page_index += 1
|
|
213
|
+
except EOFError:
|
|
214
|
+
break
|
|
215
|
+
except Exception as error:
|
|
216
|
+
print(f"Error splitting TIFF file {tiff_path}: {error}")
|
|
217
|
+
continue
|
|
218
|
+
|
|
219
|
+
return all_output_files
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _split_tiff_all_complus4t(dirname, coordinates_dict):
|
|
223
|
+
"""
|
|
224
|
+
Split all TIFF files for COMPLUS4T mode across all subdirectories.
|
|
225
|
+
|
|
226
|
+
Args:
|
|
227
|
+
dirname: Base directory containing subdirectories
|
|
228
|
+
coordinates_dict: Dictionary mapping wafer_num to coordinates DataFrame
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
list: List of all generated TIFF file paths
|
|
232
|
+
"""
|
|
233
|
+
all_output_files = []
|
|
234
|
+
|
|
235
|
+
# For COMPLUS4T, the TIFF file is in the parent directory
|
|
236
|
+
tiff_files = glob.glob(os.path.join(dirname, '*.tiff'))
|
|
237
|
+
if not tiff_files:
|
|
238
|
+
tiff_files = glob.glob(os.path.join(dirname, '*.tif'))
|
|
239
|
+
|
|
240
|
+
if not tiff_files:
|
|
241
|
+
print("Warning: No TIFF file found in parent directory for COMPLUS4T mode")
|
|
242
|
+
return []
|
|
243
|
+
|
|
244
|
+
parent_tiff_path = tiff_files[0]
|
|
245
|
+
|
|
246
|
+
for subdir, _, _ in os.walk(dirname):
|
|
247
|
+
if subdir == dirname:
|
|
248
|
+
continue
|
|
249
|
+
|
|
250
|
+
try:
|
|
251
|
+
wafer_num = int(os.path.basename(subdir))
|
|
252
|
+
except ValueError:
|
|
253
|
+
continue
|
|
254
|
+
|
|
255
|
+
if wafer_num not in coordinates_dict:
|
|
256
|
+
continue
|
|
257
|
+
|
|
258
|
+
coordinates = coordinates_dict[wafer_num]
|
|
259
|
+
output_dir = os.path.join(dirname, str(wafer_num))
|
|
260
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
261
|
+
|
|
262
|
+
try:
|
|
263
|
+
img = Image.open(parent_tiff_path)
|
|
264
|
+
|
|
265
|
+
for idx, row in coordinates.iterrows():
|
|
266
|
+
defect_id = int(row['defect_id'])
|
|
267
|
+
page_index = defect_id - 1
|
|
268
|
+
|
|
269
|
+
try:
|
|
270
|
+
img.seek(page_index)
|
|
271
|
+
output_file = os.path.join(output_dir, f"data_page_{defect_id}.tiff")
|
|
272
|
+
img.save(output_file, format="TIFF")
|
|
273
|
+
all_output_files.append(output_file)
|
|
274
|
+
except EOFError:
|
|
275
|
+
print(f"Warning: Page {page_index} (defect_id {defect_id}) not found in TIFF for wafer {wafer_num}")
|
|
276
|
+
continue
|
|
277
|
+
except Exception as error:
|
|
278
|
+
print(f"Error splitting TIFF file for wafer {wafer_num}: {error}")
|
|
279
|
+
continue
|
|
280
|
+
|
|
281
|
+
return all_output_files
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def _split_tiff_all_normal(dirname):
|
|
285
|
+
"""
|
|
286
|
+
Split all TIFF files for normal mode across all subdirectories.
|
|
287
|
+
|
|
288
|
+
Args:
|
|
289
|
+
dirname: Base directory containing subdirectories
|
|
290
|
+
|
|
291
|
+
Returns:
|
|
292
|
+
list: List of all generated TIFF file paths
|
|
293
|
+
"""
|
|
294
|
+
all_output_files = []
|
|
295
|
+
|
|
296
|
+
for subdir, _, _ in os.walk(dirname):
|
|
297
|
+
if subdir == dirname:
|
|
298
|
+
continue
|
|
299
|
+
|
|
300
|
+
tiff_path = os.path.join(subdir, "data.tif")
|
|
301
|
+
|
|
302
|
+
if not os.path.exists(tiff_path):
|
|
303
|
+
continue
|
|
304
|
+
|
|
305
|
+
try:
|
|
306
|
+
img = Image.open(tiff_path)
|
|
307
|
+
page_index = 0
|
|
308
|
+
|
|
309
|
+
while True:
|
|
310
|
+
output_file = tiff_path.replace(".tif", "") + f"_page_{page_index + 1}.tiff"
|
|
311
|
+
img.save(output_file, format="TIFF")
|
|
312
|
+
all_output_files.append(output_file)
|
|
313
|
+
|
|
314
|
+
try:
|
|
315
|
+
img.seek(page_index + 1)
|
|
316
|
+
page_index += 1
|
|
317
|
+
except EOFError:
|
|
318
|
+
break
|
|
319
|
+
except Exception as error:
|
|
320
|
+
print(f"Error splitting TIFF file {tiff_path}: {error}")
|
|
321
|
+
continue
|
|
322
|
+
|
|
323
|
+
return all_output_files
|