|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import re |
|
from .load_images import get_mask_from_file, check_mask_for_errors, blank_if_none |
|
from .word_masking import get_word_mask |
|
from PIL import ImageChops |
|
from modules.shared import opts |
|
|
|
|
|
|
|
def compose_mask(root, args, mask_seq, val_masks, frame_image, inner_idx:int = 0): |
|
|
|
|
|
|
|
|
|
|
|
|
|
seq = "" |
|
inner_seq = "" |
|
parentheses_counter = 0 |
|
|
|
for c in mask_seq: |
|
if c == ')': |
|
parentheses_counter = parentheses_counter - 1 |
|
if parentheses_counter > 0: |
|
inner_seq += c |
|
if c == '(': |
|
parentheses_counter = parentheses_counter + 1 |
|
if parentheses_counter == 0: |
|
if len(inner_seq) > 0: |
|
inner_idx += 1 |
|
seq += compose_mask(root, args, inner_seq, val_masks, frame_image, inner_idx) |
|
inner_seq = "" |
|
else: |
|
seq += c |
|
|
|
if parentheses_counter != 0: |
|
raise Exception('Mismatched parentheses in {mask_seq}!') |
|
|
|
mask_seq = seq |
|
|
|
|
|
|
|
|
|
|
|
pattern = r'\[(?P<inner>[\S\s]*?)\]' |
|
|
|
def parse(match_object): |
|
nonlocal inner_idx |
|
inner_idx += 1 |
|
content = match_object.groupdict()['inner'] |
|
val_masks[str(inner_idx)] = get_mask_from_file(content, args).convert('1') |
|
return f"{{{inner_idx}}}" |
|
|
|
mask_seq = re.sub(pattern, parse, mask_seq) |
|
|
|
|
|
pattern = r'<(?P<inner>[\S\s]*?)>' |
|
|
|
def parse(match_object): |
|
nonlocal inner_idx |
|
inner_idx += 1 |
|
content = match_object.groupdict()['inner'] |
|
val_masks[str(inner_idx)] = get_word_mask(root, frame_image, content).convert('1') |
|
return f"{{{inner_idx}}}" |
|
|
|
mask_seq = re.sub(pattern, parse, mask_seq) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pattern = r'![\S\s]*{(?P<inner>[\S\s]*?)}' |
|
def parse(match_object): |
|
nonlocal inner_idx |
|
inner_idx += 1 |
|
content = match_object.groupdict()['inner'] |
|
savename = content |
|
if content in root.mask_preset_names: |
|
inner_idx += 1 |
|
savename = str(inner_idx) |
|
val_masks[savename] = ImageChops.invert(val_masks[content]) |
|
return f"{{{savename}}}" |
|
|
|
mask_seq = re.sub(pattern, parse, mask_seq) |
|
|
|
|
|
|
|
while True: |
|
pattern = r'{(?P<inner1>[\S\s]*?)}[\s]*&[\s]*{(?P<inner2>[\S\s]*?)}' |
|
def parse(match_object): |
|
nonlocal inner_idx |
|
inner_idx += 1 |
|
content = match_object.groupdict()['inner1'] |
|
content_second = match_object.groupdict()['inner2'] |
|
savename = content |
|
if content in root.mask_preset_names: |
|
inner_idx += 1 |
|
savename = str(inner_idx) |
|
val_masks[savename] = ImageChops.logical_and(val_masks[content], val_masks[content_second]) |
|
return f"{{{savename}}}" |
|
|
|
prev_mask_seq = mask_seq |
|
mask_seq = re.sub(pattern, parse, mask_seq) |
|
if mask_seq is prev_mask_seq: |
|
break |
|
|
|
|
|
while True: |
|
pattern = r'{(?P<inner1>[\S\s]*?)}[\s]*?\|[\s]*?{(?P<inner2>[\S\s]*?)}' |
|
def parse(match_object): |
|
nonlocal inner_idx |
|
inner_idx += 1 |
|
content = match_object.groupdict()['inner1'] |
|
content_second = match_object.groupdict()['inner2'] |
|
savename = content |
|
if content in root.mask_preset_names: |
|
inner_idx += 1 |
|
savename = str(inner_idx) |
|
val_masks[savename] = ImageChops.logical_or(val_masks[content], val_masks[content_second]) |
|
return f"{{{savename}}}" |
|
|
|
prev_mask_seq = mask_seq |
|
mask_seq = re.sub(pattern, parse, mask_seq) |
|
if mask_seq is prev_mask_seq: |
|
break |
|
|
|
|
|
while True: |
|
pattern = r'{(?P<inner1>[\S\s]*?)}[\s]*\^[\s]*{(?P<inner2>[\S\s]*?)}' |
|
def parse(match_object): |
|
nonlocal inner_idx |
|
inner_idx += 1 |
|
content = match_object.groupdict()['inner1'] |
|
content_second = match_object.groupdict()['inner2'] |
|
savename = content |
|
if content in root.mask_preset_names: |
|
inner_idx += 1 |
|
savename = str(inner_idx) |
|
val_masks[savename] = ImageChops.logical_xor(val_masks[content], val_masks[content_second]) |
|
return f"{{{savename}}}" |
|
|
|
prev_mask_seq = mask_seq |
|
mask_seq = re.sub(pattern, parse, mask_seq) |
|
if mask_seq is prev_mask_seq: |
|
break |
|
|
|
|
|
while True: |
|
pattern = r'{(?P<inner1>[\S\s]*?)}[\s]*\\[\s]*{(?P<inner2>[\S\s]*?)}' |
|
def parse(match_object): |
|
content = match_object.groupdict()['inner1'] |
|
content_second = match_object.groupdict()['inner2'] |
|
savename = content |
|
if content in root.mask_preset_names: |
|
nonlocal inner_idx |
|
inner_idx += 1 |
|
savename = str(inner_idx) |
|
val_masks[savename] = ImageChops.logical_and(val_masks[content], ImageChops.invert(val_masks[content_second])) |
|
return f"{{{savename}}}" |
|
|
|
prev_mask_seq = mask_seq |
|
mask_seq = re.sub(pattern, parse, mask_seq) |
|
if mask_seq is prev_mask_seq: |
|
break |
|
|
|
|
|
|
|
|
|
pattern = r'{(?P<inner>[\S\s]*?)}' |
|
matches = re.findall(pattern, mask_seq) |
|
|
|
if len(matches) != 1: |
|
raise Exception(f'Wrong composable mask expression format! Broken mask sequence: {mask_seq}') |
|
|
|
return f"{{{matches[0]}}}" |
|
|
|
def compose_mask_with_check(root, args, mask_seq, val_masks, frame_image): |
|
for k, v in val_masks.items(): |
|
val_masks[k] = blank_if_none(v, args.W, args.H, '1').convert('1') |
|
return check_mask_for_errors(val_masks[compose_mask(root, args, mask_seq, val_masks, frame_image, 0)[1:-1]].convert('L')) |
|
|