Yimu Pan commited on
Commit
243f893
·
1 Parent(s): e6469bc

add app file

Browse files
Files changed (2) hide show
  1. app.py +137 -0
  2. requirements.txt +5 -0
app.py ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ import numpy as np
4
+ import onnxruntime as ort
5
+ from PIL import Image, ImageDraw
6
+ from huggingface_hub import hf_hub_download
7
+
8
+ # Retrieve the token from environment variables
9
+ hf_token = os.environ.get("HF_TOKEN")
10
+
11
+ # Download the private model.onnx file
12
+ model_path = hf_hub_download(
13
+ repo_id="ymp5078/RulerNet",
14
+ filename="model.onnx",
15
+ use_auth_token=hf_token
16
+ )
17
+
18
+ # ---- Load ONNX Model ----
19
+ ort_session = ort.InferenceSession(model_path, providers=["CPUExecutionProvider"])
20
+
21
+ # ---- Utility Function ----
22
+ def outward_cumsum(initial_point, line_direction, directions, n):
23
+ left_directions = directions[n < 0][::-1]
24
+ right_directions = directions[n >= 0]
25
+
26
+ left_increments = -np.expand_dims(left_directions, axis=1) * line_direction
27
+ right_increments = np.expand_dims(right_directions, axis=1) * line_direction
28
+
29
+ zero = np.zeros((1, 2), dtype=initial_point.dtype)
30
+ left_cumulative = np.cumsum(np.vstack([zero, left_increments]), axis=0)
31
+ right_cumulative = np.cumsum(np.vstack([zero, right_increments]), axis=0)
32
+
33
+ left_points = initial_point + left_cumulative
34
+ right_points = initial_point + right_cumulative
35
+
36
+ extended_points = np.vstack([left_points[::-1], right_points[1:]])
37
+ return extended_points
38
+
39
+ # ---- Image Preprocessing ----
40
+ def preprocess_image(pil_img):
41
+ image = np.array(pil_img).astype(np.float32) / 255.0
42
+ if image.ndim == 2:
43
+ image = np.stack([image]*3, axis=-1)
44
+ elif image.shape[2] == 4:
45
+ image = image[:, :, :3]
46
+
47
+ resized = np.zeros((768, 768, 3), dtype=np.float32)
48
+ h, w = image.shape[:2]
49
+ scale = min(768 / w, 768 / h)
50
+ new_w, new_h = int(w * scale), int(h * scale)
51
+ image_resized = np.array(Image.fromarray((image * 255).astype(np.uint8)).resize((new_w, new_h))).astype(np.float32) / 255.0
52
+ top = (768 - new_h) // 2
53
+ left = (768 - new_w) // 2
54
+ resized[top:top+new_h, left:left+new_w] = image_resized
55
+
56
+ input_tensor = np.transpose(resized, (2, 0, 1))[np.newaxis, ...].copy()
57
+ return input_tensor, (top, left, new_h, new_w)
58
+
59
+ # ---- Main Inference and Drawing ----
60
+ def infer_and_draw(image_pil):
61
+ image_tensor, _ = preprocess_image(image_pil)
62
+ ort_inputs = {"input": image_tensor}
63
+ ort_outs = ort_session.run(None, ort_inputs)
64
+
65
+ left_point_2d_reconstructed = ort_outs[0][0] # shape: (2,)
66
+ dist = ort_outs[1][0][0] # scalar
67
+ ratio = ort_outs[2][0][0] # scalar
68
+ direction = ort_outs[3][0] # shape: (2,)
69
+ points_info = ort_outs[4][0]
70
+
71
+ min_x, min_y, max_x, max_y = points_info[1:].tolist()
72
+ num_points = int(points_info[0])
73
+
74
+ n = np.arange(-num_points, num_points + 1)
75
+ directions = (ratio ** n) * dist
76
+ extended_points = outward_cumsum(left_point_2d_reconstructed, direction, directions, n)
77
+
78
+ within_bounds = (
79
+ (extended_points[:, 0] >= min_x) & (extended_points[:, 0] <= max_x) &
80
+ (extended_points[:, 1] >= min_y) & (extended_points[:, 1] <= max_y)
81
+ )
82
+ best_generated_points = extended_points[within_bounds]
83
+
84
+ if len(best_generated_points) > 1:
85
+ diffs = np.linalg.norm(best_generated_points[:-1] - best_generated_points[1:], axis=1)
86
+ pred_pix_cm = np.nanmedian(diffs)
87
+ else:
88
+ pred_pix_cm = 0.0
89
+
90
+ # ---- Draw on image ----
91
+ np_img = (np.transpose(image_tensor[0], (1, 2, 0)) * 255).astype(np.uint8)
92
+ pil_img = Image.fromarray(np_img)
93
+ draw = ImageDraw.Draw(pil_img)
94
+
95
+ # Pixel grid overlay
96
+ grid_spacing = 50
97
+ width, height = pil_img.size
98
+ for x in range(0, width, grid_spacing):
99
+ draw.line([(x, 0), (x, height)], fill=(200, 200, 200), width=1)
100
+ for y in range(0, height, grid_spacing):
101
+ draw.line([(0, y), (width, y)], fill=(200, 200, 200), width=1)
102
+
103
+ r = 3
104
+ for x, y in best_generated_points:
105
+ draw.ellipse((x - r, y - r, x + r, y + r), fill="red")
106
+
107
+ x0, y0 = left_point_2d_reconstructed[0]
108
+ draw.ellipse((x0 - r, y0 - r, x0 + r, y0 + r), fill="blue")
109
+
110
+ text = f"Pix/cm: {pred_pix_cm:.2f}"
111
+ text_position = (10, 10)
112
+ text_size = draw.textbbox(text_position, text)
113
+ padding = 4
114
+ rect_coords = (
115
+ text_size[0] - padding,
116
+ text_size[1] - padding,
117
+ text_size[2] + padding,
118
+ text_size[3] + padding
119
+ )
120
+ draw.rectangle(rect_coords, fill="white")
121
+ draw.text(text_position, text, fill="black")
122
+
123
+ return pil_img, f"{pred_pix_cm:.2f}"
124
+
125
+ if __name__ == '__main__':
126
+ demo = gr.Interface(
127
+ fn=infer_and_draw,
128
+ inputs=gr.Image(type="pil"),
129
+ outputs=[
130
+ gr.Image(label="Generated Ruler Points"),
131
+ gr.Textbox(label="Predicted median pixel-per-centimeter value (with grid lines every 50 pixels):")
132
+ ],
133
+ title="ONNX (CPU) Ruler Model Visualizer",
134
+ description="Upload an image to visualize ruler points generated by the ONNX model."
135
+ )
136
+
137
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ gradio
2
+ numpy
3
+ onnxruntime
4
+ Pillow
5
+ huggingface_hub