diego2554 commited on
Commit
9895e20
1 Parent(s): ac87c65

Update rembg/bg.py

Browse files
Files changed (1) hide show
  1. rembg/bg.py +34 -162
rembg/bg.py CHANGED
@@ -1,125 +1,26 @@
1
  import io
 
2
  import numpy as np
3
- from PIL import Image, ImageOps
4
- from typing import Any, List, Optional, Tuple, Union
5
  from enum import Enum
6
- from pymatting.alpha.estimate_alpha_cf import estimate_alpha_cf
7
- from pymatting.foreground.estimate_foreground_ml import estimate_foreground_ml
8
- from scipy.ndimage import binary_erosion
9
 
10
- # Definir los valores por defecto para los parámetros
11
- DEFAULT_ALPHA_INFLUENCE = 0.5
12
- DEFAULT_SEGMENTATION_STRENGTH = 0.5
13
- DEFAULT_SMOOTHING = 0.5
14
 
15
  class ReturnType(Enum):
16
  BYTES = 0
17
  PILLOW = 1
18
  NDARRAY = 2
19
 
20
- def alpha_matting_cutout(
21
- img: PILImage,
22
- mask: PILImage,
23
- alpha_influence: float,
24
- segmentation_strength: float,
25
- erode_structure_size: int,
26
- ) -> PILImage:
27
- if img.mode == "RGBA" or img.mode == "CMYK":
28
- img = img.convert("RGB")
29
-
30
- img = np.asarray(img)
31
- mask = np.asarray(mask)
32
-
33
- is_foreground = mask > alpha_influence
34
- is_background = mask < (1.0 - alpha_influence)
35
-
36
- structure = None
37
- if erode_structure_size > 0:
38
- structure = np.ones((erode_structure_size, erode_structure_size), dtype=np.uint8)
39
-
40
- is_foreground = binary_erosion(is_foreground, structure=structure)
41
- is_background = binary_erosion(is_background, structure=structure, border_value=1)
42
-
43
- trimap = np.full(mask.shape, dtype=np.uint8, fill_value=128)
44
- trimap[is_foreground] = 255
45
- trimap[is_background] = 0
46
-
47
- img_normalized = img / 255.0
48
- trimap_normalized = trimap / 255.0
49
-
50
- alpha = estimate_alpha_cf(img_normalized, trimap_normalized)
51
- foreground = estimate_foreground_ml(img_normalized, alpha)
52
- cutout = stack_images(foreground, alpha)
53
-
54
- cutout = np.clip(cutout * 255, 0, 255).astype(np.uint8)
55
- cutout = Image.fromarray(cutout)
56
-
57
- return cutout
58
- #aca termina la modificacion
59
- def naive_cutout(img: PILImage, mask: PILImage) -> PILImage:
60
- empty = Image.new("RGBA", (img.size), 0)
61
- cutout = Image.composite(img, empty, mask)
62
- return cutout
63
-
64
-
65
- def get_concat_v_multi(imgs: List[PILImage]) -> PILImage:
66
- pivot = imgs.pop(0)
67
- for im in imgs:
68
- pivot = get_concat_v(pivot, im)
69
- return pivot
70
-
71
-
72
- def get_concat_v(img1: PILImage, img2: PILImage) -> PILImage:
73
- dst = Image.new("RGBA", (img1.width, img1.height + img2.height))
74
- dst.paste(img1, (0, 0))
75
- dst.paste(img2, (0, img1.height))
76
- return dst
77
-
78
-
79
- def post_process(mask: np.ndarray) -> np.ndarray:
80
- """
81
- Post Process the mask for a smooth boundary by applying Morphological Operations
82
- Research based on paper: https://www.sciencedirect.com/science/article/pii/S2352914821000757
83
- args:
84
- mask: Binary Numpy Mask
85
- """
86
- mask = morphologyEx(mask, MORPH_OPEN, kernel)
87
- mask = GaussianBlur(mask, (5, 5), sigmaX=2, sigmaY=2, borderType=BORDER_DEFAULT)
88
- mask = np.where(mask < 127, 0, 255).astype(np.uint8) # convert again to binary
89
- return mask
90
-
91
-
92
- def apply_background_color(img: PILImage, color: Tuple[int, int, int, int]) -> PILImage:
93
- r, g, b, a = color
94
- colored_image = Image.new("RGBA", img.size, (r, g, b, a))
95
- colored_image.paste(img, mask=img)
96
-
97
- return colored_image
98
-
99
-
100
- def fix_image_orientation(img: PILImage) -> PILImage:
101
- return ImageOps.exif_transpose(img)
102
-
103
-
104
- def download_models() -> None:
105
- for session in sessions_class:
106
- session.download_models()
107
-
108
-
109
- def remove(
110
- data: Union[bytes, PILImage, np.ndarray],
111
- alpha_matting: bool = False,
112
- alpha_matting_foreground_threshold: int = 240,
113
- alpha_matting_background_threshold: int = 10,
114
- alpha_matting_erode_size: int = 10,
115
- session: Optional[BaseSession] = None,
116
- only_mask: bool = False,
117
- post_process_mask: bool = False,
118
- bgcolor: Optional[Tuple[int, int, int, int]] = None,
119
- *args: Optional[Any],
120
- **kwargs: Optional[Any]
121
- ) -> Union[bytes, PILImage, np.ndarray]:
122
- if isinstance(data, PILImage):
123
  return_type = ReturnType.PILLOW
