TheEeeeLin commited on
Commit
88e96c2
1 Parent(s): 2735e88
.gitattributes CHANGED
@@ -4,3 +4,4 @@ hivision/creator/weights/hivision_modnet.onnx filter=lfs diff=lfs merge=lfs -tex
4
  hivision/creator/weights/modnet_photographic_portrait_matting.onnx filter=lfs diff=lfs merge=lfs -text
5
  hivision/creator/weights/rmbg-1.4.onnx filter=lfs diff=lfs merge=lfs -text
6
  hivision/creator/retinaface/weights/retinaface-resnet50.onnx filter=lfs diff=lfs merge=lfs -text
 
 
4
  hivision/creator/weights/modnet_photographic_portrait_matting.onnx filter=lfs diff=lfs merge=lfs -text
5
  hivision/creator/weights/rmbg-1.4.onnx filter=lfs diff=lfs merge=lfs -text
6
  hivision/creator/retinaface/weights/retinaface-resnet50.onnx filter=lfs diff=lfs merge=lfs -text
7
+ demo/assets/american-style.png filter=lfs diff=lfs merge=lfs -text
demo/assets/american-style.png ADDED

Git LFS Details

  • SHA256: b84b6ccd692af02cbd9b820e24e72e16db6bc48597fb773607903b054ea82f0e
  • Pointer size: 132 Bytes
  • Size of remote file: 1.47 MB
