1
1
"""
2
2
Tool to load model and binarize a given image.
3
3
"""
4
-
4
+ import argparse
5
5
import sys
6
- from glob import glob
7
6
from os import environ , devnull
8
- from os . path import join
9
- from warnings import catch_warnings , simplefilter
7
+ from pathlib import Path
8
+ from typing import Union
10
9
11
- import numpy as np
12
- from PIL import Image
13
10
import cv2
11
+ import numpy as np
12
+
14
13
environ ['TF_CPP_MIN_LOG_LEVEL' ] = '3'
15
14
stderr = sys .stderr
16
15
sys .stderr = open (devnull , 'w' )
17
16
import tensorflow as tf
18
17
from tensorflow .keras .models import load_model
19
18
from tensorflow .python .keras import backend as tensorflow_backend
20
- sys .stderr = stderr
21
19
20
+ sys .stderr = stderr
22
21
23
22
import logging
24
23
24
+
25
25
def resize_image (img_in , input_height , input_width ):
26
26
return cv2 .resize (img_in , (input_width , input_height ), interpolation = cv2 .INTER_NEAREST )
27
27
28
+
28
29
class SbbBinarizer :
29
30
30
- def __init__ (self , model_dir , logger = None ):
31
- self . model_dir = model_dir
31
+ def __init__ (self , model_dir : Union [ str , Path ] , logger = None ):
32
+ model_dir = Path ( model_dir )
32
33
self .log = logger if logger else logging .getLogger ('SbbBinarizer' )
33
34
34
35
self .start_new_session ()
35
36
36
- self .model_files = glob ('%s/*.h5' % self .model_dir )
37
+ self .model_files = list ([str (p .absolute ()) for p in model_dir .rglob ("*.h5" )])
38
+ if not self .model_files :
39
+ raise ValueError (f"No models found in { str (model_dir )} " )
37
40
38
41
self .models = []
39
42
for model_file in self .model_files :
@@ -51,54 +54,51 @@ def end_session(self):
51
54
self .session .close ()
52
55
del self .session
53
56
54
- def load_model (self , model_name ):
55
- model = load_model (join ( self . model_dir , model_name ) , compile = False )
56
- model_height = model .layers [len (model .layers )- 1 ].output_shape [1 ]
57
- model_width = model .layers [len (model .layers )- 1 ].output_shape [2 ]
58
- n_classes = model .layers [len (model .layers )- 1 ].output_shape [3 ]
57
+ def load_model (self , model_path : str ):
58
+ model = load_model (model_path , compile = False )
59
+ model_height = model .layers [len (model .layers ) - 1 ].output_shape [1 ]
60
+ model_width = model .layers [len (model .layers ) - 1 ].output_shape [2 ]
61
+ n_classes = model .layers [len (model .layers ) - 1 ].output_shape [3 ]
59
62
return model , model_height , model_width , n_classes
60
63
61
64
def predict (self , model_in , img , use_patches ):
62
65
tensorflow_backend .set_session (self .session )
63
66
model , model_height , model_width , n_classes = model_in
64
-
67
+
65
68
img_org_h = img .shape [0 ]
66
69
img_org_w = img .shape [1 ]
67
-
70
+
68
71
if img .shape [0 ] < model_height and img .shape [1 ] >= model_width :
69
- img_padded = np .zeros (( model_height , img .shape [1 ], img .shape [2 ] ))
70
-
71
- index_start_h = int ( abs ( img .shape [0 ] - model_height ) / 2. )
72
+ img_padded = np .zeros ((model_height , img .shape [1 ], img .shape [2 ]))
73
+
74
+ index_start_h = int (abs (img .shape [0 ] - model_height ) / 2. )
72
75
index_start_w = 0
73
-
74
- img_padded [ index_start_h : index_start_h + img .shape [0 ], :, : ] = img [:,:, :]
75
-
76
+
77
+ img_padded [ index_start_h : index_start_h + img .shape [0 ], :, :] = img [:, :, :]
78
+
76
79
elif img .shape [0 ] >= model_height and img .shape [1 ] < model_width :
77
- img_padded = np .zeros (( img .shape [0 ], model_width , img .shape [2 ] ))
78
-
79
- index_start_h = 0
80
- index_start_w = int ( abs ( img .shape [1 ] - model_width ) / 2. )
81
-
82
- img_padded [ :, index_start_w : index_start_w + img .shape [1 ], : ] = img [:,:, :]
83
-
84
-
80
+ img_padded = np .zeros ((img .shape [0 ], model_width , img .shape [2 ]))
81
+
82
+ index_start_h = 0
83
+ index_start_w = int (abs (img .shape [1 ] - model_width ) / 2. )
84
+
85
+ img_padded [ :, index_start_w : index_start_w + img .shape [1 ], :] = img [:, :, :]
86
+
87
+
85
88
elif img .shape [0 ] < model_height and img .shape [1 ] < model_width :
86
- img_padded = np .zeros (( model_height , model_width , img .shape [2 ] ))
87
-
88
- index_start_h = int ( abs ( img .shape [0 ] - model_height ) / 2. )
89
- index_start_w = int ( abs ( img .shape [1 ] - model_width ) / 2. )
90
-
91
- img_padded [ index_start_h : index_start_h + img .shape [0 ], index_start_w : index_start_w + img .shape [1 ], : ] = img [:,:, :]
92
-
89
+ img_padded = np .zeros ((model_height , model_width , img .shape [2 ]))
90
+
91
+ index_start_h = int (abs (img .shape [0 ] - model_height ) / 2. )
92
+ index_start_w = int (abs (img .shape [1 ] - model_width ) / 2. )
93
+
94
+ img_padded [ index_start_h : index_start_h + img .shape [0 ], index_start_w : index_start_w + img .shape [1 ], :] = img [:, :, :]
95
+
93
96
else :
94
97
index_start_h = 0
95
- index_start_w = 0
98
+ index_start_w = 0
96
99
img_padded = np .copy (img )
97
-
98
-
100
+
99
101
img = np .copy (img_padded )
100
-
101
-
102
102
103
103
if use_patches :
104
104
@@ -107,7 +107,6 @@ def predict(self, model_in, img, use_patches):
107
107
width_mid = model_width - 2 * margin
108
108
height_mid = model_height - 2 * margin
109
109
110
-
111
110
img = img / float (255.0 )
112
111
113
112
img_h = img .shape [0 ]
@@ -167,49 +166,49 @@ def predict(self, model_in, img, use_patches):
167
166
mask_true [index_y_d + 0 :index_y_u - margin , index_x_d + 0 :index_x_u - margin ] = seg
168
167
prediction_true [index_y_d + 0 :index_y_u - margin , index_x_d + 0 :index_x_u - margin , :] = seg_color
169
168
170
- elif i == nxf - 1 and j == nyf - 1 :
169
+ elif i == nxf - 1 and j == nyf - 1 :
171
170
seg_color = seg_color [margin :seg_color .shape [0 ] - 0 , margin :seg_color .shape [1 ] - 0 , :]
172
171
seg = seg [margin :seg .shape [0 ] - 0 , margin :seg .shape [1 ] - 0 ]
173
172
174
173
mask_true [index_y_d + margin :index_y_u - 0 , index_x_d + margin :index_x_u - 0 ] = seg
175
174
prediction_true [index_y_d + margin :index_y_u - 0 , index_x_d + margin :index_x_u - 0 , :] = seg_color
176
175
177
- elif i == 0 and j == nyf - 1 :
176
+ elif i == 0 and j == nyf - 1 :
178
177
seg_color = seg_color [margin :seg_color .shape [0 ] - 0 , 0 :seg_color .shape [1 ] - margin , :]
179
178
seg = seg [margin :seg .shape [0 ] - 0 , 0 :seg .shape [1 ] - margin ]
180
179
181
180
mask_true [index_y_d + margin :index_y_u - 0 , index_x_d + 0 :index_x_u - margin ] = seg
182
181
prediction_true [index_y_d + margin :index_y_u - 0 , index_x_d + 0 :index_x_u - margin , :] = seg_color
183
182
184
- elif i == nxf - 1 and j == 0 :
183
+ elif i == nxf - 1 and j == 0 :
185
184
seg_color = seg_color [0 :seg_color .shape [0 ] - margin , margin :seg_color .shape [1 ] - 0 , :]
186
185
seg = seg [0 :seg .shape [0 ] - margin , margin :seg .shape [1 ] - 0 ]
187
186
188
187
mask_true [index_y_d + 0 :index_y_u - margin , index_x_d + margin :index_x_u - 0 ] = seg
189
188
prediction_true [index_y_d + 0 :index_y_u - margin , index_x_d + margin :index_x_u - 0 , :] = seg_color
190
189
191
- elif i == 0 and j != 0 and j != nyf - 1 :
190
+ elif i == 0 and j != 0 and j != nyf - 1 :
192
191
seg_color = seg_color [margin :seg_color .shape [0 ] - margin , 0 :seg_color .shape [1 ] - margin , :]
193
192
seg = seg [margin :seg .shape [0 ] - margin , 0 :seg .shape [1 ] - margin ]
194
193
195
194
mask_true [index_y_d + margin :index_y_u - margin , index_x_d + 0 :index_x_u - margin ] = seg
196
195
prediction_true [index_y_d + margin :index_y_u - margin , index_x_d + 0 :index_x_u - margin , :] = seg_color
197
196
198
- elif i == nxf - 1 and j != 0 and j != nyf - 1 :
197
+ elif i == nxf - 1 and j != 0 and j != nyf - 1 :
199
198
seg_color = seg_color [margin :seg_color .shape [0 ] - margin , margin :seg_color .shape [1 ] - 0 , :]
200
199
seg = seg [margin :seg .shape [0 ] - margin , margin :seg .shape [1 ] - 0 ]
201
200
202
201
mask_true [index_y_d + margin :index_y_u - margin , index_x_d + margin :index_x_u - 0 ] = seg
203
202
prediction_true [index_y_d + margin :index_y_u - margin , index_x_d + margin :index_x_u - 0 , :] = seg_color
204
203
205
- elif i != 0 and i != nxf - 1 and j == 0 :
204
+ elif i != 0 and i != nxf - 1 and j == 0 :
206
205
seg_color = seg_color [0 :seg_color .shape [0 ] - margin , margin :seg_color .shape [1 ] - margin , :]
207
206
seg = seg [0 :seg .shape [0 ] - margin , margin :seg .shape [1 ] - margin ]
208
207
209
208
mask_true [index_y_d + 0 :index_y_u - margin , index_x_d + margin :index_x_u - margin ] = seg
210
209
prediction_true [index_y_d + 0 :index_y_u - margin , index_x_d + margin :index_x_u - margin , :] = seg_color
211
210
212
- elif i != 0 and i != nxf - 1 and j == nyf - 1 :
211
+ elif i != 0 and i != nxf - 1 and j == nyf - 1 :
213
212
seg_color = seg_color [margin :seg_color .shape [0 ] - 0 , margin :seg_color .shape [1 ] - margin , :]
214
213
seg = seg [margin :seg .shape [0 ] - 0 , margin :seg .shape [1 ] - margin ]
215
214
@@ -222,10 +221,8 @@ def predict(self, model_in, img, use_patches):
222
221
223
222
mask_true [index_y_d + margin :index_y_u - margin , index_x_d + margin :index_x_u - margin ] = seg
224
223
prediction_true [index_y_d + margin :index_y_u - margin , index_x_d + margin :index_x_u - margin , :] = seg_color
225
-
226
-
227
-
228
- prediction_true = prediction_true [index_start_h : index_start_h + img_org_h , index_start_w : index_start_w + img_org_w ,:]
224
+
225
+ prediction_true = prediction_true [index_start_h : index_start_h + img_org_h , index_start_w : index_start_w + img_org_w , :]
229
226
prediction_true = prediction_true .astype (np .uint8 )
230
227
231
228
else :
@@ -240,17 +237,16 @@ def predict(self, model_in, img, use_patches):
240
237
seg_color = np .repeat (seg [:, :, np .newaxis ], 3 , axis = 2 )
241
238
prediction_true = resize_image (seg_color , img_h_page , img_w_page )
242
239
prediction_true = prediction_true .astype (np .uint8 )
243
- return prediction_true [:,:, 0 ]
240
+ return prediction_true [:, :, 0 ]
244
241
245
242
def run (self , image = None , image_path = None , save = None , use_patches = False ):
246
- if (image is not None and image_path is not None ) or \
247
- (image is None and image_path is None ):
243
+ if (image is not None and image_path is not None ) or (image is None and image_path is None ):
248
244
raise ValueError ("Must pass either a opencv2 image or an image_path" )
249
245
if image_path is not None :
250
246
image = cv2 .imread (image_path )
251
247
img_last = 0
252
248
for n , (model , model_file ) in enumerate (zip (self .models , self .model_files )):
253
- self .log .info (' Predicting with model %s [%s/%s]' % ( model_file , n + 1 , len (self .model_files )) )
249
+ self .log .info (f" Predicting with model { model_file } [ { n + 1 } / { len (self .model_files )} ]" )
254
250
255
251
res = self .predict (model , image , use_patches )
256
252
@@ -270,5 +266,7 @@ def run(self, image=None, image_path=None, save=None, use_patches=False):
270
266
img_last [:, :][img_last [:, :] > 0 ] = 255
271
267
img_last = (img_last [:, :] == 0 ) * 255
272
268
if save :
269
+ # Create the output directory (and if necessary it's parents) if it doesn't exist already
270
+ Path (save ).parent .mkdir (parents = True , exist_ok = True )
273
271
cv2 .imwrite (save , img_last )
274
272
return img_last
0 commit comments