File size: 9,002 Bytes
d73301b
88a3311
5c0ed2c
d73301b
8423e33
d73301b
fac2e01
2cff9a9
 
 
 
 
d73301b
2cff9a9
 
88a3311
2cff9a9
 
 
 
 
 
 
 
 
 
 
 
68894fa
 
 
 
 
 
 
 
 
 
 
 
2cff9a9
 
 
68894fa
 
 
 
 
 
 
2cff9a9
 
 
 
 
4c6f550
 
 
 
 
 
 
 
 
 
 
 
4caae8a
cb762b0
 
4caae8a
 
 
 
 
cb762b0
68894fa
 
 
d73301b
68894fa
 
 
 
 
 
 
 
 
 
 
 
 
2cff9a9
 
 
68894fa
2cff9a9
 
 
 
68894fa
 
2cff9a9
401fd9e
68894fa
 
401fd9e
e06181a
5c0ed2c
 
2cff9a9
cb762b0
68894fa
4caae8a
5c0ed2c
68894fa
 
 
 
 
cb762b0
 
 
 
 
 
04c67c9
 
cb762b0
04c67c9
 
 
 
cb762b0
 
 
 
 
 
8423e33
68894fa
 
8423e33
 
68894fa
8423e33
e06181a
68894fa
cb762b0
68894fa
e06181a
8423e33
 
68894fa
8423e33
2cff9a9
 
 
 
68894fa
2cff9a9
d73301b
68894fa
d73301b
2cff9a9
 
 
 
68894fa
9f420c3
68894fa
 
 
 
 
 
 
 
d73301b
 
68894fa
 
 
d73301b
2cff9a9
d73301b
cb762b0
68894fa
 
 
 
 
 
 
 
 
 
 
f9d0a7f
d73301b
 
 
5c0ed2c
2cff9a9
cb762b0
000f116
401fd9e
 
 
cb762b0
 
401fd9e
09cdf11
2cff9a9
 
5c0ed2c
b1bcf24
2cff9a9
b1bcf24
0560d17
571e307
2cff9a9
d73301b
 
 
9f420c3
68894fa
955d0e8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
import gradio as gr
import rembg
from rembg import remove, new_session
from PIL import Image
import numpy as np
import logging
import time
from hashlib import md5
import json
from pathlib import Path
import tempfile
import os

# Set up minimal logging to track usage
logging.basicConfig(level=logging.INFO, filename="user_activity.log", filemode="a")
logging.info(f"rembg version: {rembg.__version__}")

# Initialize user counter file
counter_file = Path("user_count.json")
def init_counter():
    if not counter_file.exists():
        with open(counter_file, "w") as f:
            json.dump({"total_requests": 0, "unique_sessions": []}, f)

def log_user_interaction():
    init_counter()
    # Generate a unique user ID (hashed timestamp as proxy for session)
    user_id = md5(str(time.time()).encode()).hexdigest()
    
    try:
        with open(counter_file, "r") as f:
            content = f.read().strip()
            if not content:  # File is empty
                data = {"total_requests": 0, "unique_sessions": []}
            else:
                data = json.loads(content)
    except (json.JSONDecodeError, FileNotFoundError):
        # Handle corrupted or missing file
        data = {"total_requests": 0, "unique_sessions": []}
    
    data["total_requests"] += 1
    if user_id not in data["unique_sessions"]:
        data["unique_sessions"].append(user_id)
    
    try:
        with open(counter_file, "w") as f:
            json.dump(data, f)
    except Exception as e:
        logging.error(f"Failed to write counter file: {e}")
    
    # Log only the request number and timestamp
    logging.info(f"Request #{data['total_requests']} at {time.strftime('%Y%m%d-%H%M%S')}")
    return data["total_requests"], len(data["unique_sessions"])

# Define model options
MODEL_OPTIONS = {
    "": "Select a model",
    "u2net": "A pre-trained model for general use cases (default)",
    "isnet-general-use": "A new pre-trained model for general use cases",
    "isnet-anime": "High-accuracy segmentation for anime characters",
    "silueta": "A reduced-size version of u2net (43MB)",
    "unet": "Lightweight version of u2net model",
    "u2netp": "A lightweight version of u2net model",
    "u2net_human_seg": "A pre-trained model for human segmentation",
    "u2net_cloth_seg": "A pre-trained model for cloth parsing in human portraits",
}

def hex_to_rgba(hex_color):
    if not hex_color:
        return None
    hex_color = hex_color.lstrip('#')
    if len(hex_color) == 6:
        hex_color += 'FF'  # Add full opacity if no alpha is provided
    return tuple(int(hex_color[i:i + 2], 16) for i in (0, 2, 4, 6))

