def __init__(self, image, dimensions=199, model=None, initial_face=None, callback=None): """Initializes fitter for given image. Fits provided number of dimensions of given model to the image. """ self.__image = array(image) self.__model = model self.__pcs = dimensions self._dimensions = (dimensions + Face.LIGHT_COMPONENTS_COUNT + Face.DIRECTION_COMPONENTS_COUNT + Face.SCALE_COMPONENTS_COUNT) self.__callback = callback self._initial_face = initial_face if self._initial_face is None: self._initial_face = Face( coefficients=zeros(self.__pcs, dtype='f') ) coefficients = self._initial_face.coefficients if len(coefficients) != self.__pcs: correct_coefficients = zeros(self.__pcs, dtype='f') count = min(len(coefficients), self.__pcs) correct_coefficients[:count] = coefficients[:count] self._initial_face = Face( coefficients=correct_coefficients, directed_light=self._initial_face.directed_light, ambient_light=self._initial_face.ambient_light, scale=self._initial_face.scale )
def test_set_directed_light(): face = Face() face.position = (0, 0, 0) assert allclose(face.position, (0, 0, 0)) assert allclose(face.position_cartesian, (0, 0, 1)) face.position = (1, 1, 1) assert allclose(face.position, (1, 1, 1)) assert allclose(face.position_cartesian, (0, 1, 0))
def calculate_shrink(self): self.__step = 'shrink' self.__parameters[1:] = self.__parameters[0] + self.__sigma * \ (self.__parameters[1:] - self.__parameters[0]) self.__errors[1:] = [None] * (len(self.__errors) - 1) self.__end = self.__parameters[0] + self.__sigma * \ (self.__end - self.__parameters[0]) self.end_error = None for i in range(1, self._dimensions): self.request_face(Face.from_array(self.__parameters[i]), i) self.request_face(Face.from_array(self.__end), self._dimensions)
def start(self): self.__loop = 0 self.__face = self._initial_face self.__parameters = self._initial_face.as_array self.request_face(self.__face, 'init') self.__errors = {} self.__generate_errors() self.__indices = [0] * len(self.__levels) self.__directions = [1] * len(self.__levels) self.__parameters[self.__levels] = [ self.__get_value(i, self.__indices[i]) for i in range(len(self.__levels)) ] change_on = 0 while change_on != -1: self.__errors[tuple( self.__indices)] = self.__get_parameter(change_on=change_on) change_on = self.__inc_index() result = self.__convert_parameters() parameters = self._initial_face.as_array parameters[self.__levels] = result[-1][0] face = Face.from_array(parameters) self.get_face(face) self.finish(face)
def test_face_setter(): view = View() model = Model(view) face = Face() model.face = face assert model.face is face assert view.face is face
def test_receive_images(): results = [] images = [[0]*4, [1]*4, [2]*4] face = Face() view = View() model = Model(view) callback = lambda img: results.append(img) model.request_image(face, callback) model.request_image(face, callback) view.image = images[0] view.callback() assert len(results) == 1 assert allclose(results[0], images[0]) view.image = images[1] view.callback() assert len(results) == 2 assert allclose(results[1], images[1]) final_callback = lambda img: results.append([img]) model.request_image(face, callback) view.image = images[2] view.callback() assert len(results) == 3 assert allclose(results[2], [images[2]])
def __derivative_face(self, param, dx): params = self.__face.as_array if param >= 0: params[param] += dx else: params[param] += self.__light_dx return Face.from_array(params)
def start(self): face = self._initial_face.as_array for _ in range(self.__max_loops): derivatives = self.__get_derivatives(face) face += derivatives * self.__step self.finish(Face.from_array(face))
def test_request_image(): results = [] face = Face() callback = lambda img: results.append(img) model = Model(View()) model.request_image(face, callback) assert results == []
def get_face(self, face): """Get face image by face object. Accepts both `Face` instance and Face representation as `NumPy` `array`. """ if isinstance(face, ndarray): face = Face.from_array(face) return self.__model.get_image(face)
def __initiate_parameters(self): self.__step = 'start' initial_parameters = concatenate(( self._initial_face.coefficients, [self._initial_face.ambient_light], self._initial_face.directed_light )) for i in range(len(self.__parameters)): # print('Initial step {} of {}'.format(i, self._dimensions)) # self.__parameters[i] = randn(self._dimensions) * 1 # self.__parameters[i] = zeros(self._dimensions) # self.__parameters[i][:i] = self.__offset self.__parameters[i] = initial_parameters.copy() self.__parameters[i][:i] += self.__offset self.request_face(Face.from_array(self.__parameters[i]), i) # self.__end = ones(self._dimensions) # self.__end = randn(self._dimensions) self.__end = initial_parameters + self.__offset self.request_face(Face.from_array(self.__end), self._dimensions)
def test_receive_image(): results = [] face = Face() view = View() model = Model(view) callback = lambda img: results.append(img) model.request_image(face, callback) view.image = [1, 2, 3, 4] view.callback() assert allclose(results[0], view.image)
def receive_image(self, image, index=None): if index == 'init': return elif index == 'pre': self.__get_parameter(self.__current_step + 1) return shadows = image if index is None: self.finish(self.__face) return self.__errors[index] = self.get_image_deviation(shadows) if None in self.__errors: return errors = array(self.__errors) max_error = errors.max() if self.__loop >= self.__determined_loops: X = exp(-errors / max_error).sum() v = rand() best_index = -1 t = 0 for i, error in enumerate(errors): e = exp(error / max_error) / X t += e if v <= e: best_index = i break else: v -= e if best_index == -1: best_index = len(self.__errors) - 1 else: best_index = argmin(self.__errors) self.__parameters[self.__current_step] = self.__values[best_index] self.__face = Face.from_array(self.__parameters) print('{}.{}: Error of the best is {} ({})'.format( self.__loop, self.__current_step, self.__errors[best_index], min(self.__errors))) if self.__current_step + 1 == self._dimensions \ and self.__loop + 1 >= self.__max_loops: self.request_face(self.__face) return elif self.__current_step + 1 == self._dimensions: self.__current_step = 0 self.__loop += 1 self.request_face(self.__face, 'pre') return self.request_face(self.__face, 'pre')
def __generate_face_parameters(self): """Generate random face. Based on needed parameters to iterate by and initial Face. """ parameters = self._initial_face.as_array parameters[self.__iterating_parameters] = randn( len(self.__iterating_parameters)) self.__parameters.append(parameters) self.__differences.append(None) self.__values.append(None) return Face.from_array(parameters)
def test_request_images(): results = [] images = [[0]*4, [1]*4, [2]*4] face = Face() view = View() model = Model(view) callback = lambda img: results.append(img) model.request_image(face, callback) model.request_image(face, callback) assert len(results) == 0
def __next_iteration(self): self.__loop += 1 self.__current_step = -5 coefficients = (self.__face.coefficients - self.__step * self.__derivatives[:-Face.NON_PCS_COUNT]) directed_light = ( self.__face.directed_light - self.__step * self.__derivatives[Face.LIGHT_COMPONENTS_SLICE] / 50) self.__face = Face(coefficients=coefficients, directed_light=directed_light) # print(self.__derivatives) self.request_face(self.__face, 'start_iteration')
def __get_parameter(self, i): self.__current_step = i if self.__steps[i] % 2 == 0: self.__values = linspace(-4, 4, self.__steps[i] + 1, dtype='f') else: self.__values = linspace(-4, 4, self.__steps[i] + 2, dtype='f') self.__errors = [None] * self.__values.size for i, value in enumerate(self.__values): self.__values[i] = value parameters = self.__parameters.copy() parameters[self.__current_step] = value self.request_face(Face.from_array(parameters), i)
def start(self): x0 = self._initial_face.as_array.copy() final_simplex = x0.copy() final_simplex[Face.PCS_SLICE] += self.__offset final_simplex[0:-Face.NON_PCS_COUNT:2] = 1 final_simplex[1:-Face.NON_PCS_COUNT:2] = -1 final_simplex[Face.NON_PCS_SLICE] = 1 initial_simplex = array([concatenate((x0[:i], final_simplex[i:])) for i in range(self._dimensions + 1)], 'f') options = { 'initial_simplex': initial_simplex } result = minimize(self.get_face_deviation, x0, method='nelder-mead', options=options) self.finish(Face.from_array(result))
def start(self): x0 = self._initial_face.as_array.copy() final_simplex = x0.copy() final_simplex[Face.PCS_SLICE] += self.__offset final_simplex[0:-Face.NON_PCS_COUNT:2] = 1 final_simplex[1:-Face.NON_PCS_COUNT:2] = -1 final_simplex[Face.NON_PCS_SLICE] = 1 initial_simplex = array([ concatenate((x0[:i], final_simplex[i:])) for i in range(self._dimensions + 1) ], 'f') options = {'initial_simplex': initial_simplex} result = minimize(self.get_face_deviation, x0, method='nelder-mead', options=options) self.finish(Face.from_array(result))
def receive_image(self, image, index=None): if index == 'init': return elif index == 'finish': self.finish(self.__face) return self.__errors[tuple(self.__indices)] = self.get_image_deviation(image) change_on = self.__inc_index() if change_on == -1: result = self.__convert_parameters() parameters = self._initial_face.as_array parameters[self.__levels] = result[-1][0] self.__face = Face.from_array(parameters) self.request_face(self.__face, 'finish') return self.__get_parameter(change_on=change_on)
def __calculate_result(self): """Get weighted sum of achieved parameters. Normalize probabilities as their sum should be 1. Then get sum of parameters got during iterations multiplied by corresponding probabilities. Form parameters of final face and finish the fitting procedure. """ max_difference = max(self.__differences) normalized_differences = array(self.__differences) - float( sum( Decimal(diff - max_difference).exp() for diff in self.__differences).ln()) params = [ sum( Decimal(float(p[i])) * Decimal(diff).exp() for diff, p in zip(normalized_differences, self.__parameters)) for i in self.__estimating_parameters ] parameters = self._initial_face.as_array parameters[self.__estimating_parameters] = params self.finish(Face.from_array(parameters))
def construct_chain(configuration_filename, model): fitting_settings = None with open(configuration_filename) as config: fitting_settings = json.load(config) fitters = fitting_settings['fitters'] face_parameters = fitting_settings['input'].get('initial_face', {}) coefficients = face_parameters.get('coefficients', []) directed_light = face_parameters.get('directed_light', (0., 0., 0.)) ambient_light = face_parameters.get('ambient_light', 0.) initial_face = Face(coefficients=coefficients, directed_light=directed_light, ambient_light=ambient_light) face_filename = get_datafile_path(fitting_settings['input']['input_image']) image = Image.open(face_filename).convert('L') original_data = array(image.getdata()).astype('f') / 255 image_data = original_data.reshape(image.size)[::-1, :].flatten() image.close() return FittersChain(fitters, image_data, model, initial_face=initial_face)
def calculate_reflection(self): self.__step = 'reflection' self.calculate_centroid() self.__reflection = self.__centroid + self.__alpha * \ (self.__centroid - self.__end) self.request_face(Face.from_array(self.__reflection))
def model(): view = View() face = Face() model = Model(view) model.face = face yield model
def Face(): __Face.set_initial_rotation(0, 0) yield __Face __Face.set_initial_rotation(0, 0)
args = parser.parse_args() fitting_settings = None with open(args.config) as config: fitting_settings = json.load(config) fitters = fitting_settings['fitters'] face_parameters = fitting_settings['input'].get('initial_face', {}) coefficients = face_parameters.get('coefficients', []) directed_light = face_parameters.get('directed_light', (0., 0., 0.)) ambient_light = face_parameters.get('ambient_light', 0.) initial_face = Face(coefficients=coefficients, directed_light=directed_light, ambient_light=ambient_light) model_filename = get_datafile_path(fitting_settings['input']['input_image']) image = Image.open(model_filename).convert('L') original_data = array(image.getdata()).astype('f') / 255 image_data = original_data.reshape(image.size)[::-1, :].flatten() image.close() MFM.init() view = View((500, 500)) model = Model(view) model_input = ModelInput(model) chain = FittersChain(fitters, image_data, model, initial_face=initial_face)
def start(self): parameters = self._initial_face.as_array.copy() for _ in range(self.__max_loops): parameters = self.__iteration(parameters) self.finish(Face.from_array(parameters))
def test_constructor_wrong_coefficients(value): with raises(ValueError): Face(coefficients=value)
def calculate_contraction(self): self.__step = 'contraction' self.__contraction = self.__centroid + self.__rho * \ (self.__parameters[-1] - self.__centroid) self.request_face(Face.from_array(self.__contraction))
def __get_parameter(self, change_on=0): value = self.__get_value(change_on, self.__indices[change_on]) self.__parameters[self.__levels[change_on]] = value self.__face = Face.from_array(self.__parameters) return self.get_face_deviation(self.__face)
def test_set_ambient_light(): face = Face() face.ambient_light = 0 assert allclose(face.ambient_light, 0) face.ambient_light = 1 assert allclose(face.ambient_light, 1)
def test_set_position(): face = Face() face.position = (0, 0, 0) assert allclose(face.position, (0, 0, 0)) face.position = (1, 1, 1) assert allclose(face.position, (1, 1, 1))
def test_constructor_wrong_vector3d(name, value): with raises(ValueError): Face(**{name: value})
def calculate_expansion(self): self.__step = 'expansion' self.__expansion = self.__centroid + self.__gamma * \ (self.__reflection - self.__centroid) self.request_face(Face.from_array(self.__expansion))
def test_constructor(): assert isinstance(Face(), Face)
def test_set_scale(): face = Face() face.scale = (2, 2, 2) assert allclose(face.scale, (2, 2, 2)) face.scale = (1, 1, 1) assert allclose(face.scale, (1, 1, 1))