File size: 3,825 Bytes
0d8d0b4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import re
import time

class Streamer:
	def __init__(self, filepath, delay=0.02):
		self.filepath = filepath
		self.delay = delay

	def stream(self):
		"""Yield letters one by one from the file with delay"""
		with open(self.filepath, "r", encoding="utf-16") as f:
			content = f.read()
		for char in content:
			yield char
			time.sleep(self.delay)

	def __iter__(self):
		return self.stream()

# dummy tokenizer
class Tokenizer:
	def __init__(self):
		pass
	def decode(tok, skip_special_tokens=False):
		return tok

class RegexStopper:
	def __init__(self, pattern):
		super().__init__()
		self.pattern = pattern
		self.match = None
		self.decoded_so_far = ""

	def __call__(self, new_text, **kwargs):
		self.decoded_so_far += new_text
		match = self.pattern.search(self.decoded_so_far)
		if match:
			self.match = match
			self.decoded_so_far = ""
		return match



import cv2
import templates
import numpy as np
from PIL import Image, ImageFilter

def get_cnt_level(i, hierarchy):
	# hierarchy[i] -> [next, prev, child, parent]
	level = 0
	parent = hierarchy[i][3]
	while parent != -1:
		level += 1
		parent = hierarchy[parent][3]
	return level

def contour_to_path_data(contour):
	contour = contour.squeeze() # ensures shape (N,2)
	if contour.ndim != 2:
		return ""
	d = f"M {contour[0,0]} {contour[0,1]}"
	for x, y in contour[1:]:
		d += f" L {x} {y}"
	d += " Z"
	return d

def rectangle_path(width, height):
    # path string for a rectangle starting at (0, 0).
    return f"M 0 0 H{width} V{height} H0 Z"

def smooth(mask):
	img_height, img_width = mask.shape

	mask = Image.fromarray(mask).convert("L")
	blur_radius = (img_height * img_width) ** 0.5 // 100
	blur_mask = mask.filter(ImageFilter.GaussianBlur(radius=blur_radius))
	smoooth_mask = np.array(blur_mask) > (255/1.8)
	smoooth_mask = smoooth_mask.astype(np.uint8) * 255
	return smoooth_mask

def mask_to_svg(mask):
	img_height, img_width = mask.shape

	# Find contours with hierarchy
	contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
	hierarchy = np.squeeze(hierarchy, 0)  # ensures shape (N,4), hierarchy[i] -> [next, prev, child, parent]

	# Organize into SVG components
	paths = []

	mask_idx = 0
	masks = []
	mask_paths = []
	bg_mask_paths = [templates.svg.path.render(elem_class="inner", d=rectangle_path(img_width, img_height))]

	for i, cnt in enumerate(contours):
		path_data = contour_to_path_data(cnt)
		level = get_cnt_level(i, hierarchy)
		pos_class = "outer" if level % 2 == 0 else "inner"
		if level == 0:
			# Wrap any existing level 0 (most-outer clipping mask)
			if mask_paths:
				mask = templates.svg.mask.render(mask_idx=mask_idx, paths="\n\t\t\t".join(mask_paths))
				masks.append(mask)
				mask_paths = []
				mask_idx += 1

			# create new level 0
			mask_url = templates.svg.mask_url.render(mask_idx=mask_idx)
			path = templates.svg.path.render(elem_class=f"{pos_class} level0", d=path_data, mask_url=mask_url)
			mask_path = templates.svg.path.render(elem_class=pos_class, d=path_data)
		else:
			mask_path = path = templates.svg.path.render(elem_class=pos_class, d=path_data)
		paths.append(path)
		mask_paths.append(mask_path)
		bg_mask_paths.append(mask_path)

	# Wrap any existing level 0
	mask = templates.svg.mask.render(mask_idx=mask_idx, paths="\n\t\t\t".join(mask_paths))
	masks.append(mask)

	# wrap bg mask
	bg_path = templates.svg.bg_path.render(d=rectangle_path(img_width, img_height))
	bg_mask = templates.svg.bg_mask.render(paths="\n\t\t\t".join(bg_mask_paths))

	# create anatomy svg
	svg = templates.svg.anatomy.render(width=img_width, height=img_height, bg_mask=bg_mask, masks="\n".join(masks), bg_path=bg_path, paths="\n\t".join(paths))
	return svg