def __init__(self, image_path: str, destination_path: str, factor: int): self.min_factor = 0 self.max_factor = int(get_greyscale( 255, 255, 255)) # max greyscale valaue for #FFFFFF if not self.min_factor < factor < self.max_factor: raise ValueError( f"Factor value should be from 0 to {self.max_factor}") self.image = Image(image_path) self.factor = factor self.destination_path = destination_path # raw error table and output image self.width, self.height = self.image.get_size() self.greyscale_image = self.image2greyscale() # error size + 1 than input image because of lack of if statements self.error_table = [[0 for _ in range(self.height + 2)] for __ in range(self.width + 2)] self.output_image = PillowImage.new("RGB", (self.width, self.height), self.WHITE) self.output_pixels = self.output_image.load() self.output_image_name = "output_floyd_steinberg.jpg"
def __init__(self, image_path: str, destination_path: str, min_blur: float, max_blur: float, sharpen_area_size: List = None): self.image_path = image_path self.destination_path = destination_path self.input_image = Image(self.image_path) self.pixels = self.input_image.pixels if not sharpen_area_size: sharpen_area_size = [0, 0] self.sharpen_min_h, self.sharpen_max_h = sharpen_area_size[ 0], sharpen_area_size[1] self.sharpen_size = self.sharpen_max_h - self.sharpen_min_h self.sharpen_center = self.sharpen_min_h + self.sharpen_size // 2 self.filter_elements = [] self.min_factor = 0.003 self.max_factor = 0.003 self.min_blur = min_blur self.max_blur = max_blur
def make_negative(image_path: str, dest_path: str): image = Image(image_path) width, height = image.get_size() output = create_empty_image(width, height) output_pixels = output.load() for x in range(width): for y in range(height): red, green, blue = image.pixels[x, y] output_pixels[x, y] = (255 - red, 255 - green, 255 - blue) output.save(dest_path)
def make_sepia(image_path: str, dest_path: str, factor: int): image = Image(image_path) width, height = image.get_size() output = create_empty_image(width, height) output_pixels = output.load() for x in range(width): for y in range(height): red, green, blue = image.pixels[x, y] grey_red = int(get_greyscale(red, green, blue)) grey_green = int(get_greyscale(red, green, blue)) grey_blue = int(get_greyscale(red, green, blue)) output_pixels[x, y] = (grey_red + 2 * factor, grey_green + factor, grey_blue) output.save(dest_path)
class FloydSteinberg: """ Floyd Stainberg algorithm using for reducng grayscale image to black and white. Source: https://en.wikipedia.org/wiki/Floyd%E2%80%93Steinberg_dithering """ BLACK = "#000000" WHITE = "#FFFFFF" def __init__(self, image_path: str, destination_path: str, factor: int): self.min_factor = 0 self.max_factor = int(get_greyscale(255, 255, 255)) # max greyscale vlaue for #FFFFFF if not self.min_factor < factor < self.max_factor: raise ValueError(f"Factor value should be from 0 to {self.max_factor}") self.image = Image(image_path) self.factor = factor self.destination_path = destination_path # raw error table and output image self.width, self.height = self.image.get_size() self.greyscale_image = self.image2greyscale() # error size + 1 than input image because of lack of if statements self.error_table = [[0 for _ in range(self.height + 2)] for __ in range(self.width + 2)] self.output_image = PillowImage.new("RGB", (self.width, self.height), self.WHITE) self.output_pixels = self.output_image.load() self.output_image_name = "output_floyd_steinberg.jpg" def image2greyscale(self): greyscale_image = PillowImage.new("RGB", (self.width, self.height), self.WHITE) pixels = greyscale_image.load() for x in range(self.width): for y in range(self.height): grey_value = int(get_greyscale(*self.image.pixels[x, y])) pixels[x, y] = (grey_value, grey_value, grey_value) greyscale_image.save(os.path.join(self.destination_path, "output_greyscale.jpg")) return greyscale_image def process(self): input_pixels = self.greyscale_image.load() for x in range(self.width): for y in range(self.height): if self.factor > input_pixels[x, y][0] + self.error_table[x][y]: self.output_pixels[x, y] = (0, 0, 0) current_error = input_pixels[x, y][0] + self.error_table[x][y] else: self.output_pixels[x, y] = (255, 255, 255) current_error = input_pixels[x, y][0] + self.error_table[x][y] - 255 # error propagation self._propagate_error(x, y, current_error) self.output_image.save(os.path.join(self.destination_path, self.output_image_name)) def _propagate_error(self, x, y, current_error): self.error_table[x + 1][y] += + 7 / 16 * current_error self.error_table[x + 1][y + 1] += 3 / 16 * current_error self.error_table[x][y + 1] += 5 / 16 * current_error self.error_table[x - 1][y + 1] += 1 / 16 * current_error
def __init__(self, image_path: str, scale: float): self.image = Image(image_path) self.scale = scale self.new_image = None
class TiltShift: """ Tilt-shift technique """ def __init__(self, image_path: str, destination_path: str, min_blur: float, max_blur: float, sharpen_area_size: List = None): self.image_path = image_path self.destination_path = destination_path self.input_image = Image(self.image_path) self.pixels = self.input_image.pixels if not sharpen_area_size: sharpen_area_size = [0, 0] self.sharpen_min_h, self.sharpen_max_h = sharpen_area_size[ 0], sharpen_area_size[1] self.sharpen_size = self.sharpen_max_h - self.sharpen_min_h self.sharpen_center = self.sharpen_min_h + self.sharpen_size // 2 self.filter_elements = [] self.min_factor = 0.003 self.max_factor = 0.003 self.min_blur = min_blur self.max_blur = max_blur @classmethod def _make_filter_factor(cls, blur: float, index: int): return (1 / (sqrt(2 * pi) * blur)) * exp(-pow(index, 2) / (2 * pow(blur, 2))) def _make_blur(self, distance: int, sharp_area_size: int): """ :param distance: distance between point and sharp area :param sharp_area_size: sharp area size height/width :return: blur value """ return abs(self.min_blur + (self.max_blur - self.min_blur) * distance / sharp_area_size) def generate_filter_elements(self, blur: float, max_factor: int): self.filter_elements = list( itertools.takewhile( self.is_gt_min_factor, [self._make_filter_factor(blur, i) for i in range(max_factor)])) def is_gt_min_factor(self, value: float): return value >= self.min_factor def process(self): width, height = self.input_image.get_size() output = create_empty_image(width, height) output_pixels = output.load() for x in range(width): for y in range(height): if self.sharpen_min_h < y < self.sharpen_max_h: output_pixels[x, y] = self.pixels[x, y] continue blur = self._make_blur(self.sharpen_center - y, self.sharpen_size) self.generate_filter_elements(blur, 7) red = self.process_horizontal(0, x, y, width - 1) green = self.process_horizontal(1, x, y, width - 1) blue = self.process_horizontal(2, x, y, width - 1) output_pixels[x, y] = (red, green, blue) for x in range(width): for y in range(height): if self.sharpen_min_h < y < self.sharpen_max_h: output_pixels[x, y] = self.pixels[x, y] continue blur = self._make_blur(self.sharpen_center - y, self.sharpen_size) self.generate_filter_elements(blur, 7) red = self.process_vertical(0, x, y, height - 1) green = self.process_vertical(1, x, y, height - 1) blue = self.process_vertical(2, x, y, height - 1) output_pixels[x, y] = (red, green, blue) output.save( os.path.join(self.destination_path, 'output_tilt_shift.jpg')) def process_horizontal(self, index, x, y, max_value): num = self.filter_elements[0] * self.pixels[x, y][index] denum = self.filter_elements[0] for i, value in enumerate(self.filter_elements[1:]): num += value * self.pixels[abs(x - i), y][ index] + value * self.pixels[min(x + 1, max_value), y][index] denum += 2 * value return int(num / denum) def process_vertical(self, index, x, y, max_index): num = self.filter_elements[0] * self.pixels[x, y][index] denum = self.filter_elements[0] for i, value in enumerate(self.filter_elements[1:]): num += value * self.pixels[x, abs(y - i)][ index] + value * self.pixels[x, min(y + i, max_index)][index] denum += 2 * value return int(num / denum)