slapshin commited on
Commit
2d1247d
·
1 Parent(s): db617ae
Files changed (9) hide show
  1. .gitignore +2 -0
  2. .vscode/launch.json +15 -0
  3. Dockerfile +19 -7
  4. Makefile +2 -0
  5. app.py +0 -7
  6. compose.yaml +7 -0
  7. main.py +299 -0
  8. models/.gitignore +2 -0
  9. requirements.txt +9 -2
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ .venv/*
2
+ data/*
.vscode/launch.json ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ // Use IntelliSense to learn about possible attributes.
3
+ // Hover to view descriptions of existing attributes.
4
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
+ "version": "0.2.0",
6
+ "configurations": [
7
+ {
8
+ "name": "Python Debugger: App",
9
+ "type": "debugpy",
10
+ "request": "launch",
11
+ "program": "main.py",
12
+ "console": "integratedTerminal"
13
+ }
14
+ ]
15
+ }
Dockerfile CHANGED
@@ -1,16 +1,28 @@
1
- # Read the doc: https://huggingface.co/docs/hub/spaces-sdks-docker
2
  # you will also find guides on how best to write your Dockerfile
3
 
4
  FROM python:3.9
5
 
 
 
 
 
 
 
 
6
  RUN useradd -m -u 1000 user
 
 
7
  USER user
8
- ENV PATH="/home/user/.local/bin:$PATH"
9
 
10
- WORKDIR /app
 
 
 
 
 
11
 
12
- COPY --chown=user ./requirements.txt requirements.txt
13
- RUN pip install --no-cache-dir --upgrade -r requirements.txt
14
 
15
- COPY --chown=user . /app
16
- CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
 
1
+ # read the doc: https://huggingface.co/docs/hub/spaces-sdks-docker
2
  # you will also find guides on how best to write your Dockerfile
3
 
4
  FROM python:3.9
5
 
6
+ WORKDIR /code
7
+
8
+ COPY ./requirements.txt /code/requirements.txt
9
+
10
+ RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
11
+
12
+ # Set up a new user named "user" with user ID 1000
13
  RUN useradd -m -u 1000 user
14
+
15
+ # Switch to the "user" user
16
  USER user
 
17
 
18
+ # Set home to the user's home directory
19
+ ENV HOME=/home/user \
20
+ PATH=/home/user/.local/bin:$PATH
21
+
22
+ # Set the working directory to the user's home directory
23
+ WORKDIR $HOME/app
24
 
25
+ # Copy the current directory contents into the container at $HOME/app setting the owner to the user
26
+ COPY --chown=user . $HOME/app
27
 
28
+ CMD ["python", "main.py"]
 
Makefile ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ up:
2
+ docker compose up -d --build
app.py DELETED
@@ -1,7 +0,0 @@
1
- from fastapi import FastAPI
2
-
3
- app = FastAPI()
4
-
5
- @app.get("/")
6
- def greet_json():
7
- return {"Hello": "World!"}
 
 
 
 
 
 
 
 
compose.yaml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ services:
2
+ app:
3
+ build: .
4
+ ports:
5
+ - 7860:7860
6
+ volumes:
7
+ - ./data:/home/user/.cache
main.py ADDED
@@ -0,0 +1,299 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import os
3
+ import numpy as np
4
+ from PIL import Image
5
+ import torch
6
+ from transformers import SamModel, SamProcessor
7
+ import gradio as gr
8
+ import supervision as sv
9
+ from PIL import Image, ImageDraw
10
+ from ultralytics import YOLO
11
+ from segment_anything import SamAutomaticMaskGenerator, sam_model_registry
12
+
13
+ from segment_anything import sam_model_registry, SamAutomaticMaskGenerator
14
+
15
+ device = "cuda" if torch.cuda.is_available() else "cpu"
16
+
17
+ # sam_model_reg = sam_model_registry["default"]
18
+ # sam = sam_model_reg(checkpoint="models/sam_vit_h_4b8939.pth").to(device=device)
19
+ # mask_generator = SamAutomaticMaskGenerator(sam)
20
+
21
+
22
+ # Load the pre-trained SAM model
23
+ # model_type = "vit_h"
24
+ # sam = sam_model_registry[model_type](checkpoint="sam_vit_h_4b8939.pth")
25
+ # sam.to(device=device)
26
+
27
+ # model = SamModel.from_pretrained("facebook/sam-vit-base").to(device)
28
+ # processor = SamProcessor.from_pretrained("facebook/sam-vit-base")
29
+
30
+ # sam = sam_model_registry["default"](checkpoint="./models/sam_vit_h_4b8939.pth")
31
+ # mask_generator = SamAutomaticMaskGenerator(sam)
32
+
33
+ # Create a predictor
34
+ # predictor = SamPredictor(sam)
35
+
36
+ # MODELS_PATH = {
37
+ # "face_yolov8m.pt": "adetailer/face_yolov8m.pt",
38
+ # "face_yolov8n.pt": "adetailer/face_yolov8n.pt",
39
+ # "face_yolov8s.pt": "adetailer/face_yolov8s.pt",
40
+ # "female_breast_v3.2.pt": "adetailer/female_breast_v3.2.pt",
41
+ # "hand_yolov8n.pt": "adetailer/hand_yolov8n.pt",
42
+ # "hand_yolov8s.pt": "adetailer/hand_yolov8s.pt",
43
+ # "penisV2.pt": "adetailer/penisV2.pt",
44
+ # "person_yolov8m-seg.pt": "adetailer/person_yolov8m-seg.pt",
45
+ # "person_yolov8n-seg.pt": "adetailer/person_yolov8n-seg.pt",
46
+ # "person_yolov8s-seg.pt": "adetailer/person_yolov8s-seg.pt",
47
+ # "vagina-v2.6.pt": "adetailer/vagina-v2.6.pt",
48
+ # "deepfashion2_yolov8s-seg.pt": "MaskModels/deepfashion2_yolov8s-seg.pt",
49
+ # "anzhc_head_hair_seg_medium_no_dill.pt": "adetailer/anzhc_head_hair_seg_medium_no_dill.pt",
50
+ # "Eyeful_v2-Paired.pt": "adetailer/Eyeful_v2-Paired.pt",
51
+ # }
52
+
53
+
54
+ torch.hub.download_url_to_file(
55
+ "https://resources.artworks.ai/ADetailer/face_yolov8m.pt",
56
+ "models/face_yolov8m.pt",
57
+ )
58
+
59
+
60
+ MODELS_CACHE = {}
61
+
62
+
63
+ def cache_models(model_path):
64
+ global MODELS_CACHE
65
+ if model_path not in MODELS_CACHE:
66
+ MODELS_CACHE[model_path] = YOLO(model_path).to(device)
67
+ return MODELS_CACHE[model_path]
68
+
69
+
70
+ def apply_convex_hull(mask):
71
+ mask_array = np.array(mask)
72
+ _, thresh = cv2.threshold(mask_array, 127, 255, 0)
73
+ contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
74
+
75
+ for cur in contours:
76
+ hull = cv2.convexHull(cur)
77
+ cv2.fillPoly(mask_array, [hull], (255, 255, 255))
78
+
79
+ return Image.fromarray(mask_array)
80
+
81
+
82
+ def apply_padding(padding, image, xxyxy):
83
+ image_width, image_height = image.size
84
+ xyxy = [int(x) for x in xxyxy]
85
+
86
+ width = xyxy[2] - xyxy[0]
87
+ height = xyxy[3] - xyxy[1]
88
+
89
+ padding_x = int((padding - 1) * width / 2)
90
+ padding_y = int((padding - 1) * height / 2)
91
+
92
+ xyxy = [
93
+ max(0, min(xyxy[0] - padding_x, image_width)),
94
+ max(0, min(xyxy[1] - padding_y, image_height)),
95
+ min(image_width, xyxy[2] + padding_x),
96
+ min(image_height, xyxy[3] + padding_y),
97
+ ]
98
+
99
+ return xyxy
100
+
101
+
102
+ def create_mask_from_yolo(image, model_path, padding, convex_hull_required):
103
+ combined_mask = None
104
+ ret = []
105
+
106
+ model = cache_models(model_path)
107
+
108
+ results = model.predict(image)
109
+
110
+ for result in results:
111
+ masks = [] if result.masks is None else result.masks.data
112
+ for index, mask in enumerate(masks):
113
+ mask = mask.cpu().numpy()
114
+ mask = (mask * 255).astype("uint8")
115
+ mask = cv2.resize(mask, image.size)
116
+ if combined_mask is None:
117
+ combined_mask = mask
118
+ else:
119
+ combined_mask = np.maximum(combined_mask, mask)
120
+
121
+ box = result.boxes[index]
122
+
123
+ # @todo: apply `for` instead of `0 index`
124
+ xxyxy = box.xyxy[0].tolist()
125
+ xyxy_oring = apply_padding(padding, image, xxyxy)
126
+ cropped_image = image.crop(xyxy_oring)
127
+
128
+ cropped_mask = Image.fromarray(mask)
129
+ cropped_mask = cropped_mask.crop(xyxy_oring)
130
+
131
+ if convex_hull_required:
132
+ cropped_mask = apply_convex_hull(cropped_mask)
133
+
134
+ class_id = box.cls[0].item()
135
+ class_name = model.names[class_id]
136
+ confidence = box.conf[0].item()
137
+ ret.append(
138
+ (
139
+ cropped_image,
140
+ cropped_mask,
141
+ confidence,
142
+ class_name,
143
+ (xyxy_oring[0], xyxy_oring[1]),
144
+ )
145
+ )
146
+
147
+ if combined_mask is not None:
148
+ combined_mask_image = Image.fromarray(combined_mask)
149
+ return [combined_mask_image, ret], "Operation has processed successfully"
150
+
151
+ for result in results:
152
+ boxes = result.boxes
153
+ for box in boxes:
154
+ # @todo: apply `for` instead of `0 index`
155
+ xxyxy = box.xyxy[0].tolist()
156
+ xyxy = [int(x) for x in xxyxy]
157
+ mask = Image.new("L", image.size, 0)
158
+ draw = ImageDraw.Draw(mask)
159
+ draw.rectangle(xyxy, fill=255)
160
+ mask = np.array(mask)
161
+ if combined_mask is None:
162
+ combined_mask = mask
163
+ else:
164
+ combined_mask = np.maximum(combined_mask, mask)
165
+
166
+ xyxy_oring = apply_padding(padding, image, xxyxy)
167
+
168
+ cropped_mask = Image.new("L", image.size, 0)
169
+ draw = ImageDraw.Draw(cropped_mask)
170
+ draw.rectangle(xyxy, fill=255)
171
+ cropped_mask = cropped_mask.crop(xyxy_oring)
172
+
173
+ cropped_image = image.crop(xyxy_oring)
174
+
175
+ class_id = box.cls[0].item()
176
+ class_name = model.names[class_id]
177
+ confidence = box.conf[0].item()
178
+ ret.append(
179
+ (
180
+ cropped_image,
181
+ cropped_mask,
182
+ confidence,
183
+ class_name,
184
+ (xyxy_oring[0], xyxy_oring[1]),
185
+ )
186
+ )
187
+
188
+ if combined_mask is not None:
189
+ combined_mask_image = Image.fromarray(combined_mask)
190
+ return [combined_mask_image, ret], "Operation has processed successfully"
191
+
192
+ return [], "No masks has been found"
193
+
194
+
195
+ # @dataclass
196
+ # class SamPredictResponse:
197
+ # image: Optional[str] = Field(None)
198
+ # mask: str
199
+ # confidence: Optional[float] = Field(-1)
200
+ # class_name: Optional[str] = Field("unknown")
201
+ # coordinates: list[int] = Field((0, 0))
202
+
203
+
204
+ def predict(inp) -> dict[str, float]:
205
+ mask, message = create_mask_from_yolo(
206
+ inp,
207
+ "./models/face_yolov8m.pt",
208
+ 1,
209
+ False,
210
+ )
211
+ print(message)
212
+
213
+ # result = []
214
+ # if len(mask) == 9:
215
+ # result.append(SamPredictResponse(mask=encode_to_base64(mask[5])))
216
+ # elif len(mask) == 2:
217
+ # for cur in mask[1]:
218
+ # result.append(
219
+ # SamPredictResponse(
220
+ # # image=encode_to_base64(cur[0]),
221
+ # # mask=encode_to_base64(cur[1]),
222
+ # confidence=cur[2],
223
+ # class_name=cur[3],
224
+ # coordinates=(cur[4][0], cur[4][1]),
225
+ # )
226
+ # )
227
+
228
+ # return mask[1][0][0]
229
+ return mask[1][0][0], mask[1][0][1]
230
+ # return result
231
+
232
+ # masks = mask_generator.generate(np.array(inp))
233
+
234
+ # inputs = processor(np.array(inp), input_points=None, return_tensors="pt").to(device)
235
+
236
+ # with torch.no_grad():
237
+ # outputs = model(**inputs)
238
+
239
+ # masks = processor.image_processor.post_process_masks(
240
+ # outputs.pred_masks.cpu(),
241
+ # inputs["original_sizes"].cpu(),
242
+ # inputs["reshaped_input_sizes"].cpu(),
243
+ # )
244
+
245
+ # detections = sv.Detections.from_sam(sam_result=outputs)
246
+
247
+ # img = np.array(inp)
248
+
249
+ # sam_result = mask_generator.generate(img)
250
+ # detections = sv.Detections.from_sam(sam_result=sam_result)
251
+
252
+ # mask_annotator = sv.MaskAnnotator()
253
+ # label_annotator = sv.LabelAnnotator(text_position=sv.Position.CENTER_OF_MASS)
254
+
255
+ # annotated_image = mask_annotator.annotate(
256
+ # scene=inp,
257
+ # detections=detections,
258
+ # )
259
+ # annotated_image = label_annotator.annotate(
260
+ # scene=annotated_image,
261
+ # detections=detections,
262
+ # )
263
+
264
+ # mask = masks[0]
265
+ # # mask = torch.ge(predicted_logits[0, 0, 0, :, :], 0).cpu().detach().numpy()
266
+ # masked_image_np = sample_image_np.copy().astype(np.uint8) * mask[:, :, None]
267
+ # Image.fromarray(masked_image_np).save(f"figs/examples/dogs_{model_name}_mask.png")
268
+
269
+ # mask_list = [masks[0][0][0].numpy(), masks[0][0][1].numpy(), masks[0][0][2].numpy()]
270
+
271
+ # overlayed_image = np.array(inp).copy()
272
+ # for i, mask in enumerate(mask_list, start=1):
273
+
274
+ # overlayed_image[:, :, 0] = np.where(mask == 1, 255, overlayed_image[:, :, 0])
275
+ # overlayed_image[:, :, 1] = np.where(mask == 1, 0, overlayed_image[:, :, 1])
276
+ # overlayed_image[:, :, 2] = np.where(mask == 1, 0, overlayed_image[:, :, 2])
277
+
278
+ # # # axes[i].imshow(overlayed_image)
279
+ # # # axes[i].set_title(f"Mask {i}")
280
+
281
+ # return Image.fromarray(overlayed_image)
282
+ # return annotated_image
283
+
284
+
285
+ def run() -> None:
286
+ demo = gr.Interface(
287
+ fn=predict,
288
+ inputs=gr.Image(type="pil"),
289
+ outputs=[
290
+ gr.Image(type="pil", label="Image"),
291
+ gr.Image(type="pil", label="Mask"),
292
+ ],
293
+ )
294
+
295
+ demo.launch(server_name="0.0.0.0", server_port=7860)
296
+
297
+
298
+ if __name__ == "__main__":
299
+ run()
models/.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ *.pt
2
+ *.pth
requirements.txt CHANGED
@@ -1,2 +1,9 @@
1
- fastapi
2
- uvicorn[standard]
 
 
 
 
 
 
 
 
1
+ gradio
2
+ torch
3
+ torchvision
4
+ requests
5
+ transformers
6
+ # tensorflow
7
+ # segment_anything
8
+ supervision
9
+ ultralytics