Soma / scratch /morph_cutout.py
Komalpreet Kaur
feat: implement memory consolidation service with sleep cycle, add frontend visualization components, and integrate backend database orchestration.
adfa6d0 unverified
Raw
History Blame Contribute Delete
3.43 kB
import collections
from PIL import Image, ImageFilter
def main():
# Load original sleep image
img_path = r"d:\PROJECTS\Soma\frontend\src\assets\brain\sleep.png"
img = Image.open(img_path).convert("RGBA")
width, height = img.size
pixels = img.load()
# 1. Create a binary threshold mask: 255 for non-background pixels, 0 for background pixels
thresh = Image.new("L", (width, height), 0)
thresh_pixels = thresh.load()
for y in range(height):
for x in range(width):
r, g, b, a = pixels[x, y]
# Background is neutral light-grey around (200-223)
is_bg_color = (200 <= r <= 223) and (abs(r - g) <= 5) and (abs(g - b) <= 5)
if not is_bg_color:
thresh_pixels[x, y] = 255
# 2. Apply Morphological Closing to completely seal any microscopic boundary gaps!
# MaxFilter(9) dilates the 255 region by 4 pixels, closing any gaps in the outline.
dilated = thresh.filter(ImageFilter.MaxFilter(9))
# MinFilter(9) erodes it back by 4 pixels to restore the exact original boundary size.
closed = dilated.filter(ImageFilter.MinFilter(9))
# 3. Flood fill the outer background on the closed mask starting from all borders.
# Since the closed mask has no gaps, the flood fill will stay strictly outside the brain!
visited = set()
edge_pixels = []
for x in range(width):
edge_pixels.append((x, 0))
edge_pixels.append((x, height - 1))
for y in range(height):
edge_pixels.append((0, y))
edge_pixels.append((width - 1, y))
queue = collections.deque(edge_pixels)
for p in edge_pixels:
visited.add(p)
# The final silhouette mask starts as all 255 (brain). Flood filled pixels become 0 (transparent).
silhouette = Image.new("L", (width, height), 255)
sil_pixels = silhouette.load()
closed_pixels = closed.load()
while queue:
x, y = queue.popleft()
# If this pixel in the closed mask is 0 (background), it is outer background
if closed_pixels[x, y] == 0:
sil_pixels[x, y] = 0
# Propagate
for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
nx, ny = x + dx, y + dy
if 0 <= nx < width and 0 <= ny < height:
if (nx, ny) not in visited:
visited.add((nx, ny))
queue.append((nx, ny))
# 4. Smooth the silhouette mask edges with a 1.2px Gaussian Blur for a perfect anti-aliased cut-out.
smooth_silhouette = silhouette.filter(ImageFilter.GaussianBlur(1.2))
# 5. Apply the perfect silhouette to the alpha channel of the original sleep.png image
final_img = Image.new("RGBA", (width, height))
final_pixels = final_img.load()
smooth_pixels = smooth_silhouette.load()
for y in range(height):
for x in range(width):
r, g, b, a = pixels[x, y]
alpha_val = smooth_pixels[x, y]
final_pixels[x, y] = (r, g, b, alpha_val)
# 6. Save the perfect cutout back to sleep_nobg.png!
output_path = r"d:\PROJECTS\Soma\frontend\src\assets\brain\sleep_nobg.png"
final_img.save(output_path, "PNG")
print("SUCCESS: Perfect morphological cutout created successfully!")
if __name__ == "__main__":
main()