diff --git a/projet/ReadMe.md b/projet/ReadMe.md index f1e4fc1604b0a1d6f63ca076f9dcc0344cd2771b..4ac7956056623549099a27dd275d2c0542bd8be9 100644 --- a/projet/ReadMe.md +++ b/projet/ReadMe.md @@ -1,15 +1,31 @@ - -### Images récursives -### KINADINOVA Dariya +### Images récursives +### Dariya KINADINOVA #### **06/03/24 :** - J'ai lu les documents et j'ai crée un dossier "projet" et un fichier "ReadMe.md" pour documenter le processus. #### **13/03/24 :** -- J'ai commencé à travailler sur la classe Block (j'ai commencé par _ _ init _ _ et j'ai ajouté les paramètres pour is_uniform, color et coordinates) et j'ai créé deux fonctions pour la manipulation des couleurs (pour la moyenne des couleurs et leur distance). +- J'ai commencé à travailler sur la classe Block (j'ai commencé par _ _ init _ _ et j'ai ajouté les paramètres pour is_uniform, color et coordinates) et j'ai créée deux fonctions pour la manipulation des couleurs (pour la moyenne des couleurs et leur distance). #### **20/03/24 :** -- Work on Block.py and Decouper_Image.py +- Travail sur Block.py et Decouper_Image.py #### **27/03/24 :** -- I remade functions decouper, added functions list_col and is_col_close. Made functions average_color, divide_blocks to class Block using the functions previously made. Work on Image_Recursive. +- J'ai refait les fonctions decouper, ajouté les fonctions list_col et is_col_close. J'ai créée les fonctions average_color, divide_blocks pour la classe Block en utilisant les fonctions précédemment créées. Travail sur Image_Recursive. + +#### **28/03/24 :** +- J'ai décidé de refaire la classe Block car l'algorithme récursif ne fonctionnait pas comme prévu. J'ai décidé de mettre la plupart des fonctions nécessaires à l'algorithme à l'intérieur de la classe. +- Dans block.py pour les arguments dans __init__ j'ai utilisé *args avec l'aide de sa documentation sur le site. J'ai utilisé l'argument is_uniform comme argument principal, ce qui permettra de faire la différence entre un bloc et un block contenant 4 blocs. +- Au lieu de vérifier si le bloc est uniforme, j'ai créée une fonction qui vérifie si 4 blocs sont uniformes pour l'utiliser dans l'algorithme. + +#### **29/03/24 :** +- J'ai travaillé sur image_rec, au lieu qu'il retourne une image, j'ai décidé qu'il retournerait un bloc que je transformerai en image dans le code plus tard. + +#### **30/03/24 :** +- Pour average_col, je l'ai modifié pour qu'il ne prenne pas un bloc mais quatre et qu'il envoie leur couleur moyenne, ce qui est plus utile pour image_rec. +- J'ai terminé image_rec. + +#### **31/03/24**: +- Pour transformer le bloc en image, j'ai créée une fonction block_to_image à l'intérieur de la classe. Fini la fonction main() qui permettra d'utiliser la fonction rec_algorithm dans le terminal. +- j'ai renommé certaines fonctions, ajouté des exemples, complété la docstring et ajouté des commentaires sur certaines fonctions. + diff --git a/projet/codes/Block.py b/projet/codes/Block.py deleted file mode 100644 index 71ce2572f32c4297b6fe64c2808b0c8c60a978d7..0000000000000000000000000000000000000000 --- a/projet/codes/Block.py +++ /dev/null @@ -1,64 +0,0 @@ -""" -:author: dariya kinadinova -:date: 03/2024 - -""" - -from PIL import Image, ImageDraw -from Color import * -from Decouper_Image import * - -class Block: - def __init__(self, image): - """à_remplacer_par_ce_que_fait_la_fonction - - Précondition : - Exemple(s) : - $$$ - - """ - self.image = image - self.width, self.height = image.size - - def average_color(self): - """à_remplacer_par_ce_que_fait_la_fonction - - Précondition : - Exemple(s) : - $$$ - - """ - colors = liste_col(self.image, (0, 0), (self.width-1, self.height-1)) - return avg_col(colors) - - def divide_blocks(self): - """à_remplacer_par_ce_que_fait_la_fonction - - Précondition : - Exemple(s) : - $$$ - - """ - allblocks = [] - d = decouper(self.image) - for blocks in d: - allblocks.append(Block(blocks)) - return allblocks - - def is_uniform(self, coordinates: tuple()): - """à_remplacer_par_ce_que_fait_la_fonction - - Précondition : - Exemple(s) : - $$$ - - """ - x, y = coordinates - if all(self.image.getpixel((x, y)) == self.image.getpixel((x1, y1)) for x in range(self.width) for y in range(self.height)): - return True - else: - return False - - - - diff --git a/projet/codes/Color.py b/projet/codes/Color.py deleted file mode 100644 index 59edf8928aaa8bb02a8473009897987daeb88dc9..0000000000000000000000000000000000000000 --- a/projet/codes/Color.py +++ /dev/null @@ -1,63 +0,0 @@ -""" -:author: dariya kinadinova -:date: 03/2024 - -""" - -from PIL import Image, ImageDraw - -# Color manipulation -def avg_col(l:list) -> tuple(): - """renvoie la couleur moyenne d'une liste de couleurs - - Précondition : - Exemple(s) : - $$$ avg_col([(236, 210, 111), (236, 210, 111), (236, 210, 111), (236, 210, 111)]) - (236, 210, 111) - - """ - c1 = 0 - c2 = 0 - c3 = 0 - for col in l: - c1 += col[0] - c2 += col[1] - c3 += col[2] - avg1 = c1 // len(l) - avg2 = c2 // len(l) - avg3 = c3 // len(l) - return (avg1, avg2, avg3) - -def list_col(im: Image, left_top: tuple(), right_bottom: tuple()) -> list[int]: - """return a list of colors of each pixels in the given space - - Précondition : - Exemple(s) : - $$$ list_col(Image.open('calbuth.png'), (0,0), (1, 1)) - [(236, 210, 111), (236, 210, 111), (236, 210, 111), (236, 210, 111)] - - """ - x_min, y_min = left_top - x_max, y_max = right_bottom - return [im.getpixel((x, y)) for x in range(x_max+1) for y in range(y_max+1)] - -def is_col_close(color1: tuple(), color2: tuple()) -> bool: - """returns True if the distance between two colors is not more than 30, - returns False if the distance is more than 30 - - Précondition : - Exemple(s) : - $$$ is_col_close((230, 210, 210), (236, 210, 211)) - True - $$$ is_col_close((66, 135, 245), (103, 179, 82)) - False - - """ - if (abs(color1[0] - color2[0]) <= 30) and (abs(color1[1] - color2[1]) <= 30) and (abs(color1[2] - color2[2]) <= 30): - res = True - else: - res = False - return res - - - \ No newline at end of file diff --git a/projet/codes/Decouper_Image.py b/projet/codes/Decouper_Image.py deleted file mode 100644 index ed35a02ffe585abf45aca9a2c0c379704dbf4739..0000000000000000000000000000000000000000 --- a/projet/codes/Decouper_Image.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -:author: dariya kinadinova -:date: 03/2024 - -""" - -from PIL import Image, ImageDraw - - -def decouper(im: Image) -> list[Image]: - """splits image into four blocks - - Précondition : - Exemple(s) : - $$$ - - """ - im_rgb = im.convert('RGB') - size = im_rgb.size - w = size[0] - h = size[1] - crop1 = (0, 0, (w//2), (h//2)) - block_1 = im.crop(crop1) - crop2 = ((w//2), 0, w, (h//2)) - block_2 = im.crop(crop2) - crop3 = (0, (h//2), (w//2), h) - block_3 = im.crop(crop3) - crop4 = ((h//2), (w//2), h, w) - block_4 = im.crop(crop4) - l = [block_1, block_2, block_3, block_4] - return l - - - - - - - - - - diff --git a/projet/codes/Image_Recursive.py b/projet/codes/Image_Recursive.py deleted file mode 100644 index a64489e4e49f8def7fc97453424e4c70c8c2665c..0000000000000000000000000000000000000000 --- a/projet/codes/Image_Recursive.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -:author: dariya kinadinova -:date: 03/2024 - -""" -import sys -from PIL import Image, ImageDraw -from Color import * -from Decouper_Image import * -from Block import * - -def Image_Recursive(image: Image, order: int): - """à_remplacer_par_ce_que_fait_la_fonction - - Précondition : - Exemple(s) : - $$$ - - """ - im = image.convert('RGB') - b = Block(im) - if order != 0: - allblocks = b.divide_blocks() - allb = [Image_Recursive(b1.image, order -1) for b1 in allblocks] - if all(b1.is_uniform() for b1 in allb): - avg_c = average_color([b1.color for b1 in allb]) - new_b = Block(Image.new(image.size, avg_c)) - return new_b - else: - # create a block with index or a loop - block_im = Image.new(image.size) - pass - - - -def main(): - """à_remplacer_par_ce_que_fait_la_fonction - - Précondition : - Exemple(s) : - $$$ - - """ - - \ No newline at end of file diff --git a/projet/codes/block.py b/projet/codes/block.py new file mode 100644 index 0000000000000000000000000000000000000000..b1f7c202c7b6e6eaeafe73fc8a379da72b7dc921 --- /dev/null +++ b/projet/codes/block.py @@ -0,0 +1,106 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +:mod:`block` module + +:author: Dariya Kinadinova + +:date: 03/2024 + + +""" +from PIL import Image, ImageDraw +from color_manipulation import * + +class Block: + def __init__(self, *args): + """Initialiser un nouveau bloc. + + Précondition : + Exemple(s) : + $$$ bloc1 = Block(True, (240, 189, 255)) + $$$ bloc2 = Block(True, (255, 198, 240)) + $$$ bloc3 = Block(True, (247, 185, 245)) + $$$ bloc4 = Block(True, (235, 179, 245)) + $$$ bloc1.are_4_uniform(bloc2, bloc3, bloc4) + True + $$$ bloc1.get_average_color(bloc2, bloc3, bloc4) + (244, 187, 246) + $$$ big_block = Block(False, bloc1, bloc2, bloc3, bloc4) + $$$ big_block.upper_left_block.get_average_color(big_block.upper_right_block, big_block.lower_left_block, big_block.lower_right_block) + (244, 187, 246) + + """ + assert len(args) >= 1 and len(args) <= 5 , "1, 2, 3, 4 ou 5 arguments" + self.is_uniform = args[0] + if self.is_uniform: + assert len(args) == 2, "Le bloc uniforme doit avoir deux arguments" + assert type(args[1]) == tuple and len(args[1]) == 3, "La couleur doit être un tuple de 3 éléments" + self.color = args[1] + else: + assert len(args) == 5, "Le bloc non uniforme doit avoir quatre arguments representant les sous-blocs" + self.upper_left_block = args[1] + self.upper_right_block = args[2] + self.lower_left_block = args[3] + self.lower_right_block = args[4] + + def are_4_uniform(self, block2: 'Block', block3: 'Block', block4: 'Block') -> bool: + """Vérifiez si quatre blocs différents sont uniformes. + + Précondition : doit fournir 3 blocs en plus du premier bloc + Exemple(s) : + $$$ + + """ + if self.is_uniform and block2.is_uniform and block3.is_uniform and block4.is_uniform: + return is_col_close(self.color, block2.color) and \ + is_col_close(self.color, block3.color) and \ + is_col_close(self.color, block4.color) + else: + return False + + def get_average_color(self, block2: 'Block', block3: 'Block', block4: 'Block') -> tuple: + """Calcule la couleur moyenne de quatre blocs. + + Précondition : doit fournir 3 blocs en plus du premier bloc + Exemple(s) : + $$$ + + """ + r_avg = (self.color[0] + block2.color[0] + block3.color[0] + block4.color[0]) // 4 + g_avg = (self.color[1] + block2.color[1] + block3.color[1] + block4.color[1]) // 4 + b_avg = (self.color[2] + block2.color[2] + block3.color[2] + block4.color[2]) // 4 + return (r_avg, g_avg, b_avg) + + def block_to_image(self, size: tuple) -> Image: + """Transformer un bloc en image. + + Précondition : block est un objet Block, size est un tuple représentant la taille de l'image + Exemple(s) : + $$$ + + """ + if self.is_uniform: + # Si le bloc est uniforme, une nouvelle image est cree + im = Image.new('RGB', size, self.color) + else: + # Calculer les tailles + upper_left_size = (size[0] // 2, size[1] // 2) + upper_right_size = (size[0] - upper_left_size[0], upper_left_size[1]) + lower_left_size = (upper_left_size[0], size[1] - upper_left_size[1]) + lower_right_size = (size[0] - upper_left_size[0], size[1] - upper_left_size[1]) + # transformer chaque sous-bloc en image + upper_left_im = self.upper_left_block.block_to_image(upper_left_size) + upper_right_im = self.upper_right_block.block_to_image(upper_right_size) + lower_left_im = self.lower_left_block.block_to_image(lower_left_size) + lower_right_im = self.lower_right_block.block_to_image(lower_right_size) + # Creer une nouvelle image et coller les sous-blocs + im = Image.new('RGB', size) + im.paste(upper_left_im, (0, 0)) + im.paste(upper_right_im, (upper_left_size[0], 0)) + im.paste(lower_left_im, (0, upper_left_size[1])) + im.paste(lower_right_im, (upper_left_size[0], upper_left_size[1])) + return im + + diff --git a/projet/codes/color_manipulation.py b/projet/codes/color_manipulation.py new file mode 100644 index 0000000000000000000000000000000000000000..99b8b104a562a3723153f4974a3a0b641cdf377a --- /dev/null +++ b/projet/codes/color_manipulation.py @@ -0,0 +1,90 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +:mod:`manipulation des couleurs` module + +:author: Dariya Kinadinova + +:date: 03/2024 + + +""" +from PIL import Image, ImageDraw + +# Découper l'image +def decouper(im: Image) -> list[Image]: + """Divise l'image en quatre blocs. + + Précondition : + Exemple(s) : + $$$ + + """ + im_rgb = im.convert('RGB') + size = im_rgb.size + w = size[0] + h = size[1] + crop1 = (0, 0, (w//2), (h//2)) + block_1 = im.crop(crop1) + crop2 = ((w//2), 0, w, (h//2)) + block_2 = im.crop(crop2) + crop3 = (0, (h//2), (w//2), h) + block_3 = im.crop(crop3) + crop4 = ((h//2), (w//2), h, w) + block_4 = im.crop(crop4) + l = [block_1, block_2, block_3, block_4] + return l + +# Manipulation des couleurs +def avg_col(l:list) -> tuple(): + """Renvoie la couleur moyenne d'une liste de couleurs + + Précondition : + Exemple(s) : + $$$ avg_col([(236, 210, 111), (236, 210, 111), (236, 210, 111), (236, 210, 111)]) + (236, 210, 111) + + """ + c1 = 0 + c2 = 0 + c3 = 0 + for col in l: + c1 += col[0] + c2 += col[1] + c3 += col[2] + avg1 = c1 // len(l) + avg2 = c2 // len(l) + avg3 = c3 // len(l) + return (avg1, avg2, avg3) + +def list_col(im: Image, left_top: tuple(), right_bottom: tuple()) -> list[int]: + """Renvoie une liste de tuples de couleurs pour chaque pixel de la région spécifiée de l'image. + + Précondition : + Exemple(s) : + $$$ list_col(Image.open('calbuth.png'), (0,0), (1, 1)) + [(236, 210, 111), (236, 210, 111), (236, 210, 111), (236, 210, 111)] + + """ + x_min, y_min = left_top + x_max, y_max = right_bottom + return [im.getpixel((x, y)) for x in range(x_max+1) for y in range(y_max+1)] + +def is_col_close(color1: tuple(), color2: tuple()) -> bool: + """renvoie True si la distance entre deux couleurs est inférieure ou égale à 30, + renvoie False si la distance est supérieure à 30. + + Précondition : + Exemple(s) : + $$$ is_col_close((230, 210, 210), (236, 210, 211)) + True + $$$ is_col_close((66, 135, 245), (103, 179, 82)) + False + + """ + return (abs(color1[0] - color2[0]) <= 30) and (abs(color1[1] - color2[1]) <= 30) \ + and (abs(color1[2] - color2[2]) <= 30) + + + \ No newline at end of file diff --git a/projet/codes/ex.py b/projet/codes/ex.py deleted file mode 100644 index e92031c3cc3a11cd13adff79a19614245d1bddb0..0000000000000000000000000000000000000000 --- a/projet/codes/ex.py +++ /dev/null @@ -1,12 +0,0 @@ -from PIL import Image, ImageDraw - -im = Image.open('calbuth.png') -size = im.size -w = size[0] -h = size[1] -cb1 = (0) - -crop_rectangle = (0, (h//2), (w//2), h) -cropped_im = im.crop(crop_rectangle) - -print(cropped_im.size) diff --git a/projet/codes/image_rec.py b/projet/codes/image_rec.py new file mode 100644 index 0000000000000000000000000000000000000000..686c06ca776c8a84803a7df653f147604b16b8ad --- /dev/null +++ b/projet/codes/image_rec.py @@ -0,0 +1,73 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +:mod:`image récursive` module + +:author: Dariya Kinadinova + +:date: 03/2024 + + +""" +from PIL import Image, ImageDraw +from color_manipulation import * +from block import * +import sys + +# Algorithme récursif +def rec_algorithm(image: Image, order:int): + """Cet algorithme permet de créer des blocs imbriqués les uns dans les autres \ + à partir d'une image. + + Précondition : order >= 0 + Exemple(s) : + $$$ + + """ + average_color = avg_col(list_col(image, (0, 0), (image.size[0]-1, image.size[1]-1))) + rec_blocks = [] + if order != 0: + # Divise image en quatre sous-blocs + blocks = decouper(image) + for block in blocks: + # executer l'algorithme sur chaque sous-bloc en diminuant l'ordre de 1 + rec_blocks.append(rec_algorithm(block, order-1)) + if rec_blocks[0].are_4_uniform(rec_blocks[1], rec_blocks[2], rec_blocks[3]): + # si les quatre blocs sont uniforms, alors creer un bloc uniforme de couleur \ + # la couleur moyenne des quatre blocs + res = Block(True, rec_blocks[0].get_average_color(rec_blocks[1], rec_blocks[2], \ + rec_blocks[3])) + else: + # sinon, il cee et renvoie un bloc avec les quatre blocs + res = Block(False, rec_blocks[0], rec_blocks[1], rec_blocks[2], rec_blocks[3]) + else: + # il cree et renvoie un bloc de la couleur moyenne de l'image + res = Block(True, average_color) + return res + +def main(): + """permet d'utiliser le terminal + + Précondition : + Exemple(s) : + $$$ + + """ + if len(sys.argv) != 3: + print("usage: image_rec.py image.png order") + else: + im_path = sys.argv[1] + order = int(sys.argv[2]) + im = Image.open(im_path) + block = rec_algorithm(im, order) + res_im = block.block_to_image(im.size) + res_im.show() + +if __name__ == "__main__": + main() + +# Le terminal doit être ouvert dans le dossier du projet +# Par exemple: +# $ python3 codes\image_rec.py images\calbuth.png 5 + \ No newline at end of file diff --git a/projet/codes/calbuth.png b/projet/images/calbuth.png similarity index 100% rename from projet/codes/calbuth.png rename to projet/images/calbuth.png diff --git a/projet/file.bmp b/projet/images/file.bmp similarity index 100% rename from projet/file.bmp rename to projet/images/file.bmp