demo/locales.py CHANGED
@@ -182,22 +182,22 @@ LOCALES = {
182
  "bg_color": {
183
  "en": {
184
  "label": "Background color",
185
- "choices": list(color_list_dict_EN.keys()) + ["Custom(RGB)", "Custom(HEX)"],
186
  "develop": color_list_dict_EN,
187
  },
188
  "zh": {
189
  "label": "背景颜色",
190
- "choices": list(color_list_dict_CN.keys()) + ["自定义(RGB)", "自定义(HEX)"],
191
  "develop": color_list_dict_CN,
192
  },
193
  "ja": {
194
  "label": "背景色",
195
- "choices": list(color_list_dict_EN.keys()) + ["カスタム(RGB)", "カスタム(HEX)"],
196
  "develop": color_list_dict_EN,
197
  },
198
  "ko": {
199
  "label": "배경색",
200
- "choices": list(color_list_dict_EN.keys()) + ["사용자 지정(RGB)", "사용자 지정(HEX)"],
201
  "develop": color_list_dict_EN,
202
  },
203
  },
 
182
  "bg_color": {
183
  "en": {
184
  "label": "Background color",
185
+ "choices": list(color_list_dict_EN.keys()) + ["American Style"] + ["Custom(RGB)", "Custom(HEX)"],
186
  "develop": color_list_dict_EN,
187
  },
188
  "zh": {
189
  "label": "背景颜色",
190
+ "choices": list(color_list_dict_CN.keys()) + ["美式证件照"] + ["自定义(RGB)", "自定义(HEX)"],
191
  "develop": color_list_dict_CN,
192
  },
193
  "ja": {
194
  "label": "背景色",
195
+ "choices": list(color_list_dict_EN.keys()) + ["American Style"] + ["カスタム(RGB)", "カスタム(HEX)"],
196
  "develop": color_list_dict_EN,
197
  },
198
  "ko": {
199
  "label": "배경색",
200
+ "choices": list(color_list_dict_EN.keys()) + ["American Style"] + ["사용자 지정(RGB)", "사용자 지정(HEX)"],
201
  "develop": color_list_dict_EN,
202
  },
203
  },
demo/processor.py CHANGED
@@ -3,6 +3,7 @@ from hivision import IDCreator
3
  from hivision.error import FaceError, APIError
4
  from hivision.utils import (
5
  add_background,
 
6
  resize_image_to_kb,
7
  add_watermark,
8
  save_image_dpi_to_bytes,
@@ -16,10 +17,13 @@ from hivision.plugin.template.template_calculator import generte_template_photo
16
  from demo.utils import range_check
17
  import gradio as gr
18
  import os
 
19
  import time
20
  from demo.locales import LOCALES
21
 
22
 
 
 
23
  class IDPhotoProcessor:
24
  def process(
25
  self,
@@ -217,11 +221,12 @@ class IDPhotoProcessor:
217
  custom_color_hex_value,
218
  ):
219
  """处理颜色模式"""
220
- # 如果选择了自定义颜色
221
  if idphoto_json["color_mode"] == LOCALES["bg_color"][language]["choices"][-2]:
222
  idphoto_json["color_bgr"] = tuple(
223
  map(range_check, [custom_color_R, custom_color_G, custom_color_B])
224
  )
 
225
  elif idphoto_json["color_mode"] == LOCALES["bg_color"][language]["choices"][-1]:
226
  hex_color = custom_color_hex_value
227
  # 将十六进制颜色转换为RGB颜色,如果长度为6,则直接转换,如果长度为7,则去掉#号再转换
@@ -238,6 +243,9 @@ class IDPhotoProcessor:
238
  raise ValueError(
239
  "Invalid hex color. You can only use 6 or 7 characters. For example: #FFFFFF or FFFFFF"
240
  )
 
 
 
241
  else:
242
  hex_color = LOCALES["bg_color"][language]["develop"][color_option]
243
  idphoto_json["color_bgr"] = tuple(
@@ -311,7 +319,7 @@ class IDPhotoProcessor:
311
 
312
  # 渲染背景
313
  result_image_standard, result_image_hd = self._render_background(
314
- result_image_standard, result_image_hd, idphoto_json
315
  )
316
 
317
  # 添加水印
@@ -349,7 +357,7 @@ class IDPhotoProcessor:
349
  idphoto_json,
350
  )
351
 
352
- # 如果output_image_path_dict为None
353
  if output_image_path_dict is None:
354
  return self._create_response(
355
  result_image_standard,
@@ -358,9 +366,10 @@ class IDPhotoProcessor:
358
  result_image_hd_png,
359
  gr.update(value=result_image_layout, visible=result_image_layout_visible),
360
  gr.update(value=result_image_template, visible=result_image_template_visible),
 
361
  )
 
362
  else:
363
- # 如果output_image_path_dict不为None,
364
  if output_image_path_dict["layout"]["processed"]:
365
  result_image_layout = output_image_path_dict["layout"]["path"]
366
  return self._create_response(
@@ -378,25 +387,40 @@ class IDPhotoProcessor:
378
  result_image_hd_png,
379
  gr.update(value=result_image_layout, visible=result_image_layout_visible),
380
  gr.update(value=result_image_template, visible=result_image_template_visible),
 
381
  )
382
 
383
  # 渲染背景
384
- def _render_background(self, result_image_standard, result_image_hd, idphoto_json):
385
  """渲染背景"""
386
  render_modes = {0: "pure_color", 1: "updown_gradient", 2: "center_gradient"}
387
  render_mode = render_modes[idphoto_json["render_mode"]]
388
 
389
- result_image_standard = np.uint8(
390
- add_background(
391
- result_image_standard, bgr=idphoto_json["color_bgr"], mode=render_mode
 
 
392
  )
393
- )
394
- result_image_hd = np.uint8(
395
- add_background(
396
- result_image_hd, bgr=idphoto_json["color_bgr"], mode=render_mode
 
 
 
 
 
 
 
 
 
 
 
 
 
 
397
  )
398
- )
399
-
400
  return result_image_standard, result_image_hd
401
 
402
  # 生成排版照片
@@ -425,7 +449,8 @@ class IDPhotoProcessor:
425
  )
426
 
427
  return result_image_layout, True
428
-
 
429
  def _generate_image_template(
430
  self,
431
  idphoto_json,
@@ -480,6 +505,7 @@ class IDPhotoProcessor:
480
  result_image_hd,
481
  result_image_layout,
482
  idphoto_json,
 
483
  ):
484
  """如果需要,调整图片大小"""
485
  # 设置输出路径
@@ -504,10 +530,10 @@ class IDPhotoProcessor:
504
  if custom_kb and custom_dpi:
505
  # 为所有输出路径添加DPI信息
506
  for key in output_paths:
507
- output_paths[key]["path"] += f"_{custom_dpi}dpi.jpg"
508
  # 为标准图像添加KB信息
509
  output_paths["standard"]["path"] = output_paths["standard"]["path"].replace(
510
- ".jpg", f"_{custom_kb}kb.jpg"
511
  )
512
 
513
  # 调整标准图像大小并保存
@@ -534,7 +560,7 @@ class IDPhotoProcessor:
534
  # 只有自定义DPI的情况
535
  elif custom_dpi:
536
  for key in output_paths:
537
- output_paths[key]["path"] += f"_{custom_dpi}dpi.jpg"
538
  # 保存所有图像,使用自定义DPI
539
  if key == "layout" and result_image_layout is None:
540
  pass
@@ -550,7 +576,7 @@ class IDPhotoProcessor:
550
 
551
  # 只有自定义KB的情况
552
  elif custom_kb:
553
- output_paths["standard"]["path"] += f"_{custom_kb}kb.jpg"
554
  # 只调整标准图像大小并保存
555
  resize_image_to_kb(
556
  result_image_standard,
@@ -573,6 +599,7 @@ class IDPhotoProcessor:
573
  result_image_hd_png,
574
  result_layout_image_gr,
575
  result_image_template_gr,
 
576
  ):
577
  """创建响应"""
578
  response = [
@@ -582,6 +609,7 @@ class IDPhotoProcessor:
582
  result_image_hd_png,
583
  result_layout_image_gr,
584
  result_image_template_gr,
 
585
  gr.update(visible=False),
586
  ]
587
 
 
3
  from hivision.error import FaceError, APIError
4
  from hivision.utils import (
5
  add_background,
6
+ add_background_with_image,
7
  resize_image_to_kb,
8
  add_watermark,
9
  save_image_dpi_to_bytes,
 
17
  from demo.utils import range_check
18
  import gradio as gr
19
  import os
20
+ import cv2
21
  import time
22
  from demo.locales import LOCALES
23
 
24
 
25
+ base_path = os.path.dirname(os.path.abspath(__file__))
26
+
27
  class IDPhotoProcessor:
28
  def process(
29
  self,
 
221
  custom_color_hex_value,
222
  ):
223
  """处理颜色模式"""
224
+ # 如果选择了自定义颜色BGR
225
  if idphoto_json["color_mode"] == LOCALES["bg_color"][language]["choices"][-2]:
226
  idphoto_json["color_bgr"] = tuple(
227
  map(range_check, [custom_color_R, custom_color_G, custom_color_B])
228
  )
229
+ # 如果选择了自定义颜色HEX
230
  elif idphoto_json["color_mode"] == LOCALES["bg_color"][language]["choices"][-1]:
231
  hex_color = custom_color_hex_value
232
  # 将十六进制颜色转换为RGB颜色,如果长度为6,则直接转换,如果长度为7,则去掉#号再转换
 
243
  raise ValueError(
244
  "Invalid hex color. You can only use 6 or 7 characters. For example: #FFFFFF or FFFFFF"
245
  )
246
+ # 如果选择了美式证件照
247
+ elif idphoto_json["color_mode"] == LOCALES["bg_color"][language]["choices"][-3]:
248
+ idphoto_json["color_bgr"] = (255, 255, 255)
249
  else:
250
  hex_color = LOCALES["bg_color"][language]["develop"][color_option]
251
  idphoto_json["color_bgr"] = tuple(
 
319
 
320
  # 渲染背景
321
  result_image_standard, result_image_hd = self._render_background(
322
+ result_image_standard, result_image_hd, idphoto_json, language
323
  )
324
 
325
  # 添加水印
 
357
  idphoto_json,
358
  )
359
 
360
+ # 如果output_image_path_dict为None,即没有设置KB和DPI
361
  if output_image_path_dict is None:
362
  return self._create_response(
363
  result_image_standard,
 
366
  result_image_hd_png,
367
  gr.update(value=result_image_layout, visible=result_image_layout_visible),
368
  gr.update(value=result_image_template, visible=result_image_template_visible),
369
+ gr.update(visible = result_image_template_visible),
370
  )
371
+ # 如果output_image_path_dict不为None,即设置了KB和DPI
372
  else:
 
373
  if output_image_path_dict["layout"]["processed"]:
374
  result_image_layout = output_image_path_dict["layout"]["path"]
375
  return self._create_response(
 
387
  result_image_hd_png,
388
  gr.update(value=result_image_layout, visible=result_image_layout_visible),
389
  gr.update(value=result_image_template, visible=result_image_template_visible),
390
+ gr.update(visible = result_image_template_visible),
391
  )
392
 
393
  # 渲染背景
394
+ def _render_background(self, result_image_standard, result_image_hd, idphoto_json, language):
395
  """渲染背景"""
396
  render_modes = {0: "pure_color", 1: "updown_gradient", 2: "center_gradient"}
397
  render_mode = render_modes[idphoto_json["render_mode"]]
398
 
399
+ if idphoto_json["color_mode"] != LOCALES["bg_color"][language]["choices"][-3]:
400
+ result_image_standard = np.uint8(
401
+ add_background(
402
+ result_image_standard, bgr=idphoto_json["color_bgr"], mode=render_mode
403
+ )
404
  )
405
+ result_image_hd = np.uint8(
406
+ add_background(
407
+ result_image_hd, bgr=idphoto_json["color_bgr"], mode=render_mode
408
+ )
409
+ )
410
+ # 如果选择了美式证件照
411
+ else:
412
+ result_image_standard = np.uint8(
413
+ add_background_with_image(
414
+ result_image_standard,
415
+ background_image=cv2.imread(os.path.join(base_path, "assets", "american-style.png"))
416
+ )
417
+ )
418
+ result_image_hd = np.uint8(
419
+ add_background_with_image(
420
+ result_image_hd,
421
+ background_image=cv2.imread(os.path.join(base_path, "assets", "american-style.png"))
422
+ )
423
  )
 
 
424
  return result_image_standard, result_image_hd
425
 
426
  # 生成排版照片
 
449
  )
450
 
451
  return result_image_layout, True
452
+
453
+ # 生成模板照片
454
  def _generate_image_template(
455
  self,
456
  idphoto_json,
 
505
  result_image_hd,
506
  result_image_layout,
507
  idphoto_json,
508
+ format="png",
509
  ):
510
  """如果需要,调整图片大小"""
511
  # 设置输出路径
 
530
  if custom_kb and custom_dpi:
531
  # 为所有输出路径添加DPI信息
532
  for key in output_paths:
533
+ output_paths[key]["path"] += f"_{custom_dpi}dpi.{format}"
534
  # 为标准图像添加KB信息
535
  output_paths["standard"]["path"] = output_paths["standard"]["path"].replace(
536
+ f".{format}", f"_{custom_kb}kb.{format}"
537
  )
538
 
539
  # 调整标准图像大小并保存
 
560
  # 只有自定义DPI的情况
561
  elif custom_dpi:
562
  for key in output_paths:
563
+ output_paths[key]["path"] += f"_{custom_dpi}dpi.{format}"
564
  # 保存所有图像,使用自定义DPI
565
  if key == "layout" and result_image_layout is None:
566
  pass
 
576
 
577
  # 只有自定义KB的情况
578
  elif custom_kb:
579
+ output_paths["standard"]["path"] += f"_{custom_kb}kb.{format}"
580
  # 只调整标准图像大小并保存
581
  resize_image_to_kb(
582
  result_image_standard,
 
599
  result_image_hd_png,
600
  result_layout_image_gr,
601
  result_image_template_gr,
602
+ result_image_template_accordion_gr,
603
  ):
604
  """创建响应"""
605
  response = [
 
609
  result_image_hd_png,
610
  result_layout_image_gr,
611
  result_image_template_gr,
612
+ result_image_template_accordion_gr,
613
  gr.update(visible=False),
614
  ]
615
 
demo/ui.py CHANGED
@@ -73,6 +73,7 @@ def create_ui(
73
  with gr.Tab(
74
  LOCALES["key_param"][DEFAULT_LANG]["label"]
75
  ) as key_parameter_tab:
 
76
  with gr.Row():
77
  mode_options = gr.Radio(
78
  choices=LOCALES["size_mode"][DEFAULT_LANG]["choices"],
@@ -80,11 +81,13 @@ def create_ui(
80
  value=LOCALES["size_mode"][DEFAULT_LANG]["choices"][0],
81
  min_width=520,
82
  )
 
83
  face_alignment_options = gr.CheckboxGroup(
84
  label=LOCALES["face_alignment"][DEFAULT_LANG]["label"],
85
  choices=LOCALES["face_alignment"][DEFAULT_LANG]["choices"],
86
  interactive=True,
87
  )
 
88
  with gr.Row(visible=True) as size_list_row:
89
  size_list_options = gr.Dropdown(
90
  choices=LOCALES["size_list"][DEFAULT_LANG]["choices"],
@@ -92,6 +95,7 @@ def create_ui(
92
  value=LOCALES["size_list"][DEFAULT_LANG]["choices"][0],
93
  elem_id="size_list",
94
  )
 
95
  with gr.Row(visible=False) as custom_size_px:
96
  custom_size_height_px = gr.Number(
97
  value=413,
@@ -103,6 +107,7 @@ def create_ui(
103
  label=LOCALES["custom_size_px"][DEFAULT_LANG]["width"],
104
  interactive=True,
105
  )
 
106
  with gr.Row(visible=False) as custom_size_mm:
107
  custom_size_height_mm = gr.Number(
108
  value=35,
@@ -115,6 +120,7 @@ def create_ui(
115
  interactive=True,
116
  )
117
 
 
118
  color_options = gr.Radio(
119
  choices=LOCALES["bg_color"][DEFAULT_LANG]["choices"],
120
  label=LOCALES["bg_color"][DEFAULT_LANG]["label"],
@@ -131,6 +137,7 @@ def create_ui(
131
  with gr.Row(visible=False) as custom_color_hex:
132
  custom_color_hex_value = gr.Text(value="000000", label="Hex", interactive=True)
133
 
 
134
  render_options = gr.Radio(
135
  choices=LOCALES["render_mode"][DEFAULT_LANG]["choices"],
136
  label=LOCALES["render_mode"][DEFAULT_LANG]["label"],
@@ -353,19 +360,19 @@ def create_ui(
353
  img_output_standard = gr.Image(
354
  label=LOCALES["standard_photo"][DEFAULT_LANG]["label"],
355
  height=350,
356
- format="jpeg",
357
  )
358
  # 高清照
359
  img_output_standard_hd = gr.Image(
360
  label=LOCALES["hd_photo"][DEFAULT_LANG]["label"],
361
  height=350,
362
- format="jpeg",
363
  )
364
  # 排版照
365
  img_output_layout = gr.Image(
366
  label=LOCALES["layout_photo"][DEFAULT_LANG]["label"],
367
  height=350,
368
- format="jpeg",
369
  )
370
  # 模版照片
371
  with gr.Accordion(
@@ -374,7 +381,7 @@ def create_ui(
374
  img_output_template = gr.Gallery(
375
  label=LOCALES["template_photo"][DEFAULT_LANG]["label"],
376
  height=350,
377
- format="jpeg",
378
  )
379
  # 抠图图像
380
  with gr.Accordion(
@@ -733,6 +740,7 @@ def create_ui(
733
  img_output_standard_hd_png,
734
  img_output_layout,
735
  img_output_template,
 
736
  notification,
737
  ],
738
  )
 
73
  with gr.Tab(
74
  LOCALES["key_param"][DEFAULT_LANG]["label"]
75
  ) as key_parameter_tab:
76
+ # 尺寸模式
77
  with gr.Row():
78
  mode_options = gr.Radio(
79
  choices=LOCALES["size_mode"][DEFAULT_LANG]["choices"],
 
81
  value=LOCALES["size_mode"][DEFAULT_LANG]["choices"][0],
82
  min_width=520,
83
  )
84
+ # 人脸对齐
85
  face_alignment_options = gr.CheckboxGroup(
86
  label=LOCALES["face_alignment"][DEFAULT_LANG]["label"],
87
  choices=LOCALES["face_alignment"][DEFAULT_LANG]["choices"],
88
  interactive=True,
89
  )
90
+ # 尺寸列表
91
  with gr.Row(visible=True) as size_list_row:
92
  size_list_options = gr.Dropdown(
93
  choices=LOCALES["size_list"][DEFAULT_LANG]["choices"],
 
95
  value=LOCALES["size_list"][DEFAULT_LANG]["choices"][0],
96
  elem_id="size_list",
97
  )
98
+ # 自定义尺寸px
99
  with gr.Row(visible=False) as custom_size_px:
100
  custom_size_height_px = gr.Number(
101
  value=413,
 
107
  label=LOCALES["custom_size_px"][DEFAULT_LANG]["width"],
108
  interactive=True,
109
  )
110
+ # 自定义尺寸mm
111
  with gr.Row(visible=False) as custom_size_mm:
112
  custom_size_height_mm = gr.Number(
113
  value=35,
 
120
  interactive=True,
121
  )
122
 
123
+ # 背景颜色
124
  color_options = gr.Radio(
125
  choices=LOCALES["bg_color"][DEFAULT_LANG]["choices"],
126
  label=LOCALES["bg_color"][DEFAULT_LANG]["label"],
 
137
  with gr.Row(visible=False) as custom_color_hex:
138
  custom_color_hex_value = gr.Text(value="000000", label="Hex", interactive=True)
139
 
140
+ # 渲染模式
141
  render_options = gr.Radio(
142
  choices=LOCALES["render_mode"][DEFAULT_LANG]["choices"],
143
  label=LOCALES["render_mode"][DEFAULT_LANG]["label"],
 
360
  img_output_standard = gr.Image(
361
  label=LOCALES["standard_photo"][DEFAULT_LANG]["label"],
362
  height=350,
363
+ format="png",
364
  )
365
  # 高清照
366
  img_output_standard_hd = gr.Image(
367
  label=LOCALES["hd_photo"][DEFAULT_LANG]["label"],
368
  height=350,
369
+ format="png",
370
  )
371
  # 排版照
372
  img_output_layout = gr.Image(
373
  label=LOCALES["layout_photo"][DEFAULT_LANG]["label"],
374
  height=350,
375
+ format="png",
376
  )
377
  # 模版照片
378
  with gr.Accordion(
 
381
  img_output_template = gr.Gallery(
382
  label=LOCALES["template_photo"][DEFAULT_LANG]["label"],
383
  height=350,
384
+ format="png",
385
  )
386
  # 抠图图像
387
  with gr.Accordion(
 
740
  img_output_standard_hd_png,
741
  img_output_layout,
742
  img_output_template,
743
+ template_image_accordion,
744
  notification,
745
  ],
746
  )
hivision/creator/__init__.py CHANGED
@@ -144,9 +144,10 @@ class IDCreator:
144
  print("执行人脸对齐")
145
  print("旋转角度:", ctx.face["roll_angle"])
146
  # 根据角度旋转原图和抠图
 
147
  ctx.origin_image, ctx.matting_image, _, _, _, _ = rotate_bound_4channels(
148
- ctx.origin_image,
149
- cv2.split(ctx.matting_image)[-1],
150
  -1 * ctx.face["roll_angle"],
151
  )
152
 
 
144
  print("执行人脸对齐")
145
  print("旋转角度:", ctx.face["roll_angle"])
146
  # 根据角度旋转原图和抠图
147
+ b, g, r, a = cv2.split(ctx.matting_image)
148
  ctx.origin_image, ctx.matting_image, _, _, _, _ = rotate_bound_4channels(
149
+ cv2.merge((b, g, r)),
150
+ a,
151
  -1 * ctx.face["roll_angle"],
152
  )
153
 
hivision/utils.py CHANGED
@@ -298,6 +298,36 @@ def add_background(input_image, bgr=(0, 0, 0), mode="pure_color"):
298
 
299
  return output
300
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
 
302
  def add_watermark(
303
  image, text, size=50, opacity=0.5, angle=45, color="#8B8B1B", space=75
 
298
 
299
  return output
300
 
301
+ def add_background_with_image(input_image: np.ndarray, background_image: np.ndarray) -> np.ndarray:
302
+ """
303
+ 本函数的功能为为透明图像加上背景。
304
+ :param input_image: numpy.array(4 channels), 透明图像
305
+ :param background_image: numpy.array(3 channels), 背景图像
306
+ :return: output: 合成好的输出图像
307
+ """
308
+ height, width = input_image.shape[:2]
309
+ try:
310
+ b, g, r, a = cv2.split(input_image)
311
+ except ValueError:
312
+ raise ValueError(
313
+ "The input image must have 4 channels. 输入图像必须有4个通道,即透明图像。"
314
+ )
315
+
316
+ # 确保背景图像与输入图像大小一致
317
+ background_image = cv2.resize(background_image, (width, height), cv2.INTER_AREA)
318
+ background_image = cv2.cvtColor(background_image, cv2.COLOR_BGR2RGB)
319
+ b2, g2, r2 = cv2.split(background_image)
320
+
321
+ a_cal = a / 255.0
322
+
323
+ # 修正混合公式
324
+ output = cv2.merge(
325
+ (b * a_cal + b2 * (1 - a_cal),
326
+ g * a_cal + g2 * (1 - a_cal),
327
+ r * a_cal + r2 * (1 - a_cal))
328
+ )
329
+
330
+ return output.astype(np.uint8)
331
 
332
  def add_watermark(
333
  image, text, size=50, opacity=0.5, angle=45, color="#8B8B1B", space=75