Upload 2 files
Browse files
README.md
ADDED
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
license: apache-2.0
|
3 |
+
pipeline_tag: image-segmentation
|
4 |
+
language: []
|
5 |
+
base_model: isnet-general-use.pth
|
6 |
+
model_type: ty_fashion_bg_remover
|
7 |
+
tags:
|
8 |
+
- computer-vision
|
9 |
+
- image-background-removal
|
10 |
+
- image-matting
|
11 |
+
- e-commerce
|
12 |
+
- is-net
|
13 |
+
---
|
14 |
+
|
15 |
+
# TY Fashion Background Remover
|
16 |
+
|
17 |
+
_IS-Net-based fashion image background removal model for removing background of fashion images on the Trendyol e-commerce catalogue._
|
18 |
+
|
19 |
+
## Model Details
|
20 |
+
|
21 |
+
- **Architecture**: IS-Net
|
22 |
+
- **Objective**: Fine-tuning isnet-general-use model with TY fashion images to better performance of fashion images
|
23 |
+
- **Training Data**: Large-scale Trendyol fashion product image dataset containing human models
|
24 |
+
- **Hardware**: Multi-GPU training with PyTorch
|
25 |
+
- **Framework**: PyTorch
|
26 |
+
|
27 |
+
## Intended Use
|
28 |
+
|
29 |
+
- Isolate human models in fashion product images by removing the image background
|
30 |
+
|
31 |
+
## Usage
|
32 |
+
|
33 |
+
Complete example to load the model, remove background of an image, and save the results:
|
34 |
+
|
35 |
+
```python
|
36 |
+
"""
|
37 |
+
ONNX inference script for image segmentation model.
|
38 |
+
|
39 |
+
This script loads an ONNX model and performs inference on an input image to generate
|
40 |
+
an alpha mask. The mask is combined with the RGB image and saved as output.
|
41 |
+
"""
|
42 |
+
|
43 |
+
import onnxruntime as ort
|
44 |
+
from utils import process_image
|
45 |
+
|
46 |
+
if __name__ == "__main__":
|
47 |
+
MODEL_PATH = "model.onnx"
|
48 |
+
SRC = "https://cdn.dsmcdn.com/ty184/product/media/images/20210924/23/136268224/224296134/1/1_org_zoom.jpg"
|
49 |
+
OUTPUT_FILE = "out.png"
|
50 |
+
|
51 |
+
# Initialize ONNX runtime session with CUDA and CPU providers
|
52 |
+
ort_session = ort.InferenceSession(
|
53 |
+
MODEL_PATH,
|
54 |
+
providers=["CUDAExecutionProvider", "CPUExecutionProvider"]
|
55 |
+
)
|
56 |
+
|
57 |
+
process_image(SRC, ort_session, MODEL_PATH, OUTPUT_FILE)
|
58 |
+
```
|
59 |
+
|
60 |
+
## Model Performance
|
61 |
+
|
62 |
+
- **Achieve high-accuracy image matting**: Especially for intricate details on human models, such as hair and clothing textures.
|
63 |
+
|
64 |
+
### Training Configuration
|
65 |
+
|
66 |
+
- **Backbone**: IS-Net general use model trained on DIS dataset V1.0: DIS5K
|
67 |
+
- **Model Input Size**: 1800x1200
|
68 |
+
- **Training Framework**: Torch 1.13.1
|
69 |
+
|
70 |
+
## Limitations
|
71 |
+
|
72 |
+
- **Domain Specificity**: Optimized for e-commerce fashion product images with human models included; may not generalize well to other image domains
|
73 |
+
- **Image Quality**: Performance may degrade on low-quality, heavily compressed, or significantly distorted images
|
74 |
+
- **Category Bias**: Performance may vary across different product categories based on training data distribution
|
75 |
+
|
76 |
+
## Ethical Considerations
|
77 |
+
|
78 |
+
- **Commercial Use**: Designed for e-commerce applications; consider potential impacts on market competition
|
79 |
+
- **Privacy**: Ensure compliance with data protection regulations when processing product images
|
80 |
+
- **Fairness**: Monitor for biased similarity judgments across different product categories or brands
|
81 |
+
|
82 |
+
## Citation
|
83 |
+
|
84 |
+
```bibtex
|
85 |
+
@misc{trendyol2025fashionbgremover,
|
86 |
+
title={TY Fashion Background Remover},
|
87 |
+
author={Trendyol Data Science Team},
|
88 |
+
year={2025},
|
89 |
+
howpublished={\url{https://huggingface.co/trendyol/ty-fashion-bg-remover}}
|
90 |
+
}
|
91 |
+
```
|
92 |
+
|
93 |
+
## Model Card Authors
|
94 |
+
|
95 |
+
- Trendyol Data Science Team
|
96 |
+
|
97 |
+
## License
|
98 |
+
|
99 |
+
This model is released by Trendyol as a source-available, non-open-source model.
|
100 |
+
|
101 |
+
### You are allowed to:
|
102 |
+
|
103 |
+
- View, download, and evaluate the model weights.
|
104 |
+
- Use the model for non-commercial research and internal testing.
|
105 |
+
- Use the model or its derivatives for commercial purposes, provided that:
|
106 |
+
- You cite Trendyol as the original model creator.
|
107 |
+
- You notify Trendyol in advance via [[email protected]] or other designated contact.
|
108 |
+
|
109 |
+
### You are not allowed to:
|
110 |
+
|
111 |
+
- Redistribute or host the model or its derivatives on third-party platforms without prior written consent from Trendyol.
|
112 |
+
- Use the model in applications violating ethical standards, including but not limited to surveillance, misinformation, or harm to individuals or groups.
|
113 |
+
|
114 |
+
By downloading or using this model, you agree to the terms above.
|
115 |
+
|
116 |
+
© 2025 Trendyol Teknoloji A.Ş. All rights reserved.
|
117 |
+
|
118 |
+
See the [LICENSE](LICENSE) file for more details.
|
119 |
+
|
120 |
+
---
|
121 |
+
|
122 |
+
_For technical support or questions about this model, please contact the Trendyol Data Science team._
|
utils.py
ADDED
@@ -0,0 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import cv2
|
2 |
+
import numpy as np
|
3 |
+
import requests
|
4 |
+
from PIL import Image
|
5 |
+
from io import BytesIO
|
6 |
+
import torch
|
7 |
+
from pathlib import Path
|
8 |
+
import torch.nn.functional as F
|
9 |
+
from typing import Dict, Any, List, Union, Tuple
|
10 |
+
from torchvision.transforms.functional import normalize
|
11 |
+
|
12 |
+
INPUT_SIZE = [1200, 1800]
|
13 |
+
|
14 |
+
def keep_large_components(a: np.ndarray) -> np.ndarray:
|
15 |
+
"""Remove small connected components from a binary mask, keeping only large regions.
|
16 |
+
|
17 |
+
Args:
|
18 |
+
a: Input binary mask as numpy array of shape (H,W) or (H,W,1)
|
19 |
+
|
20 |
+
Returns:
|
21 |
+
Processed mask with only large connected components remaining, shape (H,W,1)
|
22 |
+
"""
|
23 |
+
dilate_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(9, 9))
|
24 |
+
a_mask = (a > 25).astype(np.uint8) * 255
|
25 |
+
|
26 |
+
# Apply the Component analysis function
|
27 |
+
analysis = cv2.connectedComponentsWithStats(a_mask, 4, cv2.CV_32S)
|
28 |
+
(totalLabels, label_ids, values, centroid) = analysis
|
29 |
+
|
30 |
+
# Find the components to be kept
|
31 |
+
h, w = a.shape[:2]
|
32 |
+
area_limit = 50000 * (h * w) / (INPUT_SIZE[1] * INPUT_SIZE[0])
|
33 |
+
i_to_keep = []
|
34 |
+
for i in range(1, totalLabels):
|
35 |
+
area = values[i, cv2.CC_STAT_AREA]
|
36 |
+
if area > area_limit:
|
37 |
+
i_to_keep.append(i)
|
38 |
+
|
39 |
+
if len(i_to_keep) > 0:
|
40 |
+
# Or masks to be kept
|
41 |
+
final_mask = np.zeros_like(a, dtype=np.uint8)
|
42 |
+
for i in i_to_keep:
|
43 |
+
componentMask = (label_ids == i).astype("uint8") * 255
|
44 |
+
final_mask = cv2.bitwise_or(final_mask, componentMask)
|
45 |
+
|
46 |
+
# Remove other components
|
47 |
+
# Keep edges
|
48 |
+
final_mask = cv2.dilate(final_mask, dilate_kernel, iterations = 2)
|
49 |
+
a = cv2.bitwise_and(a, final_mask)
|
50 |
+
a = a.reshape((a.shape[0], a.shape[1], 1))
|
51 |
+
|
52 |
+
return a
|
53 |
+
|
54 |
+
def read_img(img: Union[str, Path]) -> np.ndarray:
|
55 |
+
"""Read an image from a URL or local path.
|
56 |
+
|
57 |
+
Args:
|
58 |
+
img: URL or file path to image
|
59 |
+
|
60 |
+
Returns:
|
61 |
+
Image as numpy array in RGB format with shape (H,W,3)
|
62 |
+
"""
|
63 |
+
if img[0: 4] == 'http':
|
64 |
+
response = requests.get(img)
|
65 |
+
im = np.asarray(Image.open(BytesIO(response.content)))
|
66 |
+
|
67 |
+
else:
|
68 |
+
im = cv2.imread(str(img))
|
69 |
+
im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
|
70 |
+
|
71 |
+
return im
|
72 |
+
|
73 |
+
def preprocess_input(im: np.ndarray) -> torch.Tensor:
|
74 |
+
"""Preprocess image for model input.
|
75 |
+
|
76 |
+
Args:
|
77 |
+
im: Input image as numpy array of shape (H,W,C)
|
78 |
+
|
79 |
+
Returns:
|
80 |
+
Preprocessed image as normalized torch tensor of shape (1,3,H,W)
|
81 |
+
"""
|
82 |
+
if len(im.shape) < 3:
|
83 |
+
im = im[:, :, np.newaxis]
|
84 |
+
|
85 |
+
if im.shape[2] == 4: # if image has alpha channel, remove it
|
86 |
+
im = im[:,:,:3]
|
87 |
+
|
88 |
+
im_tensor = torch.tensor(im, dtype=torch.float32).permute(2,0,1)
|
89 |
+
im_tensor = F.upsample(torch.unsqueeze(im_tensor,0), INPUT_SIZE, mode="bilinear").type(torch.uint8)
|
90 |
+
image = torch.divide(im_tensor,255.0)
|
91 |
+
image = normalize(image,[0.5,0.5,0.5],[1.0,1.0,1.0])
|
92 |
+
|
93 |
+
if torch.cuda.is_available():
|
94 |
+
image=image.cuda()
|
95 |
+
|
96 |
+
return image
|
97 |
+
|
98 |
+
def postprocess_output(result: np.ndarray, orig_im_shape: Tuple[int, int]) -> np.ndarray:
|
99 |
+
"""Postprocess ONNX model output.
|
100 |
+
|
101 |
+
Args:
|
102 |
+
result: Model output as numpy array of shape (1,1,H,W)
|
103 |
+
orig_im_shape: Original image dimensions (height, width)
|
104 |
+
|
105 |
+
Returns:
|
106 |
+
Processed binary mask as numpy array of shape (H,W,1)
|
107 |
+
"""
|
108 |
+
result = torch.squeeze(F.upsample(
|
109 |
+
torch.from_numpy(result).unsqueeze(0), (orig_im_shape), mode='bilinear'), 0)
|
110 |
+
ma = torch.max(result)
|
111 |
+
mi = torch.min(result)
|
112 |
+
result = (result-mi)/(ma-mi)
|
113 |
+
|
114 |
+
# a is alpha channel. 255 means foreground, 0 means background.
|
115 |
+
a = (result*255).permute(1,2,0).cpu().data.numpy().astype(np.uint8)
|
116 |
+
|
117 |
+
# postprocessing
|
118 |
+
a = keep_large_components(a)
|
119 |
+
|
120 |
+
return a
|
121 |
+
|
122 |
+
def process_image(src: Union[str, Path], ort_session: Any, model_path: Union[str, Path], outname: str) -> None:
|
123 |
+
"""Process an image through ONNX model to generate alpha mask and save result.
|
124 |
+
|
125 |
+
Args:
|
126 |
+
src: Source image URL or path
|
127 |
+
ort_session: ONNX runtime inference session
|
128 |
+
model_path: Path to ONNX model file
|
129 |
+
outname: Output filename for saving result
|
130 |
+
|
131 |
+
Returns:
|
132 |
+
None
|
133 |
+
"""
|
134 |
+
# Load and preprocess image
|
135 |
+
image_orig = read_img(src)
|
136 |
+
image = preprocess_input(image_orig)
|
137 |
+
|
138 |
+
# Prepare ONNX input
|
139 |
+
inputs: Dict[str, Any] = {ort_session.get_inputs()[0].name: image.numpy()}
|
140 |
+
|
141 |
+
# Get ONNX output and post-process
|
142 |
+
result = ort_session.run(None, inputs)[0][0]
|
143 |
+
alpha = postprocess_output(result, (image_orig.shape[0], image_orig.shape[1]))
|
144 |
+
|
145 |
+
# Combine RGB image with alpha mask and save
|
146 |
+
img_w_alpha = np.dstack((cv2.cvtColor(image_orig, cv2.COLOR_BGR2RGB), alpha))
|
147 |
+
cv2.imwrite(outname, img_w_alpha)
|
148 |
+
print(f"Saved: {outname}")
|