def remove_background(input_path, bg_color=None, transparent_bg=True, model_choice="", alpha_matting=False, post_process_mask=False, only_mask=False):
    print(f"DEBUG: Function called with input_path: {input_path}")
    print(f"DEBUG: Parameters - bg_color: {bg_color}, transparent_bg: {transparent_bg}, model_choice: {model_choice}")
    
    try:
        # Check if input path is valid
        if not input_path or not os.path.exists(input_path):
            print(f"ERROR: Invalid input path: {input_path}")
            return None
            
        print("DEBUG: Starting background removal...")
        
        # Log user interaction (minimal) - with error handling
        try:
            log_user_interaction()
        except Exception as e:
            print(f"WARNING: Failed to log user interaction: {e}")
            # Continue with background removal even if logging fails

        # Open the input image
        input_image = Image.open(input_path)
        print(f"DEBUG: Opened image with size: {input_image.size}, mode: {input_image.mode}")

        # Extract the original filename without extension
        original_filename = os.path.splitext(os.path.basename(input_path))[0]
        # Create the desired output filename
        output_filename = f"{original_filename}_removebg.png"
        print(f"DEBUG: Output filename will be: {output_filename}")

        # Extract the model name from the choice
        model_name = model_choice.split(' | ')[0] if model_choice and ' | ' in model_choice else model_choice
        print(f"DEBUG: Using model: {model_name if model_name else 'default'}")
        
        # Set up the session with the chosen model, or None if no model is selected
        session = new_session(model_name) if model_name else None
        
        # Use transparent background if selected, otherwise use color
        bg_color_rgba = None if transparent_bg else hex_to_rgba(bg_color)
        print(f"DEBUG: Background color RGBA: {bg_color_rgba}")
        
        # Prepare additional options
        remove_kwargs = {}
        
        # Only add session if we have one
        if session is not None:
            remove_kwargs["session"] = session
        
        # Only add bgcolor if we have one
        if bg_color_rgba is not None:
            remove_kwargs["bgcolor"] = bg_color_rgba
            
        # Add other parameters
        if alpha_matting:
            remove_kwargs.update({
                "alpha_matting": True,
                "alpha_matting_foreground_threshold": 270,
                "alpha_matting_background_threshold": 20,
                "alpha_matting_erode_size": 11
            })
        
        if post_process_mask:
            remove_kwargs["post_process_mask"] = True
            
        if only_mask:
            remove_kwargs["only_mask"] = True

        print(f"DEBUG: Remove kwargs: {remove_kwargs}")

        # Convert PIL Image to numpy array
        input_array = np.array(input_image)
        print(f"DEBUG: Input array shape: {input_array.shape}")

        # Use the remove function
        print("DEBUG: Calling rembg.remove()...")
        output_array = remove(input_array, **remove_kwargs)
        print(f"DEBUG: Output array shape: {output_array.shape}")

        # Convert numpy array back to PIL Image
        output_image = Image.fromarray(output_array)
        print(f"DEBUG: Output image size: {output_image.size}, mode: {output_image.mode}")

        # Preserve transparency for transparent background or only_mask
        if transparent_bg or only_mask:
            if output_image.mode != 'RGBA':
                output_image = output_image.convert('RGBA')
                print("DEBUG: Converted to RGBA mode")
        elif output_image.mode != 'RGB':
            output_image = output_image.convert('RGB')
            print("DEBUG: Converted to RGB mode")

        # Create a temporary directory and save the image with the desired filename
        temp_dir = tempfile.mkdtemp()
        output_path = os.path.join(temp_dir, output_filename)
        output_image.save(output_path, format="PNG")
        print(f"DEBUG: Saved output to: {output_path}")

        # Verify the file was created
        if os.path.exists(output_path):
            file_size = os.path.getsize(output_path)
            print(f"DEBUG: Output file created successfully, size: {file_size} bytes")
            return output_path
        else:
            print("ERROR: Output file was not created")
            return None

    except Exception as e:
        print(f"ERROR: Exception occurred: {str(e)}")
        import traceback
        traceback.print_exc()
        logging.error(f"An error occurred: {e}")
        return None

# Fixed examples with proper values for all inputs
examples = [
    [
        'scifi_man1.jpg',  # input_path
        "#FFFFFF",         # bg_color (white)
        True,              # transparent_bg
        "",                # model_choice (empty string, which is in the choices)
        False,             # alpha_matting
        False,             # post_process_mask
        False              # only_mask
    ]
]

# Gradio interface
iface = gr.Interface(
    fn=remove_background,
    inputs=[
        gr.Image(type="filepath", label="Input Image"),
        gr.ColorPicker(label="Background Color (ignored if transparent is selected)", value="#FFFFFF"),
        gr.Checkbox(label="Transparent Background", value=False),
        gr.Dropdown(
            choices=[""] + [f"{k} | {v}" for k, v in MODEL_OPTIONS.items() if k != ""],
            label="Model Selection",
            value="",  # Changed from empty to match choices
            allow_custom_value=False
        ),
        gr.Checkbox(label="Enable Alpha Matting", value=False),
        gr.Checkbox(label="Post-Process Mask", value=False),
        gr.Checkbox(label="Only Return Mask", value=False)
    ],
    outputs=[
        gr.Image(type="filepath", label="Output Image (PNG)")
    ],
    examples=examples,
    title="Background Remover v2.9",
    description="Upload an image to remove the background. Choose a solid color or transparent background, select a model, and customize with alpha matting and other options. Right-click the output image to save as PNG.",
    allow_flagging="never",
)

if __name__ == "__main__":
    print("Starting Background Remover app...")
    iface.launch()