Skip to content

Commit 0d7cb75

Browse files
Update notebook and inference script
1 parent 7950b94 commit 0d7cb75

3 files changed

Lines changed: 240 additions & 113 deletions

File tree

‎inference.py‎

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from skimage.transform import rescale, resize
1313
from skimage.util import img_as_ubyte
1414
from skimage.exposure import rescale_intensity
15+
from skimage.segmentation import clear_border
1516

1617
from preprocessing import keep_n_biggest_objects
1718

@@ -20,12 +21,16 @@
2021
pipe = load(f)
2122

2223

23-
def extract_digit_from_digit_square(image: np.ndarray) -> np.ndarray:
24+
def extract_digit_from_digit_roi(image: np.ndarray) -> np.ndarray:
2425
image = img_as_ubyte(image)
2526

2627
resized = rescale(image, scale=0.5)
2728

28-
binary = resized > threshold_otsu(resized)
29+
try:
30+
binary = resized > threshold_otsu(resized)
31+
except ValueError:
32+
return img_as_ubyte(np.zeros((50, 50)))
33+
2934
labelled = label(binary)
3035

3136
light_square = keep_n_biggest_objects(labelled, n=1)
@@ -54,20 +59,26 @@ def extract_digit_from_digit_square(image: np.ndarray) -> np.ndarray:
5459
return digit_crop
5560

5661

57-
def detect_digit_squares(image: np.ndarray, n_squares=12) -> pd.DataFrame:
62+
def detect_digit_roi(image: np.ndarray, max_objects=12) -> pd.DataFrame:
63+
# RGB => Grayscale
5864
gray = rgb2gray(image)
59-
binary = gray < threshold_otsu(gray)
65+
66+
# Otsu threshold
67+
binary = gray > threshold_otsu(gray)
68+
69+
# Labelling + keep biggest object
6070
labelled = label(binary)
61-
grid_frame = keep_n_biggest_objects(labelled, n=1)
62-
filled_grid_frame = ndi.binary_fill_holes(grid_frame)
63-
digit_squares = np.logical_and(filled_grid_frame, grid_frame == 0)
64-
digit_squares_labelled = label(digit_squares)
65-
digit_squares_cleaned = keep_n_biggest_objects(digit_squares_labelled, n=n_squares)
71+
72+
# Remove object touching the image border (incl. the white background, probably)
73+
labelled = clear_border(labelled)
74+
75+
# Keep the biggest `max_objects` objects only
76+
digit_crops = keep_n_biggest_objects(labelled, n=max_objects)
6677

6778
# Return a dataframe with intensity image and centroids
6879
df = pd.DataFrame(
6980
regionprops_table(
70-
digit_squares_cleaned,
81+
digit_crops,
7182
intensity_image=gray,
7283
properties=["intensity_image", "bbox"],
7384
)
@@ -77,40 +88,41 @@ def detect_digit_squares(image: np.ndarray, n_squares=12) -> pd.DataFrame:
7788

7889

7990
def classify_digit_square(digit_square_img: np.ndarray) -> str:
80-
digit = extract_digit_from_digit_square(digit_square_img)
91+
digit = extract_digit_from_digit_roi(digit_square_img)
8192

8293
# Normalize intensity values
8394
digit_normed = rescale_intensity(digit, out_range=(0, 1))
8495

96+
# Flatten pixels
8597
pixel_features = np.reshape(digit_normed[None], (1, -1))
98+
99+
# Predict
86100
pred_label = pipe.predict(pixel_features)[0]
87101

88102
return pred_label
89103

90104

91-
def draw_boxes(img, df: pd.DataFrame):
105+
def draw_boxes(img, df: pd.DataFrame, font_size=1.5, thickness=2):
92106
boxes = df[['bbox-0', 'bbox-1', 'bbox-2', 'bbox-3']].values
93107
labels = df["pred"].values
94108

95109
output = img.copy()
96110
for i, box in enumerate(boxes):
97111
y1, x1, y2, x2 = map(int, box)
98112

99-
cv2.rectangle(output, (x1, y1), (x2, y2), color=(0, 255, 0), thickness=2)
113+
cv2.rectangle(output, (x1, y1), (x2, y2), color=(0, 255, 0), thickness=thickness)
100114

101115
text = str(labels[i])
102116

103117
(text_w, text_h), baseline = cv2.getTextSize(
104118
text=text,
105119
fontFace=cv2.FONT_HERSHEY_SIMPLEX,
106-
fontScale=0.5,
107-
thickness=1,
120+
fontScale=font_size,
121+
thickness=thickness,
108122
)
109123

110-
# Put label above box if there is room, otherwise inside/top edge
111-
text_y = y1 - 8 if y1 - 8 > text_h else y1 + text_h + 8
124+
text_y = y1 + text_h + 14
112125

113-
# Background rectangle for text
114126
cv2.rectangle(
115127
output,
116128
(x1, text_y - text_h - baseline),
@@ -124,9 +136,9 @@ def draw_boxes(img, df: pd.DataFrame):
124136
text=text,
125137
org=(x1, text_y),
126138
fontFace=cv2.FONT_HERSHEY_SIMPLEX,
127-
fontScale=0.5,
139+
fontScale=font_size,
128140
color=(0, 0, 0),
129-
thickness=1,
141+
thickness=thickness,
130142
lineType=cv2.LINE_AA,
131143
)
132144

@@ -139,13 +151,15 @@ def main(camera_idx: int):
139151
if not cap.isOpened():
140152
raise RuntimeError("Could not open camera")
141153

154+
cv2.namedWindow("Camera", cv2.WINDOW_NORMAL)
155+
142156
while True:
143157
ret, frame = cap.read()
144158
if not ret:
145159
print("Failed to grab frame")
146160
break
147161

148-
df = detect_digit_squares(frame)
162+
df = detect_digit_roi(frame)
149163

150164
df["pred"] = df["intensity_image"].apply(classify_digit_square)
151165

0 commit comments

Comments
 (0)