diff --git a/code/BMPFile.py b/code/BMPFile.py index 23c4f1b..fdb337a 100644 --- a/code/BMPFile.py +++ b/code/BMPFile.py @@ -234,8 +234,8 @@ class BMPContent: self.map.append( [] ) # on créé la colonne for pixel in range(0, header.width): - newPixel = RGBPixel() - newPixel.setBin(binContent, header.width, header.padding, i, header.bpp) + newPixel = RGBPixel(y=header.height-line-1, x=pixel) + newPixel.setBin(binContent, header.width, header.padding, i, bpp=header.bpp) self.map[line].append( newPixel ); i += header.bpp / 8.0 # on passe à la suite @@ -304,13 +304,16 @@ class BMPContent: # classe contenant un pixel RGB # ################################# class RGBPixel: - def __init__(self, r=0, g=0, b=0, bpp=24): + def __init__(self, r=0, g=0, b=0, x=-1, y=-1, bpp=24): if bpp not in [1,4,8,24]: if not hasattr(self, 'bpp'): # si l'attribut n'est pas déjà défini, alors on met la valeur par défaut self.bpp = 24 else: self.bpp = bpp + self.x = x + self.y = y + self.r = r self.g = g self.b = b @@ -331,7 +334,7 @@ class RGBPixel: self.binData = chr(g) + chr(b) + chr(r) - def setRGB(self, r, g, b, bpp=24): + def setRGB(self, r, g, b,x=-1, y=-1, bpp=24): self.__init__(r, g, b, bpp); def setBin(self, binData, width, padding, index, bpp=24): diff --git a/code/Noise.py b/code/Noise.py index 6063755..9952073 100644 --- a/code/Noise.py +++ b/code/Noise.py @@ -1,6 +1,7 @@ # ~*~ encoding: utf-8 ~*~ # import random +import time class Noise: @@ -173,10 +174,10 @@ class Noise: if random.randint(0,1) == 1: maxColor = max(pixelMap[y][x].r, pixelMap[y][x].g, pixelMap[y][x].b) - randomAdd = random.randint(0, (255-maxColor) / 10 ) + randomAdd = random.randint(0, (255-maxColor) / 5 ) else: minColor = min(pixelMap[y][x].r, pixelMap[y][x].g, pixelMap[y][x].b) - randomAdd = - random.randint(0, minColor / 10 ) + randomAdd = - random.randint(0, minColor / 5 ) pixelMap[y][x].setRGB( pixelMap[y][x].r + randomAdd, @@ -489,4 +490,91 @@ class Noise: pass def Gaussian_unset(self, pixelMap, seuil=5): - pass \ No newline at end of file + pass + + + + + + + + + + + + + + + + + + + + + + + + + # récupère la forme complète autour du pixel donné # + # @param pixel pixel de base + # @param pixelMap matrice de pixels + # + # @return retourne la liste des pixels composant la forme (références) + # + # + # + # + def getShape(self, originalPixel, pixelMap, seuil=10): + width = len( pixelMap[0] ) + height = len( pixelMap ) + + shape = [] # contiendra les pixels de la forme + waiting = [originalPixel] # contient les pixels à traiter + + # on continue d'analyser tant qu'il y a des pixels à traiter + while len(waiting) > 0: + pixel = waiting[0] + + # on ajoute le pixel à la forme + shape.append( pixel ) + + xm, xM = pixel.x, pixel.x # valeurs minimales et maximales de x autour du pixel + ym, yM = pixel.y, pixel.y # valeurs minimales et maximales de y autour du pixel + + + # si on est pas sur le bord gauche + if pixel.x > 0: + xm = pixel.x - 1 + + # si on est pas sur le bord droit + if pixel.x < width-1: + xM = pixel.x + 1 + + # si on est pas sur le bord haut + if pixel.y > 0: + ym = pixel.y - 1 + + # si on est pas sur le bord bas + if pixel.y < height-1: + yM = pixel.y + 1 + + + + # on parcourt les pixels alentours + for j in range(ym, yM+1): + for i in range(xm, xM+1): + currentP = pixelMap[j][i] + # si le pixel n'a pas une couleur trop éloignée du pixel central + if abs(pixel.r-currentP.r) <= seuil and abs(pixel.g-currentP.g) <= seuil and abs(pixel.b-currentP.b) <= seuil: + # on ajoute le pixel à la liste d'attente + if not( currentP in shape or currentP in waiting): + waiting.append( currentP ) + + + # on retire le pixel de la liste d'attente + try: + waiting.remove( pixel ) + except: + pass + + return shape; \ No newline at end of file diff --git a/code/bmp.py b/code/bmp.py index 624fb3f..fd3627e 100644 --- a/code/bmp.py +++ b/code/bmp.py @@ -47,48 +47,108 @@ print "| 22) %s |" % exactLength("Difference en image", 21, -1) print "| 23) %s |" % exactLength("Fusion d'images (+)", 21, -1) print "| 24) %s |" % exactLength("Fusion d'images (-)", 21, -1) print "+---------------------------+" +print "| %s |" % exactLength("TESTS DE FORMES", 25, 0) +print "| %s |" % exactLength("", 25, 0) +print "| 30) %s |" % exactLength("Reveler une teinte", 21, -1) +print "| 31) %s |" % exactLength("Colorer une forme", 21, -1) +print "+---------------------------+" print while True: action = int( raw_input("choix: ") ) - if action >= 0 and action < 30: + if action >= 0 and action < 40: break; -print -print "+---------------------------+---------+" - +startStr = "\n+---------------------------+---------+" +result = "" execTime = Timer(); execTime.reset(); -result = "" # fichier if action == 0: - testManualCreation() # teste la création d'un fichier à partir d'une matrice uniquement + w = raw_input("width [100]: ") + h = raw_input("height [100]: ") + arg1, arg2 = 100, 100 + if w != "": + arg1 = int(w) + if h != "": + arg2 = int(h) + print startStr + testManualCreation(arg1, arg2) # teste la création d'un fichier à partir d'une matrice uniquement elif action == 1: + print startStr result = testFileIntegrity() # teste le PARSE/UNPARSE elif action == 2: + print startStr result = printIntPalette() # affiche la palette d'une image # bruits elif action == 10: - testSaltAndPepper() # teste le bruitage/débruitage de type "Sel & Poivre" + inS = raw_input("seuil bruitage [50]: ") + outS = raw_input("seuil débruitage [1] : ") + outB = raw_input("borne débruitage [1] : ") + s = raw_input("Lissage ? (0-1): ") + arg1, arg2, arg3, arg4 = 50, 1, 1, 1 + if inS != "": + arg1 = int(inS) + if outS != "": + arg2 = int(outS) + if outB != "": + arg3 = int(outB) + if s != "": + arg4 = int(s) + print startStr + testSaltAndPepper(arg1, arg2, arg3, arg4) # teste le bruitage/débruitage de type "Sel & Poivre" elif action == 11: + print startStr testAdditiveNoise() # teste le bruitage/débruitage de type "Additif" elif action == 12: + print startStr testSmooth() # teste le lissage # performances elif action == 20: + print startStr printImageQuality() # compare 2 images et donne le pourcentage de ressemblance/différence elif action == 21: + print startStr print "not implemented yet" exit() printImageQualityByPower() # compare 2 images et donne le pourcentage de ressemblance/différence (utilisant la puissance) elif action == 22: + print startStr imageForImageQuality() # crée une image correspondant aux différences de 2 images elif action == 23: + print startStr mergeImagesAdditive() # crée une image étant la fusion (addition) de 2 images elif action == 24: + print startStr mergeImagesSubstractive() # crée une image étant la fusion (soustractive) de 2 images +elif action == 30: + r = raw_input("rouge [0]: ") + g = raw_input("vert [0]: ") + b = raw_input("bleu [0]: ") + s = raw_input("seuil [50]: ") + arg1, arg2, arg3, arg4 = 0,0,0,50 + if r != "": + arg1 = int(r) + if g != "": + arg2 = int(g) + if b != "": + arg3 = int(b) + if s != "": + arg4 = int(s) + print startStr + revealShapes(arg1, arg2, arg3, arg4) # révèle la couleur spécifiée +elif action == 31: + x = raw_input("abscisses(x) [0]: ") + y = raw_input("ordonnées(y) [0]: ") + arg1, arg2 = 0,0 + if x != "": + arg1 = int(x) + if y != "": + arg2 = int(y) + print startStr + colorShape(arg1, arg2) # colorie la forme contenant le pixel de coordonnées donné else: print "Wrong choice" exit(); diff --git a/code/mask.bmp b/code/mask.bmp new file mode 100644 index 0000000..e199a71 Binary files /dev/null and b/code/mask.bmp differ diff --git a/code/shapes/1.bmp b/code/shapes/1.bmp new file mode 100644 index 0000000..2624dfe Binary files /dev/null and b/code/shapes/1.bmp differ diff --git a/code/shapes/2.bmp b/code/shapes/2.bmp new file mode 100644 index 0000000..d904526 Binary files /dev/null and b/code/shapes/2.bmp differ diff --git a/code/shapes/multi_356.bmp b/code/shapes/multi_356.bmp new file mode 100644 index 0000000..b0f3e7f Binary files /dev/null and b/code/shapes/multi_356.bmp differ diff --git a/code/shapes/rect_100.bmp b/code/shapes/rect_100.bmp new file mode 100644 index 0000000..7c28af1 Binary files /dev/null and b/code/shapes/rect_100.bmp differ diff --git a/code/shapes/start_68.bmp b/code/shapes/start_68.bmp new file mode 100644 index 0000000..3b94432 Binary files /dev/null and b/code/shapes/start_68.bmp differ diff --git a/code/tests.py b/code/tests.py index 6beae4c..d79acfc 100644 --- a/code/tests.py +++ b/code/tests.py @@ -75,6 +75,41 @@ def exactLength(text, length, position=0): +# teste la création d'image manuelle (UNPARSE) à partir d'une matrice uniquement # +################################################################################## +# @sysarg 1 le fichier de sortie +# @stsarg 2 / +# +# @history +# Unparse une matrice de pixels aléatoire de taille 100x100 +# L'enregistre dans le fichier de sortie +def testManualCreation(width=100, height=100): + + t = Timer(); + + print "| Creating Image |",; t.reset(); + img = BMPFile() + for y in range(0, height): + img.content.map.append( [] ) + for x in range(0, width): + img.content.map[y].append( RGBPixel( + random.randint(0, 255), + random.randint(0, 255), + random.randint(0, 255), + bpp=24 + ) ); + + img.unparse(); + print "%s |" % (t.get()) + + + print "| Writing Image |",; t.reset(); + img.write( sys.argv[2] ) + print "%s |" % (t.get()) + + + + # teste les fonctions PARSE et UNPARSE ########################################################## @@ -142,6 +177,39 @@ def testFileIntegrity(): +# Affiche la palette afin de savoir si elle est connue ou nouvelle # +#################################################################### +# @sysarg 1 le fichier d'entrée +# @stsarg 2 / +# +# @history +# Affiche la palette au format [] +def printIntPalette(): + img = BMPFile(); + + t = Timer(); + + print "| Reading Image |",; t.reset(); + with open( sys.argv[1] ) as file: + binFile = file.read() + print "%s |" % (t.get()) + + + print "| Parsing File |",; t.reset(); + img.parse(binFile); + print "%s |" % (t.get()) + + return img.intPalette; + + + + + + + + + + # teste les fonction de bruitage et débruitage de type "Poivre et Sel" # ######################################################################## # @sysarg 1 le fichier d'origine @@ -153,7 +221,7 @@ def testFileIntegrity(): # Parse le fichier d'origine # Bruite l'image' et l'enregistre dans "SaltAndPepper.bmp" # Débruite l'image et l'enregistre dans le fichier de sortie -def testSaltAndPepper(): +def testSaltAndPepper(seuilSet=50, seuilUnset=1, borneUnset=1, smooth=1): t = Timer(); @@ -177,7 +245,7 @@ def testSaltAndPepper(): print "| Creating Salt&Pepper |",; t.reset(); - noise.SaltAndPepper_set(img.content.map, seuil=20) + noise.SaltAndPepper_set(img.content.map, seuil=seuilSet) print "%s |" % (t.get()) # Unparsing @@ -194,12 +262,13 @@ def testSaltAndPepper(): print "| Removing Salt&Pepper |",; t.reset(); - noise.SaltAndPepper_unset(img.content.map, seuil=1, borne=1) + noise.SaltAndPepper_unset(img.content.map, seuil=seuilUnset, borne=borneUnset) print "%s |" % (t.get()) - print "| Lissage |",; t.reset(); - noise.smooth(img.content.map); - print "%s |" % (t.get()) + if smooth != 0: + print "| Lissage |",; t.reset(); + noise.smooth(img.content.map); + print "%s |" % (t.get()) # Unparsing print "| Unparsing file |",; t.reset(); @@ -355,76 +424,6 @@ def testSmooth(): -# teste la création d'image manuelle (UNPARSE) à partir d'une matrice uniquement # -################################################################################## -# @sysarg 1 le fichier de sortie -# @stsarg 2 / -# -# @history -# Unparse une matrice de pixels aléatoire de taille 100x100 -# L'enregistre dans le fichier de sortie -def testManualCreation(): - - t = Timer(); - - print "| Creating Image |",; t.reset(); - img = BMPFile() - for y in range(0, 100): - img.content.map.append( [] ) - for x in range(0, 100): - img.content.map[y].append( RGBPixel( - random.randint(0, 255), - random.randint(0, 255), - random.randint(0, 255), - bpp=24 - ) ); - - img.unparse(); - print "%s |" % (t.get()) - - - print "| Writing Image |",; t.reset(); - img.write( sys.argv[2] ) - print "%s |" % (t.get()) - - - - -# Affiche la palette afin de savoir si elle est connue ou nouvelle # -#################################################################### -# @sysarg 1 le fichier d'entrée -# @stsarg 2 / -# -# @history -# Affiche la palette au format [] -def printIntPalette(): - img = BMPFile(); - - t = Timer(); - - print "| Reading Image |",; t.reset(); - with open( sys.argv[1] ) as file: - binFile = file.read() - print "%s |" % (t.get()) - - - print "| Parsing File |",; t.reset(); - img.parse(binFile); - print "%s |" % (t.get()) - - return img.intPalette; - - - - - - - - - - - - @@ -712,35 +711,113 @@ def mergeImagesSubstractive(): -# dure environ 4min 13s -def calSaltAndPepper(): +# Révèle la couleur RGB spécifiée en blanc et le reste en noir # +################################################################ +# @sysarg 1 Image à traiter +# @stsarg 2 Image de sortie +# +# @history +# Parse le fichier d'entrée +# colore l'image +# Unparse le tout et l'enregistre dans le fichier de sortie +def revealShapes(red=0,green=0,blue=0, seuil=50): t = Timer(); - + img = BMPFile() + + rMin, rMax = red-seuil, red+seuil + gMin, gMax = green-seuil, green+seuil + bMin, bMax = blue-seuil, blue+seuil + # lecture du fichier - print "Reading Image -",; t.reset(); - with open( sys.argv[1] ) as file: - binFile = file.read() + print "| Reading file |",; t.reset(); + with open( sys.argv[1] ) as f: + binFile = f.read(); + print "%s |" % (t.get()) + + # parsage + print "| Parsing image |",; t.reset(); + img.parse( binFile ); print "%s |" % (t.get()) - img = BMPFile(); # Instanciation du BMPFile - noise = Noise(); # Instanciation du NoiseObject - - - for seuil in range(0,100,10): - for borne in range(0,30,10): - - img.parse( binFile ); - - print "SaltAndPepper (%s) (%s) -" % (seuil, borne),; t.reset(); - noise.SaltAndPepper_unset(img.content.map, seuil=seuil, borne=borne) - img.unparse(newBpp=8) - img.write( "SaltAndPepper/%s_%s.bmp" % (seuil, borne) ) - print "%s |" % (t.get()) - - + # coloration + print "| Revealing color |",; t.reset(); + for line in img.content.map: + for pixel in line: + # si on a la couleur spécifiée + if rMin <= pixel.r <= rMax and gMin <= pixel.g <= gMax and bMin <= pixel.b <= bMax: + pixel.setRGB(255,255,255) # on colore en blanc + else: + pixel.setRGB(0,0,0) # sinon on colore en noir + print "%s |" % (t.get()) + print "| Unparsing |",; t.reset(); + img.unparse(newBpp=24); + print "%s |" % (t.get()) + + print "| Writing File |",; t.reset(); + with open( sys.argv[2], "w") as f: + f.write( img.binData ); + print "%s |" % (t.get()) + + + +# Colore une la forme contenant le pixel de coordonnées donnée # +################################################################ +# @sysarg 1 Image à traiter +# @stsarg 2 Image de sortie +# +# @history +# Parse le fichier d'entrée +# colore la forme +# Unparse le tout et l'enregistre dans le fichier de sortie +def colorShape(x=0, y=0): + t = Timer(); + img = BMPFile() + noise = Noise() + + # lecture du fichier + print "| Reading file |",; t.reset(); + with open( sys.argv[1] ) as f: + binFile = f.read(); + print "%s |" % (t.get()) + + # parsage + print "| Parsing image |",; t.reset(); + img.parse( binFile ); + print "%s |" % (t.get()) + + + + # condition (si blanc uniquement) + if img.content.map[y][x].r != 255 or img.content.map[y][x].g != 255 or img.content.map[y][x].b != 255: + print "\n*** must be a WHITE pixel" + exit() + + + + + + # récupère la forme + print "| Getting shape |",; t.reset(); + shape = noise.getShape(img.content.map[y][x], img.content.map) + + # on colorie la forme en rouge + for pixel in shape: + pixel.setRGB(255,0,0); + print "%s |" % (t.get()) + + + + print "| Unparsing |",; t.reset(); + img.unparse(newBpp=24); + print "%s |" % (t.get()) + + print "| Writing File |",; t.reset(); + with open( sys.argv[2], "w") as f: + f.write( img.binData ); + print "%s |" % (t.get()) \ No newline at end of file diff --git a/docs/Noise.readme b/docs/Noise.readme index 6372d66..c3d8b6f 100644 --- a/docs/Noise.readme +++ b/docs/Noise.readme @@ -147,46 +147,64 @@ def getShapeRecursive(self, coords, pixelMap, pixelList ): # return PixelList self.getShapeRecursive( [x, y, x, y-1], pixelMap, pixelList) # 8 self.getShapeRecursive( [x, y, x+1, y-1], pixelMap, pixelList) # 9 + + +# identique à la version récursive mais sans récursivité (+ réécriture) + +### ALGO ### +HA. + On reconnaît une forme distincte par l'écart de teinte/contraste avec les alentours + A l'échelle du pixel, 2 méthodes de distinction de forme: + 1- On détecte les contours + recherche d'un contour (écart) + suivi du contour + transposition en forme + 2- détection de la forme + élargissement de zone jusqu'à un contour (écart) + + Alternative de niveau 1: + * balayage des abscisses puis racollage + +### CODE ### +def getShape(self, coords, pixelMap, pixelList): + # coords = [lastx, lasty, x, y] + width = len( pixelMap[0] ) + height = len( pixelMap ) - def getShape(self, coords, pixelMap, pixelList): - # coords = [lastx, lasty, x, y] - width = len( pixelMap[0] ) - height = len( pixelMap ) - - lastx = coords[0] - lasty = coords[1] - x = coords[2] - y = coords[3] + lastx = coords[0] + lasty = coords[1] + x = coords[2] + y = coords[3] - if x=0 and y=0: + if x=0 and y=0: - already = False; - for pix in pixelList: - if pix == pixelMap[y][x]: - already = True; - break + already = False; + for pix in pixelList: + if pix == pixelMap[y][x]: + already = True; + break - # si le pixel n'est pas déjà dans le tableau - if not already: + # si le pixel n'est pas déjà dans le tableau + if not already: - # si trop de différence - lastP = pixelMap[lasty][lastx] - pix = pixelMap[y][x] + # si trop de différence + lastP = pixelMap[lasty][lastx] + pix = pixelMap[y][x] - if abs(lastP.r-pix.r) <= 50 and abs(lastP.g-pix.g) <= 50 and abs(lastP.b-pix.b) <= 50: + if abs(lastP.r-pix.r) <= 50 and abs(lastP.g-pix.g) <= 50 and abs(lastP.b-pix.b) <= 50: - return pixelMap[y][x]; + return pixelMap[y][x]; - # self.getShape( [x, y, x-1, y+1], pixelMap, pixelList) # 1 - # self.getShape( [x, y, x, y+1], pixelMap, pixelList) # 2 - # self.getShape( [x, y, x+1, y+1], pixelMap, pixelList) # 3 + # self.getShape( [x, y, x-1, y+1], pixelMap, pixelList) # 1 + # self.getShape( [x, y, x, y+1], pixelMap, pixelList) # 2 + # self.getShape( [x, y, x+1, y+1], pixelMap, pixelList) # 3 - # self.getShape( [x, y, x-1, y ], pixelMap, pixelList) # 4 - # # current pixel - # self.getShape( [x, y, x+1, y ], pixelMap, pixelList) # 6 + # self.getShape( [x, y, x-1, y ], pixelMap, pixelList) # 4 + # # current pixel + # self.getShape( [x, y, x+1, y ], pixelMap, pixelList) # 6 - # self.getShape( [x, y, x-1, y-1], pixelMap, pixelList) # 7 - # self.getShape( [x, y, x, y-1], pixelMap, pixelList) # 8 - # self.getShape( [x, y, x+1, y-1], pixelMap, pixelList) # 9 + # self.getShape( [x, y, x-1, y-1], pixelMap, pixelList) # 7 + # self.getShape( [x, y, x, y-1], pixelMap, pixelList) # 8 + # self.getShape( [x, y, x+1, y-1], pixelMap, pixelList) # 9 - return None # return none si le pixel n'est plus de la forme \ No newline at end of file + return None # return none si le pixel n'est plus de la forme \ No newline at end of file diff --git a/dossier/Salt&Pepper.svg b/dossier/Salt&Pepper.svg new file mode 100644 index 0000000..6a26ae6 --- /dev/null +++ b/dossier/Salt&Pepper.svg @@ -0,0 +1,583 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + 1,1 + 1,2 + 1,3 + 2,3 + 3,3 + 3,2 + 3,1 + 2,1 + 2,2 + + + + + + + + + + + + 1,1 + 1,2 + 1,3 + 2,3 + 3,3 + 3,2 + 3,1 + 2,1 + 2,2 + + + + + + + + + + + + 1,1 + 1,2 + 1,3 + 2,3 + 3,3 + 3,2 + 3,1 + 2,1 + 2,2 + + +