VReason-Demo / utils.py
EvidenceAIResearch's picture
Upload RadGenome demo Space
0d8d0b4 verified
Raw
History Blame Contribute Delete
3.83 kB
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