jeff86 commited on
Commit
2a91e82
·
verified ·
1 Parent(s): 07b05ad

Create deploy_api.py

Browse files
Files changed (1) hide show
  1. deploy_api.py +370 -0
deploy_api.py ADDED
@@ -0,0 +1,370 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, UploadFile, Form, File
2
+ from hivision import IDCreator
3
+ from hivision.error import FaceError
4
+ from hivision.creator.layout_calculator import (
5
+ generate_layout_array,
6
+ generate_layout_image,
7
+ )
8
+ from hivision.creator.choose_handler import choose_handler
9
+ from hivision.utils import (
10
+ add_background,
11
+ resize_image_to_kb,
12
+ bytes_2_base64,
13
+ base64_2_numpy,
14
+ hex_to_rgb,
15
+ add_watermark,
16
+ save_image_dpi_to_bytes,
17
+ )
18
+ import numpy as np
19
+ import cv2
20
+ from starlette.middleware.cors import CORSMiddleware
21
+
22
+ app = FastAPI()
23
+ creator = IDCreator()
24
+
25
+ # 添加 CORS 中间件 解决跨域问题
26
+ app.add_middleware(
27
+ CORSMiddleware,
28
+ allow_origins=["*"], # 允许的请求来源
29
+ allow_credentials=True, # 允许携带 Cookie
30
+ allow_methods=[
31
+ "*"
32
+ ], # 允许的请求方法,例如:GET, POST 等,也可以指定 ["GET", "POST"]
33
+ allow_headers=["*"], # 允许的请求头,也可以指定具体的头部
34
+ )
35
+
36
+ # 证件照智能制作接口
37
+ @app.get("/")
38
+ async def welcome():
39
+ result_message = {
40
+ "status": True,
41
+ }
42
+ return result_message
43
+
44
+ # 证件照智能制作接口
45
+ @app.post("/idphoto")
46
+ async def idphoto_inference(
47
+ input_image: UploadFile = File(None),
48
+ input_image_base64: str = Form(None),
49
+ height: int = Form(413),
50
+ width: int = Form(295),
51
+ human_matting_model: str = Form("modnet_photographic_portrait_matting"),
52
+ face_detect_model: str = Form("mtcnn"),
53
+ hd: bool = Form(True),
54
+ dpi: int = Form(300),
55
+ face_align: bool = Form(False),
56
+ head_measure_ratio: float = Form(0.2),
57
+ head_height_ratio: float = Form(0.45),
58
+ top_distance_max: float = Form(0.12),
59
+ top_distance_min: float = Form(0.10),
60
+ brightness_strength: float = Form(0),
61
+ contrast_strength: float = Form(0),
62
+ sharpen_strength: float = Form(0),
63
+ saturation_strength: float = Form(0),
64
+ ):
65
+ # 如果传入了base64,则直接使用base64解码
66
+ if input_image_base64:
67
+ img = base64_2_numpy(input_image_base64)
68
+ # 否则使用上传的图片
69
+ else:
70
+ image_bytes = await input_image.read()
71
+ nparr = np.frombuffer(image_bytes, np.uint8)
72
+ img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
73
+
74
+ # ------------------- 选择抠图与人脸检测模型 -------------------
75
+ choose_handler(creator, human_matting_model, face_detect_model)
76
+
77
+ # 将字符串转为元组
78
+ size = (int(height), int(width))
79
+ try:
80
+ result = creator(
81
+ img,
82
+ size=size,
83
+ head_measure_ratio=head_measure_ratio,
84
+ head_height_ratio=head_height_ratio,
85
+ head_top_range=(top_distance_max, top_distance_min),
86
+ face_alignment=face_align,
87
+ brightness_strength=brightness_strength,
88
+ contrast_strength=contrast_strength,
89
+ sharpen_strength=sharpen_strength,
90
+ saturation_strength=saturation_strength,
91
+ )
92
+ except FaceError:
93
+ result_message = {"status": False}
94
+ # 如果检测到人脸数量等于1, 则返回标准证和高清照结果(png 4通道图像)
95
+ else:
96
+ result_image_standard_bytes = save_image_dpi_to_bytes(cv2.cvtColor(result.standard, cv2.COLOR_RGBA2BGRA), None, dpi)
97
+
98
+ result_message = {
99
+ "status": True,
100
+ "image_base64_standard": bytes_2_base64(result_image_standard_bytes),
101
+ }
102
+
103
+ # 如果hd为True, 则增加高清照结果(png 4通道图像)
104
+ if hd:
105
+ result_image_hd_bytes = save_image_dpi_to_bytes(cv2.cvtColor(result.hd, cv2.COLOR_RGBA2BGRA), None, dpi)
106
+ result_message["image_base64_hd"] = bytes_2_base64(result_image_hd_bytes)
107
+
108
+ return result_message
109
+
110
+
111
+ # 人像抠图接口
112
+ @app.post("/human_matting")
113
+ async def human_matting_inference(
114
+ input_image: UploadFile = File(None),
115
+ input_image_base64: str = Form(None),
116
+ human_matting_model: str = Form("hivision_modnet"),
117
+ dpi: int = Form(300),
118
+ ):
119
+ if input_image_base64:
120
+ img = base64_2_numpy(input_image_base64)
121
+ else:
122
+ image_bytes = await input_image.read()
123
+ nparr = np.frombuffer(image_bytes, np.uint8)
124
+ img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
125
+
126
+ # ------------------- 选择抠图与人脸检测模型 -------------------
127
+ choose_handler(creator, human_matting_model, None)
128
+
129
+ try:
130
+ result = creator(
131
+ img,
132
+ change_bg_only=True,
133
+ )
134
+ except FaceError:
135
+ result_message = {"status": False}
136
+
137
+ else:
138
+ result_image_standard_bytes = save_image_dpi_to_bytes(cv2.cvtColor(result.standard, cv2.COLOR_RGBA2BGRA), None, dpi)
139
+ result_message = {
140
+ "status": True,
141
+ "image_base64": bytes_2_base64(result_image_standard_bytes),
142
+ }
143
+ return result_message
144
+
145
+
146
+ # 透明图像添加纯色背景接口
147
+ @app.post("/add_background")
148
+ async def photo_add_background(
149
+ input_image: UploadFile = File(None),
150
+ input_image_base64: str = Form(None),
151
+ color: str = Form("000000"),
152
+ kb: int = Form(None),
153
+ dpi: int = Form(300),
154
+ render: int = Form(0),
155
+ ):
156
+ render_choice = ["pure_color", "updown_gradient", "center_gradient"]
157
+
158
+ if input_image_base64:
159
+ img = base64_2_numpy(input_image_base64)
160
+ else:
161
+ image_bytes = await input_image.read()
162
+ nparr = np.frombuffer(image_bytes, np.uint8)
163
+ img = cv2.imdecode(nparr, cv2.IMREAD_UNCHANGED)
164
+
165
+ color = hex_to_rgb(color)
166
+ color = (color[2], color[1], color[0])
167
+
168
+ result_image = add_background(
169
+ img,
170
+ bgr=color,
171
+ mode=render_choice[render],
172
+ ).astype(np.uint8)
173
+
174
+ result_image = cv2.cvtColor(result_image, cv2.COLOR_RGB2BGR)
175
+ if kb:
176
+ result_image_bytes = resize_image_to_kb(result_image, None, int(kb), dpi=dpi)
177
+ else:
178
+ result_image_bytes = save_image_dpi_to_bytes(result_image, None, dpi=dpi)
179
+
180
+ result_messgae = {
181
+ "status": True,
182
+ "image_base64": bytes_2_base64(result_image_bytes),
183
+ }
184
+
185
+ return result_messgae
186
+
187
+
188
+ # 六寸排版照生成接口
189
+ @app.post("/generate_layout_photos")
190
+ async def generate_layout_photos(
191
+ input_image: UploadFile = File(None),
192
+ input_image_base64: str = Form(None),
193
+ height: int = Form(413),
194
+ width: int = Form(295),
195
+ kb: int = Form(None),
196
+ dpi: int = Form(300),
197
+ ):
198
+ # try:
199
+ if input_image_base64:
200
+ img = base64_2_numpy(input_image_base64)
201
+ else:
202
+ image_bytes = await input_image.read()
203
+ nparr = np.frombuffer(image_bytes, np.uint8)
204
+ img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
205
+
206
+ size = (int(height), int(width))
207
+
208
+ typography_arr, typography_rotate = generate_layout_array(
209
+ input_height=size[0], input_width=size[1]
210
+ )
211
+
212
+ result_layout_image = generate_layout_image(
213
+ img, typography_arr, typography_rotate, height=size[0], width=size[1]
214
+ ).astype(np.uint8)
215
+
216
+ result_layout_image = cv2.cvtColor(result_layout_image, cv2.COLOR_RGB2BGR)
217
+ if kb:
218
+ result_layout_image_bytes = resize_image_to_kb(
219
+ result_layout_image, None, int(kb), dpi=dpi
220
+ )
221
+ else:
222
+ result_layout_image_bytes = save_image_dpi_to_bytes(result_layout_image, None, dpi=dpi)
223
+
224
+ result_layout_image_base64 = bytes_2_base64(result_layout_image_bytes)
225
+
226
+ result_messgae = {
227
+ "status": True,
228
+ "image_base64": result_layout_image_base64,
229
+ }
230
+
231
+ return result_messgae
232
+
233
+
234
+ # 透明图像添加水印接口
235
+ @app.post("/watermark")
236
+ async def watermark(
237
+ input_image: UploadFile = File(None),
238
+ input_image_base64: str = Form(None),
239
+ text: str = Form("Hello"),
240
+ size: int = 20,
241
+ opacity: float = 0.5,
242
+ angle: int = 30,
243
+ color: str = "#000000",
244
+ space: int = 25,
245
+ kb: int = Form(None),
246
+ dpi: int = Form(300),
247
+ ):
248
+ if input_image_base64:
249
+ img = base64_2_numpy(input_image_base64)
250
+ else:
251
+ image_bytes = await input_image.read()
252
+ nparr = np.frombuffer(image_bytes, np.uint8)
253
+ img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
254
+
255
+ try:
256
+ result_image = add_watermark(img, text, size, opacity, angle, color, space)
257
+
258
+ result_image = cv2.cvtColor(result_image, cv2.COLOR_RGB2BGR)
259
+ if kb:
260
+ result_image_bytes = resize_image_to_kb(result_image, None, int(kb), dpi=dpi)
261
+ else:
262
+ result_image_bytes = save_image_dpi_to_bytes(result_image, None, dpi=dpi)
263
+ result_image_base64 = bytes_2_base64(result_image_bytes)
264
+
265
+ result_messgae = {
266
+ "status": True,
267
+ "image_base64": result_image_base64,
268
+ }
269
+ except Exception as e:
270
+ result_messgae = {
271
+ "status": False,
272
+ "error": str(e),
273
+ }
274
+
275
+ return result_messgae
276
+
277
+
278
+ # 设置照片KB值接口(RGB图)
279
+ @app.post("/set_kb")
280
+ async def set_kb(
281
+ input_image: UploadFile = File(None),
282
+ input_image_base64: str = Form(None),
283
+ dpi: int = Form(300),
284
+ kb: int = Form(50),
285
+ ):
286
+ if input_image_base64:
287
+ img = base64_2_numpy(input_image_base64)
288
+ else:
289
+ image_bytes = await input_image.read()
290
+ nparr = np.frombuffer(image_bytes, np.uint8)
291
+ img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
292
+
293
+ try:
294
+ result_image = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
295
+ result_image_bytes = resize_image_to_kb(result_image, None, int(kb), dpi=dpi)
296
+ result_image_base64 = bytes_2_base64(result_image_bytes)
297
+
298
+ result_messgae = {
299
+ "status": True,
300
+ "image_base64": result_image_base64,
301
+ }
302
+ except Exception as e:
303
+ result_messgae = {
304
+ "status": False,
305
+ "error": e,
306
+ }
307
+
308
+ return result_messgae
309
+
310
+
311
+ # 证件照智能裁剪接口
312
+ @app.post("/idphoto_crop")
313
+ async def idphoto_crop_inference(
314
+ input_image: UploadFile = File(None),
315
+ input_image_base64: str = Form(None),
316
+ height: int = Form(413),
317
+ width: int = Form(295),
318
+ face_detect_model: str = Form("mtcnn"),
319
+ hd: bool = Form(True),
320
+ dpi: int = Form(300),
321
+ head_measure_ratio: float = Form(0.2),
322
+ head_height_ratio: float = Form(0.45),
323
+ top_distance_max: float = Form(0.12),
324
+ top_distance_min: float = Form(0.10),
325
+ ):
326
+ if input_image_base64:
327
+ img = base64_2_numpy(input_image_base64)
328
+ else:
329
+ image_bytes = await input_image.read()
330
+ nparr = np.frombuffer(image_bytes, np.uint8)
331
+ img = cv2.imdecode(nparr, cv2.IMREAD_UNCHANGED) # 读取图像(4通道)
332
+
333
+ # ------------------- 选择抠图与人脸检测模型 -------------------
334
+ choose_handler(creator, face_detect_option=face_detect_model)
335
+
336
+ # 将字符串转为元组
337
+ size = (int(height), int(width))
338
+ try:
339
+ result = creator(
340
+ img,
341
+ size=size,
342
+ head_measure_ratio=head_measure_ratio,
343
+ head_height_ratio=head_height_ratio,
344
+ head_top_range=(top_distance_max, top_distance_min),
345
+ crop_only=True,
346
+ )
347
+ except FaceError:
348
+ result_message = {"status": False}
349
+ # 如果检测到人脸数量等于1, 则返回标准证和高清照结果(png 4通道图像)
350
+ else:
351
+ result_image_standard_bytes = save_image_dpi_to_bytes(cv2.cvtColor(result.standard, cv2.COLOR_RGBA2BGRA), None, dpi)
352
+
353
+ result_message = {
354
+ "status": True,
355
+ "image_base64_standard": bytes_2_base64(result_image_standard_bytes),
356
+ }
357
+
358
+ # 如果hd为True, 则增加高清照结果(png 4通道图像)
359
+ if hd:
360
+ result_image_hd_bytes = save_image_dpi_to_bytes(cv2.cvtColor(result.hd, cv2.COLOR_RGBA2BGRA), None, dpi)
361
+ result_message["image_base64_hd"] = bytes_2_base64(result_image_hd_bytes)
362
+
363
+ return result_message
364
+
365
+
366
+ if __name__ == "__main__":
367
+ import uvicorn
368
+
369
+ # 在8080端口运行推理服务
370
+ uvicorn.run(app, host="0.0.0.0", port=8080)