Files
bmad4ever-comfyui_quilting/patch_search.py
T
Bruno Madeira 0287e2d4a2 Refactoring + fixes + added node (ImageMakeSeamlessSB)
* refactored patch_search.py
* fixed H Seam position on v2
* fixed seamless node bar total steps not accounting for batch size
* added uicd logic to make_seamless2.py
* removed mains from make_seamless.py & make_seamless2.py
* other minor cleanups

- triggered error in find_patch_vx due to random gen having a value equal or lesser than zero as argument.
Was not able to reproduce the error again so far.
Conjecture: it may be the case that the min error was negative due to lack of precision when using patch v3, resulting in an empty list of candidates if tolerance is not zero; if this is the case the error should happen only when using version 3.
2024-07-31 16:10:14 +01:00

111 lines
3.9 KiB
Python

from .jena2020.generate import findPatchVertical, findPatchHorizontal, findPatchBoth
import numpy as np
import cv2 as cv
epsilon = np.finfo(float).eps
# region get methods by version
def get_find_patch_to_the_right_method(version: int):
match version:
case 0:
return findPatchHorizontal
case _:
def vx_right(left_block, image, block_size, overlap, tolerance, rng):
return find_patch_vx(left_block, None, None, None,
image, block_size, overlap, tolerance, rng, version)
return vx_right
def get_find_patch_below_method(version: int):
match version:
case 0:
return findPatchVertical
case _:
def vx_below(top_block, image, block_size, overlap, tolerance, rng):
return find_patch_vx(None, None, top_block, None,
image, block_size, overlap, tolerance, rng, version)
return vx_below
def get_find_patch_both_method(version: int):
match version:
case 0:
return findPatchBoth
case _:
def vx_both(left_block, top_block, image, block_size, overlap, tolerance, rng):
return find_patch_vx(left_block, None, top_block, None,
image, block_size, overlap, tolerance, rng, version)
return vx_both
def get_generic_find_patch_method(version: int):
def vx_patch_find(ref_block_left, ref_block_right, ref_block_top, ref_block_bottom,
texture, block_size, overlap, tolerance, rng):
return find_patch_vx(ref_block_left, ref_block_right, ref_block_top, ref_block_bottom,
texture, block_size, overlap, tolerance, rng, version)
return vx_patch_find
def compute_errors(diffs: list[np.ndarray], version: int) -> np.ndarray:
match version:
case 1:
return np.add.reduce(diffs)
case 2:
return np.maximum.reduce(diffs)
case 3:
return 1 - np.minimum.reduce(diffs) # values from 0 to 2
case _:
raise NotImplemented()
def get_match_template_method(version: int) -> int:
match version:
case 1:
return cv.TM_SQDIFF
case 2:
return cv.TM_SQDIFF
case 3:
return cv.TM_CCORR_NORMED
case _:
raise NotImplemented()
# endregion
def find_patch_vx(ref_block_left, ref_block_right, ref_block_top, ref_block_bottom,
texture, block_size, overlap, tolerance,
rng: np.random.Generator, version):
blks_diffs = []
template_method = get_match_template_method(version)
if ref_block_left is not None:
blks_diffs.append(cv.matchTemplate(
image=texture[:, :-block_size + overlap],
templ=ref_block_left[:, -overlap:], method=template_method))
if ref_block_right is not None:
blks_diffs.append(cv.matchTemplate(
image=np.roll(texture, -block_size + overlap, axis=1)[:, :-block_size + overlap],
templ=ref_block_right[:, :overlap], method=template_method))
if ref_block_top is not None:
blks_diffs.append(cv.matchTemplate(
image=texture[:-block_size + overlap, :],
templ=ref_block_top[-overlap:, :], method=template_method))
if ref_block_bottom is not None:
blks_diffs.append(cv.matchTemplate(
image=np.roll(texture, -block_size + overlap, axis=0)[:-block_size + overlap, :],
templ=ref_block_bottom[:overlap, :], method=template_method))
err_mat = compute_errors(blks_diffs, version)
min_val = np.min(err_mat[err_mat > 0 if tolerance > 0 else True]) # ignore zeroes to enforce tolerance usage
y, x = np.nonzero(err_mat <= (1.0 + tolerance) * min_val)
c = rng.integers(len(y))
y, x = y[c], x[c]
return texture[y:y + block_size, x:x + block_size]