Spaces:
Build error
Build error
Commit ·
5754201
1
Parent(s): 1fb00de
feat: add color extraction
Browse files- setup.py +10 -7
- src/api/image_prep_api.py +32 -1
- src/components/color_extraction.py +38 -0
setup.py
CHANGED
|
@@ -1,17 +1,20 @@
|
|
| 1 |
from setuptools import setup, find_packages
|
| 2 |
|
| 3 |
HYPER_E_DOT = "-e ."
|
|
|
|
|
|
|
| 4 |
def getRequirements(requirementsPath: str) -> list[str]:
|
| 5 |
with open(requirementsPath) as file:
|
| 6 |
requirements = file.read().split("\n")
|
| 7 |
requirements.remove(HYPER_E_DOT)
|
| 8 |
return requirements
|
| 9 |
|
|
|
|
| 10 |
setup(
|
| 11 |
-
name
|
| 12 |
-
author
|
| 13 |
-
author_email
|
| 14 |
-
version
|
| 15 |
-
packages
|
| 16 |
-
install_requires
|
| 17 |
-
)
|
|
|
|
| 1 |
from setuptools import setup, find_packages
|
| 2 |
|
| 3 |
HYPER_E_DOT = "-e ."
|
| 4 |
+
|
| 5 |
+
|
| 6 |
def getRequirements(requirementsPath: str) -> list[str]:
|
| 7 |
with open(requirementsPath) as file:
|
| 8 |
requirements = file.read().split("\n")
|
| 9 |
requirements.remove(HYPER_E_DOT)
|
| 10 |
return requirements
|
| 11 |
|
| 12 |
+
|
| 13 |
setup(
|
| 14 |
+
name="Jewel Mirror",
|
| 15 |
+
author="Ishwor Subedi",
|
| 16 |
+
author_email="ishworr.subedi@gmail.com",
|
| 17 |
+
version="0.1",
|
| 18 |
+
packages=find_packages(),
|
| 19 |
+
install_requires=getRequirements(requirementsPath="./requirements.txt")
|
| 20 |
+
)
|
src/api/image_prep_api.py
CHANGED
|
@@ -6,6 +6,8 @@ author @ github.com/ishworrsubedii
|
|
| 6 |
import base64
|
| 7 |
import os
|
| 8 |
from io import BytesIO
|
|
|
|
|
|
|
| 9 |
import numpy as np
|
| 10 |
import replicate
|
| 11 |
import requests
|
|
@@ -14,12 +16,14 @@ from fastapi import APIRouter, UploadFile, File, HTTPException
|
|
| 14 |
from fastapi.responses import JSONResponse
|
| 15 |
|
| 16 |
from src.components.auto_crop import crop_transparent_image
|
|
|
|
| 17 |
|
| 18 |
preprocessing_router = APIRouter()
|
| 19 |
|
| 20 |
rmbg: str = os.getenv("RMBG")
|
| 21 |
|
| 22 |
enhancer: str = os.getenv("ENHANCER")
|
|
|
|
| 23 |
|
| 24 |
|
| 25 |
def replicate_bg(input):
|
|
@@ -131,7 +135,7 @@ async def crop_transparent(image: UploadFile):
|
|
| 131 |
|
| 132 |
|
| 133 |
@preprocessing_router.post("/background_replace")
|
| 134 |
-
async def
|
| 135 |
image_bytes = await image.read()
|
| 136 |
bg_image = await bg_image.read()
|
| 137 |
|
|
@@ -156,3 +160,30 @@ async def nto_id(image: UploadFile = File(...), bg_image: UploadFile = File(...)
|
|
| 156 |
|
| 157 |
except Exception as e:
|
| 158 |
raise HTTPException(status_code=500, detail=f"Failed to process image: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
import base64
|
| 7 |
import os
|
| 8 |
from io import BytesIO
|
| 9 |
+
|
| 10 |
+
import cv2
|
| 11 |
import numpy as np
|
| 12 |
import replicate
|
| 13 |
import requests
|
|
|
|
| 16 |
from fastapi.responses import JSONResponse
|
| 17 |
|
| 18 |
from src.components.auto_crop import crop_transparent_image
|
| 19 |
+
from src.components.color_extraction import ColorExtractionRMBG
|
| 20 |
|
| 21 |
preprocessing_router = APIRouter()
|
| 22 |
|
| 23 |
rmbg: str = os.getenv("RMBG")
|
| 24 |
|
| 25 |
enhancer: str = os.getenv("ENHANCER")
|
| 26 |
+
color_extraction_rmbg = ColorExtractionRMBG()
|
| 27 |
|
| 28 |
|
| 29 |
def replicate_bg(input):
|
|
|
|
| 135 |
|
| 136 |
|
| 137 |
@preprocessing_router.post("/background_replace")
|
| 138 |
+
async def bg_replace(image: UploadFile = File(...), bg_image: UploadFile = File(...)):
|
| 139 |
image_bytes = await image.read()
|
| 140 |
bg_image = await bg_image.read()
|
| 141 |
|
|
|
|
| 160 |
|
| 161 |
except Exception as e:
|
| 162 |
raise HTTPException(status_code=500, detail=f"Failed to process image: {e}")
|
| 163 |
+
|
| 164 |
+
|
| 165 |
+
@preprocessing_router.post("/rem_bg_color_extraction")
|
| 166 |
+
async def remove_background_color_extraction(image: UploadFile = File(...), hex_color: str = "#FFFFFF",
|
| 167 |
+
threshold: int = 30):
|
| 168 |
+
image_bytes = await image.read()
|
| 169 |
+
image = Image.open(BytesIO(image_bytes)).convert("RGBA")
|
| 170 |
+
image = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
|
| 171 |
+
|
| 172 |
+
result = color_extraction_rmbg.extract_color(image, hex_color, threshold)
|
| 173 |
+
result = Image.fromarray(cv2.cvtColor(result, cv2.COLOR_RGB2BGR)).convert("RGBA")
|
| 174 |
+
act_img_base_64 = BytesIO()
|
| 175 |
+
result.save(act_img_base_64, format="PNG")
|
| 176 |
+
image_bytes_ = base64.b64encode(act_img_base_64.getvalue()).decode("utf-8")
|
| 177 |
+
|
| 178 |
+
image_data_uri = f"data:image/png;base64,{image_bytes_}"
|
| 179 |
+
|
| 180 |
+
try:
|
| 181 |
+
response = {
|
| 182 |
+
"output": f"{image_data_uri}",
|
| 183 |
+
'code': 200
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
return JSONResponse(content=response, status_code=200)
|
| 187 |
+
|
| 188 |
+
except Exception as e:
|
| 189 |
+
raise HTTPException(status_code=500, detail=f"Failed to process image: {e}")
|
src/components/color_extraction.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
project @ NTO-TCP-HF
|
| 3 |
+
created @ 2024-10-28
|
| 4 |
+
author @ github.com/ishworrsubedii
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import cv2
|
| 8 |
+
import numpy as np
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class ColorExtractionRMBG:
|
| 12 |
+
def __init__(self):
|
| 13 |
+
self.HSV_LOWER = None
|
| 14 |
+
self.HSV_UPPER = None
|
| 15 |
+
|
| 16 |
+
def hex_to_rgb(self, hex_color: str):
|
| 17 |
+
hex_color = hex_color.lstrip("#")
|
| 18 |
+
return tuple(int(hex_color[i:i + 2], 16) for i in (0, 2, 4))
|
| 19 |
+
|
| 20 |
+
def rgb_to_hsv(self, rgb_color):
|
| 21 |
+
rgb_array = np.uint8([[rgb_color]])
|
| 22 |
+
hsv_array = cv2.cvtColor(rgb_array, cv2.COLOR_RGB2HSV)
|
| 23 |
+
return hsv_array[0][0]
|
| 24 |
+
|
| 25 |
+
def set_thresholds(self, hex_color: str, threshold: int):
|
| 26 |
+
hsv_color = self.rgb_to_hsv(self.hex_to_rgb(hex_color))
|
| 27 |
+
lower_bound = np.clip([hsv_color[0] - threshold, 50, 50], 0, 255)
|
| 28 |
+
upper_bound = np.clip([hsv_color[0] + threshold, 255, 255], 0, 255)
|
| 29 |
+
return lower_bound, upper_bound
|
| 30 |
+
|
| 31 |
+
def extract_color(self, image: np.ndarray, hex_color: str, threshold: int):
|
| 32 |
+
self.HSV_LOWER, self.HSV_UPPER = self.set_thresholds(hex_color, threshold)
|
| 33 |
+
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
|
| 34 |
+
mask = cv2.inRange(hsv, self.HSV_LOWER, self.HSV_UPPER)
|
| 35 |
+
result = cv2.bitwise_and(image, image, mask=mask)
|
| 36 |
+
result = cv2.cvtColor(result, cv2.COLOR_BGR2BGRA)
|
| 37 |
+
result[:, :, 3] = mask
|
| 38 |
+
return result
|