asimfayaz commited on
Commit
c9cfa1e
·
1 Parent(s): f154f5d

Fix OpenMP fork issues in background removal by using multiprocessing with spawn method. Maintains high-quality alpha matting while avoiding threading conflicts.

Browse files
Files changed (1) hide show
  1. hy3dshape/hy3dshape/rembg.py +93 -19
hy3dshape/hy3dshape/rembg.py CHANGED
@@ -12,35 +12,109 @@
12
  # fine-tuning enabling code and other elements of the foregoing made publicly available
13
  # by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
14
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  from PIL import Image
16
  from rembg import remove, new_session
17
 
18
 
19
- class BackgroundRemover():
20
- def __init__(self):
21
- self.session = new_session()
22
-
23
- def __call__(self, image: Image.Image):
24
- try:
25
- # First try with alpha matting for better quality
 
 
 
 
26
  output = remove(
27
  image,
28
- session=self.session,
29
  bgcolor=[255, 255, 255, 0],
30
  alpha_matting=True,
31
- alpha_matting_foreground_threshold=220, # Lower threshold for foreground
32
- alpha_matting_background_threshold=5, # Lower background threshold
33
- alpha_matting_erode_structure_size=5, # Smaller erode size
34
- alpha_matting_base_size=512, # Smaller scale for matting
35
  )
36
- return output
37
- except ZeroDivisionError:
38
- # If alpha matting fails, fall back to simpler method
39
- print("Alpha matting failed, falling back to standard background removal")
40
  output = remove(
41
  image,
42
- session=self.session,
43
  bgcolor=[255, 255, 255, 0],
44
- alpha_matting=False, # Disable alpha matting
45
  )
46
- return output
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  # fine-tuning enabling code and other elements of the foregoing made publicly available
13
  # by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
14
 
15
+ import os
16
+ import io
17
+ import multiprocessing
18
+ import traceback
19
+ import numpy as np
20
+
21
+ # Set OpenMP environment variables to prevent fork() errors
22
+ os.environ["OMP_NUM_THREADS"] = "1" # Limit OpenMP to single thread
23
+ os.environ["PYTHONFAULTHANDLER"] = "1" # Better error reporting
24
+ os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE" # Avoid Intel MKL errors
25
+ os.environ["OMP_THREAD_LIMIT"] = "1" # Limit total number of OpenMP threads
26
+
27
  from PIL import Image
28
  from rembg import remove, new_session
29
 
30
 
31
+ def _remove_bg_in_process(image_bytes, use_alpha_matting=True):
32
+ """Function to run in a separate process to avoid OpenMP issues"""
33
+ try:
34
+ # Create a new session in this process
35
+ session = new_session()
36
+
37
+ # Convert bytes back to PIL Image
38
+ image = Image.open(io.BytesIO(image_bytes))
39
+
40
+ if use_alpha_matting:
41
+ # High quality mode with alpha matting
42
  output = remove(
43
  image,
44
+ session=session,
45
  bgcolor=[255, 255, 255, 0],
46
  alpha_matting=True,
47
+ alpha_matting_foreground_threshold=220,
48
+ alpha_matting_background_threshold=5,
49
+ alpha_matting_erode_structure_size=5,
50
+ alpha_matting_base_size=512,
51
  )
52
+ else:
53
+ # Fallback mode without alpha matting
 
 
54
  output = remove(
55
  image,
56
+ session=session,
57
  bgcolor=[255, 255, 255, 0],
58
+ alpha_matting=False,
59
  )
60
+
61
+ # Convert back to bytes
62
+ output_bytes = io.BytesIO()
63
+ output.save(output_bytes, format='PNG')
64
+ return output_bytes.getvalue()
65
+
66
+ except Exception as e:
67
+ print(f"Background removal process error: {e}")
68
+ traceback.print_exc()
69
+ return None
70
+
71
+
72
+ class BackgroundRemover():
73
+ def __init__(self):
74
+ # Set multiprocessing start method to 'spawn' to avoid OpenMP fork issues
75
+ # Only set if not already set
76
+ if multiprocessing.get_start_method(allow_none=True) != 'spawn':
77
+ try:
78
+ multiprocessing.set_start_method('spawn', force=True)
79
+ except RuntimeError:
80
+ # If already set and not 'spawn', we'll have to work with what we have
81
+ print("Warning: Could not set multiprocessing start method to 'spawn'")
82
+
83
+ # We don't initialize the session here anymore as it will be created in the subprocess
84
+ self.session = None
85
+
86
+ def __call__(self, image: Image.Image):
87
+ try:
88
+ # Convert image to bytes for passing to subprocess
89
+ img_bytes = io.BytesIO()
90
+ image.save(img_bytes, format='PNG')
91
+ img_bytes = img_bytes.getvalue()
92
+
93
+ # Create a process context
94
+ ctx = multiprocessing.get_context('spawn')
95
+
96
+ # Try with alpha matting first (high quality)
97
+ with ctx.Pool(processes=1) as pool:
98
+ result = pool.apply(_remove_bg_in_process, args=(img_bytes, True))
99
+
100
+ if result is not None:
101
+ return Image.open(io.BytesIO(result))
102
+
103
+ # If alpha matting fails, try without it
104
+ print("Alpha matting failed, falling back to standard background removal")
105
+ with ctx.Pool(processes=1) as pool:
106
+ result = pool.apply(_remove_bg_in_process, args=(img_bytes, False))
107
+
108
+ if result is not None:
109
+ return Image.open(io.BytesIO(result))
110
+
111
+ # If all else fails, return the original image
112
+ print("Background removal completely failed, returning original image")
113
+ return image
114
+
115
+ except Exception as e:
116
+ print(f"Background removal error in main process: {e}")
117
+ traceback.print_exc()
118
+ # If all else fails, just return the original image
119
+ # This ensures the pipeline doesn't break completely
120
+ return image