import colorsys # Polygon regions. from PIL import Image, ImageChops from pprint import pprint import cv2 # Polygon regions. import numpy as np import PIL import torch SPLROW = ";" SPLCOL = "," KEYROW = "ADDROW" KEYCOL = "ADDCOL" KEYBASE = "ADDBASE" KEYCOMM = "ADDCOMM" KEYBRK = "BREAK" NLN = "\n" DKEYINOUT = { # Out/in, horizontal/vertical or row/col first. ("out",False): KEYROW, ("in",False): KEYCOL, ("out",True): KEYCOL, ("in",True): KEYROW, } fidentity = lambda x: x ffloatd = lambda c: (lambda x: floatdef(x,c)) fspace = lambda x: " {} ".format(x) fcountbrk = lambda x: x.count(KEYBRK) fint = lambda x: int(x) def floatdef(x, vdef): """Attempt conversion to float, use default value on error. Mainly for empty ratios, double commas. """ try: return float(x) except ValueError: print("'{}' is not a number, converted to {}".format(x,vdef)) return vdef class Region(): """Specific Region used to split a layer to single prompts.""" def __init__(self, st, ed, base, breaks): """Range with start and end values, base weight and breaks count for context splitting.""" self.start = st # Range for the cell (cols only). self.end = ed self.base = base # How much of the base prompt is applied (difference). self.breaks = breaks # How many unrelated breaks the prompt contains. class Row(): """Row containing cell refs and its own ratio range.""" def __init__(self, st, ed, cols): """Range with start and end values, base weight and breaks count for context splitting.""" self.start = st # Range for the row. self.end = ed self.cols = cols # List of cells. def is_l2(l): return isinstance(l[0],list) def l2_count(l): cnt = 0 for row in l: cnt + cnt + len(row) return cnt def list_percentify(l): """ Convert each row in L2 to relative part of 100%. Also works on L1, applying once globally. """ lret = [] if is_l2(l): for row in l: # row2 = [float(v) for v in row] row2 = [v / sum(row) for v in row] lret.append(row2) else: row = l[:] # row2 = [float(v) for v in row] row2 = [v / sum(row) for v in row] lret = row2 return lret def list_cumsum(l): """ Apply cumsum to L2 per row, ie newl[n] = l[0:n].sum . Works with L1. Actually edits l inplace, idc. """ lret = [] if is_l2(l): for row in l: for (i,v) in enumerate(row): if i > 0: row[i] = v + row[i - 1] lret.append(row) else: row = l[:] for (i,v) in enumerate(row): if i > 0: row[i] = v + row[i - 1] lret = row return lret def list_rangify(l): """ Merge every 2 elems in L2 to a range, starting from 0. """ lret = [] if is_l2(l): for row in l: row2 = [0] + row row3 = [] for i in range(len(row2) - 1): row3.append([row2[i],row2[i + 1]]) lret.append(row3) else: row2 = [0] + l row3 = [] for i in range(len(row2) - 1): row3.append([row2[i],row2[i + 1]]) lret = row3 return lret def ratiosdealer(split_ratio2,split_ratio2r): split_ratio2 = list_percentify(split_ratio2) split_ratio2 = list_cumsum(split_ratio2) split_ratio2 = list_rangify(split_ratio2) split_ratio2r = list_percentify(split_ratio2r) split_ratio2r = list_cumsum(split_ratio2r) split_ratio2r = list_rangify(split_ratio2r) return split_ratio2,split_ratio2r def round_dim(x,y): """Return division of two numbers, rounding 0.5 up. Seems that dimensions which are exactly 0.5 are rounded up - see 680x488, second iter. A simple mod check should get the job done. If not, can always brute force the divisor with +-1 on each of h/w. """ return x // y + (x % y >= y // 2) def keyconverter(self,split_ratio,usebase): '''convert BREAKS to ADDCOMM/ADDBASE/ADDCOL/ADDROW''' if SPLROW not in split_ratio: # Commas only - interpret as 1d. split_ratio2 = split_l2(split_ratio, SPLROW, SPLCOL, map_function = ffloatd(1)) split_ratio2r = [1] else: (split_ratio2r,split_ratio2) = split_l2(split_ratio, SPLROW, SPLCOL, indsingles = True, map_function = ffloatd(1)) (split_ratio2,split_ratio2r) = ratiosdealer(split_ratio2,split_ratio2r) #print(keychanger,p.prompt) txtkey = fspace(DKEYINOUT[("in", False)]) + NLN lkeys = [txtkey.join([""] * len(cell)) for cell in split_ratio2] txtkey = fspace(DKEYINOUT[("out", False)]) + NLN template = txtkey.join(lkeys) if usebase: template = fspace(KEYBASE) + NLN + template changer = template.split(NLN) changer = [l.strip() for l in changer] keychanger=changer[:-1] for change in keychanger: if change == KEYBASE and KEYBASE in self.SR_prompt: continue self.SR_prompt= self.SR_prompt.replace(KEYBRK,change,1) def split_l2(s, key_row, key_col, indsingles = False, map_function = fidentity, split_struct = None): lret = [] if split_struct is None: lrows = s.split(key_row) lrows = [row.split(key_col) for row in lrows] # print(lrows) for r in lrows: cell = [map_function(x) for x in r] lret.append(cell) if indsingles: lsingles = [row[0] for row in lret] lcells = [row[1:] if len(row) > 1 else row for row in lret] lret = (lsingles,lcells) else: lrows = str(s).split(key_row) r = 0 lcells = [] lsingles = [] vlast = 1 for row in lrows: row2 = row.split(key_col) row2 = [map_function(x) for x in row2] vlast = row2[-1] indstop = False while not indstop: if (r >= len(split_struct) # Too many cell values, ignore. or (len(row2) == 0 and len(split_struct) > 0)): # Cell exhausted. indstop = True if not indstop: if indsingles: # Singles split. lsingles.append(row2[0]) # Row ratio. if len(row2) > 1: row2 = row2[1:] if len(split_struct[r]) >= len(row2): # Repeat last value. indstop = True broadrow = row2 + [row2[-1]] * (len(split_struct[r]) - len(row2)) r = r + 1 lcells.append(broadrow) else: # Overfilled this row, cut and move to next. broadrow = row2[:len(split_struct[r])] row2 = row2[len(split_struct[r]):] r = r + 1 lcells.append(broadrow) # If not enough new rows, repeat the last one for entire base, preserving structure. cur = len(lcells) while cur < len(split_struct): lcells.append([vlast] * len(split_struct[cur])) cur = cur + 1 lret = lcells if indsingles: lsingles = lsingles + [lsingles[-1]] * (len(split_struct) - len(lsingles)) lret = (lsingles,lcells) return lret def matrixdealer(self, split_ratio, baseratio): # print(split_ratio, baseratio) prompt = self.SR_prompt if KEYBASE in prompt: prompt = prompt.split(KEYBASE,1)[1] if (KEYCOL in prompt.upper() or KEYROW in prompt.upper()): # breaks = prompt.count(KEYROW) + prompt.count(KEYCOL) + int(self.usebase) # Prompt anchors, count breaks between special keywords. # print('prompt:', prompt) lbreaks = split_l2(prompt, KEYROW, KEYCOL, map_function = fcountbrk) # print('lbreaks', lbreaks) if (SPLROW not in split_ratio and (KEYROW in prompt.upper()) != (KEYCOL in prompt.upper())): # By popular demand, 1d integrated into 2d. # This works by either adding a single row value (inner), # or setting flip to the reverse (outer). # Only applies when using just ADDROW / ADDCOL keys, and commas in ratio. split_ratio = "1" + SPLCOL + split_ratio (split_ratio2r,split_ratio2) = split_l2(split_ratio, SPLROW, SPLCOL, indsingles = True, map_function = ffloatd(1), split_struct = lbreaks) else: # Standard ratios, split to rows and cols. (split_ratio2r,split_ratio2) = split_l2(split_ratio, SPLROW, SPLCOL, indsingles = True, map_function = ffloatd(1), split_struct = lbreaks) # print('split_ratio2r', split_ratio2r) # print('split_ratio2', split_ratio2) # More like "bweights", applied per cell only. baseratio2 = split_l2(baseratio, SPLROW, SPLCOL, map_function = ffloatd(0), split_struct = lbreaks) # print(baseratio2) (split_ratio,split_ratior) = ratiosdealer(split_ratio2,split_ratio2r) baseratio = baseratio2 # Merge various L2s to cells and rows. drows = [] for r,_ in enumerate(lbreaks): dcells = [] for c,_ in enumerate(lbreaks[r]): d = Region(split_ratio[r][c][0], split_ratio[r][c][1], baseratio[r][c], lbreaks[r][c]) dcells.append(d) drow = Row(split_ratior[r][0], split_ratior[r][1], dcells) drows.append(drow) self.split_ratio = drows self.baseratio = baseratio # class test: # def __init__(self, prompt,split_ratio=None,baseratio=0.2,usebase=False): # self.prompt = prompt # self.split_ratio = split_ratio # self.baseratio = 0.2 # self.usebase = usebase # test_prompt='a girl BREAK a cute boy BREAK a dog BREAK a tree.' # split_ratio='1,1,1;1,1,1' # x=test(test_prompt,split_ratio) # keyconverter(x,split_ratio,usebase=False) # print(x.prompt) # matrixdealer(x, split_ratio, 0.2)