124
  img = data
125
  elif isinstance(data, bytes):
@@ -129,57 +30,28 @@ def remove(
129
  return_type = ReturnType.NDARRAY
130
  img = Image.fromarray(data)
131
  else:
132
- raise ValueError("Input type {} is not supported.".format(type(data)))
133
 
134
- # Fix image orientation
135
  img = fix_image_orientation(img)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
 
137
- if session is None:
138
- session = new_session("u2net", *args, **kwargs)
139
-
140
- masks = session.predict(img, *args, **kwargs)
141
- cutouts = []
142
-
143
- for mask in masks:
144
- if post_process_mask:
145
- mask = Image.fromarray(post_process(np.array(mask)))
146
-
147
- if only_mask:
148
- cutout = mask
149
-
150
- elif alpha_matting:
151
- try:
152
- cutout = alpha_matting_cutout(
153
- img,
154
- mask,
155
- alpha_matting_foreground_threshold,
156
- alpha_matting_background_threshold,
157
- alpha_matting_erode_size,
158
- )
159
- except ValueError:
160
- cutout = naive_cutout(img, mask)
161
-
162
- else:
163
- cutout = naive_cutout(img, mask)
164
-
165
- cutouts.append(cutout)
166
-
167
- cutout = img
168
- if len(cutouts) > 0:
169
- cutout = get_concat_v_multi(cutouts)
170
-
171
- if bgcolor is not None and not only_mask:
172
- cutout = apply_background_color(cutout, bgcolor)
173
-
174
- if ReturnType.PILLOW == return_type:
175
- return cutout
176
-
177
- if ReturnType.NDARRAY == return_type:
178
- return np.asarray(cutout)
179
-
180
- bio = io.BytesIO()
181
- cutout.save(bio, "PNG")
182
- bio.seek(0)
183
-
184
- return bio.read()
185
 
 
1
  import io
2
+ from typing import Any, Union
3
  import numpy as np
4
+ from PIL import Image
 
5
  from enum import Enum
 
 
 
6
 
7
+ from rembg import new_session, remove
8
+ from rembg.sessions.base import BaseSession
9
+ from rembg.util.util import fix_image_orientation
 
10
 
11
  class ReturnType(Enum):
12
  BYTES = 0
13
  PILLOW = 1
14
  NDARRAY = 2
15
 
16
+ def remove_background(
17
+ data: Union[bytes, Image.Image, np.ndarray],
18
+ alpha_influence: float = 0.5,
19
+ segmentation_strength: float = 0.5,
20
+ smoothing: float = 0.5,
21
+ model: str = "u2net",
22
+ ) -> Union[bytes, Image.Image, np.ndarray]:
23
+ if isinstance(data, Image.Image):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  return_type = ReturnType.PILLOW
25
  img = data
26
  elif isinstance(data, bytes):
 
30
  return_type = ReturnType.NDARRAY
31
  img = Image.fromarray(data)
32
  else:
33
+ raise ValueError("Input type {} is not supported.".format(type(data))
34
 
 
35
  img = fix_image_orientation(img)
36
+ session = new_session(model)
37
+ output = remove(
38
+ img,
39
+ alpha_matting=True,
40
+ alpha_matting_foreground_threshold=alpha_influence * 255,
41
+ alpha_matting_background_threshold=(1 - alpha_influence) * 255,
42
+ alpha_matting_erode_size=int(segmentation_strength * 20),
43
+ alpha_matting_smoothing=smoothing,
44
+ session=session
45
+ )
46
+
47
+ if return_type == ReturnType.PILLOW:
48
+ return output
49
+ elif return_type == ReturnType.NDARRAY:
50
+ return np.array(output)
51
+ else:
52
+ bio = io.BytesIO()
53
+ output.save(bio, "PNG")
54
+ bio.seek(0)
55
+ return bio.read()
56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57