Spaces:
Sleeping
Sleeping
Commit
·
5e5e999
1
Parent(s):
96961ef
feat: add API endpoint for clothing generation without mask; implement functionality within pipeline
Browse files- app.py +53 -13
- logs/running_logs.log +30 -0
- src/components/necklaceTryOn.py +49 -0
- src/pipelines/completePipeline.py +5 -1
app.py
CHANGED
@@ -19,7 +19,7 @@ from pydantic import BaseModel
|
|
19 |
import replicate
|
20 |
|
21 |
pipeline = Pipeline()
|
22 |
-
app = FastAPI(title="Magical Mirror Web Plugin")
|
23 |
|
24 |
app.add_middleware(
|
25 |
CORSMiddleware,
|
@@ -33,9 +33,56 @@ key: str = os.getenv("SUPABASE_KEY")
|
|
33 |
supabase: Client = create_client(url, key)
|
34 |
|
35 |
|
36 |
-
class
|
37 |
-
|
38 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
|
40 |
|
41 |
@app.post("/clothingTryOn")
|
@@ -237,13 +284,6 @@ async def product_data(
|
|
237 |
raise HTTPException(status_code=500, detail=f"Failed to fetch or process data: {e}")
|
238 |
|
239 |
|
240 |
-
class NecklaceTryOnIDEntity(BaseModel):
|
241 |
-
necklaceImageId: str
|
242 |
-
necklaceCategory: str
|
243 |
-
storename: str
|
244 |
-
api_token: str
|
245 |
-
|
246 |
-
|
247 |
async def parse_necklace_try_on_id(necklaceImageId: str = Form(...),
|
248 |
necklaceCategory: str = Form(...),
|
249 |
storename: str = Form(...),
|
@@ -281,8 +321,8 @@ async def necklace_try_on_id(necklace_try_on_id: NecklaceTryOnIDEntity = Depends
|
|
281 |
|
282 |
return JSONResponse(content=error_message, status_code=404)
|
283 |
|
284 |
-
result, headetText, mask = await pipeline.
|
285 |
-
|
286 |
|
287 |
inMemFile = BytesIO()
|
288 |
inMemFileMask = BytesIO()
|
|
|
19 |
import replicate
|
20 |
|
21 |
pipeline = Pipeline()
|
22 |
+
app = FastAPI(title="Magical Mirror Web Plugin", description="API for Magical Mirror Application ", version="1.0")
|
23 |
|
24 |
app.add_middleware(
|
25 |
CORSMiddleware,
|
|
|
33 |
supabase: Client = create_client(url, key)
|
34 |
|
35 |
|
36 |
+
class NecklaceTryOnIDEntity(BaseModel):
|
37 |
+
necklaceImageId: str
|
38 |
+
necklaceCategory: str
|
39 |
+
storename: str
|
40 |
+
api_token: str
|
41 |
+
|
42 |
+
|
43 |
+
@app.post("/clothingTryOnV2")
|
44 |
+
async def clothing_try_on_v2(image: UploadFile = File(...), clothing_type: str = Form(...)):
|
45 |
+
image_bytes = await image.read()
|
46 |
+
image = Image.open(BytesIO(image_bytes)).convert("RGB")
|
47 |
+
|
48 |
+
mask = await pipeline.shoulderPointMaskGeneration_(image=image)
|
49 |
+
|
50 |
+
mask_img_base_64, act_img_base_64 = BytesIO(), BytesIO()
|
51 |
+
mask.save(mask_img_base_64, format="WEBP")
|
52 |
+
image.save(act_img_base_64, format="WEBP")
|
53 |
+
mask_bytes_ = base64.b64encode(mask_img_base_64.getvalue()).decode("utf-8")
|
54 |
+
image_bytes_ = base64.b64encode(act_img_base_64.getvalue()).decode("utf-8")
|
55 |
+
|
56 |
+
mask_data_uri = f"data:image/webp;base64,{mask_bytes_}"
|
57 |
+
image_data_uri = f"data:image/webp;base64,{image_bytes_}"
|
58 |
+
|
59 |
+
input = {
|
60 |
+
"mask": mask_data_uri,
|
61 |
+
"image": image_data_uri,
|
62 |
+
"prompt": f"Dull {clothing_type}, non-reflective clothing, properly worn, natural setting, elegant, natural look, neckline without jewellery, simple, perfect eyes, perfect face, perfect body, high quality, realistic, photorealistic, high resolution,traditional full sleeve blouse",
|
63 |
+
"negative_prompt": "necklaces, jewellery, jewelry, necklace, neckpiece, garland, chain, neck wear, jewelled neck, jeweled neck, necklace on neck, jewellery on neck, accessories, watermark, text, changed background, wider body, narrower body, bad proportions, extra limbs, mutated hands, changed sizes, altered proportions, unnatural body proportions, blury, ugly",
|
64 |
+
"num_inference_steps": 25
|
65 |
+
}
|
66 |
+
|
67 |
+
output = replicate.run(
|
68 |
+
"stability-ai/stable-diffusion-inpainting:95b7223104132402a9ae91cc677285bc5eb997834bd2349fa486f53910fd68b3",
|
69 |
+
input=input
|
70 |
+
)
|
71 |
+
image_url = output[0]
|
72 |
+
|
73 |
+
response = requests.get(image_url)
|
74 |
+
result = Image.open(BytesIO(response.content)).resize(image.size)
|
75 |
+
|
76 |
+
in_mem_file = BytesIO()
|
77 |
+
result.save(in_mem_file, format="WEBP", quality=85)
|
78 |
+
base_64_output = base64.b64encode(in_mem_file.getvalue()).decode('utf-8')
|
79 |
+
|
80 |
+
response = {
|
81 |
+
"output": f"data:image/WEBP;base64,{base_64_output}",
|
82 |
+
'code': 200
|
83 |
+
}
|
84 |
+
|
85 |
+
return JSONResponse(content=response, status_code=200)
|
86 |
|
87 |
|
88 |
@app.post("/clothingTryOn")
|
|
|
284 |
raise HTTPException(status_code=500, detail=f"Failed to fetch or process data: {e}")
|
285 |
|
286 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
287 |
async def parse_necklace_try_on_id(necklaceImageId: str = Form(...),
|
288 |
necklaceCategory: str = Form(...),
|
289 |
storename: str = Form(...),
|
|
|
321 |
|
322 |
return JSONResponse(content=error_message, status_code=404)
|
323 |
|
324 |
+
result, headetText, mask = await pipeline.necklaceTryOn_(image=image, jewellery=jewellery,
|
325 |
+
storename=necklace_try_on_id.storename)
|
326 |
|
327 |
inMemFile = BytesIO()
|
328 |
inMemFileMask = BytesIO()
|
logs/running_logs.log
CHANGED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[2024-10-10 20:52:18,370: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: detecting pose and landmarks]
|
2 |
+
[2024-10-10 20:52:18,695: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: estimating neck points]
|
3 |
+
[2024-10-10 20:52:18,695: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: generating shoulder point mask]
|
4 |
+
[2024-10-10 20:56:13,263: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: detecting pose and landmarks]
|
5 |
+
[2024-10-10 20:56:13,569: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: estimating neck points]
|
6 |
+
[2024-10-10 20:56:13,569: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: generating shoulder point mask]
|
7 |
+
[2024-10-10 20:56:13,569: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: generating shoulder point mask]
|
8 |
+
[2024-10-10 20:57:20,291: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: detecting pose and landmarks]
|
9 |
+
[2024-10-10 20:57:20,597: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: estimating neck points]
|
10 |
+
[2024-10-10 20:57:20,597: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: generating shoulder point mask]
|
11 |
+
[2024-10-10 20:57:20,597: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: generating shoulder point mask]
|
12 |
+
[2024-10-10 21:01:04,285: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: detecting pose and landmarks]
|
13 |
+
[2024-10-10 21:01:04,583: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: estimating neck points]
|
14 |
+
[2024-10-10 21:01:04,583: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: generating shoulder point mask]
|
15 |
+
[2024-10-10 21:01:04,583: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: generating shoulder point mask]
|
16 |
+
[2024-10-10 21:02:43,963: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: detecting pose and landmarks]
|
17 |
+
[2024-10-10 21:02:44,284: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: estimating neck points]
|
18 |
+
[2024-10-10 21:02:44,284: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: generating shoulder point mask]
|
19 |
+
[2024-10-10 21:02:44,284: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: generating shoulder point mask]
|
20 |
+
[2024-10-10 21:07:16,992: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: detecting pose and landmarks]
|
21 |
+
[2024-10-10 21:07:17,246: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: estimating neck points]
|
22 |
+
[2024-10-10 21:07:17,246: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: generating shoulder point mask]
|
23 |
+
[2024-10-10 21:08:15,909: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: detecting pose and landmarks]
|
24 |
+
[2024-10-10 21:08:16,206: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: estimating neck points]
|
25 |
+
[2024-10-10 21:08:16,206: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: generating shoulder point mask]
|
26 |
+
[2024-10-10 21:09:24,365: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: detecting pose and landmarks]
|
27 |
+
[2024-10-10 21:09:24,665: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: estimating neck points]
|
28 |
+
[2024-10-10 21:09:24,665: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: generating shoulder point mask]
|
29 |
+
[2024-10-10 21:09:24,665: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: generating shoulder point mask]
|
30 |
+
[2024-10-10 21:09:24,671: INFO: necklaceTryOn: SHOULDER POINT MASK GENERATION :: mask generated successfully]
|
src/components/necklaceTryOn.py
CHANGED
@@ -1,3 +1,5 @@
|
|
|
|
|
|
1 |
from cvzone.FaceMeshModule import FaceMeshDetector
|
2 |
from src.utils import addWatermark, returnBytesData
|
3 |
from src.utils.exceptions import CustomException
|
@@ -251,3 +253,50 @@ class NecklaceTryOn:
|
|
251 |
except Exception as e:
|
252 |
logger.error(f"{CustomException(e)}:: {storename}")
|
253 |
raise CustomException(e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import time
|
2 |
+
|
3 |
from cvzone.FaceMeshModule import FaceMeshDetector
|
4 |
from src.utils import addWatermark, returnBytesData
|
5 |
from src.utils.exceptions import CustomException
|
|
|
253 |
except Exception as e:
|
254 |
logger.error(f"{CustomException(e)}:: {storename}")
|
255 |
raise CustomException(e)
|
256 |
+
|
257 |
+
def shoulderPointMaskGeneration(self, image: Image.Image) -> Image.Image:
|
258 |
+
image = np.array(image)
|
259 |
+
copy_image = image.copy()
|
260 |
+
|
261 |
+
logger.info(f"SHOULDER POINT MASK GENERATION :: detecting pose and landmarks")
|
262 |
+
|
263 |
+
image = self.detector.findPose(image)
|
264 |
+
lmList, _ = self.detector.findPosition(image, bboxWithHands=False, draw=False)
|
265 |
+
|
266 |
+
img, faces = self.meshDetector.findFaceMesh(image, draw=False)
|
267 |
+
leftLandmarkIndex = 172
|
268 |
+
rightLandmarkIndex = 397
|
269 |
+
|
270 |
+
leftLandmark, rightLandmark = faces[0][leftLandmarkIndex], faces[0][rightLandmarkIndex]
|
271 |
+
landmarksDistance = int(
|
272 |
+
((leftLandmark[0] - rightLandmark[0]) ** 2 + (leftLandmark[1] - rightLandmark[1]) ** 2) ** 0.5)
|
273 |
+
|
274 |
+
logger.info(f"SHOULDER POINT MASK GENERATION :: estimating neck points")
|
275 |
+
|
276 |
+
avg_x1 = int(leftLandmark[0] - landmarksDistance * 0.12)
|
277 |
+
avg_x2 = int(rightLandmark[0] + landmarksDistance * 0.12)
|
278 |
+
|
279 |
+
avg_y1 = int(leftLandmark[1] + landmarksDistance * 0.5)
|
280 |
+
avg_y2 = int(rightLandmark[1] + landmarksDistance * 0.5)
|
281 |
+
|
282 |
+
offset = 50
|
283 |
+
avg_y1 -= offset
|
284 |
+
avg_y2 -= offset
|
285 |
+
|
286 |
+
logger.info(f"SHOULDER POINT MASK GENERATION :: generating shoulder point mask")
|
287 |
+
|
288 |
+
logger.info("SHOULDER POINT MASK GENERATION :: generating shoulder point mask")
|
289 |
+
|
290 |
+
mask = np.zeros_like(image[:, :, 0])
|
291 |
+
|
292 |
+
mask[avg_y1:, :] = 255
|
293 |
+
|
294 |
+
pts = np.array([[0, 0], [image.shape[1], 0], [avg_x2, avg_y2], [avg_x1, avg_y1]], np.int32)
|
295 |
+
pts = pts.reshape((-1, 1, 2))
|
296 |
+
cv2.fillPoly(mask, [pts], 0)
|
297 |
+
|
298 |
+
black_n_white_mask = np.zeros_like(image[:, :, 0])
|
299 |
+
black_n_white_mask[avg_y1:, :] = 255
|
300 |
+
logger.info("SHOULDER POINT MASK GENERATION :: mask generated successfully")
|
301 |
+
|
302 |
+
return Image.fromarray(black_n_white_mask.astype(np.uint8))
|
src/pipelines/completePipeline.py
CHANGED
@@ -7,8 +7,12 @@ class Pipeline:
|
|
7 |
def __init__(self) -> None:
|
8 |
self.necklaceTryOnObj = NecklaceTryOn()
|
9 |
|
10 |
-
async def
|
11 |
Union[Image.Image, str]]:
|
12 |
result, headerText, mask = self.necklaceTryOnObj.necklaceTryOn(image=image, jewellery=jewellery,
|
13 |
storename=storename)
|
14 |
return [result, headerText, mask]
|
|
|
|
|
|
|
|
|
|
7 |
def __init__(self) -> None:
|
8 |
self.necklaceTryOnObj = NecklaceTryOn()
|
9 |
|
10 |
+
async def necklaceTryOn_(self, image: Image.Image, jewellery: Image.Image, storename: str) -> list[
|
11 |
Union[Image.Image, str]]:
|
12 |
result, headerText, mask = self.necklaceTryOnObj.necklaceTryOn(image=image, jewellery=jewellery,
|
13 |
storename=storename)
|
14 |
return [result, headerText, mask]
|
15 |
+
|
16 |
+
async def shoulderPointMaskGeneration_(self, image: Image.Image) -> Image.Image:
|
17 |
+
mask = self.necklaceTryOnObj.shoulderPointMaskGeneration(image=image)
|
18 |
+
return mask
|