82 lines
2.5 KiB
Python
82 lines
2.5 KiB
Python
import collections
|
|
from PIL import Image
|
|
|
|
def remove_background(image_path, output_path):
|
|
# Load image and convert to RGBA
|
|
img = Image.open(image_path).convert("RGBA")
|
|
width, height = img.size
|
|
pixels = img.load()
|
|
|
|
# Visited grid to prevent loops
|
|
visited = [[False for _ in range(height)] for _ in range(width)]
|
|
|
|
# Queue for BFS
|
|
queue = collections.deque()
|
|
|
|
# Helper to check if color matches checkerboard background
|
|
def is_background_color(r, g, b):
|
|
# White squares
|
|
if r > 240 and g > 240 and b > 240:
|
|
return True
|
|
# Grey squares
|
|
if 210 < r < 240 and 210 < g < 240 and 210 < b < 240:
|
|
# Check if it's neutral grey
|
|
if abs(r - g) < 5 and abs(g - b) < 5:
|
|
return True
|
|
return False
|
|
|
|
# Initialize queue with all border pixels
|
|
for x in range(width):
|
|
# Top border
|
|
r, g, b, a = pixels[x, 0]
|
|
if is_background_color(r, g, b):
|
|
queue.append((x, 0))
|
|
visited[x][0] = True
|
|
|
|
# Bottom border
|
|
r, g, b, a = pixels[x, height - 1]
|
|
if is_background_color(r, g, b):
|
|
queue.append((x, height - 1))
|
|
visited[x][height - 1] = True
|
|
|
|
for y in range(height):
|
|
# Left border
|
|
r, g, b, a = pixels[0, y]
|
|
if is_background_color(r, g, b):
|
|
queue.append((0, y))
|
|
visited[0][y] = True
|
|
|
|
# Right border
|
|
r, g, b, a = pixels[width - 1, y]
|
|
if is_background_color(r, g, b):
|
|
queue.append((width - 1, y))
|
|
visited[width - 1][y] = True
|
|
|
|
# Perform BFS
|
|
directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
|
|
while queue:
|
|
cx, cy = queue.popleft()
|
|
|
|
# Set this background pixel to fully transparent
|
|
pixels[cx, cy] = (0, 0, 0, 0)
|
|
|
|
# Check neighbors
|
|
for dx, dy in directions:
|
|
nx, ny = cx + dx, cy + dy
|
|
if 0 <= nx < width and 0 <= ny < height:
|
|
if not visited[nx][ny]:
|
|
r, g, b, a = pixels[nx, ny]
|
|
if is_background_color(r, g, b):
|
|
visited[nx][ny] = True
|
|
queue.append((nx, ny))
|
|
|
|
# Save the transparent image
|
|
img.save(output_path, "PNG")
|
|
print(f"Background successfully removed and saved to {output_path}")
|
|
|
|
if __name__ == "__main__":
|
|
remove_background(
|
|
"public/images/slider-courier-mask-purple.png",
|
|
"public/images/slider-courier-mask-purple.png"
|
|
)
|