nicka360 commited on
Commit
047076d
·
1 Parent(s): ce73de7

Add initial A360 Croptool Gradio app scaffold

Browse files
Files changed (2) hide show
  1. app.py +163 -0
  2. requirements.txt +4 -0
app.py ADDED
@@ -0,0 +1,163 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from PIL import Image
3
+ from typing import Tuple, Optional
4
+
5
+ # -------------------------------------------------------------------
6
+ # A360 Croptool – Model-Agnostic Cropping Test Harness
7
+ #
8
+ # NOTE:
9
+ # - This version only stubs the model calls.
10
+ # - I will later plug in:
11
+ # • RetinaFace / InsightFace (face + landmarks)
12
+ # • YOLOv8/YOLOv9 (face/body/region detection)
13
+ # • Face Alignment nets
14
+ # • SAM / SAM-HQ
15
+ # • BiSeNet (face parsing)
16
+ # • CLIPSeg (text-guided cropping)
17
+ # -------------------------------------------------------------------
18
+
19
+ FACE_MODEL_CHOICES = [
20
+ "RetinaFace (InsightFace)",
21
+ "InsightFace 2D Landmarks (2d106)",
22
+ "Face-Alignment (1adrianb)",
23
+ ]
24
+
25
+ BODY_MODEL_CHOICES = [
26
+ "YOLOv8 Body Detector",
27
+ "YOLOv9 Body / Part Detector",
28
+ "Human Pose (OpenPose-style)",
29
+ ]
30
+
31
+ SEGMENTATION_MODEL_CHOICES = [
32
+ "SAM / SAM-HQ",
33
+ "BiSeNet Face Parsing",
34
+ "CLIPSeg (text-guided)",
35
+ ]
36
+
37
+ CROP_TARGET_CHOICES = [
38
+ "Full Face",
39
+ "Eyes / Upper Face",
40
+ "Lips / Lower Face",
41
+ "Jawline / Chin",
42
+ "Neck",
43
+ "Chest / Breasts",
44
+ "Abdomen",
45
+ "Waist / Hips",
46
+ "Arms",
47
+ "Thighs / Legs",
48
+ "Custom Region",
49
+ ]
50
+
51
+
52
+ def stub_crop(
53
+ image: Optional[Image.Image],
54
+ crop_target: str,
55
+ face_model: str,
56
+ body_model: str,
57
+ seg_model: str,
58
+ text_prompt: str,
59
+ ) -> Tuple[Image.Image, str]:
60
+ """
61
+ Placeholder cropping callback.
62
+
63
+ For now, simply returns the original image and a text summary of
64
+ the options the user selected. I'll replace this with real model
65
+ calls (RetinaFace / YOLO / SAM / CLIPSeg) later.
66
+ """
67
+ if image is None:
68
+ # Gradio will show this as an error toast
69
+ raise gr.Error("Please upload an image first.")
70
+
71
+ summary_lines = [
72
+ "Cropping request received:",
73
+ f"• Target region: {crop_target}",
74
+ f"• Face model: {face_model or 'None selected'}",
75
+ f"• Body model: {body_model or 'None selected'}",
76
+ f"• Segmentation model: {seg_model or 'None selected'}",
77
+ ]
78
+ if text_prompt.strip():
79
+ summary_lines.append(f"• Text prompt (for CLIPSeg / SAM): {text_prompt.strip()}")
80
+
81
+ summary_lines.append("")
82
+ summary_lines.append("NOTE: This is a stub implementation. "
83
+ "Model hooks are ready; image is returned unmodified for now.")
84
+
85
+ return image, "\n".join(summary_lines)
86
+
87
+
88
+ def create_app() -> gr.Blocks:
89
+ with gr.Blocks(theme="gradio/soft", css="""
90
+ .a360-header { font-size: 1.8rem; font-weight: 700; }
91
+ .a360-subtitle { opacity: 0.8; }
92
+ """) as demo:
93
+ gr.Markdown(
94
+ "<div class='a360-header'>A360 Croptool 🧬</div>"
95
+ "<div class='a360-subtitle'>"
96
+ "Test and prototype clinical cropping models for faces, bodies, and regions of interest."
97
+ "</div>"
98
+ )
99
+
100
+ with gr.Row():
101
+ with gr.Column(scale=1):
102
+ input_image = gr.Image(
103
+ label="Input Image",
104
+ type="pil",
105
+ height=480,
106
+ elem_id="input_image",
107
+ )
108
+
109
+ crop_target = gr.Dropdown(
110
+ CROP_TARGET_CHOICES,
111
+ value="Full Face",
112
+ label="Target Region",
113
+ info="What do you want to crop to?",
114
+ )
115
+
116
+ gr.Markdown("### Model Stack (configuration only – models wired later)")
117
+
118
+ face_model = gr.Radio(
119
+ FACE_MODEL_CHOICES,
120
+ value="RetinaFace (InsightFace)",
121
+ label="Face / Landmark Model",
122
+ )
123
+
124
+ body_model = gr.Radio(
125
+ BODY_MODEL_CHOICES,
126
+ value="YOLOv8 Body Detector",
127
+ label="Body / Region Model",
128
+ )
129
+
130
+ seg_model = gr.Radio(
131
+ SEGMENTATION_MODEL_CHOICES,
132
+ value="SAM / SAM-HQ",
133
+ label="Segmentation / Mask Model",
134
+ )
135
+
136
+ text_prompt = gr.Textbox(
137
+ label="Optional Text Prompt (for CLIPSeg / SAM)",
138
+ placeholder="e.g., 'crop to lips', 'crop to abdomen', 'crop to jawline'",
139
+ lines=2,
140
+ )
141
+
142
+ run_btn = gr.Button("Run Cropping Prototype", variant="primary")
143
+
144
+ with gr.Column(scale=1):
145
+ output_image = gr.Image(
146
+ label="Cropped Output (stub – currently same as input)",
147
+ height=480,
148
+ )
149
+ debug_text = gr.Markdown(label="Cropping Summary")
150
+
151
+ run_btn.click(
152
+ stub_crop,
153
+ inputs=[input_image, crop_target, face_model, body_model, seg_model, text_prompt],
154
+ outputs=[output_image, debug_text],
155
+ )
156
+
157
+ return demo
158
+
159
+
160
+ app = create_app()
161
+
162
+ if __name__ == "__main__":
163
+ app.launch()
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ gradio>=4.0.0
2
+ Pillow
3
+ numpy
4
+ opencv-python