From c53ad69b39ccbeefad8ce3fbaae01784811801c2 Mon Sep 17 00:00:00 2001 From: ihmily <961532186@qq.com> Date: Fri, 5 Jan 2024 00:17:56 +0800 Subject: [PATCH] upload --- README.md | 35 +++++ app.py | 119 ++++++++++++++ requirements.txt | 10 ++ web/index.html | 145 ++++++++++++++++++ .../images/forkme_right_gray_6d6d6d.png | Bin 0 -> 3809 bytes 5 files changed, 309 insertions(+) create mode 100644 README.md create mode 100644 app.py create mode 100644 requirements.txt create mode 100644 web/index.html create mode 100644 web/static/images/forkme_right_gray_6d6d6d.png diff --git a/README.md b/README.md new file mode 100644 index 0000000..c22bc08 --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +## Imgae matting + +Here are a few effects: + +![image-20240104235235787](C:\Users\96153\AppData\Roaming\Typora\typora-user-images\image-20240104235235787.png) + +![image-20240104235305391](C:\Users\96153\AppData\Roaming\Typora\typora-user-images\image-20240104235305391.png) + +  + +## How to Run + +Firstly, you need to download the project code and install the required dependencies + +``` +git clone https://github.com/ihmily/image-matting.git +cd image-matting +pip install -r requirements.txt +``` + +Next, you can use the following command to run the web interface + +``` +python app.py +``` + +Finally, you can visit http://127.0.0.1:8000 + +  + +## References + +[https://modelscope.cn/models/damo/cv_unet_universal-matting/summary](https://modelscope.cn/models/damo/cv_unet_universal-matting/summary) + +[https://modelscope.cn/models/damo/cv_unet_image-matting/summary](https://modelscope.cn/models/damo/cv_unet_image-matting/summary) \ No newline at end of file diff --git a/app.py b/app.py new file mode 100644 index 0000000..7b0f1e1 --- /dev/null +++ b/app.py @@ -0,0 +1,119 @@ +# -*- coding: utf-8 -*- + +import sys +from fastapi import FastAPI, File, UploadFile, Form, Response +from fastapi import Request +import requests +import cv2 +from modelscope.pipelines import pipeline +from modelscope.utils.constant import Tasks +from modelscope.outputs import OutputKeys +import numpy as np +from starlette.staticfiles import StaticFiles +from starlette.templating import Jinja2Templates + +app = FastAPI() + +model_paths = { + "universal": {'path': 'damo/cv_unet_universal-matting', 'task': Tasks.universal_matting}, + "people": {'path': 'damo/cv_unet_image-matting', 'task': Tasks.portrait_matting}, +} + +default_model = list(model_paths.keys())[0] +default_model_info = model_paths[default_model] +loaded_models = {default_model: pipeline(default_model_info['task'], model=default_model_info['path'])} + + +class ModelLoader: + def __init__(self): + self.loaded_models = {default_model: loaded_models[default_model]} + + def load_model(self, model_name): + if model_name not in self.loaded_models: + model_info = model_paths[model_name] + model_path = model_info['path'] + task_group = model_info['task'] + + self.loaded_models[model_name] = pipeline(task_group, model=model_path) + return self.loaded_models[model_name] + + +model_loader = ModelLoader() + + +@app.post("/switch_model/{new_model}") +async def switch_model(new_model: str): + if new_model not in model_paths: + return {"content": "Invalid model selection"}, 400 + model_info = model_paths[new_model] + + loaded_models[new_model] = pipeline(model_info['task'], model=model_info['path']) + model_loader.loaded_models = loaded_models + return {"content": f"Switched to model: {new_model}"}, 200 + + +@app.post("/matting") +async def matting(image: UploadFile = File(...), model: str = Form(default=default_model, alias="model")): + image_bytes = await image.read() + img = cv2.imdecode(np.frombuffer(image_bytes, np.uint8), cv2.IMREAD_COLOR) + + if model not in model_paths: + return {"content": "Invalid model selection"}, 400 + + selected_model = model_loader.load_model(model) + + result = selected_model(img) + + output_img = result[OutputKeys.OUTPUT_IMG] + + output_bytes = cv2.imencode('.png', output_img)[1].tobytes() + + return Response(content=output_bytes, media_type='image/png') + + +@app.post("/matting/url") +async def matting_url(request: Request, model: str = Form(default=default_model, alias="model")): + try: + json_data = await request.json() + image_url = json_data.get("image_url") + except Exception as e: + return {"content": f"Error parsing JSON data: {str(e)}"}, 400 + + if not image_url: + return {"content": "Image URL is required"}, 400 + + response = requests.get(image_url) + if response.status_code != 200: + return {"content": "Failed to fetch image from URL"}, 400 + + img_array = np.frombuffer(response.content, dtype=np.uint8) + img = cv2.imdecode(img_array, cv2.IMREAD_COLOR) + + if model not in model_paths: + return {"content": "Invalid model selection"}, 400 + + selected_model = model_loader.load_model(model) + + result = selected_model(img) + + output_img = result[OutputKeys.OUTPUT_IMG] + + output_bytes = cv2.imencode('.png', output_img)[1].tobytes() + + return Response(content=output_bytes, media_type='image/png') + + +templates = Jinja2Templates(directory="web") +app.mount("/static", StaticFiles(directory="web/static"), name="static") + + +@app.get("/") +async def read_index(request: Request): + return templates.TemplateResponse("index.html", {"request": request, "default_model": default_model, + "available_models": list(model_paths.keys())}) + + +if __name__ == "__main__": + import uvicorn + defult_bind_host = "0.0.0.0" if sys.platform != "win32" else "127.0.0.1" + uvicorn.run(app, host=defult_bind_host, port=8000) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..c6421a5 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,10 @@ +fastapi==0.108.0 +opencv-python +requests +modelscope>=1.10.0 +torch==2.1.2 +transformers==4.36.2 +sentencepiece==0.1.* +tensorflow +python-multipart +uvicorn \ No newline at end of file diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..37f9b8a --- /dev/null +++ b/web/index.html @@ -0,0 +1,145 @@ + + + + + + + Image Matting + + + + +
+

Image Matting

+
+ Fork me on GitHub +
+
+ + + + + + + +
+ +
+  +  +
+
+ + + + + + diff --git a/web/static/images/forkme_right_gray_6d6d6d.png b/web/static/images/forkme_right_gray_6d6d6d.png new file mode 100644 index 0000000000000000000000000000000000000000..bbccd4b346beeefb797b5437ccc20cf90428cc58 GIT binary patch literal 3809 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 literal 0 HcmV?d00001