Skip to content

Commit ac596a3

Browse files
Update inference.py
1 parent 0c12a14 commit ac596a3

1 file changed

Lines changed: 29 additions & 59 deletions

File tree

‎inference.py‎

Lines changed: 29 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,36 @@
1+
"""
2+
Inference script for digit recognition on a webcam or USB camera.
3+
"""
4+
15
import sys
26
from pickle import load
37

48
import cv2
59
import numpy as np
610
import pandas as pd
7-
import scipy.ndimage as ndi
811
from skimage.color import rgb2gray
912
from skimage.filters import threshold_otsu
1013
from skimage.measure import regionprops_table
1114
from skimage.morphology import label
12-
from skimage.transform import rescale, resize
15+
from skimage.transform import resize
1316
from skimage.util import img_as_ubyte
1417
from skimage.exposure import rescale_intensity
1518
from skimage.segmentation import clear_border
1619

1720
from preprocessing import keep_n_biggest_objects
1821

22+
1923
# Reload the sklearn `pipeline`
2024
with open("pipeline.pkl", "rb") as f:
2125
pipe = load(f)
2226

2327

24-
def extract_digit_from_digit_roi(image: np.ndarray) -> np.ndarray:
25-
"""Assuming that a digit is drawn inside the ROI, we extract a crop around it and resize it to (50, 50)."""
26-
image = img_as_ubyte(image) # Convert to 8-bit
27-
28-
# Downscale by a factor 2
29-
resized = rescale(image, scale=0.5)
30-
31-
# Otsu threshold
32-
try:
33-
binary = resized > threshold_otsu(resized)
34-
except ValueError:
35-
return img_as_ubyte(np.zeros((50, 50)))
36-
37-
# Labelling
38-
labelled = label(binary)
39-
40-
# The white background is assumed to be the biggest object
41-
light_square = keep_n_biggest_objects(labelled, n=1)
42-
43-
# We assume that the digit is the biggest "hole" in that bright background
44-
# => If the digit is connected to the border it won't be detected
45-
filled_light_square = ndi.binary_fill_holes(light_square)
46-
binary_in_light_square = np.logical_and(filled_light_square, light_square == 0)
47-
labelled_in_light_square = label(binary_in_light_square)
48-
49-
n_objects = labelled_in_light_square.max()
50-
if n_objects == 0:
51-
# Case where the ROI is empty
52-
digit_crop = resized
53-
else:
54-
# Digit = biggest object
55-
digit = keep_n_biggest_objects(labelled_in_light_square, n=1)
56-
# Extract bounding box
57-
df = pd.DataFrame(
58-
regionprops_table(digit, intensity_image=resized, properties=["bbox"])
59-
)
60-
digit_row = df.iloc[0]
61-
# Crop around the digit
62-
digit_crop = resized[digit_row["bbox-0"] : digit_row["bbox-2"], digit_row["bbox-1"] : digit_row["bbox-3"]]
63-
64-
# Resize to a fixed size
65-
digit_crop = resize(digit_crop, output_shape=(50, 50))
66-
67-
# Convert to 8-bit
68-
digit_crop = img_as_ubyte(digit_crop)
69-
70-
return digit_crop
71-
72-
73-
def detect_digit_roi(image: np.ndarray, max_objects=12) -> pd.DataFrame:
28+
def detect_digit_roi(image: np.ndarray, max_objects=12, min_area_px=2000) -> pd.DataFrame:
7429
# RGB => Grayscale
7530
gray = rgb2gray(image)
7631

7732
# Otsu threshold
78-
binary = gray > threshold_otsu(gray)
33+
binary = gray < threshold_otsu(gray)
7934

8035
# Labelling + keep biggest object
8136
labelled = label(binary)
@@ -91,16 +46,30 @@ def detect_digit_roi(image: np.ndarray, max_objects=12) -> pd.DataFrame:
9146
regionprops_table(
9247
digit_crops,
9348
intensity_image=gray,
94-
properties=["intensity_image", "bbox"],
95-
)
49+
properties=["area", "bbox"])
9650
)
9751

52+
# Size filter (ignore small objects)
53+
df = df[df["area"] > min_area_px]
54+
55+
digit_crops = []
56+
for _, row in df.iterrows():
57+
# Crop around the digit
58+
digit_crop = gray[int(row["bbox-0"]) : int(row["bbox-2"]), int(row["bbox-1"]) : int(row["bbox-3"])]
59+
60+
# Resize to a fixed size
61+
digit_crop = resize(digit_crop, output_shape=(50, 50))
62+
63+
# Convert to 8-bit
64+
digit_crop = img_as_ubyte(digit_crop)
65+
digit_crops.append(digit_crop)
66+
67+
df["roi"] = digit_crops
68+
9869
return df
9970

10071

101-
def classify_digit_square(digit_square_img: np.ndarray) -> str:
102-
digit = extract_digit_from_digit_roi(digit_square_img)
103-
72+
def classify_digit_roi(digit: np.ndarray) -> str:
10473
# Normalize intensity values
10574
digit_normed = rescale_intensity(digit, out_range=(0, 1))
10675

@@ -172,7 +141,7 @@ def main(camera_idx: int):
172141

173142
df = detect_digit_roi(frame)
174143

175-
df["pred"] = df["intensity_image"].apply(classify_digit_square)
144+
df["pred"] = df["roi"].apply(classify_digit_roi)
176145

177146
vis_frame = draw_boxes(frame, df)
178147

@@ -187,6 +156,7 @@ def main(camera_idx: int):
187156

188157

189158
if __name__ == "__main__":
159+
# Run with the correct camera index, for example: `python inference.py 4`
190160
_, camera_idx = sys.argv
191161

192162
camera_idx = int(camera_idx)

0 commit comments

Comments
 (0)