Spaces:
Running
on
Zero
Running
on
Zero
Fixed OpenMP Fork Errors and OpenCV Resize Error
Browse files- gradio_app.py +6 -0
- hy3dshape/hy3dshape/preprocessors.py +40 -3
- hy3dshape/hy3dshape/rembg.py +52 -14
gradio_app.py
CHANGED
@@ -4,6 +4,12 @@ os.environ["OMP_NUM_THREADS"] = "1" # Limit OpenMP to single thread
|
|
4 |
os.environ["PYTHONFAULTHANDLER"] = "1" # Better error reporting
|
5 |
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE" # Avoid Intel MKL errors
|
6 |
os.environ["OMP_THREAD_LIMIT"] = "1" # Limit total number of OpenMP threads
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
|
8 |
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
9 |
# except for the third-party components listed below.
|
|
|
4 |
os.environ["PYTHONFAULTHANDLER"] = "1" # Better error reporting
|
5 |
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE" # Avoid Intel MKL errors
|
6 |
os.environ["OMP_THREAD_LIMIT"] = "1" # Limit total number of OpenMP threads
|
7 |
+
os.environ["MKL_NUM_THREADS"] = "1" # Intel MKL threading
|
8 |
+
os.environ["NUMEXPR_NUM_THREADS"] = "1" # NumExpr threading
|
9 |
+
os.environ["OPENBLAS_NUM_THREADS"] = "1" # OpenBLAS threading
|
10 |
+
os.environ["VECLIB_MAXIMUM_THREADS"] = "1" # Apple vecLib threading
|
11 |
+
os.environ["OMP_DISPLAY_ENV"] = "FALSE" # Suppress OpenMP environment display
|
12 |
+
os.environ["KMP_WARNINGS"] = "FALSE" # Suppress KMP warnings
|
13 |
|
14 |
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
15 |
# except for the third-party components listed below.
|
hy3dshape/hy3dshape/preprocessors.py
CHANGED
@@ -88,17 +88,54 @@ class ImageProcessorV2:
|
|
88 |
return result, mask
|
89 |
|
90 |
def load_image(self, image, border_ratio=0.15, to_tensor=True):
|
|
|
91 |
if isinstance(image, str):
|
|
|
92 |
image = cv2.imread(image, cv2.IMREAD_UNCHANGED)
|
|
|
|
|
93 |
image, mask = self.recenter(image, border_ratio=border_ratio)
|
94 |
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
95 |
elif isinstance(image, Image.Image):
|
|
|
96 |
image = image.convert("RGBA")
|
97 |
image = np.asarray(image)
|
98 |
image, mask = self.recenter(image, border_ratio=border_ratio)
|
99 |
-
|
100 |
-
|
101 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
mask = mask[..., np.newaxis]
|
103 |
|
104 |
if to_tensor:
|
|
|
88 |
return result, mask
|
89 |
|
90 |
def load_image(self, image, border_ratio=0.15, to_tensor=True):
|
91 |
+
# Handle different input types
|
92 |
if isinstance(image, str):
|
93 |
+
# Load from file path
|
94 |
image = cv2.imread(image, cv2.IMREAD_UNCHANGED)
|
95 |
+
if image is None:
|
96 |
+
raise ValueError(f"Could not load image from path: {image}")
|
97 |
image, mask = self.recenter(image, border_ratio=border_ratio)
|
98 |
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
99 |
elif isinstance(image, Image.Image):
|
100 |
+
# Convert PIL Image to numpy array
|
101 |
image = image.convert("RGBA")
|
102 |
image = np.asarray(image)
|
103 |
image, mask = self.recenter(image, border_ratio=border_ratio)
|
104 |
+
elif isinstance(image, np.ndarray):
|
105 |
+
# Handle numpy array input
|
106 |
+
if image.size == 0:
|
107 |
+
raise ValueError("Input image array is empty")
|
108 |
+
image, mask = self.recenter(image, border_ratio=border_ratio)
|
109 |
+
else:
|
110 |
+
# Handle any other type by trying to convert to numpy array
|
111 |
+
try:
|
112 |
+
if hasattr(image, 'convert'):
|
113 |
+
# Assume it's a PIL-like image
|
114 |
+
image = image.convert("RGBA")
|
115 |
+
image = np.asarray(image)
|
116 |
+
else:
|
117 |
+
# Try direct conversion to numpy array
|
118 |
+
image = np.asarray(image)
|
119 |
+
|
120 |
+
if image.size == 0:
|
121 |
+
raise ValueError("Converted image array is empty")
|
122 |
+
image, mask = self.recenter(image, border_ratio=border_ratio)
|
123 |
+
except Exception as e:
|
124 |
+
raise ValueError(f"Could not process image input of type {type(image)}: {e}")
|
125 |
+
|
126 |
+
# Validate that we have valid arrays before resizing
|
127 |
+
if not isinstance(image, np.ndarray) or image.size == 0:
|
128 |
+
raise ValueError("Image processing failed - invalid image array")
|
129 |
+
if not isinstance(mask, np.ndarray) or mask.size == 0:
|
130 |
+
raise ValueError("Image processing failed - invalid mask array")
|
131 |
+
|
132 |
+
# Resize with error handling
|
133 |
+
try:
|
134 |
+
image = cv2.resize(image, (self.size, self.size), interpolation=cv2.INTER_CUBIC)
|
135 |
+
mask = cv2.resize(mask, (self.size, self.size), interpolation=cv2.INTER_NEAREST)
|
136 |
+
except cv2.error as e:
|
137 |
+
raise ValueError(f"OpenCV resize failed: {e}. Image shape: {image.shape if hasattr(image, 'shape') else 'unknown'}, Mask shape: {mask.shape if hasattr(mask, 'shape') else 'unknown'}")
|
138 |
+
|
139 |
mask = mask[..., np.newaxis]
|
140 |
|
141 |
if to_tensor:
|
hy3dshape/hy3dshape/rembg.py
CHANGED
@@ -73,40 +73,78 @@ 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 |
-
|
|
|
77 |
try:
|
78 |
multiprocessing.set_start_method('spawn', force=True)
|
79 |
-
|
|
|
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 |
-
|
|
|
|
|
|
|
|
|
95 |
|
96 |
# Try with alpha matting first (high quality)
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
|
103 |
# If alpha matting fails, try without it
|
104 |
print("Alpha matting failed, falling back to standard background removal")
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
110 |
|
111 |
# If all else fails, return the original image
|
112 |
print("Background removal completely failed, returning original image")
|
|
|
73 |
def __init__(self):
|
74 |
# Set multiprocessing start method to 'spawn' to avoid OpenMP fork issues
|
75 |
# Only set if not already set
|
76 |
+
current_method = multiprocessing.get_start_method(allow_none=True)
|
77 |
+
if current_method != 'spawn':
|
78 |
try:
|
79 |
multiprocessing.set_start_method('spawn', force=True)
|
80 |
+
print(f"Set multiprocessing start method to 'spawn' (was: {current_method})")
|
81 |
+
except RuntimeError as e:
|
82 |
# If already set and not 'spawn', we'll have to work with what we have
|
83 |
+
print(f"Warning: Could not set multiprocessing start method to 'spawn': {e}")
|
84 |
+
print(f"Current method: {multiprocessing.get_start_method()}")
|
85 |
|
86 |
# We don't initialize the session here anymore as it will be created in the subprocess
|
87 |
self.session = None
|
88 |
+
self.max_retries = 2 # Maximum number of retries for background removal
|
89 |
|
90 |
def __call__(self, image: Image.Image):
|
91 |
+
if not isinstance(image, Image.Image):
|
92 |
+
print(f"Warning: Expected PIL Image, got {type(image)}. Attempting conversion...")
|
93 |
+
try:
|
94 |
+
if hasattr(image, 'convert'):
|
95 |
+
image = image.convert('RGBA')
|
96 |
+
else:
|
97 |
+
# Try to create PIL Image from input
|
98 |
+
image = Image.fromarray(np.asarray(image))
|
99 |
+
except Exception as e:
|
100 |
+
print(f"Could not convert input to PIL Image: {e}")
|
101 |
+
return image
|
102 |
+
|
103 |
try:
|
104 |
+
# Ensure image is in RGBA mode
|
105 |
+
if image.mode != 'RGBA':
|
106 |
+
image = image.convert('RGBA')
|
107 |
+
|
108 |
# Convert image to bytes for passing to subprocess
|
109 |
img_bytes = io.BytesIO()
|
110 |
image.save(img_bytes, format='PNG')
|
111 |
img_bytes = img_bytes.getvalue()
|
112 |
|
113 |
# Create a process context
|
114 |
+
try:
|
115 |
+
ctx = multiprocessing.get_context('spawn')
|
116 |
+
except RuntimeError:
|
117 |
+
# Fallback to default context if spawn is not available
|
118 |
+
ctx = multiprocessing
|
119 |
|
120 |
# Try with alpha matting first (high quality)
|
121 |
+
for attempt in range(self.max_retries):
|
122 |
+
try:
|
123 |
+
with ctx.Pool(processes=1) as pool:
|
124 |
+
result = pool.apply(_remove_bg_in_process, args=(img_bytes, True))
|
125 |
+
|
126 |
+
if result is not None:
|
127 |
+
return Image.open(io.BytesIO(result))
|
128 |
+
break # Exit retry loop if we got a result (even if None)
|
129 |
+
except Exception as e:
|
130 |
+
print(f"Alpha matting attempt {attempt + 1} failed: {e}")
|
131 |
+
if attempt == self.max_retries - 1:
|
132 |
+
break
|
133 |
|
134 |
# If alpha matting fails, try without it
|
135 |
print("Alpha matting failed, falling back to standard background removal")
|
136 |
+
for attempt in range(self.max_retries):
|
137 |
+
try:
|
138 |
+
with ctx.Pool(processes=1) as pool:
|
139 |
+
result = pool.apply(_remove_bg_in_process, args=(img_bytes, False))
|
140 |
+
|
141 |
+
if result is not None:
|
142 |
+
return Image.open(io.BytesIO(result))
|
143 |
+
break # Exit retry loop if we got a result (even if None)
|
144 |
+
except Exception as e:
|
145 |
+
print(f"Standard background removal attempt {attempt + 1} failed: {e}")
|
146 |
+
if attempt == self.max_retries - 1:
|
147 |
+
break
|
148 |
|
149 |
# If all else fails, return the original image
|
150 |
print("Background removal completely failed, returning original image")
|