77 lines
2.4 KiB
Python

import random
from copy import deepcopy
from itertools import chain
from funcy import rpartial, juxt, first
from image_prediction.stitching.split_mapper import SplitMapper, HorizontalSplitMapper, VerticalSplitMapper
class BoxSplitter:
def __init__(self, noise=None):
self.__steps = None
self.__noise = (0, 0) if not noise else noise
def split_box(self, box, steps=5):
self.__steps = steps
return self.__split_recursively(box, 0)
def __split_recursively(self, box, step):
return self.__split_and_recurse(box, step) if self.__steps_left(step) else self.__base_case(box)
def __steps_left(self, step):
return step < self.__steps
@staticmethod
def __base_case(box):
return [box]
def __split_and_recurse(self, box, step):
new_boxes = self.__random_split(box)
new_boxes_per_branch = self.__tree_recurse(new_boxes, step + 1)
return chain.from_iterable(new_boxes_per_branch)
def __random_split(self, box):
splitter = random.choice([self.__split_horizontal, self.__split_vertical])
new_boxes = splitter(box)
return new_boxes
def __tree_recurse(self, boxes, step):
return map(rpartial(self.__split_recursively, step + 1), boxes)
def __split_horizontal(self, box):
return self.__split_if_large_enough(HorizontalSplitMapper(box))
def __split_vertical(self, box):
return self.__split_if_large_enough(VerticalSplitMapper(box))
def __split_if_large_enough(self, wrapped_box: SplitMapper):
return (
self.__get_child_boxes(wrapped_box)
if self.__large_enough(wrapped_box)
else self.__base_case(wrapped_box.wrapped)
)
def noise(self):
return int(round(random.uniform(*self.__noise)))
@staticmethod
def __large_enough(wrapped_box: SplitMapper):
return wrapped_box.dim >= 10
def __get_child_boxes(self, wrapped_box: SplitMapper):
split_len = random.randint(5, wrapped_box.dim - 5)
split_point = wrapped_box.c1 + split_len
box_left, box_right = juxt(deepcopy, deepcopy)(wrapped_box)
noise = - self.noise()
box_left.dim = split_len + noise
box_right.dim = wrapped_box.dim - split_len
box_left.c2 = split_point + noise
box_right.c1 = split_point + self.noise()
return box_left.wrapped, box_right.wrapped